private static IMFTranscodeProfile CreateProfile(AudioFormat audioOutput, VideoFormat videoOutput, Guid containerType) { IMFTranscodeProfile profile = null; // Create a transcode profile MFHelper.MFCreateTranscodeProfile(out profile); // Create and set the audio attributes profile.SetAudioAttributes(SimpleFastEncode.CreateAudioAttributes(audioOutput)); // Create and set the video attributes profile.SetVideoAttributes(SimpleFastEncode.CreateVideoAttributes(videoOutput)); // Create the container attributes IMFAttributes containerAttributes = null; MFHelper.MFCreateAttributes(out containerAttributes, 2); containerAttributes.SetUINT32(new Guid(Consts.MF_TRANSCODE_TOPOLOGYMODE), 1); containerAttributes.SetGUID(new Guid(Consts.MF_TRANSCODE_CONTAINERTYPE), containerType); // Set them in the transcoding profile profile.SetContainerAttributes(containerAttributes); return(profile); }
private void NegotiateStream(uint streamIndex, Guid majorType, Guid[] possibleSubtypes) { IMFMediaType outputMediaType = null; Exception lastException = null; bool foundValidType = false; foreach (Guid subType in possibleSubtypes) { try { // Create a partial media type MFHelper.MFCreateMediaType(out outputMediaType); outputMediaType.SetGUID(new Guid(Consts.MF_MT_MAJOR_TYPE), majorType); outputMediaType.SetGUID(new Guid(Consts.MF_MT_SUBTYPE), subType); // Set it as the current media type in source reader this.sourceReader.SetCurrentMediaType(streamIndex, IntPtr.Zero, outputMediaType); // Get the full media type from Source Reader this.sourceReader.GetCurrentMediaType(streamIndex, out outputMediaType); // Set it as the input media type in Sink Writer this.sinkWriter.SetInputMediaType(this.streamsInfo[streamIndex].OutputStreamIndex, outputMediaType, null); // If no exceptions were thrown a suitable media type was found foundValidType = true; // Break from the loop so no more media types are tried break; } catch (Exception ex) { // Something went wrong, the loop will continue and the next type will be tried lastException = ex; } } // If FormatFound is false no suitable type was found and the operation can't continue if (foundValidType == false) { if (lastException != null) { throw new Exception(lastException.Message, lastException); } else { throw new Exception("Unknown error occurred"); } } }
private static IMFAttributes CreateAudioAttributes(AudioFormat audioOutput) { uint codecConfig = 0; object supportedAttributes = null; // Create the audio attributes IMFAttributes audioAttributes = null; // Generate the audio media type uint elementsNumber = 0; uint selectedType = 0; int avgBitrateDiff = int.MaxValue; uint avgBytePerSecond = uint.MaxValue; // Get the available audio ouput types for the required sub type IMFCollection availableTypes = null; MFHelper.MFTranscodeGetAudioOutputAvailableTypes(audioOutput.Subtype, (uint)Enums.MFT_ENUM_FLAG.MFT_ENUM_FLAG_ALL, codecConfig, out availableTypes); // Get the number of types availableTypes.GetElementCount(out elementsNumber); // Find the best match for our needs for (uint elementIndex = 0; elementIndex < elementsNumber; elementIndex++) { // Get the next element availableTypes.GetElement(elementIndex, out supportedAttributes); audioAttributes = (IMFAttributes)supportedAttributes; // Get the byte per second audioAttributes.GetUINT32(new Guid(Consts.MF_MT_AUDIO_AVG_BYTES_PER_SECOND), out avgBytePerSecond); // If this is better than the last one found remember the index if (Math.Abs((int)avgBytePerSecond - (int)audioOutput.AvgBytePerSecond) < avgBitrateDiff) { selectedType = elementIndex; avgBitrateDiff = Math.Abs((int)avgBytePerSecond - (int)audioOutput.AvgBytePerSecond); } audioAttributes = null; } // Get the best audio type found availableTypes.GetElement(selectedType, out supportedAttributes); audioAttributes = (IMFAttributes)supportedAttributes; return(audioAttributes); }
private IMFMediaType CreateTargetVideoMediaType() { IMFMediaType mediaType = null; MFHelper.MFCreateMediaType(out mediaType); mediaType.SetGUID(new Guid(Consts.MF_MT_MAJOR_TYPE), new Guid(Consts.MFMediaType_Video)); mediaType.SetGUID(new Guid(Consts.MF_MT_SUBTYPE), this.videoOutput.Subtype); mediaType.SetUINT64(new Guid(Consts.MF_MT_FRAME_SIZE), this.videoOutput.FrameSize.Packed); mediaType.SetUINT64(new Guid(Consts.MF_MT_FRAME_RATE), this.videoOutput.FrameRate.Packed); mediaType.SetUINT64(new Guid(Consts.MF_MT_PIXEL_ASPECT_RATIO), this.videoOutput.PixelAspectRatio.Packed); mediaType.SetUINT32(new Guid(Consts.MF_MT_AVG_BITRATE), this.videoOutput.AvgBitRate); mediaType.SetUINT32(new Guid(Consts.MF_MT_INTERLACE_MODE), this.videoOutput.InterlaceMode); return(mediaType); }
private static IMFAttributes CreateVideoAttributes(VideoFormat videoOutput) { IMFAttributes videoAttributes = null; MFHelper.MFCreateAttributes(out videoAttributes, 0); videoAttributes.SetGUID(new Guid(Consts.MF_MT_SUBTYPE), videoOutput.Subtype); PackedINT32 pixelAspectRatio = new PackedINT32(1, 1); // Set the argument attributes videoAttributes.SetUINT64(new Guid(Consts.MF_MT_FRAME_RATE), videoOutput.FrameRate.Packed); videoAttributes.SetUINT64(new Guid(Consts.MF_MT_FRAME_SIZE), videoOutput.FrameSize.Packed); videoAttributes.SetUINT64(new Guid(Consts.MF_MT_PIXEL_ASPECT_RATIO), pixelAspectRatio.Packed); videoAttributes.SetUINT32(new Guid(Consts.MF_MT_INTERLACE_MODE), videoOutput.InterlaceMode); videoAttributes.SetUINT32(new Guid(Consts.MF_MT_AVG_BITRATE), videoOutput.AvgBitRate); return(videoAttributes); }
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; }
private IMFMediaType CreateTargetAudioMediaType() { IMFMediaType mediaType = null; if (audioOutput.Subtype.Equals(new Guid(Consts.MFAudioFormat_AAC))) { // Create the AAC media type MFHelper.MFCreateMediaType(out mediaType); mediaType.SetGUID(new Guid(Consts.MF_MT_MAJOR_TYPE), new Guid(Consts.MFMediaType_Audio)); mediaType.SetGUID(new Guid(Consts.MF_MT_SUBTYPE), this.audioOutput.Subtype); mediaType.SetUINT32(new Guid(Consts.MF_MT_AUDIO_AVG_BYTES_PER_SECOND), this.audioOutput.AvgBytePerSecond); mediaType.SetUINT32(new Guid(Consts.MF_MT_AUDIO_NUM_CHANNELS), this.audioOutput.NumOfChannels); mediaType.SetUINT32(new Guid(Consts.MF_MT_AUDIO_SAMPLES_PER_SECOND), this.audioOutput.SamplesPerSecond); mediaType.SetUINT32(new Guid(Consts.MF_MT_AUDIO_BLOCK_ALIGNMENT), this.audioOutput.BlockAlignment); mediaType.SetUINT32(new Guid(Consts.MF_MT_AUDIO_BITS_PER_SAMPLE), this.audioOutput.BitsPerSample); } else { // Create the WMA media type uint codecConfig = 0; uint elementsNumber = 0; uint selectedType = 0; int avgBitrateDiff = int.MaxValue; uint avgBytePerSecond = uint.MaxValue; object supportedAttributes = null; // Get the available audio ouput types for the required sub type IMFCollection availableTypes = null; MFHelper.MFTranscodeGetAudioOutputAvailableTypes(audioOutput.Subtype, (uint)Enums.MFT_ENUM_FLAG.MFT_ENUM_FLAG_ALL, codecConfig, out availableTypes); // Get the number of types availableTypes.GetElementCount(out elementsNumber); for (uint elementIndex = 0; elementIndex < elementsNumber; elementIndex++) { // Get the next element availableTypes.GetElement(elementIndex, out supportedAttributes); mediaType = (IMFMediaType)supportedAttributes; // Get the byte per second mediaType.GetUINT32(new Guid(Consts.MF_MT_AUDIO_AVG_BYTES_PER_SECOND), out avgBytePerSecond); // If this is better than the last one found remember the index if (Math.Abs((int)avgBytePerSecond - (int)audioOutput.AvgBytePerSecond) < avgBitrateDiff) { selectedType = elementIndex; avgBitrateDiff = Math.Abs((int)avgBytePerSecond - (int)audioOutput.AvgBytePerSecond); } mediaType = null; } // Get the best audio type found availableTypes.GetElement(selectedType, out supportedAttributes); mediaType = (IMFMediaType)supportedAttributes; } return(mediaType); }
/// <summary> /// Starts the asychronous encode operation /// </summary> /// <param name="inputURL">Source filename</param> /// <param name="outputURL">Targe filename</param> /// <param name="audioOutput">Audio format that will be used for audio streams</param> /// <param name="videoOutput">Video format that will be used for video streams</param> /// <param name="startPosition">Starting position of the contet</param> /// <param name="endPosition">Position where the new content will end</param> public void Encode(string inputURL, string outputURL, AudioFormat audioOutput, VideoFormat videoOutput, ulong startPosition, ulong endPosition) { // If busy with other operation ignore and return if (this.IsBusy()) { return; } try { this.presentationClock = null; this.startPosition = startPosition; this.endPosition = endPosition; object objectSource = null; // Create the media source using source resolver and the input URL uint objectType = default(uint); this.mediaSource = null; // Init source resolver IMFSourceResolver sourceResolver = null; MFHelper.MFCreateSourceResolver(out sourceResolver); sourceResolver.CreateObjectFromURL(inputURL, Consts.MF_RESOLUTION_MEDIASOURCE, null, out objectType, out objectSource); this.mediaSource = (IMFMediaSource)objectSource; // Create the media session using a global start time so MF_TOPOLOGY_PROJECTSTOP can be used to stop the session this.mediaSession = null; IMFAttributes mediaSessionAttributes = null; MFHelper.MFCreateAttributes(out mediaSessionAttributes, 1); mediaSessionAttributes.SetUINT32(new Guid(Consts.MF_SESSION_GLOBAL_TIME), 1); MFHelper.MFCreateMediaSession(mediaSessionAttributes, out this.mediaSession); // Create the event handler AsyncEventHandler mediaEventHandler = new AsyncEventHandler(this.mediaSession); mediaEventHandler.MediaEvent += this.MediaEvent; // Get the stream descriptor IMFPresentationDescriptor presentationDescriptor = null; mediaSource.CreatePresentationDescriptor(out presentationDescriptor); // Get the duration presentationDescriptor.GetUINT64(new Guid(Consts.MF_PD_DURATION), out this.duration); IMFTranscodeProfile transcodeProfile = null; Guid containerType = new Guid(Consts.MFTranscodeContainerType_MPEG4); if (outputURL.EndsWith(".wmv", StringComparison.OrdinalIgnoreCase) || outputURL.EndsWith(".wma", StringComparison.OrdinalIgnoreCase)) { containerType = new Guid(Consts.MFTranscodeContainerType_ASF); } // Generate the transcoding profile transcodeProfile = SimpleFastEncode.CreateProfile(audioOutput, videoOutput, containerType); // Create the MF topology using the profile IMFTopology topology = null; MFHelper.MFCreateTranscodeTopology(this.mediaSource, outputURL, transcodeProfile, out topology); // Set the end position topology.SetUINT64(new Guid(Consts.MF_TOPOLOGY_PROJECTSTART), 0); topology.SetUINT64(new Guid(Consts.MF_TOPOLOGY_PROJECTSTOP), (endPosition == 0) ? this.duration : endPosition); // Set the session topology this.mediaSession.SetTopology((uint)Enums.MFSESSION_SETTOPOLOGY_FLAGS.None, topology); } catch (Exception ex) { this.mediaSession = null; // Fire the EncodeError event if (this.EncodeError != null) { this.EncodeError(new Exception(ex.Message, ex)); } } }