未验证 提交 450ce380 编写于 作者: O Omar Raad 提交者: GitHub

Fix video capture for 32/64 arch (#1474)

* Update structs to support both 32/64 systems

* Remove TODOs

* Simplify Resolution

* Split classes into files
上级 5ce2bb28
......@@ -5,31 +5,10 @@
#pragma warning disable SA1300 // Element should begin with upper-case letter
#pragma warning disable SA1307 // Field should begin with upper-case letter
internal enum VideoSettings : int
{
VIDIOC_QUERYCAP = -2140645888,
VIDIOC_ENUM_FMT = -1069525502,
VIDIOC_CROPCAP = -1070836166,
VIDIOC_G_CROP = -1072409029,
VIDIOC_S_CROP = 1075074620,
VIDIOC_G_FMT = -1060350460,
VIDIOC_S_FMT = -1060350459,
VIDIOC_REQBUFS = -1072409080,
VIDIOC_QUERYBUF = -1069263351,
VIDIOC_STREAMON = 1074026002,
VIDIOC_STREAMOFF = 1074026003,
VIDIOC_QBUF = -1069263345,
VIDIOC_DQBUF = -1069263343,
VIDIOC_ENUM_FRAMESIZES = -1070836150,
VIDIOC_G_CTRL = -1073195493,
VIDIOC_S_CTRL = -1073195492,
VIDIOC_QUERYCTRL = -1069263324,
}
/// <summary>
/// videodev2.h Request Definition
/// </summary>
internal class RawVideoSettings
internal class V4l2Request
{
public static int VIDIOC_QUERYCAP = Interop._IOR('V', 0, typeof(v4l2_capability));
public static int VIDIOC_ENUM_FMT = Interop._IOWR('V', 2, typeof(v4l2_fmtdesc));
......@@ -57,4 +36,4 @@ internal class RawVideoSettings
public static int VIDIOC_S_PRIORITY = Interop._IOW('V', 68, typeof(uint));
public static int VIDIOC_ENUM_FRAMESIZES = Interop._IOWR('V', 74, typeof(v4l2_frmsizeenum));
public static int VIDIOC_PREPARE_BUF = Interop._IOWR('V', 93, typeof(v4l2_buffer));
}
\ No newline at end of file
}
......@@ -132,17 +132,35 @@ internal enum v4l2_colorspace : uint
V4L2_COLORSPACE_RAW = 11,
}
[StructLayout(LayoutKind.Sequential)]
[StructLayout(LayoutKind.Explicit)]
internal struct v4l2_pix_format
{
[FieldOffset(0)]
public uint width;
[FieldOffset(4)]
public uint height;
[FieldOffset(8)]
public PixelFormat pixelformat;
[FieldOffset(12)]
public v4l2_field field;
[FieldOffset(16)]
public uint bytesperline;
[FieldOffset(20)]
public uint sizeimage;
[FieldOffset(24)]
public v4l2_colorspace colorspace;
[FieldOffset(28)]
public uint priv;
[FieldOffset(32)]
public uint flags;
[FieldOffset(36)]
public uint ycbcr_enc;
[FieldOffset(36)]
public uint hsv_enc;
[FieldOffset(40)]
public uint quantization;
[FieldOffset(44)]
public uint xfer_func;
}
[StructLayout(LayoutKind.Sequential)]
......@@ -174,39 +192,33 @@ internal unsafe struct v4l2_window
}
[StructLayout(LayoutKind.Sequential)]
internal struct v4l2_vbi_format
internal unsafe struct v4l2_vbi_format
{
public uint sampling_rate;
public uint offset;
public uint samples_per_line;
public uint sample_format;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
public uint[] start;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
public uint[] count;
public fixed int start[2];
public fixed uint count[2];
public uint flags;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
public uint[] reserved;
public fixed uint reserved[2];
}
[StructLayout(LayoutKind.Sequential)]
internal struct v4l2_sliced_vbi_format
internal unsafe struct v4l2_sliced_vbi_format
{
public uint service_set;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 48)]
public ushort[] service_lines;
public ushort service_set;
public fixed ushort service_lines[48];
public uint io_size;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
public uint[] reserved;
public fixed uint reserved[2];
}
[StructLayout(LayoutKind.Sequential)]
internal struct v4l2_sdr_format
internal unsafe struct v4l2_sdr_format
{
public PixelFormat pixelformat;
public uint buffersize;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 24)]
public byte[] reserved;
public fixed byte reserved[24];
}
[StructLayout(LayoutKind.Sequential)]
......@@ -216,20 +228,26 @@ internal struct v4l2_meta_format
public uint buffersize;
}
[StructLayout(LayoutKind.Sequential)]
internal struct fmt
[StructLayout(LayoutKind.Explicit)]
internal unsafe struct fmt
{
[FieldOffset(0)]
public v4l2_pix_format pix;
[FieldOffset(0)]
public v4l2_window win;
[FieldOffset(0)]
public v4l2_vbi_format vbi;
[FieldOffset(0)]
public v4l2_sliced_vbi_format sliced;
[FieldOffset(0)]
public v4l2_sdr_format sdr;
[FieldOffset(0)]
public v4l2_meta_format meta;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 200)]
public byte[] raw;
[FieldOffset(0)]
public fixed byte raw[200];
}
[StructLayout(LayoutKind.Sequential, Size = 204)]
[StructLayout(LayoutKind.Sequential)]
internal struct v4l2_format
{
public v4l2_buf_type type;
......@@ -309,8 +327,8 @@ internal struct v4l2_buffer
[StructLayout(LayoutKind.Sequential)]
public struct timeval
{
public uint tv_sec;
public uint tv_usec;
public nint tv_sec;
public nint tv_usec;
}
public timeval timestamp;
......@@ -325,7 +343,7 @@ internal struct v4l2_buffer
[FieldOffset(0)]
public uint offset;
[FieldOffset(0)]
public uint userptr;
public nuint userptr;
}
public m_union m;
......@@ -335,16 +353,21 @@ internal struct v4l2_buffer
public uint reserved;
}
[StructLayout(LayoutKind.Sequential)]
internal struct v4l2_frmsizeenum
[StructLayout(LayoutKind.Explicit)]
internal unsafe struct v4l2_frmsizeenum
{
[FieldOffset(0)]
public uint index;
[FieldOffset(4)]
public PixelFormat pixel_format;
[FieldOffset(8)]
public v4l2_frmsizetypes type;
[FieldOffset(12)]
public v4l2_frmsize_discrete discrete;
[FieldOffset(12)]
public v4l2_frmsize_stepwise stepwise;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
public uint[] reserved;
[FieldOffset(36)]
public fixed uint reserved[2];
}
[StructLayout(LayoutKind.Sequential)]
......
......@@ -111,14 +111,14 @@ namespace Iot.Device.Media
{
id = type
};
V4l2Struct(VideoSettings.VIDIOC_QUERYCTRL, ref query);
V4l2Struct(V4l2Request.VIDIOC_QUERYCTRL, ref query);
// Get current value
v4l2_control ctrl = new v4l2_control
{
id = type,
};
V4l2Struct(VideoSettings.VIDIOC_G_CTRL, ref ctrl);
V4l2Struct(V4l2Request.VIDIOC_G_CTRL, ref ctrl);
return new VideoDeviceValue(
type.ToString(),
......@@ -144,7 +144,7 @@ namespace Iot.Device.Media
};
List<PixelFormat> result = new List<PixelFormat>();
while (V4l2Struct(VideoSettings.VIDIOC_ENUM_FMT, ref fmtdesc) != -1)
while (V4l2Struct(V4l2Request.VIDIOC_ENUM_FMT, ref fmtdesc) != -1)
{
result.Add(fmtdesc.pixelformat);
fmtdesc.index++;
......@@ -158,7 +158,7 @@ namespace Iot.Device.Media
/// </summary>
/// <param name="format">Pixel format.</param>
/// <returns>Supported resolution.</returns>
public override IEnumerable<(uint Width, uint Height)> GetPixelFormatResolutions(PixelFormat format)
public override IEnumerable<Resolution> GetPixelFormatResolutions(PixelFormat format)
{
Initialize();
......@@ -168,10 +168,66 @@ namespace Iot.Device.Media
pixel_format = format
};
List<(uint Width, uint Height)> result = new List<(uint Width, uint Height)>();
while (V4l2Struct(VideoSettings.VIDIOC_ENUM_FRAMESIZES, ref size) != -1)
List<Resolution> result = new List<Resolution>();
while (V4l2Struct(V4l2Request.VIDIOC_ENUM_FRAMESIZES, ref size) != -1)
{
result.Add((size.discrete.width, size.discrete.height));
Resolution resolution;
switch (size.type)
{
case v4l2_frmsizetypes.V4L2_FRMSIZE_TYPE_DISCRETE:
resolution = new Resolution
{
Type = ResolutionType.Discrete,
MinHeight = size.discrete.height,
MaxHeight = size.discrete.height,
StepHeight = 0,
MinWidth = size.discrete.width,
MaxWidth = size.discrete.width,
StepWidth = 0,
};
break;
case v4l2_frmsizetypes.V4L2_FRMSIZE_TYPE_CONTINUOUS:
resolution = new Resolution
{
Type = ResolutionType.Continuous,
MinHeight = size.stepwise.min_height,
MaxHeight = size.stepwise.max_height,
StepHeight = 1,
MinWidth = size.stepwise.min_width,
MaxWidth = size.stepwise.max_width,
StepWidth = 1,
};
break;
case v4l2_frmsizetypes.V4L2_FRMSIZE_TYPE_STEPWISE:
resolution = new Resolution
{
Type = ResolutionType.Stepwise,
MinHeight = size.stepwise.min_height,
MaxHeight = size.stepwise.max_height,
StepHeight = size.stepwise.step_height,
MinWidth = size.stepwise.min_width,
MaxWidth = size.stepwise.max_width,
StepWidth = size.stepwise.step_width,
};
break;
default:
resolution = new Resolution
{
Type = ResolutionType.Discrete,
MinHeight = 0,
MaxHeight = 0,
StepHeight = 0,
MinWidth = 0,
MaxWidth = 0,
StepWidth = 0,
};
break;
}
result.Add(resolution);
size.index++;
}
......@@ -184,12 +240,12 @@ namespace Iot.Device.Media
{
// Start data stream
v4l2_buf_type type = v4l2_buf_type.V4L2_BUF_TYPE_VIDEO_CAPTURE;
Interop.ioctl(_deviceFileDescriptor, (int)VideoSettings.VIDIOC_STREAMON, new IntPtr(&type));
Interop.ioctl(_deviceFileDescriptor, V4l2Request.VIDIOC_STREAMON, new IntPtr(&type));
byte[] dataBuffer = GetFrameData(buffers);
// Close data stream
Interop.ioctl(_deviceFileDescriptor, (int)VideoSettings.VIDIOC_STREAMOFF, new IntPtr(&type));
Interop.ioctl(_deviceFileDescriptor, V4l2Request.VIDIOC_STREAMOFF, new IntPtr(&type));
UnmappingFrameBuffers(buffers);
......@@ -205,7 +261,7 @@ namespace Iot.Device.Media
type = v4l2_buf_type.V4L2_BUF_TYPE_VIDEO_CAPTURE,
memory = v4l2_memory.V4L2_MEMORY_MMAP,
};
V4l2Struct(VideoSettings.VIDIOC_DQBUF, ref frame);
V4l2Struct(V4l2Request.VIDIOC_DQBUF, ref frame);
// Get data from pointer
IntPtr intptr = buffers[frame.index].Start;
......@@ -213,7 +269,7 @@ namespace Iot.Device.Media
Marshal.Copy(source: intptr, destination: dataBuffer, startIndex: 0, length: (int)buffers[frame.index].Length);
// Requeue the buffer
V4l2Struct(VideoSettings.VIDIOC_QBUF, ref frame);
V4l2Struct(V4l2Request.VIDIOC_QBUF, ref frame);
return dataBuffer;
}
......@@ -227,7 +283,7 @@ namespace Iot.Device.Media
type = v4l2_buf_type.V4L2_BUF_TYPE_VIDEO_CAPTURE,
memory = v4l2_memory.V4L2_MEMORY_MMAP
};
V4l2Struct(VideoSettings.VIDIOC_REQBUFS, ref req);
V4l2Struct(V4l2Request.VIDIOC_REQBUFS, ref req);
// Mapping the applied buffer to user space
V4l2FrameBuffer[] buffers = new V4l2FrameBuffer[BufferCount];
......@@ -239,7 +295,7 @@ namespace Iot.Device.Media
type = v4l2_buf_type.V4L2_BUF_TYPE_VIDEO_CAPTURE,
memory = v4l2_memory.V4L2_MEMORY_MMAP
};
V4l2Struct(VideoSettings.VIDIOC_QUERYBUF, ref buffer);
V4l2Struct(V4l2Request.VIDIOC_QUERYBUF, ref buffer);
buffers[i].Length = buffer.length;
buffers[i].Start = Interop.mmap(IntPtr.Zero, (int)buffer.length, MemoryMappedProtections.PROT_READ | MemoryMappedProtections.PROT_WRITE, MemoryMappedFlags.MAP_SHARED, _deviceFileDescriptor, (int)buffer.m.offset);
......@@ -254,7 +310,7 @@ namespace Iot.Device.Media
type = v4l2_buf_type.V4L2_BUF_TYPE_VIDEO_CAPTURE,
memory = v4l2_memory.V4L2_MEMORY_MMAP
};
V4l2Struct(VideoSettings.VIDIOC_QBUF, ref buffer);
V4l2Struct(V4l2Request.VIDIOC_QBUF, ref buffer);
}
return buffers;
......@@ -278,7 +334,7 @@ namespace Iot.Device.Media
}
}
};
V4l2Struct(VideoSettings.VIDIOC_S_FMT, ref format);
V4l2Struct(V4l2Request.VIDIOC_S_FMT, ref format);
// Set exposure type
v4l2_control ctrl = new v4l2_control
......@@ -286,83 +342,83 @@ namespace Iot.Device.Media
id = VideoDeviceValueType.ExposureType,
value = (int)Settings.ExposureType
};
V4l2Struct(VideoSettings.VIDIOC_S_CTRL, ref ctrl);
V4l2Struct(V4l2Request.VIDIOC_S_CTRL, ref ctrl);
// Set exposure time
// If exposure type is auto, this field is invalid
ctrl.id = VideoDeviceValueType.ExposureTime;
ctrl.value = Settings.ExposureTime;
V4l2Struct(VideoSettings.VIDIOC_S_CTRL, ref ctrl);
V4l2Struct(V4l2Request.VIDIOC_S_CTRL, ref ctrl);
// Set brightness
ctrl.id = VideoDeviceValueType.Brightness;
ctrl.value = Settings.Brightness;
V4l2Struct(VideoSettings.VIDIOC_S_CTRL, ref ctrl);
V4l2Struct(V4l2Request.VIDIOC_S_CTRL, ref ctrl);
// Set contrast
ctrl.id = VideoDeviceValueType.Contrast;
ctrl.value = Settings.Contrast;
V4l2Struct(VideoSettings.VIDIOC_S_CTRL, ref ctrl);
V4l2Struct(V4l2Request.VIDIOC_S_CTRL, ref ctrl);
// Set saturation
ctrl.id = VideoDeviceValueType.Saturation;
ctrl.value = Settings.Saturation;
V4l2Struct(VideoSettings.VIDIOC_S_CTRL, ref ctrl);
V4l2Struct(V4l2Request.VIDIOC_S_CTRL, ref ctrl);
// Set sharpness
ctrl.id = VideoDeviceValueType.Sharpness;
ctrl.value = Settings.Sharpness;
V4l2Struct(VideoSettings.VIDIOC_S_CTRL, ref ctrl);
V4l2Struct(V4l2Request.VIDIOC_S_CTRL, ref ctrl);
// Set gain
ctrl.id = VideoDeviceValueType.Gain;
ctrl.value = Settings.Gain;
V4l2Struct(VideoSettings.VIDIOC_S_CTRL, ref ctrl);
V4l2Struct(V4l2Request.VIDIOC_S_CTRL, ref ctrl);
// Set gamma
ctrl.id = VideoDeviceValueType.Gamma;
ctrl.value = Settings.Gamma;
V4l2Struct(VideoSettings.VIDIOC_S_CTRL, ref ctrl);
V4l2Struct(V4l2Request.VIDIOC_S_CTRL, ref ctrl);
// Set power line frequency
ctrl.id = VideoDeviceValueType.PowerLineFrequency;
ctrl.value = (int)Settings.PowerLineFrequency;
V4l2Struct(VideoSettings.VIDIOC_S_CTRL, ref ctrl);
V4l2Struct(V4l2Request.VIDIOC_S_CTRL, ref ctrl);
// Set white balance effect
ctrl.id = VideoDeviceValueType.WhiteBalanceEffect;
ctrl.value = (int)Settings.WhiteBalanceEffect;
V4l2Struct(VideoSettings.VIDIOC_S_CTRL, ref ctrl);
V4l2Struct(V4l2Request.VIDIOC_S_CTRL, ref ctrl);
// Set white balance temperature
ctrl.id = VideoDeviceValueType.WhiteBalanceTemperature;
ctrl.value = Settings.WhiteBalanceTemperature;
V4l2Struct(VideoSettings.VIDIOC_S_CTRL, ref ctrl);
V4l2Struct(V4l2Request.VIDIOC_S_CTRL, ref ctrl);
// Set color effect
ctrl.id = VideoDeviceValueType.ColorEffect;
ctrl.value = (int)Settings.ColorEffect;
V4l2Struct(VideoSettings.VIDIOC_S_CTRL, ref ctrl);
V4l2Struct(V4l2Request.VIDIOC_S_CTRL, ref ctrl);
// Set scene mode
ctrl.id = VideoDeviceValueType.SceneMode;
ctrl.value = (int)Settings.SceneMode;
V4l2Struct(VideoSettings.VIDIOC_S_CTRL, ref ctrl);
V4l2Struct(V4l2Request.VIDIOC_S_CTRL, ref ctrl);
// Set rotate
ctrl.id = VideoDeviceValueType.Rotate;
ctrl.value = Settings.Rotate;
V4l2Struct(VideoSettings.VIDIOC_S_CTRL, ref ctrl);
V4l2Struct(V4l2Request.VIDIOC_S_CTRL, ref ctrl);
// Set horizontal flip
ctrl.id = VideoDeviceValueType.HorizontalFlip;
ctrl.value = Settings.HorizontalFlip ? 1 : 0;
V4l2Struct(VideoSettings.VIDIOC_S_CTRL, ref ctrl);
V4l2Struct(V4l2Request.VIDIOC_S_CTRL, ref ctrl);
// Set vertical flip
ctrl.id = VideoDeviceValueType.VerticalFlip;
ctrl.value = Settings.VerticalFlip ? 1 : 0;
V4l2Struct(VideoSettings.VIDIOC_S_CTRL, ref ctrl);
V4l2Struct(V4l2Request.VIDIOC_S_CTRL, ref ctrl);
}
private void FillVideoConnectionSettings()
......@@ -488,7 +544,7 @@ namespace Iot.Device.Media
/// <param name="request">V4L2 request value</param>
/// <param name="struct">The struct need to be read or set</param>
/// <returns>The ioctl result</returns>
private int V4l2Struct<T>(VideoSettings request, ref T @struct)
private int V4l2Struct<T>(int request, ref T @struct)
where T : struct
{
IntPtr ptr = Marshal.AllocHGlobal(Marshal.SizeOf(@struct));
......
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
namespace Iot.Device.Media
{
/// <summary>
/// The resolution of a video device.
/// </summary>
public class Resolution
{
/// <summary>
/// Resolution's type
/// </summary>
public ResolutionType Type { get; set; }
/// <summary>
/// Resolution's minimum height
/// </summary>
public uint MinHeight { get; set; }
/// <summary>
/// Resolution's maximum height
/// </summary>
public uint MaxHeight { get; set; }
/// <summary>
/// Resolution's step for height
/// </summary>
public uint StepHeight { get; set; }
/// <summary>
/// Resolution's minimum width
/// </summary>
public uint MinWidth { get; set; }
/// <summary>
/// Resolution's maximum width
/// </summary>
public uint MaxWidth { get; set; }
/// <summary>
/// Resolution's step for width
/// </summary>
public uint StepWidth { get; set; }
}
}
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
namespace Iot.Device.Media
{
/// <summary>
/// The resolution type of a video device.
/// </summary>
public enum ResolutionType : uint
{
/// <summary>
/// Discrete
/// </summary>
Discrete = v4l2_frmsizetypes.V4L2_FRMSIZE_TYPE_DISCRETE,
/// <summary>
/// Continuous
/// </summary>
Continuous = v4l2_frmsizetypes.V4L2_FRMSIZE_TYPE_CONTINUOUS,
/// <summary>
/// Stepwise
/// </summary>
Stepwise = v4l2_frmsizetypes.V4L2_FRMSIZE_TYPE_STEPWISE
}
}
......@@ -75,7 +75,7 @@ namespace Iot.Device.Media
/// </summary>
/// <param name="format">Pixel format.</param>
/// <returns>Supported resolution.</returns>
public abstract IEnumerable<(uint Width, uint Height)> GetPixelFormatResolutions(PixelFormat format);
public abstract IEnumerable<Resolution> GetPixelFormatResolutions(PixelFormat format);
/// <inheritdoc/>
public void Dispose()
......
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.1</TargetFramework>
<TargetFramework>net5.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
......
......@@ -20,7 +20,7 @@ Console.WriteLine();
// Get the resolutions of the format
foreach (var resolution in device.GetPixelFormatResolutions(PixelFormat.YUYV))
{
Console.Write($"{resolution.Width}x{resolution.Height} ");
Console.Write($"[{resolution.MinWidth}x{resolution.MinHeight}]->[{resolution.MaxWidth}x{resolution.MaxHeight}], Step [{resolution.StepWidth},{resolution.StepHeight}] ");
}
Console.WriteLine();
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册