/// <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> public int Read(byte[] buffer, int offset, int count) { if (transform == null) { transform = CreateTransform(); InitializeTransformForStreaming(); } // strategy will be to always read 1 second from the source, and give it to the resampler int bytesWritten = 0; // read in any leftovers from last time if (outputBufferCount > 0) { bytesWritten += ReadFromOutputBuffer(buffer, offset, count - bytesWritten); } while (bytesWritten < count) { var sample = ReadFromSource(); if (sample == null) // reached the end of our input { // be good citizens and send some end messages: EndStreamAndDrain(); // resampler might have given us a little bit more to return bytesWritten += ReadFromOutputBuffer(buffer, offset + bytesWritten, count - bytesWritten); ClearOutputBuffer(); break; } // might need to resurrect the stream if the user has read all the way to the end, // and then repositioned the input backwards if (!initializedForStreaming) { InitializeTransformForStreaming(); } // give the input to the resampler // can get MF_E_NOTACCEPTING if we didn't drain the buffer properly transform.ProcessInput(0, sample, 0); Marshal.ReleaseComObject(sample); int readFromTransform; // n.b. in theory we ought to loop here, although we'd need to be careful as the next time into ReadFromTransform there could // still be some leftover bytes in outputBuffer, which would get overwritten. Only introduce this if we find a transform that // needs it. For most transforms, alternating read/write should be OK //do //{ // keep reading from transform readFromTransform = ReadFromTransform(); bytesWritten += ReadFromOutputBuffer(buffer, offset + bytesWritten, count - bytesWritten); //} while (readFromTransform > 0); } return(bytesWritten); }
//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); }
public HResult DecodeSample(byte[] inbuffer, int insize, out byte[] outbuff, out int outsize) { // Process Input. MFTOutputDataBuffer outputDataBuffer; ProcessOutputStatus processOutputStatus = 0; IMFSample srcVideoSample; HResult mftProcessOutput; MFTOutputStreamInfo StreamInfo; IMFSample mftOutSample; IMFMediaBuffer pBuffer, srcBuffer; Debug.WriteLine("Process sample..."); outbuff = null; outsize = 0; MFExtern.MFCreateSample(out srcVideoSample); MFExtern.MFCreateMemoryBuffer(insize, out srcBuffer); srcVideoSample.AddBuffer(srcBuffer); IntPtr inputdata = IntPtr.Zero; int reconBuffCurrLen = 0; int reconBuffMaxLen = 0; Debug.WriteLine("CONTINUE...1"); // move input data to decoder srcBuffer.Lock(out inputdata, out reconBuffMaxLen, out reconBuffCurrLen); Marshal.Copy(inbuffer, 0, inputdata, insize); srcBuffer.Unlock(); srcBuffer.SetCurrentLength(insize); decodertransform.ProcessInput(0, srcVideoSample, 0); decodertransform.GetOutputStreamInfo(0, out StreamInfo); while (true) { MFExtern.MFCreateSample(out mftOutSample); MFExtern.MFCreateMemoryBuffer(StreamInfo.cbSize, out pBuffer); mftOutSample.AddBuffer(pBuffer); outputDataBuffer.dwStreamID = 0; outputDataBuffer.dwStatus = MFTOutputDataBufferFlags.None; outputDataBuffer.pEvents = null; outputDataBuffer.pSample = Marshal.GetIUnknownForObject(mftOutSample); MFTOutputDataBuffer[] odbs = { outputDataBuffer }; mftProcessOutput = decodertransform.ProcessOutput(MFTProcessOutputFlags.None, 1, odbs, out processOutputStatus); if (mftProcessOutput != HResult.MF_E_TRANSFORM_NEED_MORE_INPUT) { IMFMediaBuffer buf; int bufLength; mftOutSample.ConvertToContiguousBuffer(out buf); buf.GetCurrentLength(out bufLength); IntPtr poutputData = IntPtr.Zero; int buffCurrLen = 0; int buffMaxLen = 0; // get output data from decoder buf.Lock(out poutputData, out buffMaxLen, out buffCurrLen); outbuff = new byte[buffMaxLen]; Marshal.Copy(poutputData, outbuff, 0, buffCurrLen); buf.Unlock(); outsize = buffCurrLen; Debug.WriteLine("out put size: " + outsize + "\n"); Marshal.ReleaseComObject(buf); Marshal.ReleaseComObject(mftOutSample); } else { break; } return(mftProcessOutput); } return(mftProcessOutput); }
private void CaptureStillImages(MediaItem item) { using (var releaser = new ComReleaser()) { MF.CreateVideoDeviceSource(item.DeviceItem.SymLink, out IMFMediaSource source); releaser.Add(source); source.CreatePresentationDescriptor(out IMFPresentationDescriptor presDesc); releaser.Add(presDesc); presDesc.GetStreamDescriptorByIndex(item.DescIndex, out bool selected, out IMFStreamDescriptor strmDesc); releaser.Add(strmDesc); strmDesc.GetMediaTypeHandler(out IMFMediaTypeHandler handler); releaser.Add(handler); handler.GetMediaTypeByIndex(item.TypeIndex, out IMFMediaType type); handler.SetCurrentMediaType(type); MF.CreateSourceReaderFromMediaSource(source, out IMFSourceReader reader); if (reader == null) { return; } releaser.Add(reader); IMFTransform transform = null; MFTOutputDataBuffer[] outSamples = null; IMFSample outRgb24Sample = null; IMFMediaBuffer outRgb24Buffer = null; int rgbSize = item.Width * item.Height * 3; var needToConvert = item.SubType != MFMediaType.RGB24; if (needToConvert) { var processor = new VideoProcessorMFT(); releaser.Add(processor); transform = (IMFTransform)processor; HR(transform.SetInputType(0, type, MFTSetTypeFlags.None)); var rgbMediaType = MF.CreateMediaType(); releaser.Add(rgbMediaType); HR(type.CopyAllItems(rgbMediaType)); HR(rgbMediaType.SetGUID(MFAttributesClsid.MF_MT_SUBTYPE, MFMediaType.RGB24)); HR(rgbMediaType.SetUINT32(MFAttributesClsid.MF_MT_DEFAULT_STRIDE, 3 * item.Width)); HR(rgbMediaType.SetUINT32(MFAttributesClsid.MF_MT_SAMPLE_SIZE, rgbSize)); HR(transform.SetOutputType(0, rgbMediaType, MFTSetTypeFlags.None)); outSamples = new MFTOutputDataBuffer[1]; outSamples[0] = new MFTOutputDataBuffer(); outRgb24Sample = MF.CreateSample(); releaser.Add(outRgb24Sample); outRgb24Buffer = MF.CreateMemoryBuffer(rgbSize); releaser.Add(outRgb24Buffer); outRgb24Sample.AddBuffer(outRgb24Buffer); outSamples[0].pSample = Marshal.GetIUnknownForObject(outRgb24Sample); } while (true) { int frames = 0; var hrRS = reader.ReadSample( (int)MF_SOURCE_READER.AnyStream, MF_SOURCE_READER_CONTROL_FLAG.None, out int streamIndex, out MF_SOURCE_READER_FLAG flags, out long timeStamp, out IMFSample sample ); if (sample != null) { try { IMFSample rgbSample = sample; if (transform != null) { transform.ProcessInput(0, sample, 0); while (true) { var hrPO = transform.ProcessOutput( MFTProcessOutputFlags.None, 1, outSamples, out ProcessOutputStatus status ); if (hrPO.Succeeded()) { ConsumeBuffer(outRgb24Buffer, item); frames++; Marshal.ReleaseComObject(sample); return; //break; } else { break; } } //var hrPI = transform.ProcessInput(0, sample, 0); continue; } rgbSample.GetBufferByIndex(0, out IMFMediaBuffer buff); if (ConsumeBuffer(buff, item)) { frames++; } else { return; } } finally { Marshal.ReleaseComObject(sample); } break; } } } }
internal void ProcessInput(IMFSample sample) { _mft.ProcessInput(0, sample, 0); }