コード例 #1
0
        /// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=
        /// <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");

            // close and release our call back handler
            if (mediaSessionAsyncCallbackHandler != null)
            {
                // stop any messaging or events in the call back handler
                mediaSessionAsyncCallbackHandler.ShutDown();
                mediaSessionAsyncCallbackHandler = null;
            }

            // close the session (this is NOT the same as shutting it down)
            if (mediaSession != null)
            {
                hr = mediaSession.Close();
                if (hr != HResult.S_OK)
                {
                    // just log it
                    LogMessage("CloseAllMediaDevices call to mediaSession.Close failed. Err=" + hr.ToString());
                }
            }

            // Shut down the media source
            if (mediaSource != null)
            {
                hr = mediaSource.Shutdown();
                if (hr != HResult.S_OK)
                {
                    // just log it
                    LogMessage("CloseAllMediaDevices call to mediaSource.Shutdown failed. Err=" + hr.ToString());
                }
                Marshal.ReleaseComObject(mediaSource);
                mediaSource = null;
            }

            // Shut down the media session (note we only closed it before).
            if (mediaSession != null)
            {
                hr = mediaSession.Shutdown();
                if (hr != HResult.S_OK)
                {
                    // just log it
                    LogMessage("CloseAllMediaDevices call to mediaSession.Shutdown failed. Err=" + hr.ToString());
                }
                Marshal.ReleaseComObject(mediaSession);
                mediaSession = null;
            }

            // close the media sink
            if (mediaSink != null)
            {
                Marshal.ReleaseComObject(mediaSink);
                mediaSink = null;
            }
        }
コード例 #2
0
ファイル: MFFunctions.cs プロジェクト: zhuowp/DirectN
        public static ComObject <T> MFCreateSinkWriterFromMediaSink <T>(IMFMediaSink sink, IMFAttributes attributes = null) where T : IMFSinkWriter
        {
            if (sink == null)
            {
                throw new ArgumentNullException(nameof(sink));
            }

            MFCreateSinkWriterFromMediaSink(sink, attributes, out var writer).ThrowOnError();
            return(new ComObject <T>((T)writer));
        }
コード例 #3
0
        protected IMFTopologyNode CreateOutputNode(IMFStreamDescriptor pSourceSD)
        {
            IMFTopologyNode     pNode             = null;
            IMFMediaTypeHandler pHandler          = null;
            IMFActivate         pRendererActivate = null;

            Guid guidMajorType = Guid.Empty;
            int  hr            = 0;

            // Get the stream ID.
            int streamID = 0;

            try
            {
                try
                {
                    hr = pSourceSD.GetStreamIdentifier(out streamID); // Just for debugging, ignore any failures.
                    MFError.ThrowExceptionForHR(hr);
                }
                catch
                {
                    //TRACE("IMFStreamDescriptor::GetStreamIdentifier" + hr.ToString());
                }

                // Get the media type handler for the stream.
                hr = pSourceSD.GetMediaTypeHandler(out pHandler);
                MFError.ThrowExceptionForHR(hr);

                // Get the major media type.
                hr = pHandler.GetMajorType(out guidMajorType);
                MFError.ThrowExceptionForHR(hr);

                // Create a downstream node.
                hr = MFExtern.MFCreateTopologyNode(MFTopologyType.OutputNode, out pNode);
                MFError.ThrowExceptionForHR(hr);

                // Create an IMFActivate object for the renderer, based on the media type.
                if (MFMediaType.Audio == guidMajorType)
                {
                    // Create the audio renderer.
                    hr = MFExtern.MFCreateAudioRendererActivate(out pRendererActivate);
                    MFError.ThrowExceptionForHR(hr);
                    object sar;
                    pRendererActivate.ActivateObject(typeof(IMFMediaSink).GUID, out sar);
                    StreamingAudioRenderer = sar as IMFMediaSink;
                }
                else if (MFMediaType.Video == guidMajorType)
                {
                    // Create the video renderer.
                    pRendererActivate = CreateVideoRenderer();
                }
                else
                {
                    //TRACE(string.Format("Stream {0}: Unknown format", streamID));
                    throw new COMException("Unknown format");
                }

                // Set the IActivate object on the output node.
                hr = pNode.SetObject(pRendererActivate);
                MFError.ThrowExceptionForHR(hr);
            }
            catch (Exception ex)
            {
                // If we failed, release the pNode
                COMBase.SafeRelease(pNode);
                throw;
            }
            finally
            {
                // Clean up.
                COMBase.SafeRelease(pHandler);
                COMBase.SafeRelease(pRendererActivate);
            }
            return(pNode);
        }
コード例 #4
0
ファイル: Externs.cs プロジェクト: gitter-badger/GS
 public static extern void MFCreateASFMediaSink(
     IMFByteStream pIByteStream,
     out IMFMediaSink ppIMediaSink
     );
コード例 #5
0
ファイル: Externs.cs プロジェクト: gitter-badger/GS
 public static extern void MFCreateAudioRenderer(
     IMFAttributes pAudioAttributes,
     out IMFMediaSink ppSink
     );
コード例 #6
0
ファイル: MFFunctions.cs プロジェクト: zhuowp/DirectN
 public static ComObject <IMFSinkWriter> MFCreateSinkWriterFromMediaSink(IMFMediaSink sink, IMFAttributes attributes = null) => MFCreateSinkWriterFromMediaSink <IMFSinkWriter>(sink, attributes);
コード例 #7
0
ファイル: MFFunctions.cs プロジェクト: zhuowp/DirectN
 public static extern HRESULT MFCreateSinkWriterFromMediaSink(IMFMediaSink pMediaSink, IMFAttributes pAttributes, out IMFSinkWriter ppSinkWriter);
コード例 #8
0
        /// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=
        /// <summary>
        /// Opens the Media File Sink
        ///
        /// The caller must release the returned sink.
        /// </summary>
        /// <param name="outputFileName">the filename we write out to</param>
        /// <returns>an IMFMediaSink object or null for fail</returns>
        /// <history>
        ///    01 Nov 18  Cynic - Started
        /// </history>
        private IMFMediaSink OpenMediaFileSink(string outputFileName)
        {
            HResult       hr;
            IMFMediaSink  workingSink   = null;
            IMFByteStream outbyteStream = null;

            if ((outputFileName == null) || (outputFileName.Length == 0))
            {
                // we failed
                throw new Exception("OpenMediaFileSink: Invalid filename specified");
            }

            try
            {
                // Create the media sink. We use the filename to create a byte stream and
                // then create the sink from that. The types configure the output

                // first we need a bytestream
                hr = MFExtern.MFCreateFile(MFFileAccessMode.ReadWrite, MFFileOpenMode.DeleteIfExist, MFFileFlags.None, outputFileName, out outbyteStream);
                if (hr != HResult.S_OK)
                {
                    // we failed
                    throw new Exception("OpenMediaFileSink: Failed on call to MFExtern.MFCreateFile, retVal=" + hr.ToString());
                }
                if (outbyteStream == null)
                {
                    // we failed
                    throw new Exception("OpenMediaFileSink: Failed to create Sink bytestream, Nothing will work.");
                }

                // note the MP3 File sink does not seem to require the media type as part of its
                // configuration. The reasons for this are unknown to me. However it may be
                // due to the fact that the mp3 file spec is pretty fixed in structure and
                // as long as the input stream actually _is_ mp3 the media sink can write
                // it to the output file.
                hr = MFExtern.MFCreateMP3MediaSink(outbyteStream, out workingSink);
                if (hr != HResult.S_OK)
                {
                    // we failed
                    throw new Exception("OpenMediaFileSink: Failed on call to MFCreateMP3MediaSink, retVal=" + hr.ToString());
                }
                if (workingSink == null)
                {
                    // we failed
                    throw new Exception("OpenMediaFileSink: Failed to create media sink, 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 (workingSink != null)
                {
                    // clean up. Nothing else has this yet
                    Marshal.ReleaseComObject(workingSink);
                    workingSink = null;
                }
                workingSink = null;
                throw ex;
            }

            return(workingSink);
        }
コード例 #9
0
        /// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=
        /// <summary>
        /// Opens prepares the media session and topology and opens the media source
        /// and media sink.
        ///
        /// Once the session and topology are setup, a MESessionTopologySet event
        /// will be triggered in the callback handler. After that the events there
        /// trigger other events and everything rolls along automatically.
        /// </summary>
        /// <param name="sourceFileName">the source file name</param>
        /// <param name="outputFileName">the name of the output file</param>
        /// <history>
        ///    01 Nov 18  Cynic - Originally Written
        /// </history>
        public void PrepareSessionAndTopology(string sourceFileName, string outputFileName)
        {
            HResult                   hr;
            IMFSourceResolver         pSourceResolver = null;
            IMFTopology               pTopology       = null;
            IMFPresentationDescriptor sourcePresentationDescriptor = null;
            int sourceStreamCount = 0;
            IMFStreamDescriptor audioStreamDescriptor = null;
            bool            streamIsSelected          = false;
            IMFTopologyNode sourceAudioNode           = null;
            IMFTopologyNode outputSinkNode            = null;
            IMFMediaType    currentAudioMediaType     = null;
            int             audioStreamIndex          = -1;

            LogMessage("PrepareSessionAndTopology ");

            // we sanity check the filenames - the existence of the path and if the file already exists
            // should have been checked before this call
            if ((sourceFileName == null) || (sourceFileName.Length == 0))
            {
                throw new Exception("PrepareSessionAndTopology: source file name is invalid. Cannot continue.");
            }

            if ((outputFileName == null) || (outputFileName.Length == 0))
            {
                throw new Exception("PrepareSessionAndTopology: output file name is invalid. Cannot continue.");
            }

            try
            {
                // reset everything
                CloseAllMediaDevices();

                // Create the media session.
                hr = MFExtern.MFCreateMediaSession(null, out mediaSession);
                if (hr != HResult.S_OK)
                {
                    throw new Exception("PrepareSessionAndTopology call to MFExtern.MFCreateMediaSession failed. Err=" + hr.ToString());
                }
                if (mediaSession == null)
                {
                    throw new Exception("PrepareSessionAndTopology call to MFExtern.MFCreateMediaSession failed. mediaSession == null");
                }

                // set up our media session call back handler.
                mediaSessionAsyncCallbackHandler = new TantaAsyncCallbackHandler();
                mediaSessionAsyncCallbackHandler.Initialize();
                mediaSessionAsyncCallbackHandler.MediaSession = mediaSession;
                mediaSessionAsyncCallbackHandler.MediaSessionAsyncCallBackError = HandleMediaSessionAsyncCallBackErrors;
                mediaSessionAsyncCallbackHandler.MediaSessionAsyncCallBackEvent = HandleMediaSessionAsyncCallBackEvent;

                // Register the callback handler with the session and tell it that events can
                // start. This does not actually trigger an event it just lets the media session
                // know that it can now send them if it wishes to do so.
                hr = mediaSession.BeginGetEvent(mediaSessionAsyncCallbackHandler, null);
                if (hr != HResult.S_OK)
                {
                    throw new Exception("PrepareSessionAndTopology call to mediaSession.BeginGetEvent failed. Err=" + hr.ToString());
                }

                // Create a new topology.  A topology describes a collection of media sources, sinks, and transforms that are
                // connected in a certain order. These objects are represented within the topology by topology nodes,
                // which expose the IMFTopologyNode interface. A topology describes the path of multimedia data through these nodes.
                hr = MFExtern.MFCreateTopology(out pTopology);
                if (hr != HResult.S_OK)
                {
                    throw new Exception("PrepareSessionAndTopology call to MFExtern.MFCreateTopology failed. Err=" + hr.ToString());
                }
                if (pTopology == null)
                {
                    throw new Exception("PrepareSessionAndTopology call to MFExtern.MFCreateTopology failed. pTopology == null");
                }

                // ####
                // #### we now create the media source, this is an audio file
                // ####

                // use the file name to create the media source for the audio device. Media sources are objects that generate media data.
                // For example, the data might come from a video file, a network stream, or a hardware device, such as a camera. Each
                // media source contains one or more streams, and each stream delivers data of one type, such as audio or video.
                mediaSource = TantaWMFUtils.GetMediaSourceFromFile(sourceFileName);
                if (mediaSource == null)
                {
                    throw new Exception("PrepareSessionAndTopology call to mediaSource == null");
                }

                // A presentation is a set of related media streams that share a common presentation time.  We now get a copy of the media
                // source's presentation descriptor. Applications can use the presentation descriptor to select streams
                // and to get information about the source content.
                hr = mediaSource.CreatePresentationDescriptor(out sourcePresentationDescriptor);
                if (hr != HResult.S_OK)
                {
                    throw new Exception("PrepareSessionAndTopology call to mediaSource.CreatePresentationDescriptor failed. Err=" + hr.ToString());
                }
                if (sourcePresentationDescriptor == null)
                {
                    throw new Exception("PrepareSessionAndTopology call to mediaSource.CreatePresentationDescriptor failed. sourcePresentationDescriptor == null");
                }

                // Now we get the number of stream descriptors in the presentation. A presentation descriptor contains a list of one or more
                // stream descriptors. These describe the streams in the presentation. Streams can be either selected or deselected. Only the
                // selected streams produce data. Deselected streams are not active and do not produce any data.
                hr = sourcePresentationDescriptor.GetStreamDescriptorCount(out sourceStreamCount);
                if (hr != HResult.S_OK)
                {
                    throw new Exception("PrepareSessionAndTopology call to sourcePresentationDescriptor.GetStreamDescriptorCount failed. Err=" + hr.ToString());
                }
                if (sourceStreamCount == 0)
                {
                    throw new Exception("PrepareSessionAndTopology call to sourcePresentationDescriptor.GetStreamDescriptorCount failed. sourceStreamCount == 0");
                }

                // Look at each stream, there can be more than one stream here
                // Usually only one is enabled. This app uses the first "selected"
                // stream we come to which has the appropriate media type
                for (int i = 0; i < sourceStreamCount; i++)
                {
                    // we require the major type to be audio
                    Guid guidMajorType = TantaWMFUtils.GetMajorMediaTypeFromPresentationDescriptor(sourcePresentationDescriptor, i);
                    if (guidMajorType != MFMediaType.Audio)
                    {
                        continue;
                    }

                    // we also require the stream to be enabled
                    hr = sourcePresentationDescriptor.GetStreamDescriptorByIndex(i, out streamIsSelected, out audioStreamDescriptor);
                    if (hr != HResult.S_OK)
                    {
                        throw new Exception("PrepareSessionAndTopology call to sourcePresentationDescriptor.GetStreamDescriptorByIndex failed. Err=" + hr.ToString());
                    }
                    if (audioStreamDescriptor == null)
                    {
                        throw new Exception("PrepareSessionAndTopology call to sourcePresentationDescriptor.GetStreamDescriptorByIndex failed. audioStreamDescriptor == null");
                    }
                    // if the stream is selected, leave now we will release the audioStream descriptor later
                    if (streamIsSelected == true)
                    {
                        audioStreamIndex = i;  // record this
                        break;
                    }

                    // release the one we are not using
                    if (audioStreamDescriptor != null)
                    {
                        Marshal.ReleaseComObject(audioStreamDescriptor);
                        audioStreamDescriptor = null;
                    }
                    audioStreamIndex = -1;
                }

                // by the time we get here we should have a audioStreamDescriptor if
                // we do not, then we cannot proceed
                if (audioStreamDescriptor == null)
                {
                    throw new Exception("PrepareSessionAndTopology call to sourcePresentationDescriptor.GetStreamDescriptorByIndex failed. audioStreamDescriptor == null");
                }
                if (audioStreamIndex < 0)
                {
                    throw new Exception("PrepareSessionAndTopology call to sourcePresentationDescriptor.GetStreamDescriptorByIndex failed. audioStreamIndex < 0");
                }

                // ####
                // #### we now create the media sink, we need the type from the stream to do
                // #### this which is why we wait until now to set it up
                // ####

                currentAudioMediaType = TantaWMFUtils.GetCurrentMediaTypeFromStreamDescriptor(audioStreamDescriptor);
                if (currentAudioMediaType == null)
                {
                    throw new Exception("PrepareSessionAndTopology call to currentAudioMediaType == null");
                }

                mediaSink = OpenMediaFileSink(outputFileName);
                if (mediaSink == null)
                {
                    throw new Exception("PrepareSessionAndTopology call to mediaSink == null");
                }

                // ####
                // #### we now make up a topology branch for the audio stream
                // ####

                // Create a source node for this stream.
                sourceAudioNode = TantaWMFUtils.CreateSourceNodeForStream(mediaSource, sourcePresentationDescriptor, audioStreamDescriptor);
                if (sourceAudioNode == null)
                {
                    throw new Exception("PrepareSessionAndTopology call to CreateSourceNodeForStream failed. pSourceNode == null");
                }

                // Create the output node - this is a file sink in this case.
                outputSinkNode = TantaWMFUtils.CreateSinkNodeForStream(mediaSink);
                if (outputSinkNode == null)
                {
                    throw new Exception("PrepareSessionAndTopology call to CreateOutputNodeForStream failed. outputSinkNode == null");
                }

                // Add the nodes to the topology. First the source
                hr = pTopology.AddNode(sourceAudioNode);
                if (hr != HResult.S_OK)
                {
                    throw new Exception("PrepareSessionAndTopology call to pTopology.AddNode(sourceAudioNode) failed. Err=" + hr.ToString());
                }

                // then add the output
                hr = pTopology.AddNode(outputSinkNode);
                if (hr != HResult.S_OK)
                {
                    throw new Exception("PrepareSessionAndTopology call to pTopology.AddNode(outputSinkNode) failed. Err=" + hr.ToString());
                }

                // Connect the output stream from the source node to the input stream of the output node. The parameters are:
                //    dwOutputIndex  -  Zero-based index of the output stream on this node.
                //    *pDownstreamNode  -  Pointer to the IMFTopologyNode interface of the node to connect to.
                //    dwInputIndexOnDownstreamNode  -  Zero-based index of the input stream on the other node.
                hr = sourceAudioNode.ConnectOutput(0, outputSinkNode, 0);
                if (hr != HResult.S_OK)
                {
                    throw new Exception("PrepareSessionAndTopology call to  pSourceNode.ConnectOutput failed. Err=" + hr.ToString());
                }

                // Set the topology on the media session.
                // If SetTopology succeeds, the media session will queue an
                // MESessionTopologySet event.
                hr = mediaSession.SetTopology(0, pTopology);
                MFError.ThrowExceptionForHR(hr);

                // Release the topology
                if (pTopology != null)
                {
                    Marshal.ReleaseComObject(pTopology);
                }
            }
            catch (Exception ex)
            {
                LogMessage("Error: " + ex.Message);
                OISMessageBox(ex.Message);
            }
            finally
            {
                // Clean up
                if (pSourceResolver != null)
                {
                    Marshal.ReleaseComObject(pSourceResolver);
                }
                if (sourcePresentationDescriptor != null)
                {
                    Marshal.ReleaseComObject(sourcePresentationDescriptor);
                }
                if (audioStreamDescriptor != null)
                {
                    Marshal.ReleaseComObject(audioStreamDescriptor);
                }
                if (sourceAudioNode != null)
                {
                    Marshal.ReleaseComObject(sourceAudioNode);
                }
                if (outputSinkNode != null)
                {
                    Marshal.ReleaseComObject(outputSinkNode);
                }
                if (currentAudioMediaType != null)
                {
                    Marshal.ReleaseComObject(currentAudioMediaType);
                }
            }
        }
コード例 #10
0
        /// <summary>
        /// Creates an instance of the sink writer, given an IMFMediaSink instance.
        /// </summary>
        /// <param name="factory">A valid IMFReadWriteClassFactory instance.</param>
        /// <param name="mediaSink">An instance of IMFMediaSink used by the sink writer.</param>
        /// <param name="attributes">A instance to the IMFAttributes interface. You can use this parameter to configure the sink writer.</param>
        /// <param name="sourceReader">Receives the sink writer.</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 CreateInstanceFromObject(this IMFReadWriteClassFactory factory, IMFMediaSink mediaSink, IMFAttributes attributes, out IMFSinkWriter sinkWriter)
        {
            if (factory == null)
            {
                throw new ArgumentNullException("factory");
            }

            object tmp;

            HResult hr = factory.CreateInstanceFromObject(CLSID.CLSID_MFSinkWriter, mediaSink, attributes, typeof(IMFSinkWriterExtensions).GUID, out tmp);

            sinkWriter = hr.Succeeded() ? tmp as IMFSinkWriter : null;

            return(hr);
        }