// Token: 0x06000A59 RID: 2649 RVA: 0x0001E1A8 File Offset: 0x0001C3A8 private IMFSample ReadFromSource() { int num = this.sourceProvider.Read(this.sourceBuffer, 0, this.sourceBuffer.Length); if (num == 0) { return(null); } IMFMediaBuffer imfmediaBuffer = MediaFoundationApi.CreateMemoryBuffer(num); IntPtr destination; int num2; int num3; imfmediaBuffer.Lock(out destination, out num2, out num3); Marshal.Copy(this.sourceBuffer, 0, destination, num); imfmediaBuffer.Unlock(); imfmediaBuffer.SetCurrentLength(num); IMFSample imfsample = MediaFoundationApi.CreateSample(); imfsample.AddBuffer(imfmediaBuffer); imfsample.SetSampleTime(this.inputPosition); long num4 = MediaFoundationTransform.BytesToNsPosition(num, this.sourceProvider.WaveFormat); imfsample.SetSampleDuration(num4); this.inputPosition += num4; Marshal.ReleaseComObject(imfmediaBuffer); return(imfsample); }
// Token: 0x06000945 RID: 2373 RVA: 0x0001B0A0 File Offset: 0x000192A0 private long ConvertOneBuffer(IMFSinkWriter writer, int streamIndex, IWaveProvider inputProvider, long position, byte[] managedBuffer) { long num = 0L; IMFMediaBuffer imfmediaBuffer = MediaFoundationApi.CreateMemoryBuffer(managedBuffer.Length); int count; imfmediaBuffer.GetMaxLength(out count); IMFSample imfsample = MediaFoundationApi.CreateSample(); imfsample.AddBuffer(imfmediaBuffer); IntPtr destination; int num2; imfmediaBuffer.Lock(out destination, out count, out num2); int num3 = inputProvider.Read(managedBuffer, 0, count); if (num3 > 0) { num = MediaFoundationEncoder.BytesToNsPosition(num3, inputProvider.WaveFormat); Marshal.Copy(managedBuffer, 0, destination, num3); imfmediaBuffer.SetCurrentLength(num3); imfmediaBuffer.Unlock(); imfsample.SetSampleTime(position); imfsample.SetSampleDuration(num); writer.WriteSample(streamIndex, imfsample); } else { imfmediaBuffer.Unlock(); } Marshal.ReleaseComObject(imfsample); Marshal.ReleaseComObject(imfmediaBuffer); return(num); }
/// <summary> /// Sets the presentation time of the sample. /// </summary> /// <param name="sample">A valid IMFSample instance.</param> /// <param name="sampleTime">The presentation time.</param> /// <returns>If this function succeeds, it returns the S_OK member. Otherwise, it returns another HResult's member that describe the error.</returns> public static HResult SetSampleTime(this IMFSample sample, TimeSpan sampleTime) { if (sample == null) { throw new ArgumentNullException("sample"); } return(sample.SetSampleTime(sampleTime.Ticks)); }
private long ConvertOneBuffer(IMFSinkWriter writer, int streamIndex, IWaveProvider inputProvider, long position, byte[] managedBuffer, int seconds, ref bool flag) { long durationConverted = 0; int maxLength; IMFMediaBuffer buffer = MediaFoundationApi.CreateMemoryBuffer(managedBuffer.Length); buffer.GetMaxLength(out maxLength); IMFSample sample = MediaFoundationApi.CreateSample(); sample.AddBuffer(buffer); IntPtr ptr; int currentLength; buffer.Lock(out ptr, out maxLength, out currentLength); int oneLength = inputProvider.WaveFormat.AverageBytesPerSecond; int read = 0; if (flag) { for (int i = 0; i < seconds; i++) { read = inputProvider.Read(managedBuffer, 0, oneLength); } flag = false; } else { read = inputProvider.Read(managedBuffer, 0, oneLength); } if (read > 0) { durationConverted = BytesToNsPosition(read, inputProvider.WaveFormat); Marshal.Copy(managedBuffer, 0, ptr, read); buffer.SetCurrentLength(read); buffer.Unlock(); sample.SetSampleTime(position); sample.SetSampleDuration(durationConverted); writer.WriteSample(streamIndex, sample); //writer.Flush(streamIndex); } else { buffer.Unlock(); } Marshal.ReleaseComObject(sample); Marshal.ReleaseComObject(buffer); return(durationConverted); }
private void DuplicateSample(IMFSample pInSample, out IMFSample pOutSample) { MFError throwonhr; int flags; long lTime; throwonhr = MFExtern.MFCreateSample(out pOutSample); throwonhr = pInSample.CopyAllItems(pOutSample); HResult hr = pInSample.GetSampleDuration(out lTime); if (Succeeded(hr)) { throwonhr = pOutSample.SetSampleDuration(lTime); } hr = pInSample.GetSampleTime(out lTime); if (Succeeded(hr)) { throwonhr = pOutSample.SetSampleTime(lTime); } hr = pInSample.GetSampleFlags(out flags); if (Succeeded(hr)) { throwonhr = pOutSample.SetSampleFlags(flags); } IMFMediaBuffer mb; throwonhr = MFExtern.MFCreateMemoryBuffer(m_imageHeightInPixels * m_imageWidthInPixels * 4, out mb); try { // Set the data size on the output buffer. throwonhr = mb.SetCurrentLength(m_cbImageSizeOutput); throwonhr = pOutSample.AddBuffer(mb); } finally { SafeRelease(mb); } }
protected override int OnFrame(IMFSample pSample, IMFMediaBuffer pBuffer, long llTimestamp, string ssFormat) { int hr; if (IsCapturing()) { if (BFirstSample) { LlBaseTime = llTimestamp; BFirstSample = false; } // re-base the time stamp llTimestamp -= LlBaseTime; hr = pSample.SetSampleTime(llTimestamp); //if (Succeeded(hr)) //{ // var displayTask = Task<int>.Factory.StartNew(() => Draw.DrawFrame(pBuffer)); // var recordTask = Task<int>.Factory.StartNew(() => PWriter.WriteSample(0, pSample)); // Task.WaitAll(displayTask, recordTask); // hr = displayTask.Result; // if (Succeeded(hr)) // hr = recordTask.Result; //} //Parallel.Invoke(()=>Draw.DrawFrame(pBuffer),()=> PWriter.WriteSample(0, pSample)); if (Succeeded(hr)) { hr = Draw.DrawFrame(pBuffer, !string.IsNullOrEmpty(ssFormat), ssFormat); } if (Succeeded(hr)) { hr = PWriter.WriteSample(0, pSample); } } else { hr = Draw.DrawFrame(pBuffer, !string.IsNullOrEmpty(ssFormat), ssFormat); } return(hr); }
private int ReadFromTransform() { MFT_OUTPUT_DATA_BUFFER[] array = new MFT_OUTPUT_DATA_BUFFER[1]; IMFSample iMFSample = MediaFoundationApi.CreateSample(); IMFMediaBuffer iMFMediaBuffer = MediaFoundationApi.CreateMemoryBuffer(this.outputBuffer.Length); iMFSample.AddBuffer(iMFMediaBuffer); iMFSample.SetSampleTime(this.outputPosition); array[0].pSample = iMFSample; _MFT_PROCESS_OUTPUT_STATUS mFT_PROCESS_OUTPUT_STATUS; int num = this.transform.ProcessOutput(_MFT_PROCESS_OUTPUT_FLAGS.None, 1, array, out mFT_PROCESS_OUTPUT_STATUS); if (num == -1072861838) { Marshal.ReleaseComObject(iMFMediaBuffer); Marshal.ReleaseComObject(iMFSample); return(0); } if (num != 0) { Marshal.ThrowExceptionForHR(num); } IMFMediaBuffer iMFMediaBuffer2; array[0].pSample.ConvertToContiguousBuffer(out iMFMediaBuffer2); IntPtr source; int num2; int num3; iMFMediaBuffer2.Lock(out source, out num2, out num3); this.outputBuffer = BufferHelpers.Ensure(this.outputBuffer, num3); Marshal.Copy(source, this.outputBuffer, 0, num3); this.outputBufferOffset = 0; this.outputBufferCount = num3; iMFMediaBuffer2.Unlock(); this.outputPosition += MediaFoundationTransform.BytesToNsPosition(this.outputBufferCount, this.WaveFormat); Marshal.ReleaseComObject(iMFMediaBuffer); iMFSample.RemoveAllBuffers(); Marshal.ReleaseComObject(iMFSample); Marshal.ReleaseComObject(iMFMediaBuffer2); return(num3); }
private void SetSampleAttributes(StspSampleHeader sampleHeader, IMFSample sample) { ThrowIfError(sample.SetSampleTime(sampleHeader.ullTimestamp)); ThrowIfError(sample.SetSampleDuration(sampleHeader.ullDuration)); SET_SAMPLE_ATTRIBUTE(sampleHeader, sample, MFSampleExtension_BottomFieldFirst, StspSampleFlags.StspSampleFlag_BottomFieldFirst); SET_SAMPLE_ATTRIBUTE(sampleHeader, sample, MFSampleExtension_CleanPoint, StspSampleFlags.StspSampleFlag_CleanPoint); SET_SAMPLE_ATTRIBUTE(sampleHeader, sample, MFSampleExtension_DerivedFromTopField, StspSampleFlags.StspSampleFlag_DerivedFromTopField); SET_SAMPLE_ATTRIBUTE(sampleHeader, sample, MFSampleExtension_Discontinuity, StspSampleFlags.StspSampleFlag_Discontinuity); SET_SAMPLE_ATTRIBUTE(sampleHeader, sample, MFSampleExtension_Interlaced, StspSampleFlags.StspSampleFlag_Interlaced); SET_SAMPLE_ATTRIBUTE(sampleHeader, sample, MFSampleExtension_RepeatFirstField, StspSampleFlags.StspSampleFlag_RepeatFirstField); SET_SAMPLE_ATTRIBUTE(sampleHeader, sample, MFSampleExtension_SingleField, StspSampleFlags.StspSampleFlag_SingleField); /* show debug info... * int cbTotalLen; * sample.GetTotalLength(out cbTotalLen); * var isKeyFrame = Convert.ToBoolean(sampleHeader.dwFlags & (int)StspSampleFlags.StspSampleFlag_CleanPoint); * Debug.WriteLine($"{DateTime.Now.ToString()} Received sample {sampleHeader.ullTimestamp} Duration-{sampleHeader.ullDuration} Length-{cbTotalLen} " + (isKeyFrame ? "key frame" : "")); */ }
/// <summary>Generates the "tail" of the audio effect.</summary> /// <param name="InputMessageNumber">Message number to use with OutputSample.</param> /// <remarks> /// Generates the "tail" of the audio effect. The tail is the portion /// of the delay effect that is heard after the input stream ends. /// /// To generate the tail, the client must drain the MFT by sending /// the MFT_MESSAGE_COMMAND_DRAIN message and then call ProcessOutput /// to get the tail samples. /// </remarks> private void ProcessEffectTail(int InputMessageNumber) { IMFMediaBuffer pOutputBuffer = null; MFError throwonhr; IntPtr pbOutputData = IntPtr.Zero; // Pointer to the memory in the output buffer. int cbOutputLength = 0; // Size of the output buffer. int cbBytesProcessed = 0; // How much data we processed. IMFSample pOutSample = null; // Allocate an output buffer. throwonhr = MFExtern.MFCreateMemoryBuffer(m_cbTailSamples, out pOutputBuffer); try { throwonhr = MFExtern.MFCreateSample(out pOutSample); throwonhr = pOutSample.AddBuffer(pOutputBuffer); // Lock the output buffer. int cb; throwonhr = pOutputBuffer.Lock(out pbOutputData, out cbOutputLength, out cb); // Calculate how many audio samples we can process. cbBytesProcessed = Math.Min(m_cbTailSamples, cbOutputLength); // Round to the next lowest multiple of nBlockAlign. cbBytesProcessed -= (cbBytesProcessed % m_Alignment); // Fill the output buffer with silence, because we are also using it as the input buffer. FillBufferWithSilence(pbOutputData, cbBytesProcessed); // Process the data. ProcessAudio(pbOutputData, pbOutputData, cbBytesProcessed / m_Alignment); // Set the data length on the output buffer. throwonhr = pOutputBuffer.SetCurrentLength(cbBytesProcessed); if (m_rtTimestamp >= 0) { long hnsDuration = (cbBytesProcessed / m_AvgBytesPerSec) * UNITS; // Set the time stamp and duration on the output sample. throwonhr = pOutSample.SetSampleTime(m_rtTimestamp); throwonhr = pOutSample.SetSampleDuration(hnsDuration); } // Done. m_cbTailSamples = 0; OutputSample(pOutSample, InputMessageNumber); } catch { SafeRelease(pOutSample); throw; } finally { if (pbOutputData != IntPtr.Zero) { pOutputBuffer.Unlock(); } SafeRelease(pOutputBuffer); } }
protected override int OnFrame(IMFSample pSample, IMFMediaBuffer pBuffer, long llTimestamp, string ssFormat) { int hr; if (IsCapturing()) { if (BFirstSample) { LlBaseTime = llTimestamp; BFirstSample = false; } // re-base the time stamp llTimestamp -= LlBaseTime; hr = pSample.SetSampleTime(llTimestamp); //if (Succeeded(hr)) //{ // var displayTask = Task<int>.Factory.StartNew(() => Draw.DrawFrame(pBuffer)); // var recordTask = Task<int>.Factory.StartNew(() => PWriter.WriteSample(0, pSample)); // Task.WaitAll(displayTask, recordTask); // hr = displayTask.Result; // if (Succeeded(hr)) // hr = recordTask.Result; //} //Parallel.Invoke(()=>Draw.DrawFrame(pBuffer),()=> PWriter.WriteSample(0, pSample)); if (Succeeded(hr)) hr = Draw.DrawFrame(pBuffer, !string.IsNullOrEmpty(ssFormat), ssFormat); if (Succeeded(hr)) hr = PWriter.WriteSample(0, pSample); } else hr = Draw.DrawFrame(pBuffer, !string.IsNullOrEmpty(ssFormat), ssFormat); return hr; }
/// <summary> /// This is the routine that performs the transform. Unless the sinkWriter object /// is set all we do is pass the sample on. If the sink writer object is set /// we give the sample to it for writing. There are two modes - one where we just /// give the sinkwriter the input sample and the other where we clone the input /// sample and rebase the timestamps. /// /// An override of the abstract version in MFTBase_Sync. /// </summary> /// <param name="pOutputSamples">The structure to populate with output values.</param> /// <returns>S_Ok unless error.</returns> protected override HResult OnProcessOutput(ref MFTOutputDataBuffer outputSampleDataStruct) { HResult hr = HResult.S_OK; IMFMediaBuffer inputMediaBuffer = null; IMFSample sinkWriterSample = null; IMFAttributes sampleAttributes; // in this MFT we are processing in place, the input sample is the output sample, the media buffer of the // input sample is the media buffer of the output sample. Thats for the pipeline. If a sink writer exists // we also write the sample data out to the sink writer. This provides the effect of displaying on the // screen and simultaneously recording. // There are two ways the sink writer can be given the media sample data. It can just be given the // input sample directly or a copy of the sample can be made and that copy given to the sink writer. // There is also an additional complication - the sample has a timestamp and video cameras tend // to just use the current date and time as a timestamp. There are several reports that MP4 files // need to have their first frame starting at zero and then every subsequent frame adjusted to that // new base time. Certainly the Microsoft supplied example code (and see the // CaptureToFileViaReaderWriter also) take great care to do this. This requirement does not // seem to exist - my tests indicate it is not necessary to start from 0 in the mp4 file. Maybe the // Sink Writer has been improved and now does this automatically. For demonstration purposes // the timebase-rebase functionality has been included and choosing that mode copies the sample // and resets the time. If the user does not rebase the time we simply send the input sample // to the Sink Writer as-is. try { // Set status flags. outputSampleDataStruct.dwStatus = MFTOutputDataBufferFlags.None; // The output sample is the input sample. We get a new IUnknown for the Input // sample since we are going to release it below. The client will release this // new IUnknown outputSampleDataStruct.pSample = Marshal.GetIUnknownForObject(InputSample); // are we recording? if (workingSinkWriter != null) { // we do everything in a lock lock (sinkWriterLockObject) { // are we in timebase rebase mode? if (wantTimebaseRebase == false) { // we are not. Just give the input sample to the Sink Writer which will // write it out. hr = workingSinkWriter.WriteSample(sinkWriterVideoStreamId, InputSample); if (hr != HResult.S_OK) { throw new Exception("OnProcessOutput call to WriteSample(a) failed. Err=" + hr.ToString()); } } else { // the timebase rebase option has been chosen. We need to create a copy of the input sample // so we can adjust the time on it. // Get the data buffer from the input sample. If the sample contains more than one buffer, // this method copies the data from the original buffers into a new buffer, and replaces // the original buffer list with the new buffer. The new buffer is returned in the inputMediaBuffer parameter. // If the sample contains a single buffer, this method returns a pointer to the original buffer. // In typical use, most samples do not contain multiple buffers. hr = InputSample.ConvertToContiguousBuffer(out inputMediaBuffer); if (hr != HResult.S_OK) { throw new Exception("OnProcessOutput call to InputSample.ConvertToContiguousBuffer failed. Err=" + hr.ToString()); } // get some other things from the input sample hr = InputSample.GetSampleDuration(out long sampleDuration); if (hr != HResult.S_OK) { throw new Exception("OnProcessOutput call to InputSample.GetSampleDuration failed. Err=" + hr.ToString()); } hr = InputSample.GetTotalLength(out int sampleSize); if (hr != HResult.S_OK) { throw new Exception("OnProcessOutput call to InputSample.GetTotalLength failed. Err=" + hr.ToString()); } hr = InputSample.GetSampleTime(out long sampleTimeStamp); if (hr != HResult.S_OK) { throw new Exception("OnProcessOutput call to InputSample.GetSampleTime failed. Err=" + hr.ToString()); } // get the attributes from the input sample if (InputSample is IMFAttributes) { sampleAttributes = (InputSample as IMFAttributes); } else { sampleAttributes = null; } // we have all the information we need to create a new output sample sinkWriterSample = WMFUtils.CreateMediaSampleFromBuffer(sampleTimeStamp, sampleDuration, inputMediaBuffer, sampleSize, sampleAttributes); if (sinkWriterSample == null) { throw new Exception("OnProcessOutput, Error on call to CreateMediaSampleFromBuffer sinkWriterSample == null"); } // we have a sample, if so is it the first non null one? if (isFirstSample) { // yes it is set up our timestamp firstSampleBaseTime = sampleTimeStamp; isFirstSample = false; } // rebase the time stamp sampleTimeStamp -= firstSampleBaseTime; hr = sinkWriterSample.SetSampleTime(sampleTimeStamp); if (hr != HResult.S_OK) { throw new Exception("OnProcessOutput call to InputSample.SetSampleTime failed. Err=" + hr.ToString()); } // write the sample out hr = workingSinkWriter.WriteSample(sinkWriterVideoStreamId, sinkWriterSample); if (hr != HResult.S_OK) { throw new Exception("OnProcessOutput call to WriteSample(b) failed. Err=" + hr.ToString()); } } } } } finally { // clean up if (inputMediaBuffer != null) { Marshal.ReleaseComObject(inputMediaBuffer); } if (sinkWriterSample != null) { Marshal.ReleaseComObject(sinkWriterSample); } // Release the current input sample so we can get another one. // the act of setting it to null releases it because the property // is coded that way InputSample = null; } return(HResult.S_OK); }
override protected HResult OnProcessOutput(ref MFTOutputDataBuffer pOutputSamples) { HResult hr = HResult.S_OK; MFError throwonhr; // Since we don't specify MFTOutputStreamInfoFlags.ProvidesSamples, this can't be null. if (pOutputSamples.pSample != IntPtr.Zero) { long hnsDuration; long hnsTime; IMFMediaBuffer pInput = null; IMFMediaBuffer pOutput = null; IMFSample pOutSample = null; try { // Get the data buffer from the input sample. If the sample has // multiple buffers, you might be able to get (slightly) better // performance processing each buffer in turn rather than forcing // a new, full-sized buffer to get created. throwonhr = InputSample.ConvertToContiguousBuffer(out pInput); // Turn pointer to interface pOutSample = Marshal.GetUniqueObjectForIUnknown(pOutputSamples.pSample) as IMFSample; // Get the output buffer. throwonhr = pOutSample.ConvertToContiguousBuffer(out pOutput); OnProcessOutput(pInput, pOutput); // Set status flags. pOutputSamples.dwStatus = MFTOutputDataBufferFlags.None; // Copy the duration and time stamp from the input sample, // if present. hr = InputSample.GetSampleDuration(out hnsDuration); if (Succeeded(hr)) { throwonhr = pOutSample.SetSampleDuration(hnsDuration); } hr = InputSample.GetSampleTime(out hnsTime); if (Succeeded(hr)) { throwonhr = pOutSample.SetSampleTime(hnsTime); } } finally { SafeRelease(pInput); SafeRelease(pOutput); SafeRelease(pOutSample); // Release the current input sample so we can get another one. InputSample = null; } } else { return(HResult.E_INVALIDARG); } return(HResult.S_OK); }
public HResult OnReadSample( HResult hrStatus, int dwStreamIndex, MF_SOURCE_READER_FLAG dwStreamFlags, long llTimeStamp, IMFSample pSample // Can be null ) { HResult hr = HResult.S_OK; try { lock (this) { if (!IsCapturing()) { return(HResult.S_OK); } if (Failed(hrStatus)) { hr = hrStatus; goto done; } if (pSample != null) { if (m_bFirstSample) { m_llBaseTime = llTimeStamp; m_bFirstSample = false; } // rebase the time stamp llTimeStamp -= m_llBaseTime; hr = pSample.SetSampleTime(llTimeStamp); if (Failed(hr)) { goto done; } hr = m_pWriter.WriteSample(0, pSample); if (Failed(hr)) { goto done; } } // Read another sample. hr = m_pReader.ReadSample( MF_SOURCE_READER_FIRST_VIDEO_STREAM, 0, IntPtr.Zero, // actual IntPtr.Zero, // flags IntPtr.Zero, // timestamp IntPtr.Zero // sample ); done: if (Failed(hr)) { PostMessage(m_hwndEvent, m_iMessageID, new IntPtr((int)hr), IntPtr.Zero); } } } catch (Exception e) { hr = (HResult)Marshal.GetHRForException(e); } finally { SafeRelease(pSample); } return(hr); }
private void SetSampleAttributes(StspSampleHeader sampleHeader, IMFSample sample) { ThrowIfError(sample.SetSampleTime(sampleHeader.ullTimestamp)); ThrowIfError(sample.SetSampleDuration(sampleHeader.ullDuration)); }
public int OnReadSample( int hrStatus, int dwStreamIndex, MF_SOURCE_READER_FLAG dwStreamFlags, long llTimeStamp, IMFSample pSample // Can be null ) { int hr = S_Ok; try { lock (this) { if (!IsCapturing()) { return S_Ok; } if (Failed(hrStatus)) { hr = hrStatus; goto done; } if (pSample != null) { if (m_bFirstSample) { m_llBaseTime = llTimeStamp; m_bFirstSample = false; } // rebase the time stamp llTimeStamp -= m_llBaseTime; hr = pSample.SetSampleTime(llTimeStamp); if (Failed(hr)) { goto done; } hr = m_pWriter.WriteSample(0, pSample); if (Failed(hr)) { goto done; } } // Read another sample. hr = m_pReader.ReadSample( MF_SOURCE_READER_FIRST_VIDEO_STREAM, 0, IntPtr.Zero, // actual IntPtr.Zero, // flags IntPtr.Zero, // timestamp IntPtr.Zero // sample ); done: if (Failed(hr)) { PostMessage(m_hwndEvent, m_iMessageID, new IntPtr(hr), IntPtr.Zero); } } } catch (Exception e) { hr = Marshal.GetHRForException(e); } finally { SafeRelease(pSample); } return hr; }
// IMFSourceReaderCallback methods //------------------------------------------------------------------- // OnReadSample // // Called when the IMFMediaSource::ReadSample method completes. //------------------------------------------------------------------- public int OnReadSample(int hrStatus, int dwStreamIndex, MF_SOURCE_READER_FLAG dwStreamFlags, long llTimestamp, IMFSample pSample) { int hr = hrStatus; IMFMediaBuffer pBuffer = null; lock (this) { try { if (Succeeded(hr)) { if (pSample != null) { // Get the video frame buffer from the sample. hr = pSample.GetBufferByIndex(0, out pBuffer); // Draw the frame. if (Succeeded(hr)) { hr = m_draw.DrawFrame(pBuffer); } if (Succeeded(hr)) { if (m_bFirstSample) { m_llBaseTime = llTimestamp; m_bFirstSample = false; } // rebase the time stamp llTimestamp -= m_llBaseTime; hr = pSample.SetSampleTime(llTimestamp); if (Succeeded(hr)) { hr = m_pWriter.WriteSample(0, pSample); } } } } // Request the next frame. if (Succeeded(hr)) { // Ask for the first sample. hr = m_pReader.ReadSample((int)MF_SOURCE_READER.FirstVideoStream, 0, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero); } if (Failed(hr)) { NotifyError(hr); } } finally { //SafeRelease(pBuffer); SafeRelease(pSample); } } return hr; }
// IMFSourceReaderCallback methods //------------------------------------------------------------------- // OnReadSample // // Called when the IMFMediaSource::ReadSample method completes. //------------------------------------------------------------------- public HResult OnReadSample(HResult hrStatus, int dwStreamIndex, MF_SOURCE_READER_FLAG dwStreamFlags, long llTimestamp, IMFSample pSample) { HResult hr = hrStatus; IMFMediaBuffer pBuffer = null; lock (this) { try { if (Succeeded(hr)) { if (pSample != null) { // Get the video frame buffer from the sample. hr = pSample.GetBufferByIndex(0, out pBuffer); // Draw the frame. if (Succeeded(hr)) { hr = m_draw.DrawFrame(pBuffer); } if (Succeeded(hr)) { if (m_bFirstSample) { m_llBaseTime = llTimestamp; m_bFirstSample = false; } // rebase the time stamp llTimestamp -= m_llBaseTime; hr = pSample.SetSampleTime(llTimestamp); if (Succeeded(hr)) { hr = m_pWriter.WriteSample(0, pSample); } } } } // Request the next frame. if (Succeeded(hr)) { // Ask for the first sample. hr = m_pReader.ReadSample((int)MF_SOURCE_READER.FirstVideoStream, 0, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero); } if (Failed(hr)) { NotifyError(hr); } } finally { //SafeRelease(pBuffer); SafeRelease(pSample); } } return(hr); }
/// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+= /// <summary> /// This is the routine that performs the transform. Assumes InputSample is set. /// /// An override of the abstract version in TantaMFTBase_Sync. /// </summary> /// <param name="outputSampleDataStruct">The structure to populate with output data.</param> /// <returns>S_Ok unless error.</returns> /// <history> /// 01 Nov 18 Cynic - Ported In /// </history> protected override HResult OnProcessOutput(ref MFTOutputDataBuffer outputSampleDataStruct) { long hnsDuration; long hnsTime; HResult hr = HResult.S_OK; IMFMediaBuffer inputMediaBuffer = null; IMFMediaBuffer outputMediaBuffer = null; IMFSample outputSample = null; // Since we don't specify MFTOutputStreamInfoFlags.ProvidesSamples, this can't be null. // we expect the caller to have allocated the memory for this if (outputSampleDataStruct.pSample == IntPtr.Zero) { return(HResult.E_INVALIDARG); } try { // Get the data buffer from the input sample. If the sample contains more than one buffer, // this method copies the data from the original buffers into a new buffer, and replaces // the original buffer list with the new buffer. The new buffer is returned in the inputMediaBuffer parameter. // If the sample contains a single buffer, this method returns a pointer to the original buffer. // In typical use, most samples do not contain multiple buffers. hr = InputSample.ConvertToContiguousBuffer(out inputMediaBuffer); if (hr != HResult.S_OK) { throw new Exception("OnProcessOutput call to InputSample.ConvertToContiguousBuffer failed. Err=" + hr.ToString()); } // Turn pointer into an interface. The GetUniqueObjectForIUnknown method ensures that we // receive a unique Runtime Callable Wrapper, because it does not match an IUnknown pointer // to an existing object. Use this method when you have to create a unique RCW that is not // impacted by other code that calls the ReleaseComObject method. outputSample = Marshal.GetUniqueObjectForIUnknown(outputSampleDataStruct.pSample) as IMFSample; if (outputSample == null) { throw new Exception("OnProcessOutput call to GetUniqueObjectForIUnknown failed. outputSample == null"); } // Now get the output buffer. A media sample contains zero or more buffers. Each buffer manages a block of // memory, and is represented by the IMFMediaBuffer interface. A sample can have multiple buffers. // The buffers are kept in an ordered list and accessed by index value. This call gets us a single // pointer to a single contigous buffer which is much more useful. hr = outputSample.ConvertToContiguousBuffer(out outputMediaBuffer); if (hr != HResult.S_OK) { throw new Exception("OnProcessOutput call to InputSample.ConvertToContiguousBuffer failed. Err=" + hr.ToString()); } // now that we have an input and output buffer, do the work to convert them to grayscale. // Writing into outputMediaBuffer will write to the approprate location in the outputSample // since we took care to Marshal it that way ConvertMediaBufferToGrayscale(inputMediaBuffer, outputMediaBuffer); // Set status flags. outputSampleDataStruct.dwStatus = MFTOutputDataBufferFlags.None; // Copy the duration from the input sample, if present. The // Media Session needs these in order to keep everything sync'ed hr = InputSample.GetSampleDuration(out hnsDuration); if (hr == HResult.S_OK) { hr = outputSample.SetSampleDuration(hnsDuration); if (hr != HResult.S_OK) { throw new Exception("OnProcessOutput call to OutSample.SetSampleDuration failed. Err=" + hr.ToString()); } } // Copy the time stamp from the input sample, if present. hr = InputSample.GetSampleTime(out hnsTime); if (hr == HResult.S_OK) { hr = outputSample.SetSampleTime(hnsTime); if (hr != HResult.S_OK) { throw new Exception("OnProcessOutput call to OutSample.SetSampleTime failed. Err=" + hr.ToString()); } } } finally { // clean up SafeRelease(inputMediaBuffer); SafeRelease(outputMediaBuffer); SafeRelease(outputSample); // Release the current input sample so we can get another one. // the act of setting it to null releases it because the property // is coded that way InputSample = null; } return(HResult.S_OK); }