// 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> /// A centralized place to close down all media devices. /// </summary> /// <history> /// 01 Nov 18 Cynic - Started /// </history> private void CloseAllMediaDevices() { //HResult hr; LogMessage("CloseAllMediaDevices"); // Shut down the source reader if (sourceReader != null) { Marshal.ReleaseComObject(sourceReader); sourceReader = null; } // close the sink writer if (sinkWriter != null) { // note we could Finalize_() this here but there // is no need. That is done when the stream ends Marshal.ReleaseComObject(sinkWriter); sinkWriter = null; } if (sourceReaderNativeVideoMediaType != null) { Marshal.ReleaseComObject(sourceReaderNativeVideoMediaType); sourceReaderNativeVideoMediaType = null; } if (sourceReaderNativeAudioMediaType != null) { Marshal.ReleaseComObject(sourceReaderNativeAudioMediaType); sourceReaderNativeAudioMediaType = null; } }
public CCapture(IntPtr hVideo, IntPtr hEvent) : base(hVideo, hEvent) { PWriter = null; BFirstSample = false; LlBaseTime = 0; }
public CCapture(IntPtr hVideo, IntPtr hEvent) : base(hVideo, hEvent) { PWriter = null; BFirstSample = false; LlBaseTime = 0; }
private void PerformEncode(IMFSinkWriter writer, int streamIndex, MediaFoundationReader inputProvider, int first, int last) { int maxLength = inputProvider.WaveFormat.AverageBytesPerSecond * 4; var managedBuffer = new byte[maxLength]; writer.BeginWriting(); first++; bool flag = true; double time = Math.Round(inputProvider.TotalTime.TotalSeconds - last, 0); long position = 0; long duration; do { duration = ConvertOneBuffer(writer, streamIndex, inputProvider, position, managedBuffer, first, ref flag); position += duration; int percent = (int)(inputProvider.CurrentTime.TotalSeconds / inputProvider.TotalTime.TotalSeconds * 100); //LoadProgressChanged.Raise(this, new LoadProgressChangedEventArgs(percent, inputProvider.CurrentTime, inputProvider.TotalTime)); OnLoadProgressChanged(percent, inputProvider.CurrentTime, inputProvider.TotalTime); if (inputProvider.CurrentTime.TotalSeconds >= time) { duration = 0; } } while (duration > 0); writer.DoFinalize(); }
HResult ConfigureEncoder( EncodingParameters eparams, IMFMediaType pType, IMFSinkWriter pWriter, out int pdwStreamIndex ) { HResult hr = HResult.S_OK; IMFMediaType pType2 = null; hr = MFExtern.MFCreateMediaType(out pType2); if (Succeeded(hr)) { hr = pType2.SetGUID(MFAttributesClsid.MF_MT_MAJOR_TYPE, MFMediaType.Video); } if (Succeeded(hr)) { hr = pType2.SetGUID(MFAttributesClsid.MF_MT_SUBTYPE, eparams.subtype); } if (Succeeded(hr)) { hr = pType2.SetUINT32(MFAttributesClsid.MF_MT_AVG_BITRATE, eparams.bitrate); } if (Succeeded(hr)) { hr = CopyAttribute(pType, pType2, MFAttributesClsid.MF_MT_FRAME_SIZE); } if (Succeeded(hr)) { hr = CopyAttribute(pType, pType2, MFAttributesClsid.MF_MT_FRAME_RATE); } if (Succeeded(hr)) { hr = CopyAttribute(pType, pType2, MFAttributesClsid.MF_MT_PIXEL_ASPECT_RATIO); } if (Succeeded(hr)) { hr = CopyAttribute(pType, pType2, MFAttributesClsid.MF_MT_INTERLACE_MODE); } pdwStreamIndex = 0; if (Succeeded(hr)) { hr = pWriter.AddStream(pType2, out pdwStreamIndex); } SafeRelease(pType2); return(hr); }
private void ClearAll() { this.streamsInfo.Clear(); this.sourceFilename = string.Empty; this.targetFilename = string.Empty; this.sourceReader = null; this.sinkWriter = null; this.selectedStreams = 0; }
/// <summary> /// Indicates a gap in an input streamIndex. /// </summary> /// <param name="sinkWriter">A valid IMFSinkWriter instance.</param> /// <param name="streamIndex">The zero-based index of the streamIndex.</param> /// <param name="timestamp">The position in the streamIndex where the gap in the data occurs, relative to the start of the streamIndex.</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 SendStreamTick(this IMFSinkWriter sinkWriter, int streamIndex, TimeSpan timestamp) { if (sinkWriter == null) { throw new ArgumentNullException("sinkWriter"); } return(sinkWriter.SendStreamTick(streamIndex, timestamp.Ticks)); }
public CCapture(IntPtr hwnd, int iMessageID) { m_pReader = null; m_pWriter = null; m_hwndEvent = hwnd; m_iMessageID = iMessageID; m_bFirstSample = false; m_llBaseTime = 0; m_pwszSymbolicLink = null; }
public CCapture(IntPtr hwnd, int iMessageID) { m_pReader = null; m_pWriter = null; m_hwndEvent = hwnd; m_iMessageID = iMessageID; m_bFirstSample = false; m_llBaseTime = 0; m_pwszSymbolicLink = 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); }
public static ComObject <T> GetServiceForStream <T>(this IMFSinkWriter input, uint streamIndex, Guid serviceId, Guid interfaceId) { if (input == null) { throw new ArgumentNullException(nameof(input)); } if (input.GetServiceForStream(streamIndex, serviceId, interfaceId, out var ppv).IsError) { return(null); } return(new ComObject <T>((T)ppv)); }
/// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+= /// <summary> /// A centralized place to close down all media devices /// </summary> /// <history> /// 01 Nov 18 Cynic - Started /// </history> private void CloseAllMediaDevices() { // close the async call back handler CloseAsyncCallBackHandler(workingSourceReaderCallBackHandler); workingSourceReaderCallBackHandler = null; // close the media sink CloseSinkWriter(workingSinkWriter); workingSinkWriter = null; // Close the media source CloseSourceReader(workingSourceReader); workingSourceReader = null; }
/// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+= /// <summary> /// Close the Media sink /// </summary> /// <param name="writerObject">the media source object</param> /// <history> /// 01 Nov 18 Cynic - Started /// </history> private void CloseSinkWriter(IMFSinkWriter writerObject) { // End any active captures if (writerObject == null) { LogMessage("CloseSinkWriter rwriterObject == null"); return; } // close and release HResult hr = writerObject.Finalize_(); Marshal.ReleaseComObject(writerObject); }
private void PerformEncode(IMFSinkWriter writer, int streamIndex, IWaveProvider inputProvider) { int num = inputProvider.WaveFormat.AverageBytesPerSecond * 4; byte[] managedBuffer = new byte[num]; writer.BeginWriting(); long num2 = 0L; long num3; do { num3 = this.ConvertOneBuffer(writer, streamIndex, inputProvider, num2, managedBuffer); num2 += num3; } while (num3 > 0L); writer.DoFinalize(); }
public int StopCapture() { var hr = S_Ok; lock (LockSync) { if (PWriter != null) { hr = PWriter.Finalize_(); SafeRelease(PWriter); PWriter = null; } } return(hr); }
/// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+= /// <summary> /// Opens the Sink Writer object /// </summary> /// <param name="outputFileName">the filename we write out to</param> /// <returns>an IMFSinkWriter object or null for fail</returns> /// <history> /// 01 Nov 18 Cynic - Started /// </history> private IMFSinkWriter OpenSinkWriter(string outputFileName) { HResult hr; IMFSinkWriter workingWriter = null; if ((outputFileName == null) || (outputFileName.Length == 0)) { // we failed throw new Exception("OpenSinkWriter: Invalid filename specified"); } try { // Create the sink writer. This takes the URL of an output file or a pointer to a byte stream and // creates the media sink internally. You could also use the more round-about // MFCreateSinkWriterFromMediaSink takes a pointer to a media sink that has already been created by // the application. If you are using one of the built-in media sinks, the MFCreateSinkWriterFromURL // function is preferable, because the caller does not need to configure the media sink. hr = MFExtern.MFCreateSinkWriterFromURL(outputFileName, null, null, out workingWriter); if (hr != HResult.S_OK) { // we failed throw new Exception("OpenSinkWriter: Failed on call to MFCreateSinkWriterFromURL, retVal=" + hr.ToString()); } if (workingWriter == null) { // we failed throw new Exception("OpenSinkWriter: Failed to create Sink Writer, Nothing will work."); } } catch (Exception ex) { // note this clean up is in the Catch block not the finally block. // if there are no errors we return it to the caller. The caller // is expected to clean up after itself if (workingWriter != null) { // clean up. Nothing else has this yet Marshal.ReleaseComObject(workingWriter); workingWriter = null; } workingWriter = null; throw ex; } return(workingWriter); }
// Constructor public CPreview(IntPtr hVideo, IntPtr hEvent) { m_pReader = null; m_hwndEvent = hEvent; m_pwszSymbolicLink = null; m_draw = new DrawDevice(); m_pWriter = null; m_bFirstSample = false; m_llBaseTime = 0; int hr = MFExtern.MFStartup(0x20070, MFStartup.Lite); MFError.ThrowExceptionForHR(hr); hr = m_draw.CreateDevice(hVideo); MFError.ThrowExceptionForHR(hr); }
// Constructor public CPreview(IntPtr hVideo, IntPtr hEvent) { m_pReader = null; m_hwndEvent = hEvent; m_pwszSymbolicLink = null; m_draw = new DrawDevice(); m_pWriter = null; m_bFirstSample = false; m_llBaseTime = 0; HResult hr = MFExtern.MFStartup(0x20070, MFStartup.Lite); MFError.ThrowExceptionForHR(hr); hr = m_draw.CreateDevice(hVideo); MFError.ThrowExceptionForHR(hr); }
private void PerformEncode(IMFSinkWriter writer, int streamIndex, IWaveProvider inputProvider) { int maxLength = inputProvider.WaveFormat.AverageBytesPerSecond * 4; var managedBuffer = new byte[maxLength]; writer.BeginWriting(); long position = 0; long duration = 0; do { duration = ConvertOneBuffer(writer, streamIndex, inputProvider, position, managedBuffer); position += duration; } while (duration > 0); writer.DoFinalize(); }
//------------------------------------------------------------------- // CloseDevice // // Releases all resources held by this object. //------------------------------------------------------------------- public HResult CloseDevice() { lock (this) { if (m_pWriter != null) { m_pWriter.Finalize_(); SafeRelease(m_pWriter); m_pWriter = null; } SafeRelease(m_pReader); m_pReader = null; m_pwszSymbolicLink = null; } return(HResult.S_OK); }
/// <summary> /// stops the process of recording. finalizes and then releases the sink writer /// </summary> /// <returns>z success, nz fail</returns> public int StopRecording() { LogMessage("StopRecording called"); // End any active captures if (workingSinkWriter != null) { lock (sinkWriterLockObject) { // close and release workingSinkWriter.Finalize_(); Marshal.ReleaseComObject(workingSinkWriter); workingSinkWriter = null; } } // reset these sinkWriterVideoStreamId = -1; isFirstSample = true; firstSampleBaseTime = 0; wantTimebaseRebase = false; return(0); }
public void Encode(string outputFile, IWaveProvider inputProvider) { if (inputProvider.WaveFormat.Encoding != WaveFormatEncoding.Pcm && inputProvider.WaveFormat.Encoding != WaveFormatEncoding.IeeeFloat) { throw new ArgumentException("Encode input format must be PCM or IEEE float"); } MediaType mediaType = new MediaType(inputProvider.WaveFormat); IMFSinkWriter imfsinkWriter = MediaFoundationEncoder.CreateSinkWriter(outputFile); try { int num; imfsinkWriter.AddStream(this.outputMediaType.MediaFoundationObject, out num); imfsinkWriter.SetInputMediaType(num, mediaType.MediaFoundationObject, null); this.PerformEncode(imfsinkWriter, num, inputProvider); } finally { Marshal.ReleaseComObject(imfsinkWriter); Marshal.ReleaseComObject(mediaType.MediaFoundationObject); } }
private void CreateReaderAndWriter() { object sourceReaderObject = null; object sinkWriterObject = null; IMFAttributes attributes = null; // Create the class factory IMFReadWriteClassFactory factory = (IMFReadWriteClassFactory)(new MFReadWriteClassFactory()); // Create the attributes MFHelper.MFCreateAttributes(out attributes, 1); attributes.SetUINT32(new Guid(Consts.MF_READWRITE_ENABLE_HARDWARE_TRANSFORMS), 1); // Use the factory to create the Source Reader factory.CreateInstanceFromURL(new Guid(CLSID.MFSourceReader), this.sourceFilename, attributes, new Guid(IID.IMFSourceReader), out sourceReaderObject); this.sourceReader = (IMFSourceReader)sourceReaderObject; // Use the factory to create the Sink Writer factory.CreateInstanceFromURL(new Guid(CLSID.MFSinkWriter), this.targetFilename, attributes, new Guid(IID.IMFSinkWriter), out sinkWriterObject); this.sinkWriter = (IMFSinkWriter)sinkWriterObject; }
/// <summary> /// Queries the underlying media sink or encoder for an interface. /// </summary> /// <typeparam name="T">The COM interface being requested.</typeparam> /// <param name="sinkWriter">A valid IMFSinkWriter instance.</param> /// <param name="streamIndex">The zero-based index of a streamIndex to query or -1 to query the media sink itself.</param> /// <param name="guidService">A service identifier GUID.</param> /// <param name="service">Receives an instance of the requested interface.</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 GetServiceForStream <T>(this IMFSinkWriter sinkWriter, int streamIndex, Guid guidService, out T service) where T : class { if (sinkWriter == null) { throw new ArgumentNullException("sinkWriter"); } Type typeOfT = typeof(T); if (!typeOfT.IsInterface) { throw new ArgumentOutOfRangeException("T", "T must be a COM visible interface."); } object tmp; HResult hr = sinkWriter.GetServiceForStream(streamIndex, guidService, typeOfT.GUID, out tmp); service = hr.Succeeded() ? tmp as T : null; return(hr); }
public HResult EndCaptureSession() { HResult hr = HResult.S_OK; lock (this) { if (m_pWriter != null) { hr = m_pWriter.Finalize_(); SafeRelease(m_pWriter); m_pWriter = null; } if (m_pReader != null) { SafeRelease(m_pReader); m_pReader = null; } } return(hr); }
private static void WriteAudioFrame(long frameDuration, IMFSinkWriter writer, int audioStreamIndex, long rtStart, byte[] audioFrameBuffer) { Marshal.ThrowExceptionForHR((int)MFExtern.MFCreateSample(out IMFSample sample)); try { Marshal.ThrowExceptionForHR((int)MFExtern.MFCreateMemoryBuffer(audioFrameBuffer.Length, out IMFMediaBuffer buffer)); try { Marshal.ThrowExceptionForHR((int)buffer.Lock(out IntPtr pData, out int maxLength, out int currentLength)); try { Marshal.Copy(audioFrameBuffer, 0, pData, audioFrameBuffer.Length); } finally { Marshal.ThrowExceptionForHR((int)buffer.Unlock()); } Marshal.ThrowExceptionForHR((int)buffer.SetCurrentLength(audioFrameBuffer.Length)); Marshal.ThrowExceptionForHR((int)sample.AddBuffer(buffer)); } finally { Marshal.ReleaseComObject(buffer); } Marshal.ThrowExceptionForHR((int)sample.SetSampleTime(rtStart)); Marshal.ThrowExceptionForHR((int)sample.SetSampleDuration(frameDuration)); Marshal.ThrowExceptionForHR((int)writer.WriteSample(audioStreamIndex, sample)); } finally { Marshal.ReleaseComObject(sample); } }
public static extern HRESULT MFCreateSinkWriterFromMediaSink(IMFMediaSink pMediaSink, IMFAttributes pAttributes, out IMFSinkWriter ppSinkWriter);
public static extern void MFCreateSinkWriterFromURL([In, MarshalAs(UnmanagedType.LPWStr)] string pwszOutputURL, [In] IMFByteStream pByteStream, [In] IMFAttributes pAttributes, [Out] out IMFSinkWriter ppSinkWriter);
//------------------------------------------------------------------- // CloseDevice // // Releases all resources held by this object. //------------------------------------------------------------------- public int CloseDevice() { lock (this) { if (m_pWriter != null) { m_pWriter.Finalize_(); SafeRelease(m_pWriter); m_pWriter = null; } SafeRelease(m_pReader); m_pReader = null; m_pwszSymbolicLink = null; } return S_Ok; }
public int EndCaptureSession() { int hr = S_Ok; lock (this) { if (m_pWriter != null) { hr = m_pWriter.Finalize_(); SafeRelease(m_pWriter); m_pWriter = null; } if (m_pReader != null) { SafeRelease(m_pReader); m_pReader = null; } } return hr; }
int ConfigureEncoder( IMFMediaType pType, IMFSinkWriter pWriter, out int pdwStreamIndex ) { int hr = S_Ok; IMFMediaType pType2 = null; hr = MFExtern.MFCreateMediaType(out pType2); if (Succeeded(hr)) { hr = pType2.SetGUID(MFAttributesClsid.MF_MT_MAJOR_TYPE, MFMediaType.Video); } if (Succeeded(hr)) { hr = pType2.SetGUID(MFAttributesClsid.MF_MT_SUBTYPE, MEDIATYPE); } if (Succeeded(hr)) { hr = pType2.SetUINT32(MFAttributesClsid.MF_MT_AVG_BITRATE, TARGET_BIT_RATE); } if (Succeeded(hr)) { hr = CopyAttribute(pType, pType2, MFAttributesClsid.MF_MT_FRAME_SIZE); } if (Succeeded(hr)) { hr = CopyAttribute(pType, pType2, MFAttributesClsid.MF_MT_FRAME_RATE); } if (Succeeded(hr)) { hr = CopyAttribute(pType, pType2, MFAttributesClsid.MF_MT_PIXEL_ASPECT_RATIO); } if (Succeeded(hr)) { hr = CopyAttribute(pType, pType2, MFAttributesClsid.MF_MT_INTERLACE_MODE); } pdwStreamIndex = 0; if (Succeeded(hr)) { hr = pWriter.AddStream(pType2, out pdwStreamIndex); } SafeRelease(pType2); return hr; }
private void PerformEncode(IMFSinkWriter writer, int streamIndex, IWaveProvider inputProvider) { int maxLength = inputProvider.WaveFormat.AverageBytesPerSecond * 4; var managedBuffer = new byte[maxLength]; writer.BeginWriting(); long position = 0; long duration = 0; do { duration = ConvertOneBuffer(writer, streamIndex, inputProvider, position, managedBuffer); position += duration; } while (duration > 0); writer.DoFinalize(); }
private long ConvertOneBuffer(IMFSinkWriter writer, int streamIndex, IWaveProvider inputProvider, long position, byte[] managedBuffer) { 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 read = inputProvider.Read(managedBuffer, 0, maxLength); 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; }
public static extern HRESULT MFCreateSinkWriterFromURL([MarshalAs(UnmanagedType.LPWStr)] string pwszOutputURL, IMFByteStream pByteStream, IMFAttributes pAttributes, out IMFSinkWriter ppSinkWriter);
public static ComObject <T> GetServiceForStream <T>(this IMFSinkWriter input, uint streamIndex) => GetServiceForStream <T>(input, streamIndex, Guid.Empty, typeof(T).GUID);
public int StopCapture() { var hr = S_Ok; lock (LockSync) { if (PWriter != null) { hr = PWriter.Finalize_(); SafeRelease(PWriter); PWriter = null; } } return hr; }
/// <summary> /// Opens the Sink Writer object /// </summary> /// <param name="outputFileName">the filename we write out to</param> /// <param name="wantDisableThrottling">if true we set a flag that disabled throttling</param> /// <returns>an IMFSinkWriter object or null for fail</returns> private IMFSinkWriter OpenSinkWriter(string outputFileName, bool wantDisableThrottling) { HResult hr; IMFSinkWriter workingWriter = null; IMFAttributes attributeContainer = null; if ((outputFileName == null) || (outputFileName.Length == 0)) { // we failed throw new Exception("OpenSinkWriter: Invalid filename specified"); } try { if (wantDisableThrottling == true) { // Initialize an attribute store. We will use this to // specify the enumeration parameters. hr = MFExtern.MFCreateAttributes(out attributeContainer, 1); if (hr != HResult.S_OK) { // we failed throw new Exception("OpenSinkWriter: failed on call to MFCreateAttributes, retVal=" + hr.ToString()); } if (attributeContainer == null) { // we failed throw new Exception("OpenSinkWriter: attributeContainer == MFAttributesClsid.null"); } // setup the attribute container hr = attributeContainer.SetUINT32(MFAttributesClsid.MF_SINK_WRITER_DISABLE_THROTTLING, 1); if (hr != HResult.S_OK) { // we failed throw new Exception("OpenSinkWriter: failed setting up the attributes, retVal=" + hr.ToString()); } } try { // Create the sink writer. This takes the URL of an output file or a pointer to a byte stream and // creates the media sink internally. You could also use the more round-about // MFCreateSinkWriterFromMediaSink takes a pointer to a media sink that has already been created by // the application. If you are using one of the built-in media sinks, the MFCreateSinkWriterFromURL // function is preferable, because the caller does not need to configure the media sink. hr = MFExtern.MFCreateSinkWriterFromURL(outputFileName, null, null, out workingWriter); if (hr != HResult.S_OK) { // we failed throw new Exception("OpenSinkWriter: Failed on call to MFCreateSinkWriterFromURL, retVal=" + hr.ToString()); } if (workingWriter == null) { // we failed throw new Exception("OpenSinkWriter: Failed to create Sink Writer, Nothing will work."); } } catch (Exception ex) { // note this clean up is in the Catch block not the finally block. // if there are no errors we return it to the caller. The caller // is expected to clean up after itself if (workingWriter != null) { // clean up. Nothing else has this yet Marshal.ReleaseComObject(workingWriter); workingWriter = null; } workingWriter = null; throw ex; } } finally { if (attributeContainer != null) { // clean up. Marshal.ReleaseComObject(attributeContainer); } } return(workingWriter); }
private static int ConfigureEncoder(EncodingParameters eparams, IMFMediaType pType, IMFSinkWriter pWriter, out int pdwStreamIndex) { IMFMediaType pType2; var hr = MFExtern.MFCreateMediaType(out pType2); if (Succeeded(hr)) { hr = pType2.SetGUID(MFAttributesClsid.MF_MT_MAJOR_TYPE, MFMediaType.Video); } if (Succeeded(hr)) { hr = pType2.SetGUID(MFAttributesClsid.MF_MT_SUBTYPE, eparams.Subtype); } if (Succeeded(hr)) { hr = pType2.SetUINT32(MFAttributesClsid.MF_MT_AVG_BITRATE, eparams.Bitrate); } if (Succeeded(hr)) { hr = CopyAttribute(pType, pType2, MFAttributesClsid.MF_MT_FRAME_SIZE); } if (Succeeded(hr)) { hr = CopyAttribute(pType, pType2, MFAttributesClsid.MF_MT_FRAME_RATE); } if (Succeeded(hr)) { hr = CopyAttribute(pType, pType2, MFAttributesClsid.MF_MT_PIXEL_ASPECT_RATIO); } if (Succeeded(hr)) { hr = CopyAttribute(pType, pType2, MFAttributesClsid.MF_MT_INTERLACE_MODE); } pdwStreamIndex = 0; if (Succeeded(hr)) { hr = pWriter.AddStream(pType2, out pdwStreamIndex); } SafeRelease(pType2); return hr; }
private void PerformEncode(IMFSinkWriter writer, int streamIndex, IWaveProvider inputProvider) { int maxLength = inputProvider.WaveFormat.AverageBytesPerSecond*4; var managedBuffer = new byte[maxLength]; writer.BeginWriting(); long position = 0; long duration = 0; do { duration = ConvertOneBuffer(writer, streamIndex, inputProvider, position, managedBuffer); position += duration; } while (duration > 0); //We are going to check the stats of the writer and ensure no more bytes are queued before we call DoFinalize() MF_SINK_WRITER_STATISTICS stats = new MF_SINK_WRITER_STATISTICS(); stats.cb = Marshal.SizeOf(stats); bool finished = false; const int sleepMs = 10; const int maxTimeInSeconds = 5; const int maxTries = (maxTimeInSeconds*1000)/sleepMs; var tries = 0; try { while (!finished) { writer.GetStatistics(streamIndex, stats); if (tries == maxTries) { var msg = string.Format( "Unable to save the MP3 file. Sink writer still has {0} bytes in the queue after waiting for {1} seconds.", stats.dwByteCountQueued, maxTimeInSeconds); throw new Exception(msg); } if (stats.dwByteCountQueued == 0) { finished = true; } else { //sleeping could be optional, but don't want to hog the CPU System.Threading.Thread.Sleep(sleepMs); } tries++; } } finally { writer.DoFinalize(); } }
/// <summary> /// Starts the process of recording. creates the sink writer. We do not /// check to see if the filename is viable or already exists. This is /// assumed to have been done before this call. /// </summary> /// <param name="outputFileName">the output file name</param> /// <param name="incomingVideoMediaType">the incoming media type</param> /// <param name="wantTimebaseRebaseIn">if true we rebase all incoming sample /// times to zero from the point we started recording and send a copy of the /// sample to the sink writer instead of the input sample</param> /// <returns>z success, nz fail</returns> public int StartRecording(string outputFileName, IMFMediaType incomingVideoMediaType, bool wantTimebaseRebaseIn) { HResult hr; LogMessage("MFTSampleGrabber_Sync, StartRecording called"); // first stop any recordings now StopRecording(); // check the output file name for sanity if ((outputFileName == null) || (outputFileName.Length == 0)) { LogMessage("StartRecording (outputFileName==null)|| (outputFileName.Length==0)"); return(100); } // check the media type for sanity if (incomingVideoMediaType == null) { LogMessage("StartRecording videoMediaType == null"); return(150); } lock (sinkWriterLockObject) { // create the sink writer workingSinkWriter = OpenSinkWriter(outputFileName, true); if (workingSinkWriter == null) { LogMessage("StartRecording failed to create sink writer"); return(200); } // now configure the SinkWriter. This sets up the sink writer so that it knows what format // the output data should be written in. The format we give the writer does not // need to be the same as the format receives as input - however to make life easier for ourselves // we will copy a lot of the settings from the videoType retrieved above // create a new empty media type for us to populate hr = MFExtern.MFCreateMediaType(out IMFMediaType encoderType); if (hr != HResult.S_OK) { // we failed throw new Exception("Failed on call to MFCreateMediaType, retVal=" + hr.ToString()); } // The major type defines the overall category of the media data. Major types include video, audio, script & etc. hr = encoderType.SetGUID(MFAttributesClsid.MF_MT_MAJOR_TYPE, MFMediaType.Video); if (hr != HResult.S_OK) { // we failed throw new Exception("Failed setting the MF_MT_MAJOR_TYPE, retVal=" + hr.ToString()); } // The subtype GUID defines a specific media format type within a major type. For example, within video, // the subtypes include MFMediaType.H264 (MP4), MFMediaType.WMV3 (WMV), MJPEG & etc. Within audio, the // subtypes include PCM audio, Windows Media Audio 9, & etc. hr = encoderType.SetGUID(MFAttributesClsid.MF_MT_SUBTYPE, MEDIA_TYPETO_WRITE); if (hr != HResult.S_OK) { // we failed throw new Exception("Failed setting the MF_MT_SUBTYPE, retVal=" + hr.ToString()); } // this is the approximate data rate of the video stream, in bits per second, for a // video media type. The choice here is somewhat arbitrary but seems to work well. hr = encoderType.SetUINT32(MFAttributesClsid.MF_MT_AVG_BITRATE, TARGET_BIT_RATE); if (hr != HResult.S_OK) { // we failed throw new Exception("Failed setting the MF_MT_AVG_BITRATE, retVal=" + hr.ToString()); } // populate our new encoding type with the frame size of the videoType selected earlier hr = WMFUtils.CopyAttributeData(incomingVideoMediaType, encoderType, MFAttributesClsid.MF_MT_FRAME_SIZE); if (hr != HResult.S_OK) { // we failed throw new Exception("Failed copying the MF_MT_FRAME_SIZE, retVal=" + hr.ToString()); } // populate our new encoding type with the frame rate of the video type selected earlier hr = WMFUtils.CopyAttributeData(incomingVideoMediaType, encoderType, MFAttributesClsid.MF_MT_FRAME_RATE); if (hr != HResult.S_OK) { // we failed throw new Exception("Failed copying the MF_MT_FRAME_RATE, retVal=" + hr.ToString()); } // populate our new encoding type with the pixel aspect ratio of the video type selected earlier hr = WMFUtils.CopyAttributeData(incomingVideoMediaType, encoderType, MFAttributesClsid.MF_MT_PIXEL_ASPECT_RATIO); if (hr != HResult.S_OK) { // we failed throw new Exception("Failed copying the MF_MT_PIXEL_ASPECT_RATIO, retVal=" + hr.ToString()); } // populate our new encoding type with the interlace mode of the video type selected earlier hr = WMFUtils.CopyAttributeData(incomingVideoMediaType, encoderType, MFAttributesClsid.MF_MT_INTERLACE_MODE); if (hr != HResult.S_OK) { // we failed throw new Exception("Failed copying the MF_MT_INTERLACE_MODE, retVal=" + hr.ToString()); } // add a stream to the sink writer for the output Media type. The // incomingVideoMediaType specifies the format of the samples that will // be written to the file. Note that it does not necessarily need to // match the input format. hr = workingSinkWriter.AddStream(encoderType, out sinkWriterVideoStreamId); if (hr != HResult.S_OK) { // we failed throw new Exception("StartRecording Failed adding the output stream(v), retVal=" + hr.ToString()); } // Windows 10, by default, provides an adequate set of codecs which the Sink Writer can // find to write out the MP4 file. This is not true on Windows 7. // If we are not on Windows 10 we register (locally) a codec // the Sink Writer can find and use. The ColorConvertDMO is supplied by // microsoft it is just not available to enumerate on Win7 etc. // Making it available locally does not require administrator privs // but only this process can see it and it disappears when the process // closes OperatingSystem os = Environment.OSVersion; int versionID = ((os.Version.Major * 10) + os.Version.Minor); if (versionID < 62) { Guid ColorConverterDMOGUID = new Guid("98230571-0087-4204-b020-3282538e57d3"); // Register the color converter DSP for this process, in the video // processor category. This will enable the sink writer to enumerate // the color converter when the sink writer attempts to match the // media types. hr = MFExtern.MFTRegisterLocalByCLSID( ColorConverterDMOGUID, MFTransformCategory.MFT_CATEGORY_VIDEO_PROCESSOR, "", MFT_EnumFlag.SyncMFT, 0, null, 0, null ); } // Set the input format for a stream on the sink writer. Note the use of the stream index here // The input format does not have to match the target format that is written to the media sink // If the formats do not match, this call attempts to load an transform // that can convert from the input format to the target format. If it cannot find one, (and this is not // a sure thing), it will throw an exception. hr = workingSinkWriter.SetInputMediaType(sinkWriterVideoStreamId, incomingVideoMediaType, null); if (hr != HResult.S_OK) { // we failed throw new Exception("StartRecording Failed on calling SetInputMediaType(v) on the writer, retVal=" + hr.ToString()); } // set this flag now wantTimebaseRebase = wantTimebaseRebaseIn; // now we initialize the sink writer for writing. We call this method after configuring the // input streams but before we send any data to the sink writer. The underlying media sink must // have at least one input stream and we know it does because we set it up above hr = workingSinkWriter.BeginWriting(); if (hr != HResult.S_OK) { // we failed throw new Exception("StartRecording Failed on calling BeginWriting on the writer, retVal=" + hr.ToString()); } } return(0); }