private static long GetDuration(IMFSourceReader reader) { var variantPtr = Marshal.AllocHGlobal(MarshalHelpers.SizeOf <PropVariant>()); try { int hResult = reader.GetPresentationAttribute(MediaFoundationInterop.MF_SOURCE_READER_MEDIASOURCE, MediaFoundationAttributes.MF_PD_DURATION, variantPtr); if (hResult == MediaFoundationErrors.MF_E_ATTRIBUTENOTFOUND) { return(0); } if (hResult != 0) { Marshal.ThrowExceptionForHR(hResult); } var variant = MarshalHelpers.PtrToStructure <PropVariant> (variantPtr); return((long)variant.Value); } finally { PropVariant.Clear(variantPtr); Marshal.FreeHGlobal(variantPtr); } }
/// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+= /// <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; } }
private long GetLength(IMFSourceReader reader) { var variantPtr = Marshal.AllocHGlobal(MarshalHelpers.SizeOf <PropVariant>()); try { // http://msdn.microsoft.com/en-gb/library/windows/desktop/dd389281%28v=vs.85%29.aspx#getting_file_duration int hResult = reader.GetPresentationAttribute(MediaFoundationInterop.MF_SOURCE_READER_MEDIASOURCE, MediaFoundationAttributes.MF_PD_DURATION, variantPtr); if (hResult == MediaFoundationErrors.MF_E_ATTRIBUTENOTFOUND) { // this doesn't support telling us its duration (might be streaming) return(0); } if (hResult != 0) { Marshal.ThrowExceptionForHR(hResult); } var variant = MarshalHelpers.PtrToStructure <PropVariant>(variantPtr); var lengthInBytes = (((long)variant.Value) * waveFormat.AverageBytesPerSecond) / 10000000L; return(lengthInBytes); } finally { PropVariant.Clear(variantPtr); Marshal.FreeHGlobal(variantPtr); } }
/// <summary> /// Use Source Reader to allocate a sample /// </summary> /// <param name="sourceReader">The Source Reader</param> /// <param name="dwStreamIndex">The stream to pull data from</param> /// <param name="dwControlFlags">A bitwise OR of zero or more flags from the MF_SOURCE_READER_CONTROL_FLAG enumeration</param> /// <param name="pdwActualStreamIndex">Receives the zero-based index of the stream</param> /// <param name="pdwStreamFlags">Receives a bitwise OR of zero or more flags from the MF_SOURCE_READER_FLAG enumeration</param> /// <param name="pllTimestamp">Receives the time stamp of the sample, or the time of the stream event indicated in pdwStreamFlags. The time is given in 100-nanosecond units</param> public void ReadSampleFrom( IMFSourceReader sourceReader, uint dwStreamIndex, uint dwControlFlags, out uint pdwActualStreamIndex, out uint pdwStreamFlags, out ulong pllTimestamp) { // Once a sample is read avoid reading more samples if (this.read) { throw new InvalidOperationException("Already holding a sample"); } sourceReader.ReadSample(dwStreamIndex, dwControlFlags, out pdwActualStreamIndex, out pdwStreamFlags, out pllTimestamp, out this.sample); if (this.sample != null) { // Get the size of the media sample in bytes IMFMediaBuffer buffer = null; this.sample.GetBufferByIndex(0, out buffer); buffer.GetCurrentLength(out this.bufferSize); // Add the memory pressure of unmanaged memory to improve the garbage collector performance GC.AddMemoryPressure(this.bufferSize); } this.read = true; }
private static MediaType GetCurrentMediaType(IMFSourceReader reader) { IMFMediaType mediaType; reader.GetCurrentMediaType(-3, out mediaType); return(new MediaType(mediaType)); }
private long GetLength(IMFSourceReader reader) { IntPtr intPtr = Marshal.AllocHGlobal(MarshalHelpers.SizeOf <PropVariant>()); long result; try { int presentationAttribute = reader.GetPresentationAttribute(-1, MediaFoundationAttributes.MF_PD_DURATION, intPtr); if (presentationAttribute == -1072875802) { result = 0L; } else { if (presentationAttribute != 0) { Marshal.ThrowExceptionForHR(presentationAttribute); } result = (long)MarshalHelpers.PtrToStructure <PropVariant>(intPtr).Value *(long)this.waveFormat.AverageBytesPerSecond / 10000000L; } } finally { PropVariant.Clear(intPtr); Marshal.FreeHGlobal(intPtr); } return(result); }
private WaveFormat GetCurrentWaveFormat(IMFSourceReader reader) { IMFMediaType uncompressedMediaType; reader.GetCurrentMediaType(MediaFoundationInterop.MF_SOURCE_READER_FIRST_AUDIO_STREAM, out uncompressedMediaType); // Two ways to query it, first is to ask for properties (second is to convert into WaveFormatEx using MFCreateWaveFormatExFromMFMediaType) var outputMediaType = new MediaType(uncompressedMediaType); Guid actualMajorType = outputMediaType.MajorType; Debug.Assert(actualMajorType == MediaTypes.MFMediaType_Audio); Guid audioSubType = outputMediaType.SubType; int channels = outputMediaType.ChannelCount; int bits = outputMediaType.BitsPerSample; int sampleRate = outputMediaType.SampleRate; if (audioSubType == AudioSubtypes.MFAudioFormat_PCM) { return(new WaveFormat(sampleRate, bits, channels)); } if (audioSubType == AudioSubtypes.MFAudioFormat_Float) { return(WaveFormat.CreateIeeeFloatWaveFormat(sampleRate, channels)); } var subTypeDescription = FieldDescriptionHelper.Describe(typeof(AudioSubtypes), audioSubType); throw new InvalidDataException(String.Format("Unsupported audio sub Type {0}", subTypeDescription)); }
private static MediaType GetCurrentMediaType(IMFSourceReader reader) { IMFMediaType mediaType; reader.GetCurrentMediaType(MediaFoundationInterop.MF_SOURCE_READER_FIRST_AUDIO_STREAM, out mediaType); return(new MediaType(mediaType)); }
/// <summary> /// Reads from this wave stream /// </summary> /// <param name="buffer">Buffer to read into</param> /// <param name="offset">Offset in buffer</param> /// <param name="count">Bytes required</param> /// <returns>Number of bytes read; 0 indicates end of stream</returns> public override int Read(byte[] buffer, int offset, int count) { if (pReader == null) { pReader = CreateReader(settings); } if (repositionTo != -1) { Reposition(repositionTo); } int bytesWritten = 0; // read in any leftovers from last time if (decoderOutputCount > 0) { bytesWritten += ReadFromDecoderBuffer(buffer, offset, count - bytesWritten); } while (bytesWritten < count) { IMFSample pSample; MF_SOURCE_READER_FLAG dwFlags; ulong timestamp; int actualStreamIndex; pReader.ReadSample(MediaFoundationInterop.MF_SOURCE_READER_FIRST_AUDIO_STREAM, 0, out actualStreamIndex, out dwFlags, out timestamp, out pSample); if ((dwFlags & MF_SOURCE_READER_FLAG.MF_SOURCE_READERF_ENDOFSTREAM) != 0) { // reached the end of the stream break; } else if ((dwFlags & MF_SOURCE_READER_FLAG.MF_SOURCE_READERF_CURRENTMEDIATYPECHANGED) != 0) { Console.WriteLine("SAMPLE SETTINGS CHANGED!"); waveFormat = GetCurrentWaveFormat(pReader, false, 0, 0, 0); OnWaveFormatChanged(); // carry on, but user must handle the change of format } else if (dwFlags != 0) { throw new InvalidOperationException(String.Format("MediaFoundationReadError {0}", dwFlags)); } IMFMediaBuffer pBuffer; pSample.ConvertToContiguousBuffer(out pBuffer); IntPtr pAudioData; int cbBuffer; int pcbMaxLength; pBuffer.Lock(out pAudioData, out pcbMaxLength, out cbBuffer); EnsureBuffer(cbBuffer); Marshal.Copy(pAudioData, decoderOutputBuffer, 0, cbBuffer); decoderOutputOffset = 0; decoderOutputCount = cbBuffer; bytesWritten += ReadFromDecoderBuffer(buffer, offset + bytesWritten, count - bytesWritten); pBuffer.Unlock(); Marshal.ReleaseComObject(pBuffer); Marshal.ReleaseComObject(pSample); } position += bytesWritten; return(bytesWritten); }
/// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+= /// <summary> /// Gets a list of all supported video formats from a video source device /// as a nice displayable bit of text. outSb will never be null but can be /// empty. There will be one line per mediaType /// /// </summary> /// <returns>S_OK for success, nz for fail</returns> /// <param name="sourceReader">the source reader object</param> /// <param name="maxFormatsToTestFor">the max number of formats we test for</param> /// <history> /// 01 Nov 18 Cynic - Started /// </history> public static HResult GetSupportedVideoFormatsFromSourceReaderAsText(IMFSourceReader sourceReader, int maxFormatsToTestFor, out StringBuilder outSb) { IMFMediaType mediaTypeObj = null; HResult hr; // we always return something here outSb = new StringBuilder(); // sanity check if (sourceReader == null) { return(HResult.E_FAIL); } try { for (int typeIndex = 0; typeIndex < maxFormatsToTestFor; typeIndex++) { // test this hr = sourceReader.GetNativeMediaType(TantaWMFUtils.MF_SOURCE_READER_FIRST_VIDEO_STREAM, typeIndex, out mediaTypeObj); if (hr == HResult.MF_E_NO_MORE_TYPES) { // we are all done. The outSb container has been populated return(HResult.S_OK); } else if (hr != HResult.S_OK) { // we failed throw new Exception("GetSupportedVideoFormatsFromSourceReaderAsText failed on call to GetNativeMediaType, retVal=" + hr.ToString()); } // get the formats for this type StringBuilder tmpSb; hr = GetSupportedFormatsFromMediaTypeAsText(mediaTypeObj, out tmpSb); if (hr != HResult.S_OK) { // we failed throw new Exception("GetSupportedVideoFormatsFromSourceReaderAsText failed on call to GetSupportedFormatsFromMediaTypeAsText, retVal=" + hr.ToString()); } // add it here outSb.Append(typeIndex.ToString() + " "); outSb.Append(tmpSb); outSb.Append("\r\n"); outSb.Append("\r\n"); } } finally { // always release our mediaType if we have one if (mediaTypeObj != null) { Marshal.ReleaseComObject(mediaTypeObj); mediaTypeObj = null; } } // all done return(HResult.S_OK); }
/// <summary> /// Gets an attribute from the underlying media source. /// </summary> /// <param name="sourceReader">A valid IMFSourceReader instance.</param></param> /// <param name="streamIndex">The streamIndex to query.</param> /// <param name="mediaTypeIndex">The zero-based index of the media type to retrieve.</param> /// <param name="mediaType">Receives an instance of the IMFMediaType 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 GetPresentationAttribute(this IMFSourceReader sourceReader, SourceReaderFirstStreamOrMediaSource streamIndex, Guid guidAttribute, PropVariant attribute) { if (sourceReader == null) { throw new ArgumentNullException("sourceReader"); } return(sourceReader.GetPresentationAttribute((int)streamIndex, guidAttribute, attribute)); }
private void ClearAll() { this.streamsInfo.Clear(); this.sourceFilename = string.Empty; this.targetFilename = string.Empty; this.sourceReader = null; this.sinkWriter = null; this.selectedStreams = 0; }
/// <summary> /// Gets a format that is supported natively by the media source. /// </summary> /// <param name="sourceReader">A valid IMFSourceReader instance.</param></param> /// <param name="streamIndex">The streamIndex to query.</param> /// <param name="mediaTypeIndex">The zero-based index of the media type to retrieve.</param> /// <param name="mediaType">Receives an instance of the IMFMediaType 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 GetNativeMediaType(this IMFSourceReader sourceReader, SourceReaderFirstStream streamIndex, int mediaTypeIndex, out IMFMediaType mediaType) { if (sourceReader == null) { throw new ArgumentNullException("sourceReader"); } return(sourceReader.GetNativeMediaType((int)streamIndex, mediaTypeIndex, out mediaType)); }
/// <summary> /// Cleans up after finishing with this reader /// </summary> /// <param name="disposing">true if called from Dispose</param> protected override void Dispose(bool disposing) { if (pReader != null) { Marshal.ReleaseComObject(pReader); pReader = null; } base.Dispose(disposing); }
/// <summary> /// Flushes one or more streams. /// </summary> /// <param name="sourceReader">A valid IMFSourceReader instance.</param></param> /// <param name="streamIndex">The streamIndex(s) to flush.</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 Flush(this IMFSourceReader sourceReader, SourceReaderStreams stream) { if (sourceReader == null) { throw new ArgumentNullException("sourceReader"); } return(sourceReader.Flush((int)stream)); }
/// <summary> /// Selects or deselects one or more streams. /// </summary> /// <param name="sourceReader">A valid IMFSourceReader instance.</param></param></param> /// <param name="streamIndex">The stream to set.</param> /// <param name="selected">Specify True to select streams or False to deselect streams. If a stream is deselected, it will not generate data.</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 SetStreamSelection(this IMFSourceReader sourceReader, SourceReaderStreams streamIndex, bool selected) { if (sourceReader == null) { throw new ArgumentNullException("sourceReader"); } return(sourceReader.SetStreamSelection((int)streamIndex, selected)); }
/// <summary> /// Sets the media type for a stream. /// </summary> /// <param name="sourceReader">A valid IMFSourceReader instance.</param></param></param> /// <param name="streamIndex">The stream to configure.</param> /// <param name="mediaType">An instance of the IMFMediaType interface of the media type.</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 SetCurrentMediaType(this IMFSourceReader sourceReader, SourceReaderFirstStream streamIndex, IMFMediaType mediaType) { if (sourceReader == null) { throw new ArgumentNullException("sourceReader"); } return(sourceReader.SetCurrentMediaType((int)streamIndex, null, mediaType)); }
public override int Read(byte[] buffer, int offset, int count) { if (this.pReader == null) { this.pReader = this.CreateReader(this.settings); } if (this.repositionTo != -1L) { this.Reposition(this.repositionTo); } int i = 0; if (this.decoderOutputCount > 0) { i += this.ReadFromDecoderBuffer(buffer, offset, count - i); } while (i < count) { int num; MF_SOURCE_READER_FLAG mF_SOURCE_READER_FLAG; ulong num2; IMFSample iMFSample; this.pReader.ReadSample(-3, 0, out num, out mF_SOURCE_READER_FLAG, out num2, out iMFSample); if ((mF_SOURCE_READER_FLAG & MF_SOURCE_READER_FLAG.MF_SOURCE_READERF_ENDOFSTREAM) != MF_SOURCE_READER_FLAG.None) { break; } if ((mF_SOURCE_READER_FLAG & MF_SOURCE_READER_FLAG.MF_SOURCE_READERF_CURRENTMEDIATYPECHANGED) != MF_SOURCE_READER_FLAG.None) { this.waveFormat = this.GetCurrentWaveFormat(this.pReader); this.OnWaveFormatChanged(); } else if (mF_SOURCE_READER_FLAG != MF_SOURCE_READER_FLAG.None) { throw new InvalidOperationException(string.Format("MediaFoundationReadError {0}", mF_SOURCE_READER_FLAG)); } IMFMediaBuffer iMFMediaBuffer; iMFSample.ConvertToContiguousBuffer(out iMFMediaBuffer); IntPtr source; int num3; int bytesRequired; iMFMediaBuffer.Lock(out source, out num3, out bytesRequired); this.EnsureBuffer(bytesRequired); Marshal.Copy(source, this.decoderOutputBuffer, 0, bytesRequired); this.decoderOutputOffset = 0; this.decoderOutputCount = bytesRequired; i += this.ReadFromDecoderBuffer(buffer, offset + i, count - i); iMFMediaBuffer.Unlock(); Marshal.ReleaseComObject(iMFMediaBuffer); Marshal.ReleaseComObject(iMFSample); } this.position += (long)i; return(i); }
/// <summary> /// Seeks to a new position in the media source. /// </summary> /// <param name="sourceReader">A valid IMFSourceReader instance.</param></param></param> /// <param name="position">The position from which playback will be started.</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 SetCurrentPosition(this IMFSourceReader sourceReader, TimeSpan position) { if (sourceReader == null) { throw new ArgumentNullException("sourceReader"); } using (PropVariant value = new PropVariant(position.Ticks)) { return(sourceReader.SetCurrentPosition(Guid.Empty, value)); } }
protected override IMFSourceReader CreateReader(MediaFoundationReader.MediaFoundationReaderSettings settings) { IMFSourceReader expr_15 = MediaFoundationApi.CreateSourceReaderFromByteStream(MediaFoundationApi.CreateByteStream(new ComStream(this.stream))); expr_15.SetStreamSelection(-2, false); expr_15.SetStreamSelection(-3, true); expr_15.SetCurrentMediaType(-3, IntPtr.Zero, new MediaType { MajorType = MediaTypes.MFMediaType_Audio, SubType = settings.RequestFloatOutput ? AudioSubtypes.MFAudioFormat_Float : AudioSubtypes.MFAudioFormat_PCM }.MediaFoundationObject); return(expr_15); }
protected void Init(MediaFoundationReader.MediaFoundationReaderSettings initialSettings) { MediaFoundationApi.Startup(); this.settings = (initialSettings ?? new MediaFoundationReader.MediaFoundationReaderSettings()); IMFSourceReader iMFSourceReader = this.CreateReader(this.settings); this.waveFormat = this.GetCurrentWaveFormat(iMFSourceReader); iMFSourceReader.SetStreamSelection(-3, true); this.length = this.GetLength(iMFSourceReader); if (this.settings.SingleReaderObject) { this.pReader = iMFSourceReader; } }
/// <summary> /// Reads the next sample from the media source. /// </summary> /// <param name="sourceReader">A valid IMFSourceReader instance.</param></param></param> /// <param name="streamIndex">The stream to pull data from.</param> /// <param name="controlFlags">One or more members of the MF_SOURCE_READER_CONTROL_FLAG enumeration.</param> /// <param name="actualStreamIndex">Receives the zero-based index of the stream.</param> /// <param name="streamFlags">Receives one or more members of the MF_SOURCE_READER_FLAG enumeration.</param> /// <param name="timestamp">Receives the time stamp of the sample, or the time of the stream event indicated in <paramref name="streamFlags"/>.</param> /// <param name="sample">Receives an instance of the IMFSample interface or the value null.</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 ReadSample(this IMFSourceReader sourceReader, SourceReaderStreams streamIndex, MF_SOURCE_READER_CONTROL_FLAG controlFlags, out int actualStreamIndex, out MF_SOURCE_READER_FLAG streamFlags, out TimeSpan timestamp, out IMFSample sample) { if (sourceReader == null) { throw new ArgumentNullException("sourceReader"); } long tmp = 0; HResult hr = sourceReader.ReadSample((int)streamIndex, controlFlags, out actualStreamIndex, out streamFlags, out tmp, out sample); timestamp = hr.Succeeded() ? TimeSpan.FromTicks(tmp) : default(TimeSpan); return(hr); }
/// <summary> /// Creates a new MediaFoundationReader based on the supplied file /// </summary> /// <param name="file">Filename</param> /// <param name="settings">Advanced settings</param> public MediaFoundationReaderX(string file, MediaFoundationReaderSettings settings) { MediaFoundationApi.Startup(); this.settings = settings; this.file = file; var reader = CreateReader(settings); waveFormat = GetCurrentWaveFormat(reader, false, 0, 0, 0); reader.SetStreamSelection(MediaFoundationInterop.MF_SOURCE_READER_FIRST_AUDIO_STREAM, true); length = GetLength(reader); if (settings.SingleReaderObject) { pReader = reader; } }
public MediaFoundationReader(string file, MediaFoundationReader.MediaFoundationReaderSettings settings) { MediaFoundationApi.Startup(); this.settings = settings; this.file = file; IMFSourceReader imfsourceReader = this.CreateReader(settings); this.waveFormat = this.GetCurrentWaveFormat(imfsourceReader); imfsourceReader.SetStreamSelection(-3, true); this.length = this.GetLength(imfsourceReader); if (settings.SingleReaderObject) { this.pReader = imfsourceReader; } }
/// <summary> /// Gets a pointer to the underlying Source Reader object. /// </summary> /// <param name="captureSource">A valid IMFCaptureSource instance.</param> /// <param name="sourceReader">Receives an instance of the underlying Source Reader.</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 GetService(this IMFCaptureSource captureSource, out IMFSourceReader sourceReader) { if (captureSource == null) { throw new ArgumentNullException("captureSource"); } object tmp; HResult hr = captureSource.GetService(Guid.Empty, typeof(IMFSourceReader).GUID, out tmp); sourceReader = hr.Succeeded() ? tmp as IMFSourceReader : null; return(hr); }
/// <summary> /// Creates a new MediaFoundationReader based on the supplied file /// </summary> /// <param name="file">Filename</param> /// <param name="settings">Advanced settings</param> public MediaFoundationReaderX(string file, bool useOverrides, int sampleRate, int numChannels, int bitDepth) { MediaFoundationApi.Startup(); this.settings = new MediaFoundationReaderSettings(); this.file = file; var reader = CreateReader(settings); waveFormat = GetCurrentWaveFormat(reader, useOverrides, sampleRate, numChannels, bitDepth); reader.SetStreamSelection(MediaFoundationInterop.MF_SOURCE_READER_FIRST_AUDIO_STREAM, true); length = GetLength(reader); if (settings.SingleReaderObject) { pReader = reader; } }
/// <summary> /// Initializes /// </summary> protected void Init(MediaFoundationReaderSettings initialSettings) { MediaFoundationApi.Startup(); settings = initialSettings ?? new MediaFoundationReaderSettings(); var reader = CreateReader(settings); waveFormat = GetCurrentWaveFormat(reader); reader.SetStreamSelection(MediaFoundationInterop.MF_SOURCE_READER_FIRST_AUDIO_STREAM, true); length = GetLength(reader); if (settings.SingleReaderObject) { pReader = reader; } }
/// <summary> /// Creates the reader (overridable by ) /// </summary> protected virtual IMFSourceReader CreateReader2(byte[] buffer, MediaFoundationReaderSettings settings) { IMFSourceReader reader = null; //MediaFoundationInterop.MFCreateSourceReaderFromURL(file, null, out reader); reader = MediaFoundationApi.CreateSourceReaderFromByteStream(MediaFoundationApi.CreateByteStream(new ComStream(new MemoryStream(buffer)))); reader.SetStreamSelection(MediaFoundationInterop.MF_SOURCE_READER_ALL_STREAMS, false); reader.SetStreamSelection(MediaFoundationInterop.MF_SOURCE_READER_FIRST_AUDIO_STREAM, true); // Create a partial media type indicating that we want uncompressed PCM audio var partialMediaType = new MediaType(); partialMediaType.MajorType = MediaTypes.MFMediaType_Audio; partialMediaType.SubType = settings.RequestFloatOutput ? AudioSubtypes.MFAudioFormat_Float : AudioSubtypes.MFAudioFormat_PCM; var currentMediaType = GetCurrentMediaType(reader); // mono, low sample rate files can go wrong on Windows 10 unless we specify here partialMediaType.ChannelCount = currentMediaType.ChannelCount; partialMediaType.SampleRate = currentMediaType.SampleRate; try { // set the media type // can return MF_E_INVALIDMEDIATYPE if not supported reader.SetCurrentMediaType(MediaFoundationInterop.MF_SOURCE_READER_FIRST_AUDIO_STREAM, IntPtr.Zero, partialMediaType.MediaFoundationObject); } catch (COMException ex) when(ex.GetHResult() == MediaFoundationErrors.MF_E_INVALIDMEDIATYPE) { // HE-AAC (and v2) seems to halve the samplerate if (currentMediaType.SubType == AudioSubtypes.MFAudioFormat_AAC && currentMediaType.ChannelCount == 1) { partialMediaType.SampleRate = currentMediaType.SampleRate *= 2; partialMediaType.ChannelCount = currentMediaType.ChannelCount *= 2; reader.SetCurrentMediaType(MediaFoundationInterop.MF_SOURCE_READER_FIRST_AUDIO_STREAM, IntPtr.Zero, partialMediaType.MediaFoundationObject); } else { throw; } } Marshal.ReleaseComObject(currentMediaType.MediaFoundationObject); return(reader); }
/// <summary> /// Creates a new MediaFoundationReader based on the supplied file /// </summary> /// <param name="inputStream">The input stream containing a WAV.</param> /// <param name="settings">Advanced settings</param> public MediaFoundationReader(System.IO.Stream inputStream, MediaFoundationReaderSettings settings) { MediaFoundationApi.Startup(); this.settings = settings; _inputStream = inputStream; var reader = CreateReader(settings); waveFormat = GetCurrentWaveFormat(reader); reader.SetStreamSelection(MediaFoundationInterop.MF_SOURCE_READER_FIRST_AUDIO_STREAM, true); length = GetLength(reader); if (settings.SingleReaderObject) { pReader = reader; } }
/// <summary> /// Creates a new MediaFoundationReader based on the supplied file /// </summary> /// <param name="file">Filename</param> /// <param name="settings">Advanced settings</param> public MediaFoundationReader(string file, MediaFoundationReaderSettings settings) { MediaFoundationApi.Startup(); this.settings = settings; this.file = file; var reader = CreateReader(settings); waveFormat = GetCurrentWaveFormat(reader); reader.SetStreamSelection(MediaFoundationInterop.MF_SOURCE_READER_FIRST_AUDIO_STREAM, true); length = GetLength(reader); if (settings.SingleReaderObject) { pReader = reader; } }
private long GetLength(IMFSourceReader reader) { PropVariant propVariant; int presentationAttribute = reader.GetPresentationAttribute(-1, MediaFoundationAttributes.MF_PD_DURATION, out propVariant); if (presentationAttribute == -1072875802) { return(0L); } if (presentationAttribute != 0) { Marshal.ThrowExceptionForHR(presentationAttribute); } long result = (long)propVariant.Value * (long)this.waveFormat.AverageBytesPerSecond / 10000000L; propVariant.Clear(); return(result); }
/// <summary> /// Reads from this wave stream /// </summary> /// <param name="buffer">Buffer to read into</param> /// <param name="offset">Offset in buffer</param> /// <param name="count">Bytes required</param> /// <returns>Number of bytes read; 0 indicates end of stream</returns> public override int Read(byte[] buffer, int offset, int count) { if (pReader == null) { pReader = CreateReader(settings); } if (repositionTo != -1) { Reposition(repositionTo); } int bytesWritten = 0; // read in any leftovers from last time if (decoderOutputCount > 0) { bytesWritten += ReadFromDecoderBuffer(buffer, offset, count - bytesWritten); } while (bytesWritten < count) { IMFSample pSample; int dwFlags; ulong timestamp; int actualStreamIndex; pReader.ReadSample(MediaFoundationInterop.MF_SOURCE_READER_FIRST_AUDIO_STREAM, 0, out actualStreamIndex, out dwFlags, out timestamp, out pSample); if (dwFlags != 0) { // reached the end of the stream or media type changed break; }/* if (dwFlags & MF_SOURCE_READERF_CURRENTMEDIATYPECHANGED) { printf("Type change - not supported by WAVE file format.\n"); break; } if (dwFlags & MF_SOURCE_READERF_ENDOFSTREAM) { printf("End of input file.\n"); break; }*/ IMFMediaBuffer pBuffer; pSample.ConvertToContiguousBuffer(out pBuffer); IntPtr pAudioData = IntPtr.Zero; int cbBuffer; int pcbMaxLength; pBuffer.Lock(out pAudioData, out pcbMaxLength, out cbBuffer); EnsureBuffer(cbBuffer); Marshal.Copy(pAudioData, decoderOutputBuffer, 0, cbBuffer); decoderOutputOffset = 0; decoderOutputCount = cbBuffer; bytesWritten += ReadFromDecoderBuffer(buffer, offset + bytesWritten, count - bytesWritten); pBuffer.Unlock(); Marshal.ReleaseComObject(pBuffer); Marshal.ReleaseComObject(pSample); } position += bytesWritten; return bytesWritten; }
/// <summary> /// Creates a new MediaFoundationReader based on the supplied file /// </summary> /// <param name="file">Filename</param> /// <param name="settings">Advanced settings</param> public MediaFoundationReader(string file, MediaFoundationReaderSettings settings) { MediaFoundationApi.Startup(); this.settings = settings; this.file = file; var reader = CreateReader(settings); /* IMFMediaType currentMediaType; reader.GetCurrentMediaType(MediaFoundationInterop.MF_SOURCE_READER_FIRST_AUDIO_STREAM, out currentMediaType); var current = new MediaType(currentMediaType); IMFMediaType nativeMediaType; reader.GetNativeMediaType(MediaFoundationInterop.MF_SOURCE_READER_FIRST_AUDIO_STREAM, 0, out nativeMediaType); var native = new MediaType(nativeMediaType);*/ // now let's find out what we actually got IMFMediaType uncompressedMediaType; reader.GetCurrentMediaType(MediaFoundationInterop.MF_SOURCE_READER_FIRST_AUDIO_STREAM, out uncompressedMediaType); // Two ways to query it, first is to ask for properties (second is to convert into WaveFormatEx using MFCreateWaveFormatExFromMFMediaType) var outputMediaType = new MediaType(uncompressedMediaType); Guid actualMajorType = outputMediaType.MajorType; Debug.Assert(actualMajorType == MediaTypes.MFMediaType_Audio); Guid audioSubType = outputMediaType.SubType; int channels = outputMediaType.ChannelCount; int bits = outputMediaType.BitsPerSample; int sampleRate = outputMediaType.SampleRate; waveFormat = audioSubType == AudioSubtypes.MFAudioFormat_PCM ? new WaveFormat(sampleRate, bits, channels) : WaveFormat.CreateIeeeFloatWaveFormat(sampleRate, channels); reader.SetStreamSelection(MediaFoundationInterop.MF_SOURCE_READER_FIRST_AUDIO_STREAM, true); length = GetLength(reader); if (settings.SingleReaderObject) { pReader = reader; } }
private WaveFormat GetCurrentWaveFormat(IMFSourceReader reader) { IMFMediaType uncompressedMediaType; reader.GetCurrentMediaType(MediaFoundationInterop.MF_SOURCE_READER_FIRST_AUDIO_STREAM, out uncompressedMediaType); // Two ways to query it, first is to ask for properties (second is to convert into WaveFormatEx using MFCreateWaveFormatExFromMFMediaType) var outputMediaType = new MediaType(uncompressedMediaType); Guid actualMajorType = outputMediaType.MajorType; Debug.Assert(actualMajorType == MediaTypes.MFMediaType_Audio); Guid audioSubType = outputMediaType.SubType; int channels = outputMediaType.ChannelCount; int bits = outputMediaType.BitsPerSample; int sampleRate = outputMediaType.SampleRate; if (audioSubType == AudioSubtypes.MFAudioFormat_PCM) return new WaveFormat(sampleRate, bits, channels); if (audioSubType == AudioSubtypes.MFAudioFormat_Float) return WaveFormat.CreateIeeeFloatWaveFormat(sampleRate, channels); var subTypeDescription = FieldDescriptionHelper.Describe(typeof (AudioSubtypes), audioSubType); throw new InvalidDataException(String.Format("Unsupported audio sub Type {0}", subTypeDescription)); }
public static void MFCreateSourceReaderFromMediaSource( IMFMediaSource mediaSource, IMFAttributes attributes, out IMFSourceReader sourceReader) { int result = ExternMFCreateSourceReaderFromMediaSource(mediaSource, attributes, out sourceReader); if (result < 0) { throw new COMException("Exception from HRESULT: 0x" + result.ToString("X", System.Globalization.NumberFormatInfo.InvariantInfo) + " (MFCreateTranscodeTopology failed)", result); } }
/// <summary> /// Cleans up after finishing with this reader /// </summary> /// <param name="disposing">true if called from Dispose</param> protected override void Dispose(bool disposing) { if (pReader != null) { Marshal.ReleaseComObject(pReader); pReader = null; } base.Dispose(disposing); }
/// <summary> /// Reads from this wave stream /// </summary> /// <param name="buffer">Buffer to read into</param> /// <param name="offset">Offset in buffer</param> /// <param name="count">Bytes required</param> /// <returns>Number of bytes read; 0 indicates end of stream</returns> public override int Read(byte[] buffer, int offset, int count) { if (pReader == null) { pReader = CreateReader(settings); } if (repositionTo != -1) { Reposition(repositionTo); } int bytesWritten = 0; // read in any leftovers from last time if (decoderOutputCount > 0) { bytesWritten += ReadFromDecoderBuffer(buffer, offset, count - bytesWritten); } while (bytesWritten < count) { IMFSample pSample; MF_SOURCE_READER_FLAG dwFlags; ulong timestamp; int actualStreamIndex; pReader.ReadSample(MediaFoundationInterop.MF_SOURCE_READER_FIRST_AUDIO_STREAM, 0, out actualStreamIndex, out dwFlags, out timestamp, out pSample); if ((dwFlags & MF_SOURCE_READER_FLAG.MF_SOURCE_READERF_ENDOFSTREAM) != 0) { // reached the end of the stream break; } else if ((dwFlags & MF_SOURCE_READER_FLAG.MF_SOURCE_READERF_CURRENTMEDIATYPECHANGED) != 0) { waveFormat = GetCurrentWaveFormat(pReader); OnWaveFormatChanged(); // carry on, but user must handle the change of format } else if (dwFlags != 0) { throw new InvalidOperationException(String.Format("MediaFoundationReadError {0}", dwFlags)); } IMFMediaBuffer pBuffer; pSample.ConvertToContiguousBuffer(out pBuffer); IntPtr pAudioData; int cbBuffer; int pcbMaxLength; pBuffer.Lock(out pAudioData, out pcbMaxLength, out cbBuffer); EnsureBuffer(cbBuffer); Marshal.Copy(pAudioData, decoderOutputBuffer, 0, cbBuffer); decoderOutputOffset = 0; decoderOutputCount = cbBuffer; bytesWritten += ReadFromDecoderBuffer(buffer, offset + bytesWritten, count - bytesWritten); pBuffer.Unlock(); Marshal.ReleaseComObject(pBuffer); Marshal.ReleaseComObject(pSample); } position += bytesWritten; return bytesWritten; }
private long GetLength(IMFSourceReader reader) { PropVariant variant; // http://msdn.microsoft.com/en-gb/library/windows/desktop/dd389281%28v=vs.85%29.aspx#getting_file_duration int hResult = reader.GetPresentationAttribute(MediaFoundationInterop.MF_SOURCE_READER_MEDIASOURCE, MediaFoundationAttributes.MF_PD_DURATION, out variant); if (hResult == MediaFoundationErrors.MF_E_ATTRIBUTENOTFOUND) { // this doesn't support telling us its duration (might be streaming) return 0; } if (hResult != 0) { Marshal.ThrowExceptionForHR(hResult); } var lengthInBytes = (((long)variant.Value) * waveFormat.AverageBytesPerSecond) / 10000000L; variant.Clear(); return lengthInBytes; }
private static MediaType GetCurrentMediaType(IMFSourceReader reader) { IMFMediaType mediaType; reader.GetCurrentMediaType(MediaFoundationInterop.MF_SOURCE_READER_FIRST_AUDIO_STREAM, out mediaType); return new MediaType(mediaType); }
private WaveFormat GetCurrentWaveFormat(IMFSourceReader reader) { IMFMediaType uncompressedMediaType; reader.GetCurrentMediaType(MediaFoundationInterop.MF_SOURCE_READER_FIRST_AUDIO_STREAM, out uncompressedMediaType); // Two ways to query it, first is to ask for properties (second is to convert into WaveFormatEx using MFCreateWaveFormatExFromMFMediaType) var outputMediaType = new MediaType(uncompressedMediaType); Guid actualMajorType = outputMediaType.MajorType; Debug.Assert(actualMajorType == MediaTypes.MFMediaType_Audio); Guid audioSubType = outputMediaType.SubType; int channels = outputMediaType.ChannelCount; int bits = outputMediaType.BitsPerSample; int sampleRate = outputMediaType.SampleRate; return audioSubType == AudioSubtypes.MFAudioFormat_PCM ? new WaveFormat(sampleRate, bits, channels) : WaveFormat.CreateIeeeFloatWaveFormat(sampleRate, channels); }