diff --git a/src/MMALSharp/Components/MMALRawcamComponent.cs b/src/MMALSharp/Components/MMALRawcamComponent.cs new file mode 100644 index 00000000..5ece4175 --- /dev/null +++ b/src/MMALSharp/Components/MMALRawcamComponent.cs @@ -0,0 +1,158 @@ +// +// Copyright (c) Ian Auty. All rights reserved. +// Licensed under the MIT License. Please see LICENSE.txt for License info. +// + +using MMALSharp.Ports.Inputs; +using MMALSharp.Native; +using System; +using MMALSharp.Ports.Outputs; +using MMALSharp.Ports; +using MMALSharp.Handlers; +using System.Runtime.InteropServices; +using MMALSharp.Common.Utility; +using Microsoft.Extensions.Logging; +using static MMALSharp.MMALNativeExceptionHelper; +using static MMALSharp.Native.MMALParameters; + +namespace MMALSharp.Components +{ + /// + /// ---------------------------------------------------------------------------------------- + /// PLEASE NOTE: THIS IS AN EXPERIMENTAL COMPONENT AND IS NOT BASED ON PRODUCTION READY CODE - https://www.raspberrypi.org/forums/viewtopic.php?f=43&t=109137. + /// ---------------------------------------------------------------------------------------- + /// This component interfaces directly to the camera receiver peripheral to + /// pass the image data and metadata that is received over CSI, CCP2, or CPI. + /// It does not use the ISP or the VPU to perform any form of processing on the image. + /// There are a few options within the peripheral for converting between Bayer + /// bit depths, and packing/unpacking DPCM data - that functionality is exposed. + /// https://github.com/raspberrypi/firmware/blob/master/documentation/ilcomponents/rawcam.html + /// + public class MMALRawcamComponent : MMALDownstreamHandlerComponent + { + /// + /// Creates a new instance of the class. + /// + public unsafe MMALRawcamComponent() + : base(MMAL_COMPONENT_RAWCAM) + { + // Default to use still image port behaviour. + this.Inputs.Add(new InputPort((IntPtr)(&(*this.Ptr->Input[0])), this, Guid.NewGuid())); + this.Outputs.Add(new StillPort((IntPtr)(&(*this.Ptr->Output[0])), this, Guid.NewGuid())); + } + + /// + /// Creates a new instance of the class. + /// + /// The user defined output port type. + public unsafe MMALRawcamComponent(Type outputPortType) + : base(MMAL_COMPONENT_RAWCAM) + { + this.Inputs.Add(new InputPort((IntPtr)(&(*this.Ptr->Input[0])), this, Guid.NewGuid())); + this.Outputs.Add((IOutputPort)Activator.CreateInstance(outputPortType, (IntPtr)(&(*this.Ptr->Output[0])), this, Guid.NewGuid())); + } + + /// + public override IDownstreamComponent ConfigureOutputPort(int outputPort, IMMALPortConfig config, IOutputCaptureHandler handler) + { + if (config is MMALRawcamPortConfig) + { + var rawcamConfig = config as MMALRawcamPortConfig; + + this.ConfigureCameraInterface(rawcamConfig.CameraInterface); + this.ConfigureCameraClockingMode(rawcamConfig.ClockingMode); + this.ConfigureCameraRxConfig(rawcamConfig.RxConfig); + this.ConfigureTimingRegisters(rawcamConfig.TimingConfig); + } + else + { + MMALLog.Logger.LogWarning($"Rawcam component should be given port configuration of type {nameof(MMALRawcamPortConfig)}. Defaults will be used."); + } + + return base.ConfigureOutputPort(outputPort, config, handler); + } + + private unsafe void ConfigureCameraInterface(MMAL_CAMERA_INTERFACE_T cameraInterface) + { + MMAL_PARAMETER_CAMERA_INTERFACE_T param = new MMAL_PARAMETER_CAMERA_INTERFACE_T(new MMAL_PARAMETER_HEADER_T(MMALParametersCamera.MMAL_PARAMETER_CAMERA_INTERFACE, Marshal.SizeOf()), cameraInterface); + + IntPtr ptr = Marshal.AllocHGlobal(Marshal.SizeOf(param)); + + Marshal.StructureToPtr(param, ptr, false); + + try + { + MMALCheck( + MMALPort.mmal_port_parameter_set(this.Inputs[0].Ptr, (MMAL_PARAMETER_HEADER_T*)ptr), + "Unable to set camera interface type."); + } + finally + { + Marshal.FreeHGlobal(ptr); + } + } + + private unsafe void ConfigureCameraClockingMode(MMAL_CAMERA_CLOCKING_MODE_T clockingMode) + { + MMAL_PARAMETER_CAMERA_CLOCKING_MODE_T param = new MMAL_PARAMETER_CAMERA_CLOCKING_MODE_T(new MMAL_PARAMETER_HEADER_T(MMALParametersCamera.MMAL_PARAMETER_CAMERA_CLOCKING_MODE, Marshal.SizeOf()), clockingMode); + + IntPtr ptr = Marshal.AllocHGlobal(Marshal.SizeOf(param)); + + Marshal.StructureToPtr(param, ptr, false); + + try + { + MMALCheck( + MMALPort.mmal_port_parameter_set(this.Inputs[0].Ptr, (MMAL_PARAMETER_HEADER_T*)ptr), + "Unable to set camera clocking mode."); + } + finally + { + Marshal.FreeHGlobal(ptr); + } + } + + private unsafe void ConfigureCameraRxConfig(MMALRawcamRxConfig rxConfig) + { + MMAL_PARAMETER_CAMERA_RX_CONFIG_T param = new MMAL_PARAMETER_CAMERA_RX_CONFIG_T(new MMAL_PARAMETER_HEADER_T(MMALParametersCamera.MMAL_PARAMETER_CAMERA_RX_CONFIG, Marshal.SizeOf()), rxConfig.DecodeConfig, + rxConfig.EncodeConfig, rxConfig.UnpackConfig, rxConfig.PackConfig, rxConfig.DataLanes, rxConfig.EncodeBlockLength, rxConfig.EmbeddedDataLines, rxConfig.ImageId); + + IntPtr ptr = Marshal.AllocHGlobal(Marshal.SizeOf(param)); + + Marshal.StructureToPtr(param, ptr, false); + + try + { + MMALCheck( + MMALPort.mmal_port_parameter_set(this.Inputs[0].Ptr, (MMAL_PARAMETER_HEADER_T*)ptr), + "Unable to set camera peripheral config."); + } + finally + { + Marshal.FreeHGlobal(ptr); + } + } + + private unsafe void ConfigureTimingRegisters(MMALRawcamTimingConfig timingConfig) + { + MMAL_PARAMETER_CAMERA_RX_TIMING_T param = new MMAL_PARAMETER_CAMERA_RX_TIMING_T(new MMAL_PARAMETER_HEADER_T(MMALParametersCamera.MMAL_PARAMETER_CAMERA_RX_TIMING, Marshal.SizeOf()), timingConfig.Timing1, + timingConfig.Timing2, timingConfig.Timing3, timingConfig.Timing4, timingConfig.Timing5, timingConfig.Term1, timingConfig.Term2, + timingConfig.CpiTiming1, timingConfig.CpiTiming2); + + IntPtr ptr = Marshal.AllocHGlobal(Marshal.SizeOf(param)); + + Marshal.StructureToPtr(param, ptr, false); + + try + { + MMALCheck( + MMALPort.mmal_port_parameter_set(this.Inputs[0].Ptr, (MMAL_PARAMETER_HEADER_T*)ptr), + "Unable to set camera timing registers."); + } + finally + { + Marshal.FreeHGlobal(ptr); + } + } + } +} diff --git a/src/MMALSharp/Native/MMALParameters.cs b/src/MMALSharp/Native/MMALParameters.cs index c547fa2c..0b62e90d 100644 --- a/src/MMALSharp/Native/MMALParameters.cs +++ b/src/MMALSharp/Native/MMALParameters.cs @@ -1702,21 +1702,21 @@ public struct MMAL_PARAMETER_CAMERA_RX_CONFIG_T private MMAL_CAMERA_RX_CONFIG_ENCODE encode; private MMAL_CAMERA_RX_CONFIG_UNPACK unpack; private MMAL_CAMERA_RX_CONFIG_PACK pack; - private uint dataLanes, encodeBlockLength, embeddedDataLines, imageId; + private int dataLanes, encodeBlockLength, embeddedDataLines, imageId; public MMAL_CAMERA_RX_CONFIG_DECODE Decode => decode; public MMAL_CAMERA_RX_CONFIG_ENCODE Encode => encode; public MMAL_CAMERA_RX_CONFIG_UNPACK Unpack => unpack; public MMAL_CAMERA_RX_CONFIG_PACK Pack => pack; - public uint DataLanes => dataLanes; - public uint EncodeBlockLength => encodeBlockLength; - public uint EmbeddedDataLanes => embeddedDataLines; - public uint ImageId => imageId; + public int DataLanes => dataLanes; + public int EncodeBlockLength => encodeBlockLength; + public int EmbeddedDataLanes => embeddedDataLines; + public int ImageId => imageId; public MMAL_PARAMETER_CAMERA_RX_CONFIG_T(MMAL_PARAMETER_HEADER_T hdr, MMAL_CAMERA_RX_CONFIG_DECODE decode, MMAL_CAMERA_RX_CONFIG_ENCODE encode, MMAL_CAMERA_RX_CONFIG_UNPACK unpack, MMAL_CAMERA_RX_CONFIG_PACK pack, - uint dataLanes, uint encodeBlockLength, uint embeddedDataLines, uint imageId) + int dataLanes, int encodeBlockLength, int embeddedDataLines, int imageId) { this.Hdr = hdr; this.decode = decode; @@ -1734,20 +1734,20 @@ public MMAL_PARAMETER_CAMERA_RX_CONFIG_T(MMAL_PARAMETER_HEADER_T hdr, MMAL_CAMER public struct MMAL_PARAMETER_CAMERA_RX_TIMING_T { public MMAL_PARAMETER_HEADER_T Hdr; - private uint timing1, timing2, timing3, timing4, timing5, term1, term2, cpiTiming1, cpiTiming2; + private int timing1, timing2, timing3, timing4, timing5, term1, term2, cpiTiming1, cpiTiming2; - public uint Timing1 => timing1; - public uint Timing2 => timing2; - public uint Timing3 => timing3; - public uint Timing4 => timing4; - public uint Timing5 => timing5; - public uint Term1 => term1; - public uint Term2 => term2; - public uint CpiTiming1 => cpiTiming1; - public uint CpiTiming2 => cpiTiming2; + public int Timing1 => timing1; + public int Timing2 => timing2; + public int Timing3 => timing3; + public int Timing4 => timing4; + public int Timing5 => timing5; + public int Term1 => term1; + public int Term2 => term2; + public int CpiTiming1 => cpiTiming1; + public int CpiTiming2 => cpiTiming2; - public MMAL_PARAMETER_CAMERA_RX_TIMING_T(MMAL_PARAMETER_HEADER_T hdr, uint timing1, uint timing2, uint timing3, uint timing4, - uint timing5, uint term1, uint term2, uint cpiTiming1, uint cpiTiming2) + public MMAL_PARAMETER_CAMERA_RX_TIMING_T(MMAL_PARAMETER_HEADER_T hdr, int timing1, int timing2, int timing3, int timing4, + int timing5, int term1, int term2, int cpiTiming1, int cpiTiming2) { this.Hdr = hdr; this.timing1 = timing1; @@ -2475,11 +2475,11 @@ public static class MMALParameters public const string MMAL_COMPONENT_DEFAULT_CLOCK = "vc.clock"; public const string MMAL_COMPONENT_DEFAULT_CAMERA_INFO = "vc.camera_info"; - // @waveform80 The following two components aren't in the MMAL headers, but do exist + // @waveform80 The following components aren't in the MMAL headers, but do exist public const string MMAL_COMPONENT_DEFAULT_NULL_SINK = "vc.null_sink"; public const string MMAL_COMPONENT_DEFAULT_RESIZER = "vc.ril.resize"; - public const string MMAL_COMPONENT_ISP = "vc.ril.isp"; + public const string MMAL_COMPONENT_RAWCAM = "vc.ril.rawcam"; } [StructLayout(LayoutKind.Sequential)] diff --git a/src/MMALSharp/Ports/MMALRawcamPortConfig.cs b/src/MMALSharp/Ports/MMALRawcamPortConfig.cs new file mode 100644 index 00000000..ac9ea75f --- /dev/null +++ b/src/MMALSharp/Ports/MMALRawcamPortConfig.cs @@ -0,0 +1,60 @@ +// +// Copyright (c) Ian Auty. All rights reserved. +// Licensed under the MIT License. Please see LICENSE.txt for License info. +// + +using MMALSharp.Native; +using System; + +namespace MMALSharp.Ports +{ + /// + /// Represents a port configuration object for use with the Rawcam component. + /// + public class MMALRawcamPortConfig : MMALPortConfig + { + /// + /// The physical camera interface type. + /// + public MMAL_CAMERA_INTERFACE_T CameraInterface { get; set; } + + /// + /// Camera peripheral clocking mode. + /// + public MMAL_CAMERA_CLOCKING_MODE_T ClockingMode { get; set; } + + /// + /// The receiver peripheral configuration for unpacking/packing DPCM, and decoding or encoding Bayer images. + /// + public MMALRawcamRxConfig RxConfig { get; set; } + + /// + /// Camera peripheral timing registers. + /// + public MMALRawcamTimingConfig TimingConfig { get; set; } + + /// + /// Create a new instance of . + /// + /// The encoding type. Set this to specify the output format. Colour format should be + /// RGB565, RGB888, ABGR8888, YUV420 packed planar, YUV422 packed + /// planar, or one of the flavours of YUYV. + /// The pixel format. + /// The output bitrate. + /// Video record timeout. + /// The physical camera interface type. + /// Camera peripheral clocking mode. + /// The receiver peripheral configuration for unpacking/packing DPCM, and decoding or encoding Bayer images. + /// Camera peripheral timing registers. + public MMALRawcamPortConfig(MMALEncoding encodingType, MMALEncoding pixelFormat, int bitrate, DateTime? timeout, + MMAL_CAMERA_INTERFACE_T cameraInterface, MMAL_CAMERA_CLOCKING_MODE_T clockingMode, MMALRawcamRxConfig rxConfig, + MMALRawcamTimingConfig timingConfig) + : base(encodingType, pixelFormat, 0, bitrate, timeout, null, false) + { + this.CameraInterface = cameraInterface; + this.ClockingMode = clockingMode; + this.RxConfig = rxConfig; + this.TimingConfig = timingConfig; + } + } +} diff --git a/src/MMALSharp/Ports/MMALRawcamRxConfig.cs b/src/MMALSharp/Ports/MMALRawcamRxConfig.cs new file mode 100644 index 00000000..ba6fa0b1 --- /dev/null +++ b/src/MMALSharp/Ports/MMALRawcamRxConfig.cs @@ -0,0 +1,85 @@ +// +// Copyright (c) Ian Auty. All rights reserved. +// Licensed under the MIT License. Please see LICENSE.txt for License info. +// + +using MMALSharp.Native; + +namespace MMALSharp.Ports +{ + /// + /// The receiver peripheral configuration for unpacking/packing DPCM, and decoding or encoding Bayer images. + /// + public class MMALRawcamRxConfig + { + /// + /// Bayer decoding value. + /// + public MMAL_CAMERA_RX_CONFIG_DECODE DecodeConfig { get; set; } + + /// + /// Bayer encoding value. + /// + public MMAL_CAMERA_RX_CONFIG_ENCODE EncodeConfig { get; set; } + + /// + /// DPCM unpacking value. + /// + public MMAL_CAMERA_RX_CONFIG_UNPACK UnpackConfig { get; set; } + + /// + /// DPCM packing value. + /// + public MMAL_CAMERA_RX_CONFIG_PACK PackConfig { get; set; } + + /// + /// Unsure. + /// + public int DataLanes { get; set; } + + /// + /// Unsure. + /// + public int EncodeBlockLength { get; set; } + + /// + /// Unsure. + /// + public int EmbeddedDataLines { get; set; } + + /// + /// Unsure. + /// + public int ImageId { get; set; } + + /// + /// Creates a new instance of for use with the Rawcam component port configuration. + /// + /// Bayer decoding value. + /// Bayer encoding value. + /// DPCM unpacking value. + /// DPCM packing value. + /// Data lanes value - unsure. + /// Encode block length value - Unsure. + /// Embedded data lanes value - Unsure. + /// Image ID value - Unsure. + public MMALRawcamRxConfig(MMAL_CAMERA_RX_CONFIG_DECODE decodeConfig, + MMAL_CAMERA_RX_CONFIG_ENCODE encodeConfig, + MMAL_CAMERA_RX_CONFIG_UNPACK unpackConfig, + MMAL_CAMERA_RX_CONFIG_PACK packConfig, + int dataLanes, + int encodeBlockLength, + int embeddedDataLanes, + int imageId) + { + this.DecodeConfig = decodeConfig; + this.EncodeConfig = encodeConfig; + this.UnpackConfig = unpackConfig; + this.PackConfig = packConfig; + this.DataLanes = dataLanes; + this.EncodeBlockLength = encodeBlockLength; + this.EmbeddedDataLines = embeddedDataLanes; + this.ImageId = imageId; + } + } +} diff --git a/src/MMALSharp/Ports/MMALRawcamTimingConfig.cs b/src/MMALSharp/Ports/MMALRawcamTimingConfig.cs new file mode 100644 index 00000000..c33690f7 --- /dev/null +++ b/src/MMALSharp/Ports/MMALRawcamTimingConfig.cs @@ -0,0 +1,91 @@ +// +// Copyright (c) Ian Auty. All rights reserved. +// Licensed under the MIT License. Please see LICENSE.txt for License info. +// + +namespace MMALSharp.Ports +{ + /// + /// Camera peripheral timing registers. + /// + public class MMALRawcamTimingConfig + { + /// + /// Timing register 1 value. + /// + public int Timing1 { get; set; } + + /// + /// Timing register 2 value. + /// + public int Timing2 { get; set; } + + /// + /// Timing register 3 value. + /// + public int Timing3 { get; set; } + + /// + /// Timing register 4 value. + /// + public int Timing4 { get; set; } + + /// + /// Timing register 5 value. + /// + public int Timing5 { get; set; } + + /// + /// Unsure. + /// + public int Term1 { get; set; } + + /// + /// Unsure. + /// + public int Term2 { get; set; } + + /// + /// CPI Timing register 1 value. + /// + public int CpiTiming1 { get; set; } + + /// + /// CPI Timing register 2 value. + /// + public int CpiTiming2 { get; set; } + + /// + /// Creates a new instance of . + /// + /// Timing register 1 value. + /// Timing register 2 value. + /// Timing register 3 value. + /// Timing register 4 value. + /// Timing register 5 value. + /// Term 1 value - Unsure? + /// Term 2 value - Unsure? + /// CPI Timing register 1 value. + /// CPI Timing register 2 value. + public MMALRawcamTimingConfig(int timing1, + int timing2, + int timing3, + int timing4, + int timing5, + int term1, + int term2, + int cpiTiming1, + int cpiTiming2) + { + this.Timing1 = timing1; + this.Timing2 = timing2; + this.Timing3 = timing3; + this.Timing4 = timing4; + this.Timing5 = timing5; + this.Term1 = term1; + this.Term2 = term2; + this.CpiTiming1 = cpiTiming1; + this.CpiTiming2 = cpiTiming2; + } + } +}