public static byte[] GetDataFromMediaSample(IMFSample sample) { IMFMediaBuffer pMediaBuffer = null; IntPtr pBuffer; int maxLen = 0, curLen = 0; //HResult hr = sample.LockStore(); HResult hr = sample.ConvertToContiguousBuffer(out pMediaBuffer); MFError.ThrowExceptionForHR(hr); try { hr = pMediaBuffer.Lock(out pBuffer, out maxLen, out curLen); MFError.ThrowExceptionForHR(hr); try { byte[] data = new byte[curLen]; Marshal.Copy(pBuffer, data, 0, curLen); return(data); } finally { hr = pMediaBuffer.Unlock(); } } finally { //hr = sample.UnlockStore(); COMBase.SafeRelease(pMediaBuffer); } }
/// <summary> /// Disposes the <see cref="MFResampler"/> object. /// </summary> public void Dispose() { if (this.resampler != null) { Marshal.ReleaseComObject(this.resampler); this.resampler = null; } if (this.inputBuffer != null) { Marshal.ReleaseComObject(this.inputBuffer); this.inputBuffer = null; } if (this.inputSample != null) { Marshal.ReleaseComObject(this.inputSample); this.inputSample = null; } if (this.outputBuffer != null) { Marshal.ReleaseComObject(this.outputBuffer); this.outputBuffer = null; } if (this.outputSample != null) { Marshal.ReleaseComObject(this.outputSample); this.outputSample = null; } }
/// <summary> /// Reads data out of the source, passing it through the transform /// </summary> /// <param name="buffer">Output buffer</param> /// <param name="offset">Offset within buffer to write to</param> /// <param name="count">Desired byte count</param> /// <returns>Number of bytes read</returns> // Token: 0x06000A55 RID: 2645 RVA: 0x0001DF5C File Offset: 0x0001C15C public int Read(byte[] buffer, int offset, int count) { if (this.transform == null) { this.transform = this.CreateTransform(); this.InitializeTransformForStreaming(); } int i = 0; if (this.outputBufferCount > 0) { i += this.ReadFromOutputBuffer(buffer, offset, count - i); } while (i < count) { IMFSample imfsample = this.ReadFromSource(); if (imfsample == null) { this.EndStreamAndDrain(); i += this.ReadFromOutputBuffer(buffer, offset + i, count - i); break; } if (!this.initializedForStreaming) { this.InitializeTransformForStreaming(); } this.transform.ProcessInput(0, imfsample, 0); Marshal.ReleaseComObject(imfsample); this.ReadFromTransform(); i += this.ReadFromOutputBuffer(buffer, offset + i, count - i); } return(i); }
// 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); }
// 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); }
public HResult ProcessSample(IMFSample pSample) { Debug.WriteLine("StreamSink:ProcessSample"); if (pSample == null) { return(E_INVALIDARG); } HResult hr; lock (this) { hr = CheckShutdown(); if (Failed(hr)) { return(hr); } hr = ProcessSampleInternal(pSample); if (Failed(hr)) { return(hr); } hr = QueueEvent(MediaEventType.MEStreamSinkRequestSample, Guid.Empty, S_OK, null); if (Failed(hr)) { return(hr); } } return(hr); }
private void CleanSampleQueue() { object spEntry; IMFSample spSample = null; // For video streams leave first key frame. if (_isVideo) { while (_samples.Count > 0) { spEntry = _samples.Dequeue(); if (spEntry is IMFSample && Convert.ToBoolean(MFExtern.MFGetAttributeUINT32(spSample, MFSampleExtension_CleanPoint, 0))) { break; } } } _samples.Clear(); if (spSample != null) { _samples.Enqueue(spSample); } }
// Processes media sample received from the header internal void ProcessSample(StspSampleHeader sampleHead, IMFSample sample) { Debug.Assert(sample != null); try { ThrowIfError(CheckShutdown()); // Set sample attributes SetSampleAttributes(sampleHead, sample); // Check if we are in propper state if so deliver the sample otherwise just skip it and don't treat it as an error. if (_eSourceState == SourceState.SourceState_Started) { // Put sample on the list _samples.Enqueue(sample); // Deliver samples DeliverSamples(); } else { Throw(HResult.MF_E_UNEXPECTED); } } catch (Exception ex) { HandleError(ex.HResult); } }
public void ScheduleSample(IMFSample pSample, bool bPresentNow) { if (m_bSchedulerThread == false) { throw new COMException("Scheduler thread not started", (int)HResult.MF_E_NOT_INITIALIZED); } if (bPresentNow || (m_pClock == null)) { // Present the sample immediately. m_pCB.PresentSample(pSample, 0); SafeRelease(pSample); } else { // Queue the sample and ask the scheduler thread to wake up. lock (m_ScheduledSamples) { m_ScheduledSamples.Enqueue(pSample); } lock (m_ScheduledSamples) { m_EventQueue.Enqueue(ScheduleEvent.eSchedule); } m_hMsgEvent.Set(); } }
override protected void OnProcessSample(IMFSample pInputSample, bool Discontinuity, int InputMessageNumber) { MFError throwonhr; IMFMediaBuffer pInput; // While we accept types that *might* be interlaced, if we actually receive // an interlaced sample, reject it. if (m_MightBeInterlaced) { int ix; // Returns a bool: true = interlaced, false = progressive throwonhr = pInputSample.GetUINT32(MFAttributesClsid.MFSampleExtension_Interlaced, out ix); if (ix != 0) { SafeRelease(pInputSample); return; } } // Set the Discontinuity flag on the sample that's going to OutputSample. HandleDiscontinuity(Discontinuity, pInputSample); int i = MFExtern.MFGetAttributeUINT32(Attributes, ClsidRotate, 0); bool IsOdd = (i & 1) == 1; // Does the specified rotation give a different orientation than // the old one? if (IsOdd != m_WasOdd) { // Yes, change the output type. OutputSample(null, InputMessageNumber); m_WasOdd = IsOdd; } // 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 = pInputSample.ConvertToContiguousBuffer(out pInput); try { // Process it. DoWork(pInput, (RotateFlipType)i); // Send the modified input sample to the output sample queue. OutputSample(pInputSample, InputMessageNumber); } finally { // If (somewhere) there is .Net code that is holding on to an instance of // the same buffer as pInput, this will yank the RCW out from underneath // it, probably causing it to crash. But if we don't release it, our memory // usage explodes. SafeRelease(pInput); } }
override protected void OnProcessSample(IMFSample pInputSample, bool Discontinuity, int InputMessageNumber) { MFError throwonhr; // Set the Discontinuity flag on the sample that's going to OutputSample. HandleDiscontinuity(Discontinuity, pInputSample); int cb; int cbBytesProcessed = 0; // How much data we processed. int cbInputLength; IntPtr pbInputData = IntPtr.Zero; IMFMediaBuffer pInputBuffer; // Convert to a single contiguous buffer. // NOTE: This does not cause a copy unless there are multiple buffers throwonhr = pInputSample.ConvertToContiguousBuffer(out pInputBuffer); try { // Lock the input buffer. throwonhr = pInputBuffer.Lock(out pbInputData, out cb, out cbInputLength); // Round to the next lowest multiple of nBlockAlign. cbBytesProcessed = cbInputLength - (cbInputLength % m_Alignment); // Process the data. ProcessAudio(pbInputData, pbInputData, cbBytesProcessed / m_Alignment); // Set the data length on the output buffer. throwonhr = pInputBuffer.SetCurrentLength(cbBytesProcessed); long hnsTime = 0; // Ignore failure if the input sample does not have a time stamp. This is // not an error condition. The client may not care about time stamps, and // we don't need them. if (Succeeded(pInputSample.GetSampleTime(out hnsTime))) { long hnsDuration = (cbBytesProcessed / m_AvgBytesPerSec) * UNITS; m_rtTimestamp = hnsTime + hnsDuration; } else { m_rtTimestamp = -1; } OutputSample(pInputSample, InputMessageNumber); } finally { if (pbInputData != IntPtr.Zero) { pInputBuffer.Unlock(); } SafeRelease(pInputBuffer); } }
private HResult ToMFSample(IBufferPacket packet, out IMFSample sample) { sample = null; IMFSample spSample; var hr = MFExtern.MFCreateSample(out spSample); if (MFError.Failed(hr)) { return(hr); } //Get the media buffer IMFMediaBuffer mediaBuffer; hr = StreamConvertor.ConverToMediaBuffer(packet, out mediaBuffer); if (MFError.Failed(hr)) { return(hr); } var len = 0; mediaBuffer.GetCurrentLength(out len); hr = spSample.AddBuffer(mediaBuffer); if (MFError.Failed(hr)) { return(hr); } sample = spSample; return(hr); }
override protected void OnProcessSample(IMFSample pInputSample, bool Discontinuity, int InputMessageNumber) { MFError throwonhr; IMFMediaBuffer pInput; // Set the Discontinuity flag on the sample that's going to OutputSample. HandleDiscontinuity(Discontinuity, pInputSample); // 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 = pInputSample.ConvertToContiguousBuffer(out pInput); try { // Process it. DoWork(pInput); // Send the modified input sample to the output sample queue. OutputSample(pInputSample, InputMessageNumber); m_FrameCount++; } finally { // If (somewhere) there is .Net code that is holding on to an instance of // the same buffer as pInput, this will yank the RCW out from underneath // it, probably causing it to crash. But if we don't release it, our memory // usage explodes. SafeRelease(pInput); } }
protected void Draw() { HResult hr; IMFSample mfsample = null; try { // 現在表示すべき IMFSample が TextureMediaSink の TMS_SAMPLE 属性に設定されているので、それを取得する。 if ((hr = this.MediaSinkAttributes.GetUnknown(TMS_SAMPLE, out mfsample)).Failed()) { return; } if (null == mfsample) { return; // 未設定 } var sample = new SharpDX.MediaFoundation.Sample(Marshal.GetIUnknownForObject(mfsample)); // MediaFoundation.NET to SharpDX.MediaFoundation // 注意: // 変数 mfsample は RCW(Runtime Callable Wrapper) オブジェクトであり、内部に COM (ネイティブIMFSample) への参照を保持している。 // このあと mfsample への参照が 0 になっても、内部の COM は mfsample が GC によりファイナライズされるまで Release されないことに注意。(RCW の仕様) // D3D11TextureMediaSink.dll では、mfsample の内包する COM の実体がこのプログラム(とdll)が終了するまで不変であるよう設計されているため、直接の問題はない。 // (RCW による同一の COM への AddRef は1回しか行われないので、mfsample に何度値を設定しても、内部の COM 参照カウンタは初回以降増加しない。) // IMFSample からメディアバッファを取得。 using (var mediaBuffer = sample.GetBufferByIndex(0)) { // メディアバッファからDXGIバッファを取得。 using (var dxgiBuffer = mediaBuffer.QueryInterfaceOrNull <SharpDX.MediaFoundation.DXGIBuffer>()) { // DXGIバッファから転送元 Texture2D を取得。 dxgiBuffer.GetResource(typeof(SharpDX.Direct3D11.Texture2D).GUID, out IntPtr ppv); using (var texture = new SharpDX.Direct3D11.Texture2D(ppv)) { // 転送元 Texture2D のサブリソースインデックスを取得。 int subIndex = dxgiBuffer.SubresourceIndex; // // これで、IMFSample から ID3D11Texture2D を取得することができた。 // 今回のデモでは、これを単純に SwapChain に矩形描画することにする。 // // SwapChain から転送先 Texture2D を取得。 using (var dst = this.DXGISwapChain.GetBackBuffer <SharpDX.Direct3D11.Texture2D>(0)) { // 転送。 this.D3DDevice.ImmediateContext.CopySubresourceRegion(texture, subIndex, null, dst, 0); } } } } } finally { // GetUnknown で TMS_SAMPLE を得たとき、その IMFSample は TextureMediaSink から更新されないよう lock されている。 // この lock を解除するために、TMS_SAMPLE 属性に何か(なんでもいい)を SetUnknwon する。これで IMFSample が TextureMediaSink から更新可能になる。 this.MediaSinkAttributes.SetUnknown(TMS_SAMPLE, mfsample); } }
/// <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)); }
void SET_SAMPLE_ATTRIBUTE(StspSampleHeader sampleHeader, IMFSample pSample, Guid flag, StspSampleFlags flagValue) { var value = (int)flagValue; if ((value & sampleHeader.dwFlagMasks) == value) { ThrowIfError(pSample.SetUINT32(flag, ((value & sampleHeader.dwFlags) == value) ? 1 : 0)); } }
/// <summary> /// Disposes the <see cref="WasapiCaptureClient"/> object. /// </summary> public void Dispose() { if (this.captureThread != null) { this.shutdownEvent.Set(); this.captureThread.Join(); this.captureThread = null; } if (this.shutdownEvent != null) { this.shutdownEvent.Close(); this.shutdownEvent = null; } if (this.audioClient != null) { Marshal.ReleaseComObject(this.audioClient); this.audioClient = null; } if (this.captureClient != null) { Marshal.ReleaseComObject(this.captureClient); this.captureClient = null; } if (this.resampler != null) { Marshal.ReleaseComObject(this.resampler); this.resampler = null; } if (this.inputBuffer != null) { Marshal.ReleaseComObject(this.inputBuffer); this.inputBuffer = null; } if (this.inputSample != null) { Marshal.ReleaseComObject(this.inputSample); this.inputSample = null; } if (this.outputBuffer != null) { Marshal.ReleaseComObject(this.outputBuffer); this.outputBuffer = null; } if (this.outputSample != null) { Marshal.ReleaseComObject(this.outputSample); this.outputSample = null; } }
public static long GetSampleTime(this IMFSample obj) { if (obj == null) { throw new ArgumentNullException(nameof(obj)); } obj.GetSampleTime(out var value).ThrowOnError(); return(value); }
public static long GetSampleDuration(this IMFSample input) { if (input == null) { throw new ArgumentNullException(nameof(input)); } input.GetSampleDuration(out var value).ThrowOnError(); return(value); }
/// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+= /// <summary> /// Called when the sample grabber sink processes a sample. We can use this /// to do what we want with the sample /// </summary> /// <param name="guidMajorMediaType">the media type</param> /// <param name="sampleFlags">the sample flags</param> /// <param name="sampleSize">the sample size</param> /// <param name="sampleDuration">the sample duration</param> /// <param name="sampleTimeStamp">the sample time</param> /// <param name="sampleBuffer">the sample buffer</param> /// <param name="sampleAttributes">the attributes for the sample</param> /// <history> /// 01 Nov 18 Cynic - Ported in /// </history> public HResult OnProcessSampleEx(Guid guidMajorMediaType, int sampleFlags, long sampleTimeStamp, long sampleDuration, IntPtr sampleBuffer, int sampleSize, IMFAttributes sampleAttributes) { IMFSample outputSample = null; HResult hr; try { if (sinkWriter == null) { string errMsg = "OnProcessSample, Error sinkWriter==null"; SampleGrabberAsyncCallBackError(this, errMsg, null); return(HResult.E_FAIL); } // we have all the information we need to create a new output sample outputSample = TantaWMFUtils.CreateMediaSampleFromIntPtr(sampleFlags, sampleTimeStamp, sampleDuration, sampleBuffer, sampleSize, sampleAttributes); if (outputSample == null) { string errMsg = "OnProcessSample, Error on call to CreateMediaSampleFromBuffer outputSample == null"; SampleGrabberAsyncCallBackError(this, errMsg, null); return(HResult.E_FAIL); } lock (sinkWriter) { // write the sample out hr = sinkWriter.WriteSample(sinkWriterMediaStreamId, outputSample); if (Failed(hr)) { string errMsg = "OnProcessSample, Error on WriteSample =" + hr.ToString(); SampleGrabberAsyncCallBackError(this, errMsg, null); return(hr); } // if you do not set MF_SINK_WRITER_DISABLE_THROTTLING on the sink writer, the // calls below can sometimes be useful to avoid the sink writer stalling for a bit // while it waits for one stream or the other. In fact is a bit disconcerting // that we do not seem to get any of these in the sample grabber. // sinkWriter.SendStreamTick(sinkWriterMediaStreamId, sampleTimeStamp); // sinkWriter.NotifyEndOfSegment(sinkWriterMediaStreamId); } } finally { if (outputSample != null) { Marshal.ReleaseComObject(outputSample); outputSample = null; } } return(HResult.S_OK); }
protected MFTBase() { Trace("MFTImplementation"); m_TransformLockObject = new object(); m_pInputType = null; m_pOutputType = null; m_pSample = null; }
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 bool ShouldDropSample(IMFSample pSample) { if (!_isVideo) { return(false); } bool fCleanPoint = MFExtern.MFGetAttributeUINT32(pSample, MFSampleExtension_CleanPoint, 0) > 0; bool fDrop = _flRate != 1.0f && !fCleanPoint; long hnsTimeStamp = 0; ThrowIfError(pSample.GetSampleTime(out hnsTimeStamp)); if (!fDrop && _fDropTime) { if (_fInitDropTime) { _hnsStartDroppingAt = hnsTimeStamp; _fInitDropTime = false; } fDrop = hnsTimeStamp < (_hnsStartDroppingAt + _hnsAmountToDrop); if (!fDrop) { //Debug.WriteLine($"Ending dropping time on sample ts={hnsTimeStamp} _hnsStartDroppingAt={_hnsStartDroppingAt} _hnsAmountToDrop={_hnsAmountToDrop}"); ResetDropTime(); } else { //Debug.WriteLine($"Dropping sample ts={hnsTimeStamp} _hnsStartDroppingAt={_hnsStartDroppingAt} _hnsAmountToDrop={_hnsAmountToDrop}"); } } if (!fDrop && (_eDropMode == MFQualityDropMode.Mode1 || _fWaitingForCleanPoint)) { // Only key frames fDrop = !fCleanPoint; if (fCleanPoint) { _fWaitingForCleanPoint = false; } if (fDrop) { //Debug.WriteLine($"Dropping sample ts={hnsTimeStamp}"); } } return(fDrop); }
//----------------------------------------------------------------------------- // ReturnSample // // Returns a sample to the pool. //----------------------------------------------------------------------------- public void ReturnSample(IMFSample pSample) { lock (this) { if (!m_bInitialized) { throw new COMException("SamplePool::ReturnSample", (int)HResult.MF_E_NOT_INITIALIZED); } m_VideoSampleQueue.Enqueue(pSample); m_cPending--; // Since we're locked, we don't need InterlockedDecrement } }
/// <summary> /// Retrieves the presentation time of the sample. /// </summary> /// <param name="sample">A valid IMFSample instance.</param> /// <param name="sampleTime">Receives 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 GetSampleTime(this IMFSample sample, out TimeSpan sampleTime) { if (sample == null) { throw new ArgumentNullException("sample"); } long tmp; HResult hr = sample.GetSampleDuration(out tmp); sampleTime = hr.Succeeded() ? TimeSpan.FromTicks(tmp) : default(TimeSpan); return(hr); }
override protected void OnProcessSample(IMFSample pInputSample, bool Discontinuity, int InputMessageNumber) { // Set the Discontinuity flag on the sample that's going to OutputSample. HandleDiscontinuity(Discontinuity, pInputSample); // Since m_pAttributes is not threadsafe, bad things // could happen here if m_ThreadCount > 1. If I really // needed to support multiple threads here, I would // probably copy the m_Slims.Wait() logic from OutputSample. MFError throwonhr = Attributes.SetUINT32(m_SampleCountGuid, m_iSampleCount); m_iSampleCount++; // Send the unmodified input sample to the output sample queue. OutputSample(pInputSample, InputMessageNumber); }
//todo: put the process work to background thread to speed up. public HResult ProcessSample(IMFSample videoSample) { HResult hr = HResult.S_OK; MFTOutputStatusFlags mftOutFlags; MFTOutputStreamInfo StreamInfo; if (videoSample == null) { return(hr); } pDecoderTransform.ProcessInput(0, videoSample, 0); pDecoderTransform.GetOutputStatus(out mftOutFlags); pDecoderTransform.GetOutputStreamInfo(0, out StreamInfo); while (true) { IMFMediaBuffer resultBuffer; //reset the cache buffer. MFExtern.MFCreateMemoryBuffer(StreamInfo.cbSize, out resultBuffer); _mftOutSample.RemoveAllBuffers(); _mftOutSample.AddBuffer(resultBuffer); ProcessOutputStatus outputStatus; var mftProcessOutput = pDecoderTransform.ProcessOutput(0, 1, _mftOutBufferContainer, out outputStatus); if (mftProcessOutput == HResult.MF_E_TRANSFORM_NEED_MORE_INPUT) { //continue provice input data. break; } else if (_mftOutBufferContainer[0].dwStatus == MFTOutputDataBufferFlags.Incomplete) { //todo: the decoded data include more than one samples,we need to receive all data items. } else { IMFMediaBuffer buffer; _mftOutSample.ConvertToContiguousBuffer(out buffer); invokeDecodeComplete(buffer, StreamInfo.cbSize); } } return(hr); }
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); } }
/// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+= /// <summary> /// Called when the sample grabber sink processes a sample. We can use this /// to do what we want with the media data /// </summary> /// <param name="guidMajorMediaType">the media type</param> /// <param name="sampleFlags">the sample flags</param> /// <param name="sampleSize">the sample size</param> /// <param name="sampleDuration">the sample duration</param> /// <param name="sampleTimeStamp">the sample time</param> /// <param name="sampleBuffer">the sample buffer</param> /// <param name="sampleAttributes">the attributes for the sample</param> /// <history> /// 01 Nov 18 Cynic - Ported in /// </history> public HResult OnProcessSampleEx(Guid guidMajorMediaType, int sampleFlags, long sampleTimeStamp, long sampleDuration, IntPtr sampleBuffer, int sampleSize, IMFAttributes sampleAttributes) { IMFSample outputSample = null; HResult hr; try { if (sinkWriter == null) { string errMsg = "OnProcessSample, Error sinkWriter==null"; SampleGrabberAsyncCallBackError(this, errMsg, null); return(HResult.E_FAIL); } // we have all the information we need to create a new output sample outputSample = TantaWMFUtils.CreateMediaSampleFromIntPtr(sampleFlags, sampleTimeStamp, sampleDuration, sampleBuffer, sampleSize, null); if (outputSample == null) { string errMsg = "OnProcessSample, Error on call to CreateMediaSampleFromBuffer outputSample == null"; SampleGrabberAsyncCallBackError(this, errMsg, null); return(HResult.E_FAIL); } // write the sample out hr = sinkWriter.WriteSample(sinkWriterMediaStreamId, outputSample); if (Failed(hr)) { string errMsg = "OnProcessSample, Error on WriteSample =" + hr.ToString(); SampleGrabberAsyncCallBackError(this, errMsg, null); return(hr); } } finally { if (outputSample != null) { Marshal.ReleaseComObject(outputSample); outputSample = null; } } return(HResult.S_OK); }
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); }
protected void DeliverSample(IMFSample pSample, bool bRepaint) { Debug.Assert(pSample != null); D3DPresentEngine.DeviceState state; // If we are not actively playing, OR we are scrubbing (rate = 0) OR this is a // repaint request, then we need to present the sample immediately. Otherwise, // schedule it normally. bool bPresentNow = ((m_RenderState != RenderState.Started) || IsScrubbing() || bRepaint); // Check the D3D device state. int hr = S_Ok; try { m_pD3DPresentEngine.CheckDeviceState(out state); m_scheduler.ScheduleSample(pSample, bPresentNow); } catch (Exception e) { // Notify the EVR that we have failed during streaming. The EVR will notify the // pipeline (ie, it will notify the Filter Graph Manager in DirectShow or the // Media Session in Media Foundation). hr = Marshal.GetHRForException(e); NotifyEvent(EventCode.ErrorAbort, new IntPtr(hr), IntPtr.Zero); throw; } if (state == D3DPresentEngine.DeviceState.DeviceReset) { // The Direct3D device was re-set. Notify the EVR. NotifyEvent(EventCode.DisplayChanged, IntPtr.Zero, IntPtr.Zero); } }
protected void DeliverFrameStepSample(IMFSample pSample) { // For rate 0, discard any sample that ends earlier than the clock time. if (IsScrubbing() && (m_pClock != null) && IsSampleTimePassed(m_pClock, pSample)) { // Discard this sample. Marshal.ReleaseComObject(pSample); } else if (m_FrameStep.state >= FrameStepRate.Scheduled) { // A frame was already submitted. Put this sample on the frame-step queue, // in case we are asked to step to the next frame. If frame-stepping is // cancelled, this sample will be processed normally. m_FrameStep.samples.Enqueue(pSample); } else { // We're ready to frame-step. // Decrement the number of steps. if (m_FrameStep.steps > 0) { m_FrameStep.steps--; } if (m_FrameStep.steps > 0) { // This is not the last step. Discard this sample. Marshal.ReleaseComObject(pSample); } else if (m_FrameStep.state == FrameStepRate.WaitingStart) { // This is the right frame, but the clock hasn't started yet. Put the // sample on the frame-step queue. When the clock starts, the sample // will be processed. m_FrameStep.samples.Enqueue(pSample); } else { // This is the right frame *and* the clock has started. Deliver this sample. DeliverSample(pSample, false); // Save this value. m_FrameStep.SetSample(pSample); // NOTE: We do not AddRef the IUnknown pointer, because that would prevent the // sample from invoking the OnSampleFree callback after the sample is presented. // We use this IUnknown pointer purely to identify the sample later; we never // attempt to dereference the pointer. // Update our state. m_FrameStep.state = FrameStepRate.Scheduled; } } }
protected void CompleteFrameStep(IMFSample pSample) { int hr; long hnsSampleTime = 0; long hnsSystemTime = 0; // Update our state. m_FrameStep.state = FrameStepRate.Complete; m_FrameStep.pSampleNoRef = IntPtr.Zero; // Notify the EVR that the frame-step is complete. NotifyEvent(EventCode.StepComplete, IntPtr.Zero, IntPtr.Zero); // FALSE = completed (not cancelled) // If we are scrubbing (rate == 0), also send the "scrub time" event. if (IsScrubbing()) { // Get the time stamp from the sample. try { hr = pSample.GetSampleTime(out hnsSampleTime); MFError.ThrowExceptionForHR(hr); } catch { // No time stamp. Use the current presentation time. if (m_pClock != null) { hr = m_pClock.GetCorrelatedTime(0, out hnsSampleTime, out hnsSystemTime); MFError.ThrowExceptionForHR(hr); } } // This event (EventCode.ScrubTime) isn't defined until DirectShowNet v2.1 NotifyEvent((EventCode)0x23, new IntPtr((int)hnsSampleTime), new IntPtr(hnsSampleTime >> 32)); } }
//----------------------------------------------------------------------------- // CreateD3DSample // // Creates an sample object (IMFSample) to hold a Direct3D swap chain. //----------------------------------------------------------------------------- protected void CreateD3DSample(IDirect3DSwapChain9 pSwapChain, out IMFSample ppVideoSample) { int hr; IDirect3DSurface9 pSurface = null; // Caller holds the object lock. try { // Get the back buffer surface. pSwapChain.GetBackBuffer(0, D3DBACKBUFFER_TYPE.Mono, out pSurface); // Create the sample. hr = MFExtern.MFCreateVideoSampleFromSurface(pSurface, out ppVideoSample); MFError.ThrowExceptionForHR(hr); } finally { SafeRelease(pSurface); pSurface = null; } }
protected abstract int OnFrame(IMFSample pSample, IMFMediaBuffer pBuffer, long llTimestamp, string ssFormat);
protected void TrackSample(IMFSample pSample) { IMFTrackedSample pTracked = null; pTracked = (IMFTrackedSample)pSample; int hr = pTracked.SetAllocator(this, null); MFError.ThrowExceptionForHR(hr); }
public bool ProcessSample(IMFSample pSample, out int plNextSleep) { int hr; long hnsPresentationTime = 0; long hnsTimeNow = 0; long hnsSystemTime = 0; bool bPresentNow = true; plNextSleep = 0; if (m_pClock != null) { // Get the sample's time stamp. It is valid for a sample to // have no time stamp. try { hr = pSample.GetSampleTime(out hnsPresentationTime); MFError.ThrowExceptionForHR(hr); // Get the clock time. (But if the sample does not have a time stamp, // we don't need the clock time.) hr = m_pClock.GetCorrelatedTime(0, out hnsTimeNow, out hnsSystemTime); MFError.ThrowExceptionForHR(hr); } catch { } // Calculate the time until the sample's presentation time. // A negative value means the sample is late. long hnsDelta = hnsPresentationTime - hnsTimeNow; if (m_fRate < 0) { // For reverse playback, the clock runs backward. Therefore the delta is reversed. hnsDelta = -hnsDelta; } if (hnsDelta < -m_PerFrame_1_4th) { // This sample is late. bPresentNow = true; } else if (hnsDelta > (3 * m_PerFrame_1_4th)) { // This sample is still too early. Go to sleep. plNextSleep = Utils.MFTimeToMsec(hnsDelta - (3 * m_PerFrame_1_4th)); // Adjust the sleep time for the clock rate. (The presentation clock runs // at m_fRate, but sleeping uses the system clock.) plNextSleep = (int)(plNextSleep / Math.Abs(m_fRate)); // Don't present yet. bPresentNow = false; } } if (bPresentNow) { m_pCB.PresentSample(pSample, hnsPresentationTime); // pSample released by caller along with DeQueue } return bPresentNow; }
protected override int OnFrame(IMFSample pSample, IMFMediaBuffer pBuffer, long llTimestamp, string ssFormat) => Draw.DrawFrame(pBuffer, !string.IsNullOrEmpty(ssFormat), ssFormat);
public void Dispose() { Sample = null; if (Target != null) { Target.Dispose(); Target = null; } }
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; }
//----------------------------------------------------------------------------- // GetSample // // Gets a sample from the pool. If no samples are available, the method // returns ppSample = null //----------------------------------------------------------------------------- public void GetSample(out IMFSample ppSample) { lock (this) { if (!m_bInitialized) { throw new COMException("SamplePool::GetSample1", MFError.MF_E_NOT_INITIALIZED); } if (m_VideoSampleQueue.Count == 0) { ppSample = null; return; } // Get a sample from the allocated queue. ppSample = (IMFSample)m_VideoSampleQueue.Dequeue(); m_cPending++; // Since we're locked, we don't need InterlockedIncrement } }
//----------------------------------------------------------------------------- // PresentSample // // Presents a video frame. // // pSample: Pointer to the sample that contains the surface to present. If // this parameter is NULL, the method paints a black rectangle. // llTarget: Target presentation time. // // This method is called by the scheduler and/or the presenter. //----------------------------------------------------------------------------- public void PresentSample(IMFSample pSample, long llTarget) { int hr; IMFMediaBuffer pBuffer = null; IDirect3DSurface9 pSurface = null; IDirect3DSwapChain9 pSwapChain = null; object o; try { if (pSample != null) { // Get the buffer from the sample. hr = pSample.GetBufferByIndex(0, out pBuffer); MFError.ThrowExceptionForHR(hr); // Get the surface from the buffer. hr = MFExtern.MFGetService(pBuffer, MFServices.MR_BUFFER_SERVICE, typeof(IDirect3DSurface9).GUID, out o); MFError.ThrowExceptionForHR(hr); pSurface = o as IDirect3DSurface9; } else if (m_pSurfaceRepaint != null) { // Redraw from the last surface. pSurface = m_pSurfaceRepaint; } if (pSurface != null) { // Get the swap chain from the surface. pSurface.GetContainer(typeof(IDirect3DSwapChain9).GUID, out o); pSwapChain = o as IDirect3DSwapChain9; // Present the swap chain. PresentSwapChain(pSwapChain, pSurface); // Store this pointer in case we need to repaint the surface. if (m_pSurfaceRepaint != pSurface) { SafeRelease(m_pSurfaceRepaint); m_pSurfaceRepaint = pSurface; } } else { // No surface. All we can do is paint a black rectangle. PaintFrameWithGDI(); } } catch (Exception e) { hr = Marshal.GetHRForException(e); if (hr == (int)D3DError.DeviceLost || hr == (int)D3DError.DeviceNotReset || hr == (int)D3DError.DeviceHung) { // We failed because the device was lost. Fill the destination rectangle. PaintFrameWithGDI(); // Ignore. We need to reset or re-create the device, but this method // is probably being called from the scheduler thread, which is not the // same thread that created the device. The Reset(Ex) method must be // called from the thread that created the device. // The presenter will detect the state when it calls CheckDeviceState() // on the next sample. } } finally { SafeRelease(pSwapChain); pSwapChain = null; //SafeRelease(pSurface); pSurface = null; SafeRelease(pBuffer); pBuffer = null; } }
protected bool IsSampleTimePassed(IMFClock pClock, IMFSample pSample) { Debug.Assert(pClock != null); Debug.Assert(pSample != null); if (pSample == null || pClock == null) { throw new COMException("IsSampleTimePassed", E_Pointer); } int hr; bool bRet = false; long hnsTimeNow = 0; long hnsSystemTime = 0; long hnsSampleStart = 0; long hnsSampleDuration = 0; // The sample might lack a time-stamp or a duration, and the // clock might not report a time. try { hr = pClock.GetCorrelatedTime(0, out hnsTimeNow, out hnsSystemTime); MFError.ThrowExceptionForHR(hr); hr = pSample.GetSampleTime(out hnsSampleStart); MFError.ThrowExceptionForHR(hr); hr = pSample.GetSampleDuration(out hnsSampleDuration); MFError.ThrowExceptionForHR(hr); if (hnsSampleStart + hnsSampleDuration < hnsTimeNow) { bRet = true; } } catch { } return bRet; }
protected void SetDesiredSampleTime(IMFSample pSample, long hnsSampleTime, long hnsDuration) { if (pSample == null) { throw new COMException("SetDesiredSampleTime", E_Pointer); } IMFDesiredSample pDesired = null; pDesired = (IMFDesiredSample)pSample; // This method has no return value. pDesired.SetDesiredSampleTimeAndDuration(hnsSampleTime, hnsDuration); //SafeRelease(pDesired); }
public void ScheduleSample(IMFSample pSample, bool bPresentNow) { if (m_bSchedulerThread == false) { throw new COMException("Scheduler thread not started", MFError.MF_E_NOT_INITIALIZED); } if (bPresentNow || (m_pClock == null)) { // Present the sample immediately. m_pCB.PresentSample(pSample, 0); SafeRelease(pSample); } else { // Queue the sample and ask the scheduler thread to wake up. lock (m_ScheduledSamples) { m_ScheduledSamples.Enqueue(pSample); } lock (m_ScheduledSamples) { m_EventQueue.Enqueue(ScheduleEvent.eSchedule); } m_hMsgEvent.Set(); } }
//----------------------------------------------------------------------------- // ReturnSample // // Returns a sample to the pool. //----------------------------------------------------------------------------- public void ReturnSample(IMFSample pSample) { lock (this) { if (!m_bInitialized) { throw new COMException("SamplePool::ReturnSample", MFError.MF_E_NOT_INITIALIZED); } m_VideoSampleQueue.Enqueue(pSample); m_cPending--; // Since we're locked, we don't need InterlockedDecrement } }
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) { var hr = hrStatus; IMFMediaBuffer pBuffer = null; lock (LockSync) { try { if (pSample != null) { // Get the video frame buffer from the sample. if (Succeeded(hr)) hr = pSample.GetBufferByIndex(0, out pBuffer); if (Succeeded(hr)) { hr = OnFrame(pSample, pBuffer, llTimestamp, snapFormat); snapFormat = string.Empty; } } // Request the next frame. if (Succeeded(hr)) { // Read next sample. hr = PReader.ReadSample( (int) MF_SOURCE_READER.FirstVideoStream, 0, IntPtr.Zero, // actual IntPtr.Zero, // flags IntPtr.Zero, // time stamp IntPtr.Zero // sample ); } if (Failed(hr)) { NotifyError(hr); } } finally { SafeRelease(pBuffer); SafeRelease(pSample); } } return hr; }
protected void ClearDesiredSampleTime(IMFSample pSample) { if (pSample == null) { throw new COMException("ClearDesiredSampleTime", E_Pointer); } IMFDesiredSample pDesired = null; object pUnkSwapChain = null; // We store some custom attributes on the sample, so we need to cache them // and reset them. // // This works around the fact that IMFDesiredSample::Clear() removes all of the // attributes from the sample. int counter; int hr; hr = pSample.GetUINT32(MFSamplePresenter_SampleCounter, out counter); MFError.ThrowExceptionForHR(hr); try { Guid IID_IUnknown = new Guid("00000000-0000-0000-C000-000000000046"); hr = pSample.GetUnknown(MFSamplePresenter_SampleSwapChain, IID_IUnknown, out pUnkSwapChain); MFError.ThrowExceptionForHR(hr); } catch { } pDesired = (IMFDesiredSample)pSample; pDesired.Clear(); hr = pSample.SetUINT32(MFSamplePresenter_SampleCounter, counter); MFError.ThrowExceptionForHR(hr); if (pUnkSwapChain != null) { hr = pSample.SetUnknown(MFSamplePresenter_SampleSwapChain, pUnkSwapChain); MFError.ThrowExceptionForHR(hr); } SafeRelease(pUnkSwapChain); //SafeRelease(pDesired); }
//------------------------------------------------------------------- // Name: ProcessSample // Description: Receives an input sample. [Asynchronous] // // Note: The client should only give us a sample after we send an // MEStreamSinkRequestSample event. //------------------------------------------------------------------- public int ProcessSample(IMFSample pSample) { TRACE("CWavStream::ProcessSample"); lock (this) { if (pSample == null) { throw new COMException("Null pSample", E_InvalidArgument); } CheckShutdown(); // Validate the operation. ValidateOperation(CAsyncOperation.StreamOperation.OpProcessSample); // Add the sample to the sample queue. m_SampleQueue.Enqueue(pSample); // Unless we are paused, start an async operation to dispatch the next sample. if (m_state != State.Paused) { // Queue the operation. QueueAsyncOperation(CAsyncOperation.StreamOperation.OpProcessSample); } } return S_Ok; }
//------------------------------------------------------------------- // Name: WriteSampleToFile // Description: Output one media sample to the file. //------------------------------------------------------------------- void WriteSampleToFile(IMFSample pSample) { int hr; int i; long time; int cBufferCount; // Number of buffers in the sample. IntPtr pData; int cbData = 0; int cbWritten = 0; // Get the time stamp hr = pSample.GetSampleTime(out time); MFError.ThrowExceptionForHR(hr); // If the time stamp is too early, just discard this sample. if (time < m_StartTime) { return; } // Note: If there is no time stamp on the sample, proceed anyway. // Find how many buffers are in this sample. hr = pSample.GetBufferCount(out cBufferCount); MFError.ThrowExceptionForHR(hr); // Loop through all the buffers in the sample. for (int iBuffer = 0; iBuffer < cBufferCount; iBuffer++) { IMFMediaBuffer pBuffer = null; hr = pSample.GetBufferByIndex(iBuffer, out pBuffer); MFError.ThrowExceptionForHR(hr); try { // Lock the buffer and write the data to the file. hr = pBuffer.Lock(out pData, out i, out cbData); MFError.ThrowExceptionForHR(hr); hr = m_pByteStream.Write(pData, cbData, out cbWritten); MFError.ThrowExceptionForHR(hr); hr = pBuffer.Unlock(); MFError.ThrowExceptionForHR(hr); // Update the running tally of bytes written. m_cbDataWritten += cbData; } finally { SafeRelease(pBuffer); } } // for loop }
// 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); } } } // 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; }
private void CreateAudioSample(out IMFSample ppSample) { int hr; m_Log.WriteLine("CreateAudioSample"); ppSample = null; IMFMediaBuffer pBuffer = null; IMFSample pSample = null; int cbBuffer = 0; IntPtr pData = IntPtr.Zero; long duration = 0; // Start with one second of data, rounded up to the nearest block. cbBuffer = Utils.AlignUp(m_Riff.Format().nAvgBytesPerSec, m_Riff.Format().nBlockAlign); // Don't request any more than what's left. cbBuffer = Math.Min(cbBuffer, m_Riff.BytesRemainingInChunk()); // Create the buffer. hr = MFExtern.MFCreateMemoryBuffer(cbBuffer, out pBuffer); MFError.ThrowExceptionForHR(hr); int a, b; // Get a pointer to the buffer memory. hr = pBuffer.Lock(out pData, out a, out b); MFError.ThrowExceptionForHR(hr); try { // Fill the buffer m_Riff.ReadDataFromChunk(pData, cbBuffer); } finally { // Unlock the buffer. hr = pBuffer.Unlock(); MFError.ThrowExceptionForHR(hr); } // Set the size of the valid data in the buffer. hr = pBuffer.SetCurrentLength(cbBuffer); MFError.ThrowExceptionForHR(hr); // Create a new sample and add the buffer to it. hr = MFExtern.MFCreateSample(out pSample); MFError.ThrowExceptionForHR(hr); hr = pSample.AddBuffer(pBuffer); MFError.ThrowExceptionForHR(hr); // Set the time stamps, duration, and sample flags. hr = pSample.SetSampleTime(m_rtCurrentPosition); MFError.ThrowExceptionForHR(hr); duration = Utils.AudioDurationFromBufferSize(m_Riff.Format(), cbBuffer); hr = pSample.SetSampleDuration(duration); MFError.ThrowExceptionForHR(hr); // Set the discontinuity flag. if (m_discontinuity) { hr = pSample.SetUINT32(MFAttributesClsid.MFSampleExtension_Discontinuity, 1); MFError.ThrowExceptionForHR(hr); } // Update our current position. m_rtCurrentPosition += duration; // Give the pointer to the caller. ppSample = pSample; //SAFE_RELEASE(pBuffer); //SAFE_RELEASE(pSample); }