private void createSession(string sFilePath)
        {
            try
            {
                MFError throwonhr = null;

                if (m_pSession == null)
                {
                    throwonhr = MFExtern.MFCreateMediaSession(null, out m_pSession);
                }
                else
                {
                    Stop();
                }

                // Create the media source.

                CreateMediaSource(sFilePath);

                if (m_pSource == null)
                {
                    return;
                }

                IMFPresentationDescriptor lPresentationDescriptor = null;

                m_pSource.CreatePresentationDescriptor(out lPresentationDescriptor);

                if (lPresentationDescriptor == null)
                {
                    return;
                }

                lPresentationDescriptor.GetUINT64(MFAttributesClsid.MF_PD_DURATION, out mMediaDuration);

                IMFTopology pTopology = null;

                // Create a partial topology.
                CreateTopologyFromSource(out pTopology);

                HResult hr = HResult.S_OK;
                // Set the topology on the media session.
                hr = m_pSession.SetTopology(MFSessionSetTopologyFlags.Immediate, pTopology);

                StartPlayback();
            }
            catch (Exception)
            {
            }
        }
        private static HResult ProcessMediaSession(string VideoFile)
        {
            HResult hr = S_OK;

            IMFMediaSource  source       = null;
            IMFTopology     topology     = null;
            IMFMediaSinkAlt mediaSink    = null;
            IMFMediaSession mediaSession = null;

            hr = CreateMediaSource(VideoFile, out source);

            if (Failed(hr))
            {
                return(hr);
            }

            hr = CreateTopology(out topology, out mediaSink, source);
            if (Failed(hr))
            {
                topology  = null;
                mediaSink = null;
                source    = null;
                return(hr);
            }

            hr = MF.CreateMediaSession(null, out mediaSession);
            if (Failed(hr))
            {
                topology     = null;
                mediaSink    = null;
                source       = null;
                mediaSession = null;
                return(hr);
            }

            hr = mediaSession.SetTopology(MFSessionSetTopologyFlags.None, topology);
            if (Failed(hr))
            {
                topology     = null;
                mediaSink    = null;
                source       = null;
                mediaSession = null;
                return(hr);
            }

            hr = RunMediaSession(mediaSession);

            return(hr);
        }
Example #3
0
        ////////////////////////////////////////////////////////////////////////////////////////
        //  Name: CPlayer::QueueNextSegment (Private)
        //  Description:
        //      Queues the next topology on the session.
        //
        //  Parameter:
        //      pPresentationDescriptor: [in] Presentation descriptor for the next topology
        //      pSegmentId: [out] Receives the corresponding segment identifier for the topology
        //
        //  Note: The presentation descriptor is received from the MENewPresentation event.
        //          This event tells the session about the next topology in the sequencer.
        //          If NULL is passed, this method queues the first topology on the media session.
        /////////////////////////////////////////////////////////////////////////////////////////

        private void QueueNextSegment(
            IMFPresentationDescriptor pPresentationDescriptor,
            out int pSegmentId)
        {
            HResult hr;
            IMFMediaSourceTopologyProvider pMediaSourceTopologyProvider;
            IMFTopology pTopology;

            int SegId = 0;

            // Get the Segment ID.
            hr = m_pSequencerSource.GetPresentationContext(
                pPresentationDescriptor,
                out SegId,
                out pTopology);
            MFError.ThrowExceptionForHR(hr);

            SafeRelease(pTopology);

            Debug.WriteLine(string.Format("CPlayer::QueueNextSegment: {0}", SegId));

            //Get the topology for the presentation descriptor
            pMediaSourceTopologyProvider = (IMFMediaSourceTopologyProvider)m_pSequencerSource;

            hr = pMediaSourceTopologyProvider.GetMediaSourceTopology(
                pPresentationDescriptor,
                out pTopology);
            MFError.ThrowExceptionForHR(hr);

            try
            {
                //Set the topology on the media session
                hr = m_pMediaSession.SetTopology(MFSessionSetTopologyFlags.None, pTopology);
                MFError.ThrowExceptionForHR(hr);

                pSegmentId = SegId;
            }
            finally
            {
                //clean up
                SafeRelease(pTopology);
            }
        }
Example #4
0
        /// <summary>
        /// Open from a Url address
        /// </summary>
        /// <param name="sURL"></param>
        /// <returns></returns>
        public int OpenURL(string sURL)
        {
            TRACE("Media::OpenURL");
            TRACE("URL = " + sURL);

            // 1. Create a new media session
            // 2. Create the media source
            // 3. Create the topology
            // 4. Queue the topology [asynchronous]
            // 5. Start playback [asynchronous - does not happen in this method]

            int hr = S_Ok;

            try
            {
                IMFTopology pTopology = null;

                // Create the media session.
                CreateSession();
                // Create the media source.
                CreateMediaSource(sURL);
                // Create a partial topology.
                CreateTopologyFromSource(out pTopology);
                // Set the topology on the media session.
                m_pSession.SetTopology(0, pTopology);
                // Set our state to "open pending"
                m_state = MediaState.OpenPending;
                NotifyState();

                SafeRelease(pTopology);

                // If SetTopology succeeded, the media session will queue an
                // MESessionTopologySet event.
            }
            catch (Exception e)
            {
                hr = Marshal.GetHRForException(e);
                NotifyError(hr);
                m_state = MediaState.Ready;
            }

            return(hr);
        }
        private void SetFirstTopology(IMFSequencerSource pSequencerSource, IMFMediaSession pMediaSession)
        {
            IMFMediaSource pMediaSource;
            IMFPresentationDescriptor pPresentationDescriptor;
            IMFMediaSourceTopologyProvider pMediaSourceTopologyProvider;
            IMFTopology pTopology;

            pMediaSource = pSequencerSource as IMFMediaSource;

            // Create the presentation descriptor for the media source.
            int hr = pMediaSource.CreatePresentationDescriptor(out pPresentationDescriptor);
            MFError.ThrowExceptionForHR(hr);

            // Get the topology provider from the sequencer source.
            pMediaSourceTopologyProvider = pSequencerSource as IMFMediaSourceTopologyProvider;
            // Get the first topology from the topology provider.
            hr = pMediaSourceTopologyProvider.GetMediaSourceTopology(pPresentationDescriptor, out pTopology);
            MFError.ThrowExceptionForHR(hr);

            // Set the topology on the media session.
            hr = pMediaSession.SetTopology(0, pTopology);
            MFError.ThrowExceptionForHR(hr);
        }
Example #6
0
        /// <summary>
        /// Loads IWaveProvider.
        /// </summary>
        /// <param name="waveProvider">The waveProvider to be loaded.</param>
        public void Init(IWaveProvider waveProvider)
        {
            MediaFoundationApi.Startup();
            m_sourcewave = waveProvider;
            int          readcount;
            MemoryStream msByteStrem = new MemoryStream();

            byte[] _data;
            do
            {
                readcount = 0;
                _data     = new byte[32767];
                readcount = waveProvider.Read(_data, 0, _data.Length);
                if (readcount < 0)
                {
                    continue;
                }
                msByteStrem.Write(_data, 0, readcount);
            } while (readcount >= _data.Length | readcount < 0);//Creates a IMFByteStream and fills it with the data in waveProvider.
            ComStream     csByteStream = new ComStream(msByteStrem);
            IMFByteStream mfByteStream = MediaFoundationApi.CreateByteStream(csByteStream);

            MediaFoundationInterop.MFCreateSourceResolver(out IMFSourceResolver resolver);
            IMFAttributes streamattributes = mfByteStream as IMFAttributes;

            mfByteStream.GetLength(out long _length);
            resolver.CreateObjectFromByteStream(mfByteStream, null, SourceResolverFlags.MF_RESOLUTION_MEDIASOURCE
                                                | SourceResolverFlags.MF_RESOLUTION_CONTENT_DOES_NOT_HAVE_TO_MATCH_EXTENSION_OR_MIME_TYPE, null, out _, out object _source);//Turns the stream to IMFMediaSource
            IMFMediaSource source = _source as IMFMediaSource;

            source.CreatePresentationDescriptor(out IMFPresentationDescriptor descriptor);
            MediaFoundationInterop.MFCreateTopology(out IMFTopology topo);
            descriptor.GetStreamDescriptorCount(out uint sdcount);
            for (uint i = 0; i < sdcount; i++)//For each stream in the source,creates renderer and adds to the topology.
            {
                descriptor.GetStreamDescriptorByIndex(i, out bool IsSelected, out IMFStreamDescriptor sd);
                if (!IsSelected)
                {
                    if (SelectAllStream)
                    {
                        descriptor.SelectStream(i);
                    }
                    else
                    {
                        continue;
                    }
                }
                sd.GetMediaTypeHandler(out IMFMediaTypeHandler typeHandler);
                typeHandler.GetMajorType(out Guid streamtype);
                IMFActivate renderer;
                if (streamtype == MediaTypes.MFMediaType_Audio)
                {
                    MediaFoundationInterop.MFCreateAudioRendererActivate(out renderer);//Creates renderer for audio streams
                }
                else
                {
                    continue;
                }
                //Creats and equips the topology nodes of the certain stream
                MediaFoundationInterop.MFCreateTopologyNode(MF_TOPOLOGY_TYPE.MF_TOPOLOGY_SOURCESTREAM_NODE, out IMFTopologyNode sourcenode);
                sourcenode.SetUnknown(MediaFoundationAttributes.MF_TOPONODE_SOURCE, source);
                sourcenode.SetUnknown(MediaFoundationAttributes.MF_TOPONODE_PRESENTATION_DESCRIPTOR, descriptor);
                sourcenode.SetUnknown(MediaFoundationAttributes.MF_TOPONODE_STREAM_DESCRIPTOR, sd);
                topo.AddNode(sourcenode);
                MediaFoundationInterop.MFCreateTopologyNode(MF_TOPOLOGY_TYPE.MF_TOPOLOGY_OUTPUT_NODE, out IMFTopologyNode outputnode);
                outputnode.SetObject(renderer);
                topo.AddNode(outputnode);
                sourcenode.ConnectOutput(0, outputnode, 0);
            }
            MediaFoundationInterop.MFCreateMediaSession(IntPtr.Zero, out m_Session);
            m_Session.SetTopology(0, topo);
            m_eventthread = new Thread(ProcessEvent);
            m_eventthread.Start();
        }
Example #7
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);
                }
            }
        }
        private void Load()
        {
            MediaFoundationInterop.MFCreateSourceResolver(out IMFSourceResolver resolver);
            object unknown;

            try
            {
                resolver.CreateObjectFromURL(URL, SourceResolverFlags.MF_RESOLUTION_MEDIASOURCE | SourceResolverFlags.MF_RESOLUTION_CONTENT_DOES_NOT_HAVE_TO_MATCH_EXTENSION_OR_MIME_TYPE,
                                             null, out _, out unknown);
            }
            catch
            {
                throw new ArgumentException("Unsupported type.");
            }
            MediaFoundationInterop.MFCreateMediaSession(IntPtr.Zero, out m_Session);
            MediaFoundationInterop.MFCreateTopology(out IMFTopology topo);
            IMFMediaSource source = unknown as IMFMediaSource;

            source.CreatePresentationDescriptor(out m_pDescriptor);
            m_pDescriptor.GetUINT64(MediaFoundationAttributes.MF_PD_DURATION, out long dur);
            m_Duration = dur / 10000000;
            m_pDescriptor.GetStreamDescriptorCount(out uint sdcount);
            m_streamcount = (int)sdcount;
            for (uint i = 0; i < m_streamcount; i++)
            {
                m_pDescriptor.GetStreamDescriptorByIndex(i, out bool IsSelected, out IMFStreamDescriptor sd);
                m_DefaultStreamSelect.Add(IsSelected);
                switch (StreamSelectFlag)
                {
                case StreamSelectFlags.SelectAllStream:
                    if (!IsSelected)
                    {
                        m_pDescriptor.SelectStream(i);
                    }
                    break;

                case StreamSelectFlags.SelectNone:
                    if (IsSelected)
                    {
                        m_pDescriptor.DeselectStream(i);
                    }
                    break;
                }
                sd.GetMediaTypeHandler(out IMFMediaTypeHandler typeHandler);
                typeHandler.GetMediaTypeByIndex(0, out IMFMediaType mediaType);
                mediaType.GetMajorType(out Guid streamtype);
                IMFActivate renderer;
                if (streamtype == MediaTypes.MFMediaType_Audio)
                {
                    MediaFoundationInterop.MFCreateAudioRendererActivate(out renderer);
                    mediaType.GetUINT32(MediaFoundationAttributes.MF_MT_AUDIO_SAMPLES_PER_SECOND, out int rate);//SampleRate
                    mediaType.GetUINT32(MediaFoundationAttributes.MF_MT_AUDIO_NUM_CHANNELS, out int channelcount);
                    int samplesize;
                    try
                    {
                        mediaType.GetUINT32(MediaFoundationAttributes.MF_MT_AUDIO_BITS_PER_SAMPLE, out samplesize);
                    }
                    catch (COMException e)
                    {
                        if ((uint)e.HResult != 0xC00D36E6)
                        {
                            throw e;
                        }
                        else
                        {
                            samplesize = 8;
                        }
                    }
                    m_format.Add(new WaveFormat(rate, samplesize, channelcount));
                }
                else
                {
                    continue;
                }
                MediaFoundationInterop.MFCreateTopologyNode(MF_TOPOLOGY_TYPE.MF_TOPOLOGY_SOURCESTREAM_NODE, out IMFTopologyNode sourcenode);
                sourcenode.SetUnknown(MediaFoundationAttributes.MF_TOPONODE_SOURCE, source);
                sourcenode.SetUnknown(MediaFoundationAttributes.MF_TOPONODE_PRESENTATION_DESCRIPTOR, m_pDescriptor);
                sourcenode.SetUnknown(MediaFoundationAttributes.MF_TOPONODE_STREAM_DESCRIPTOR, sd);
                topo.AddNode(sourcenode);
                MediaFoundationInterop.MFCreateTopologyNode(MF_TOPOLOGY_TYPE.MF_TOPOLOGY_OUTPUT_NODE, out IMFTopologyNode outputnode);
                outputnode.SetObject(renderer);
                topo.AddNode(outputnode);
                sourcenode.ConnectOutput(0, outputnode, 0);
            }
            m_Session.SetTopology(0, topo);
            m_Eventthread = new Thread(ProcessEvent);
            m_Eventthread.Start();
        }