/// <summary> /// Accept the input buffers to be processed. You'll want to read /// the MSDN docs on this one. One point worth noting is that DMO /// doesn't require that one complete block be passed at a time. /// Picture a case where raw data is being read from a file, and your /// DMO is the first to process it. The chunk of data you receive /// might represent one image, 5 images, half an image, etc. Likewise, /// your input could contain both video and audio that you are splitting /// into two output streams. /// That helps explain some of the parameters you see here and in /// InternalProcessOutput. /// Note that while DMO doesn't insist on it, for this sample, we /// specifically request that only complete buffers be provided. /// </summary> /// <param name="inputStreamIndex">Stream Index</param> /// <param name="mediaBuffer">Interface that holds the input data</param> /// <param name="flags">Flags to control input processing</param> /// <param name="timestamp">Timestamp of the sample</param> /// <param name="timelength">Duration of the sample</param> /// <returns>S_FALSE if there is no output, S_OK otherwise</returns> protected override int InternalProcessInput( int inputStreamIndex, [In] IMediaBuffer mediaBuffer, DMOInputDataBuffer flags, long timestamp, long timelength) { // Check state - if we already have a buffer, we shouldn't be getting another Debug.Assert(this.inputStreams[inputStreamIndex].Buffer == null, "We already have a buffer, we shouldn't be getting another"); IntPtr bufferPointer; int bufferByteCount; int hr = mediaBuffer.GetBufferAndLength(out bufferPointer, out bufferByteCount); this.inputStreams[inputStreamIndex].BufferPointer = bufferPointer; this.inputStreams[inputStreamIndex].BufferByteCount = bufferByteCount; if (hr >= 0) { // Ignore zero length buffers if (this.inputStreams[inputStreamIndex].BufferByteCount > 0) { this.inputStreams[inputStreamIndex].Buffer = mediaBuffer; // Cast the input flags to become output flags this.bufferFlags = (DMOOutputDataBufferFlags)flags; // If there is a time, store it if (0 == (flags & DMOInputDataBuffer.Time)) { this.inputStreams[inputStreamIndex].BufferTimeStamp = MaxTime; } else { this.inputStreams[inputStreamIndex].BufferTimeStamp = timestamp; } // If there is a TimeLength, store it if (0 == (flags & DMOInputDataBuffer.TimeLength)) { this.inputStreams[inputStreamIndex].BufferTimeLength = -1; } else { this.inputStreams[inputStreamIndex].BufferTimeLength = timelength; } hr = SOK; } else { this.ReleaseInputBuffs(inputStreamIndex); hr = SFALSE; } } return(hr); }
/// <summary> /// Accept the input buffers to be processed. You'll want to read /// the MSDN docs on this one. One point worth noting is that DMO /// doesn't require that one complete block be passed at a time. /// Picture a case where raw data is being read from a file, and your /// DMO is the first to process it. The chunk of data you receive /// might represent one image, 5 images, half an image, etc. Likewise, /// your input could contain both video and audio that you are splitting /// into two output streams. /// That helps explain some of the parameters you see here and in /// InternalProcessOutput. /// Note that while DMO doesn't insist on it, for this sample, we /// specifically request that only complete buffers be provided. /// </summary> /// <param name="dwInputStreamIndex">Stream Index</param> /// <param name="pBuffer">Interface that holds the input data</param> /// <param name="dwFlags">Flags to control input processing</param> /// <param name="rtTimestamp">Timestamp of the sample</param> /// <param name="rtTimelength">Duration of the sample</param> /// <returns>S_FALSE if there is no output, S_OK otherwise</returns> override protected int InternalProcessInput( int dwInputStreamIndex, [In] IMediaBuffer pBuffer, DMOInputDataBuffer dwFlags, long rtTimestamp, long rtTimelength) { // Check state - if we already have a buffer, we shouldn't be getting another Debug.Assert(m_pBuffer == null); int cbData; int hr = pBuffer.GetBufferAndLength(out m_InBuffer, out m_cbInData); if (hr >= 0) { // Ignore zero length buffers if (m_cbInData > 0) { m_pBuffer = pBuffer; // Cast the input flags to become output flags m_Flags = (DMOOutputDataBufferFlags)dwFlags; // If there is a time, store it if (0 == (dwFlags & DMOInputDataBuffer.Time)) { m_TimeStamp = MAX_TIME; } else { m_TimeStamp = rtTimestamp; } // If there is a TimeLength, store it if (0 == (dwFlags & DMOInputDataBuffer.TimeLength)) { m_TimeLength = -1; } else { m_TimeLength = rtTimelength; } hr = S_OK; } else { ReleaseInputBuffs(); hr = S_FALSE; } } return(hr); }
/// <summary> /// The constructor. The parameters to the base class /// describe the number of input and output streams, which /// DirectShow calls Pins, followed by the number of parameters /// this class supports (can be zero), and the timeformat of those /// parameters (should include ParamClass.TimeFormatFlags.Reference /// if NumParameters > 0). /// </summary> public DmoSplit() : base(InputPinCount, OutputPinCount, NumParams, TimeFormatFlags.Reference) { m_Log.Write("Constructor\r\n"); // Initialize the data members m_TimeStamp = 0; m_TimeLength = 0; m_cbInData = 0; m_Flags = 0; m_InBuffer = IntPtr.Zero; m_pBuffer = null; }
/// <summary> /// Release all info for the most recent input buffer /// </summary> private void ReleaseInputBuffs() { if (m_pBuffer != null) { Marshal.ReleaseComObject(m_pBuffer); m_pBuffer = null; } m_InBuffer = IntPtr.Zero; m_cbInData = 0; m_Flags = 0; // I specifically DON'T release the TimeStamp so we can keep track of where we are }
/// <summary> /// Release all info for the most recent input buffer /// </summary> private void ReleaseInputBuffs() { if (this.buffer != null) { Marshal.ReleaseComObject(this.buffer); this.buffer = null; } this.bufferPointer = IntPtr.Zero; this.bufferByteCount = 0; this.bufferFlags = 0; // I specifically DON'T release the TimeStamp so we can keep track of where we are }
/// <summary> /// The constructor. The parameters to the base class /// describe the number of input and output streams, which /// DirectShow calls Pins, followed by the number of parameters /// this class supports (can be zero), and the timeformat of those /// parameters (should include ParamClass.TimeFormatFlags.Reference /// if NumParameters > 0). /// </summary> public DmoFlip() : base(InputPinCount, OutputPinCount, NumParams, TimeFormatFlags.Reference) { m_Log.Write("Constructor\r\n"); // Initialize the data members m_Width = 0; m_Height = 0; m_Stride = 0; m_BPP = 0; m_TimeStamp = 0; m_TimeLength = 0; m_cbInData = 0; m_Flags = 0; m_InBuffer = IntPtr.Zero; m_pBuffer = null; // Start describing the parameters this DMO supports. Building this // structure (painful as it is) will allow the base class to automatically // support IMediaParamInfo & IMediaParams, which allow clients to find // out what parameters you support, and to set them. // Our parameter has a minimum value of zero, and a max of // FlipMode.LAST, and a default of DEFAULTMODE; See the MSDN // docs for MP_PARAMINFO for a description of the other parameters ParamInfo p = new ParamInfo(); p.mopCaps = MPCaps.Jump; p.mpdMinValue.vInt = 0; p.mpdMaxValue.vInt = (int)FlipMode.LAST; p.mpdNeutralValue.vInt = (int)DEFAULTMODE; p.mpType = MPType.ENUM; p.szLabel = ""; p.szUnitText = "FlipMode"; // Parameter #0, using the struct, and a format string (described in MSDN // under IMediaParamInfo::GetParamText). Note that when marshaling strings, // .NET will add another \0 ParamDefine(0, p, "FlipMode\0\0None\0FlipY\0FlipX\0FlipY|FlipX\0"); }
/////////////////////////////////////////////////////////////////////////////// // Construction and Initializing methods // /////////////////////////////////////////////////////////////////////////////// #region CONSTRUCTION /// <summary> /// Initializes a new instance of the DmoOverlay class. /// The parameters to the base class /// describe the number of input and output streams, which /// DirectShow calls Pins, followed by the number of parameters /// this class supports (can be zero), and the timeformat of those /// parameters (should include ParamClass.TimeFormatFlags.Reference /// if NumParameters > 0). /// </summary> public DmoOverlay() : base(InputPinCount, OutputPinCount, NumParams, TimeFormatFlags.Reference) { // Initialize the data members this.streamWidth = 0; this.streamHeight = 0; this.streamStride = 0; this.streamBBP = 0; this.bufferTimeStamp = 0; this.bufferTimeLength = 0; this.bufferByteCount = 0; this.bufferFlags = 0; this.bufferPointer = IntPtr.Zero; this.buffer = null; // Start describing the parameters this DMO supports. Building this // structure (painful as it is) will allow the base class to automatically // support IMediaParamInfo & IMediaParams, which allow clients to find // out what parameters you support, and to set them. // See the MSDN // docs for MP_PARAMINFO for a description of the other parameters ParamInfo gazeX = new ParamInfo(); gazeX.mopCaps = MPCaps.Jump; gazeX.mpdMinValue.vInt = 0; gazeX.mpdMaxValue.vInt = 2000; gazeX.mpdNeutralValue.vInt = 1; gazeX.mpType = MPType.INT; gazeX.szLabel = "GazeX"; gazeX.szUnitText = "Pixel"; ParamInfo gazeY = new ParamInfo(); gazeY.mopCaps = MPCaps.Jump; gazeY.mpdMinValue.vInt = 0; gazeY.mpdMaxValue.vInt = 2000; gazeY.mpdNeutralValue.vInt = 1; gazeY.mpType = MPType.INT; gazeY.szLabel = "GazeY"; gazeY.szUnitText = "Pixel"; ParamInfo mouseX = new ParamInfo(); mouseX.mopCaps = MPCaps.Jump; mouseX.mpdMinValue.vInt = 0; mouseX.mpdMaxValue.vInt = 2000; mouseX.mpdNeutralValue.vInt = 1; mouseX.mpType = MPType.INT; mouseX.szLabel = "MouseX"; mouseX.szUnitText = "Pixel"; ParamInfo mouseY = new ParamInfo(); mouseY.mopCaps = MPCaps.Jump; mouseY.mpdMinValue.vInt = 0; mouseY.mpdMaxValue.vInt = 2000; mouseY.mpdNeutralValue.vInt = 1; mouseY.mpType = MPType.INT; mouseY.szLabel = "MouseY"; mouseY.szUnitText = "Pixel"; // Parameter #0, using the struct, and a format string (described in MSDN // under IMediaParamInfo::GetParamText). Note that when marshaling strings, // .NET will add another \0 ParamDefine(0, gazeX, "GazeX\0Pixel\0"); ParamDefine(1, gazeY, "GazeY\0Pixel\0"); ParamDefine(2, mouseX, "MouseX\0Pixel\0"); ParamDefine(3, mouseY, "MouseY\0Pixel\0"); // Initialize the buffers for the gaze and mouse cursor overlay bitmaps. Bitmap circleBitmap = (Bitmap)Properties.Resources.Circle; Rectangle circleRect = new Rectangle(0, 0, circleBitmap.Width, circleBitmap.Height); this.gazeCursorSize = circleRect.Size; this.gazeCursorData = circleBitmap.LockBits(circleRect, ImageLockMode.ReadOnly, circleBitmap.PixelFormat); // Get the address of the first line. IntPtr gazeCursorScan0Pointer = this.gazeCursorData.Scan0; // Declare an array to hold the bytes of the bitmap. int gazeCursorBytes = this.gazeCursorData.Stride * this.gazeCursorData.Height; this.gazeCursorArgbValues = new byte[gazeCursorBytes]; // Copy the RGB values into the array. Marshal.Copy(gazeCursorScan0Pointer, this.gazeCursorArgbValues, 0, gazeCursorBytes); Bitmap arrowBitmap = Properties.Resources.Arrow; Rectangle cursorRect = new Rectangle(0, 0, arrowBitmap.Width, arrowBitmap.Height); this.mouseCursorSize = cursorRect.Size; this.mouseCursorData = arrowBitmap.LockBits(cursorRect, ImageLockMode.ReadOnly, arrowBitmap.PixelFormat); // Get the address of the first line. IntPtr mouseCursorScan0Pointer = this.mouseCursorData.Scan0; // Declare an array to hold the bytes of the bitmap. int mouseCursorBytes = this.mouseCursorData.Stride * this.mouseCursorData.Height; this.mouseCursorArgbValues = new byte[mouseCursorBytes]; // Copy the RGB values into the array. Marshal.Copy(mouseCursorScan0Pointer, this.mouseCursorArgbValues, 0, mouseCursorBytes); }
/////////////////////////////////////////////////////////////////////////////// // Construction and Initializing methods // /////////////////////////////////////////////////////////////////////////////// #region CONSTRUCTION /// <summary> /// Initializes a new instance of the DmoMixer class. /// The parameters to the base class /// describe the number of input and output streams, which /// DirectShow calls Pins, followed by the number of parameters /// this class supports (can be zero), and the timeformat of those /// parameters (should include ParamClass.TimeFormatFlags.Reference /// if NumParameters > 0). /// </summary> public DmoMixer() : base(InputPinCount, OutputPinCount, NumParams, TimeFormatFlags.Reference) { // Initialize the data members this.bufferFlags = 0; this.inputStreams = new VideoStream[InputPinCount]; for (int i = 0; i < InputPinCount; i++) { this.inputStreams[i] = new VideoStream(); } this.outputStream = new VideoStream(); // Start describing the parameters this DMO supports. Building this // structure (painful as it is) will allow the base class to automatically // support IMediaParamInfo & IMediaParams, which allow clients to find // out what parameters you support, and to set them. // See the MSDN // docs for MP_PARAMINFO for a description of the other parameters ParamInfo backgroundColor = new ParamInfo(); backgroundColor.mopCaps = MPCaps.Jump; backgroundColor.mpdMinValue.vInt = int.MinValue; backgroundColor.mpdMaxValue.vInt = int.MaxValue; backgroundColor.mpdNeutralValue.vInt = 0; backgroundColor.mpType = MPType.INT; backgroundColor.szLabel = "BackgroundColor"; backgroundColor.szUnitText = "Color"; ParamDefine(0, backgroundColor, "BackgroundColor\0Color\0"); for (int i = 0; i < InputPinCount; i++) { ParamInfo streamLeft = new ParamInfo(); streamLeft.mopCaps = MPCaps.Jump; streamLeft.mpdMinValue.vFloat = 0; streamLeft.mpdMaxValue.vFloat = 1; streamLeft.mpdNeutralValue.vFloat = 0; streamLeft.mpType = MPType.FLOAT; streamLeft.szLabel = "Stream" + i.ToString() + "Left"; streamLeft.szUnitText = "Position"; ParamInfo streamTop = new ParamInfo(); streamTop.mopCaps = MPCaps.Jump; streamTop.mpdMinValue.vFloat = 0; streamTop.mpdMaxValue.vFloat = 1; streamTop.mpdNeutralValue.vFloat = 0; streamTop.mpType = MPType.FLOAT; streamTop.szLabel = "Stream" + i.ToString() + "Top"; streamTop.szUnitText = "Position"; ParamInfo streamWidth = new ParamInfo(); streamWidth.mopCaps = MPCaps.Jump; streamWidth.mpdMinValue.vFloat = 0; streamWidth.mpdMaxValue.vFloat = 1; streamWidth.mpdNeutralValue.vFloat = 1; streamWidth.mpType = MPType.FLOAT; streamWidth.szLabel = "Stream" + i.ToString() + "Width"; streamWidth.szUnitText = "Position"; ParamInfo streamHeight = new ParamInfo(); streamHeight.mopCaps = MPCaps.Jump; streamHeight.mpdMinValue.vFloat = 0; streamHeight.mpdMaxValue.vFloat = 1; streamHeight.mpdNeutralValue.vFloat = 1; streamHeight.mpType = MPType.FLOAT; streamHeight.szLabel = "Stream" + i.ToString() + "Height"; streamHeight.szUnitText = "Position"; ParamInfo streamAlpha = new ParamInfo(); streamAlpha.mopCaps = MPCaps.Jump; streamAlpha.mpdMinValue.vFloat = 0; streamAlpha.mpdMaxValue.vFloat = 1; streamAlpha.mpdNeutralValue.vFloat = 1; streamAlpha.mpType = MPType.FLOAT; streamAlpha.szLabel = "Stream" + i.ToString() + "Alpha"; streamAlpha.szUnitText = "Alpha"; ParamDefine((i * 5) + 1, streamLeft, "Stream" + i.ToString() + "Left\0Position\0"); ParamDefine((i * 5) + 2, streamTop, "Stream" + i.ToString() + "Top\0Position\0"); ParamDefine((i * 5) + 3, streamWidth, "Stream" + i.ToString() + "Width\0Position\0"); ParamDefine((i * 5) + 4, streamHeight, "Stream" + i.ToString() + "Height\0Position\0"); ParamDefine((i * 5) + 5, streamAlpha, "Stream" + i.ToString() + "Alpha\0Alpha\0"); } }
/// <summary> /// Release all info for the given input buffer /// </summary> /// <param name="inputStreamIndex">Index of the input stream to be released.</param> private void ReleaseInputBuffs(int inputStreamIndex) { if (this.inputStreams[inputStreamIndex].Buffer != null) { Marshal.ReleaseComObject(this.inputStreams[inputStreamIndex].Buffer); this.inputStreams[inputStreamIndex].Buffer = null; } this.inputStreams[inputStreamIndex].BufferPointer = IntPtr.Zero; this.inputStreams[inputStreamIndex].BufferByteCount = 0; this.bufferFlags = 0; // I specifically DON'T release the TimeStamp so we can keep track of where we are }
/// <summary> /// Accept the input buffers to be processed. You'll want to read /// the MSDN docs on this one. One point worth noting is that DMO /// doesn't require that one complete block be passed at a time. /// Picture a case where raw data is being read from a file, and your /// DMO is the first to process it. The chunk of data you receive /// might represent one image, 5 images, half an image, etc. Likewise, /// your input could contain both video and audio that you are splitting /// into two output streams. /// That helps explain some of the parameters you see here and in /// InternalProcessOutput. /// Note that while DMO doesn't insist on it, for this sample, we /// specifically request that only complete buffers be provided. /// </summary> /// <param name="inputStreamIndex">Stream Index</param> /// <param name="mediaBuffer">Interface that holds the input data</param> /// <param name="flags">Flags to control input processing</param> /// <param name="timestamp">Timestamp of the sample</param> /// <param name="timelength">Duration of the sample</param> /// <returns>S_FALSE if there is no output, S_OK otherwise</returns> protected override int InternalProcessInput( int inputStreamIndex, [In] IMediaBuffer mediaBuffer, DMOInputDataBuffer flags, long timestamp, long timelength) { // Check state - if we already have a buffer, we shouldn't be getting another Debug.Assert(this.inputStreams[inputStreamIndex].Buffer == null, "We already have a buffer, we shouldn't be getting another"); IntPtr bufferPointer; int bufferByteCount; int hr = mediaBuffer.GetBufferAndLength(out bufferPointer, out bufferByteCount); this.inputStreams[inputStreamIndex].BufferPointer = bufferPointer; this.inputStreams[inputStreamIndex].BufferByteCount = bufferByteCount; if (hr >= 0) { // Ignore zero length buffers if (this.inputStreams[inputStreamIndex].BufferByteCount > 0) { this.inputStreams[inputStreamIndex].Buffer = mediaBuffer; // Cast the input flags to become output flags this.bufferFlags = (DMOOutputDataBufferFlags)flags; // If there is a time, store it if (0 == (flags & DMOInputDataBuffer.Time)) { this.inputStreams[inputStreamIndex].BufferTimeStamp = MaxTime; } else { this.inputStreams[inputStreamIndex].BufferTimeStamp = timestamp; } // If there is a TimeLength, store it if (0 == (flags & DMOInputDataBuffer.TimeLength)) { this.inputStreams[inputStreamIndex].BufferTimeLength = -1; } else { this.inputStreams[inputStreamIndex].BufferTimeLength = timelength; } hr = SOK; } else { this.ReleaseInputBuffs(inputStreamIndex); hr = SFALSE; } } return hr; }
/// <summary> /// Accept the input buffers to be processed. You'll want to read /// the MSDN docs on this one. One point worth noting is that DMO /// doesn't require that one complete block be passed at a time. /// Picture a case where raw data is being read from a file, and your /// DMO is the first to process it. The chunk of data you receive /// might represent one image, 5 images, half an image, etc. Likewise, /// your input could contain both video and audio that you are splitting /// into two output streams. /// That helps explain some of the parameters you see here and in /// InternalProcessOutput. /// Note that while DMO doesn't insist on it, for this sample, we /// specifically request that only complete buffers be provided. /// </summary> /// <param name="dwInputStreamIndex">Stream Index</param> /// <param name="pBuffer">Interface that holds the input data</param> /// <param name="dwFlags">Flags to control input processing</param> /// <param name="rtTimestamp">Timestamp of the sample</param> /// <param name="rtTimelength">Duration of the sample</param> /// <returns>S_FALSE if there is no output, S_OK otherwise</returns> protected override int InternalProcessInput( int dwInputStreamIndex, [In] IMediaBuffer pBuffer, DMOInputDataBuffer dwFlags, long rtTimestamp, long rtTimelength) { // Check state - if we already have a buffer, we shouldn't be getting another Debug.Assert(m_pBuffer == null); int cbData; int hr = pBuffer.GetBufferAndLength(out m_InBuffer, out m_cbInData); if (hr >= 0) { // Ignore zero length buffers if (m_cbInData > 0) { m_pBuffer = pBuffer; // Cast the input flags to become output flags m_Flags = (DMOOutputDataBufferFlags)dwFlags; // If there is a time, store it if (0 == (dwFlags & DMOInputDataBuffer.Time)) { m_TimeStamp = MAX_TIME; } else { m_TimeStamp = rtTimestamp; } // If there is a TimeLength, store it if (0 == (dwFlags & DMOInputDataBuffer.TimeLength)) { m_TimeLength = -1; } else { m_TimeLength = rtTimelength; } hr = S_OK; } else { ReleaseInputBuffs(); hr = S_FALSE; } } return hr; }