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;
+ }
+ }
+}