我想Video4Linux的在我的管理應用程序集成。事實上,我已經宣佈了所有必需的結構和相對的ioctl。在這個問題上我提出了兩種ioctl
:SetFormat
和GetFormat
;而前者運行良好(就像我實際使用的其他打法一樣),後者正在返回我糟糕的記憶行爲。C#聯盟結構編組站
的GetFormat
IOCTL是實際執行,但一旦應用程序被訪問到的ioctl參數(無論是調試器或我的應用程序本身),它總是與下面的堆棧崩潰:
System.NullReferenceException: ...
at System.String.mempy4(...) in <filename unknown>:0
at System.String.memcpy(...) in <filename unknown>:0
at Derm.Platform.Video4Linux.ControlGetFormat(...) in <...>
...
我上過一些調查p/invoking ioctl,再次,我不明白爲什麼我的應用程序崩潰。我懷疑這是監守結構的內存佈局,但我無法解釋爲什麼SetFormat
工作而GetFormat
沒有(因爲它們使用了同樣的參數)。使用以下格式,
struct v4l2_format {
enum v4l2_buf_type type;
union {
struct v4l2_pix_format pix; /* V4L2_BUF_TYPE_VIDEO_CAPTURE */
struct v4l2_pix_format_mplane pix_mp; /* V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE */
struct v4l2_window win; /* V4L2_BUF_TYPE_VIDEO_OVERLAY */
struct v4l2_vbi_format vbi; /* V4L2_BUF_TYPE_VBI_CAPTURE */
struct v4l2_sliced_vbi_format sliced; /* V4L2_BUF_TYPE_SLICED_VBI_CAPTURE */
__u8 raw_data[200]; /* user-defined */
} fmt;
};
struct v4l2_pix_format {
__u32 width;
__u32 height;
__u32 pixelformat;
enum v4l2_field field;
__u32 bytesperline; /* for padding, zero if unused */
__u32 sizeimage;
enum v4l2_colorspace colorspace;
__u32 priv; /* private data, depends on pixelformat */
};
我traduced結構v4l2_format
[StructLayout(LayoutKind.Explicit, Pack = 4, CharSet = CharSet.Ansi)]
public struct Format
{
public Format(BufferType bufferType)
{
Type = bufferType;
Pixmap = new PixmapFormat();
RawData = new byte[RawDataLength];
}
public Format(BufferType bufferType, PixmapFormat pixmapFormat)
{
Type = bufferType;
Pixmap = pixmapFormat;
RawData = new byte[RawDataLength];
}
[FieldOffset(0)]
public BufferType Type;
[FieldOffset(4)]
public PixmapFormat Pixmap;
[FieldOffset(4)]
[MarshalAs(UnmanagedType.ByValArray, SizeConst=RawDataLength)]
public byte[] RawData;
public const int RawDataLength = 200;
}
[StructLayout(LayoutKind.Sequential, Pack = 4)]
public struct PixmapFormat
{
public PixmapFormat(uint width, uint height, PixelFormatCode pixelFormat)
{
Width = width;
Height = height;
PixelFormat = pixelFormat;
Field = Video4Linux.BufferField.Any;
BytesPerLine = 0;
SizeImage = 0;
Colorspace = Video4Linux.PixelColorspace.None;
Private = 0;
}
public UInt32 Width;
public UInt32 Height;
public PixelFormatCode PixelFormat;
public BufferField Field;
public UInt32 BytesPerLine;
public UInt32 SizeImage;
public PixelColorspace Colorspace;
public UInt32 Private;
}
最後,在這裏:
我要的P/Invoke一個ioctl
常規接收/返回結構v4l2_format
是調用ioctl的方法:
public static void ControlGetFormat(IntPtr fd, BufferType pixmapType, out PixmapFormat pixmapFormat)
{
if (fd == IntPtr.Zero)
throw new ArgumentException("invalid file descriptor", "fd");
Format format = new Format(pixmapType);
int result = IoCtrlGetFormat(fd, GetFormat.ControlCode, ref format);
if (result < 0)
ThrowExceptionOnError();
pixmapFormat = format.Pixmap;
}
private static readonly IoCtrlRequest GetFormat = new IoCtrlRequest(IoCtrlDirection.Read | IoCtrlDirection.Write, 'V', 4, typeof(Format));
[DllImport("libc", EntryPoint = "ioctl", SetLastError = true)]
private static extern int IoCtrlGetFormat(IntPtr fd, Int32 code, ref Format argument);
public static void ControlSetFormat(IntPtr fd, BufferType pixmapType, ref PixmapFormat pixmapFormat)
{
if (fd == IntPtr.Zero)
throw new ArgumentException("invalid file descriptor", "fd");
PixmapFormat pixmapFormatCopy = pixmapFormat;
Format format = new Format(pixmapType, pixmapFormatCopy);
int result = IoCtrlSetFormat(fd, SetFormat.ControlCode, ref format);
if (result < 0)
ThrowExceptionOnError();
pixmapFormat = format.Pixmap;
}
private static readonly IoCtrlRequest SetFormat = new IoCtrlRequest(IoCtrlDirection.Read | IoCtrlDirection.Write, 'V', 5, typeof(Format));
[DllImport("libc", EntryPoint = "ioctl", SetLastError = true)]
private static extern int IoCtrlSetFormat(IntPtr fd, Int32 code, ref Format argument);
我不認爲當領域之一是一個對象,具有明確工會可以工作。我會嘗試使用順序佈局,只聲明數組字段。然後使用Marshal類讀取/寫入其他字段。 –
除了數組之外,一切都是結構。是否有可能強制結構大小,排除數組字段? – Luca
我很想將v4l結構包裝成更簡單的方法,並且有非託管函數來在它們之間進行轉換 – IanNorton