public HResult OpenURL(string sURL) { TRACE("CPlayer::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.] HResult hr = HResult.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. hr = m_pSession.SetTopology(0, pTopology); MFError.ThrowExceptionForHR(hr); // Set our state to "open pending" m_state = PlayerState.OpenPending; NotifyState(); SafeRelease(pTopology); // If SetTopology succeeded, the media session will queue an // MESessionTopologySet event. } catch (Exception ce) { hr = (HResult)Marshal.GetHRForException(ce); NotifyError(hr); m_state = PlayerState.Ready; } return(hr); }
protected void CreateTopologyFromSource(out IMFTopology ppTopology) { TRACE("CPlayer::CreateTopologyFromSource"); Debug.Assert(m_pSession != null); Debug.Assert(m_pSource != null); HResult hr; IMFTopology pTopology = null; IMFPresentationDescriptor pSourcePD = null; int cSourceStreams = 0; try { // Create a new topology. hr = MFExtern.MFCreateTopology(out pTopology); MFError.ThrowExceptionForHR(hr); // Create the presentation descriptor for the media source. hr = m_pSource.CreatePresentationDescriptor(out pSourcePD); MFError.ThrowExceptionForHR(hr); // Get the number of streams in the media source. hr = pSourcePD.GetStreamDescriptorCount(out cSourceStreams); MFError.ThrowExceptionForHR(hr); TRACE(string.Format("Stream count: {0}", cSourceStreams)); // For each stream, create the topology nodes and add them to the topology. for (int i = 0; i < cSourceStreams; i++) { AddBranchToPartialTopology(pTopology, pSourcePD, i); } // Return the IMFTopology pointer to the caller. ppTopology = pTopology; } catch { // If we failed, release the topology SafeRelease(pTopology); throw; } finally { SafeRelease(pSourcePD); } }
protected void AddBranchToPartialTopology( IMFTopology pTopology, IMFPresentationDescriptor pSourcePD, int iStream ) { MFError throwonhr; TRACE("CPlayer::AddBranchToPartialTopology"); Debug.Assert(pTopology != null); IMFStreamDescriptor pSourceSD = null; IMFTopologyNode pSourceNode = null; IMFTopologyNode pOutputNode = null; bool fSelected = false; try { // Get the stream descriptor for this stream. throwonhr = pSourcePD.GetStreamDescriptorByIndex(iStream, out fSelected, out pSourceSD); // Create the topology branch only if the stream is selected. // Otherwise, do nothing. if (fSelected) { // Create a source node for this stream. CreateSourceStreamNode(pSourcePD, pSourceSD, out pSourceNode); // Create the output node for the renderer. CreateOutputNode(pSourceSD, out pOutputNode); // Add both nodes to the topology. throwonhr = pTopology.AddNode(pSourceNode); throwonhr = pTopology.AddNode(pOutputNode); // Connect the source node to the output node. throwonhr = pSourceNode.ConnectOutput(0, pOutputNode, 0); } } finally { // Clean up. SafeRelease(pSourceSD); SafeRelease(pSourceNode); SafeRelease(pOutputNode); } }
/////////////////////////////////////////////////////////////////////// // Name: CreateWavFile // Description: Creates a .wav file from an input file. /////////////////////////////////////////////////////////////////////// static void CreateWavFile(string sURL, string sOutputFile) { IMFByteStream pStream = null; IMFMediaSinkAlt pSink = null; IMFMediaSource pSource = null; IMFTopology pTopology = null; WavSinkNS.CWavSink pObj = null; HResult hr = MFExtern.MFCreateFile(MFFileAccessMode.Write, MFFileOpenMode.DeleteIfExist, MFFileFlags.None, sOutputFile, out pStream); MFError.ThrowExceptionForHR(hr); try { pObj = new WavSinkNS.CWavSink(pStream); pSink = pObj as IMFMediaSinkAlt; // Create the media source from the URL. CreateMediaSource(sURL, out pSource); // Create the topology. CreateTopology(pSource, pSink, out pTopology); // Run the media session. RunMediaSession(pTopology); hr = pSource.Shutdown(); MFError.ThrowExceptionForHR(hr); } finally { if (pStream != null) { Marshal.ReleaseComObject(pStream); } if (pSource != null) { Marshal.ReleaseComObject(pSource); } if (pTopology != null) { Marshal.ReleaseComObject(pTopology); } //pObj.Dispose(); } }
protected void CreateTopologyFromSource(out IMFTopology ppTopology) { TRACE("CPlayer::CreateTopologyFromSource"); Debug.Assert(m_pSession != null); Debug.Assert(m_pSource != null); IMFTopology pTopology = null; IMFPresentationDescriptor pSourcePD = null; int cSourceStreams = 0; MFError throwonhr; try { // Create a new topology. throwonhr = MFExtern.MFCreateTopology(out pTopology); throwonhr = pTopology.SetUINT32(MFAttributesClsid.MF_TOPOLOGY_DXVA_MODE, (int)MFTOPOLOGY_DXVA_MODE.Full); // Create the presentation descriptor for the media source. throwonhr = m_pSource.CreatePresentationDescriptor(out pSourcePD); // Get the number of streams in the media source. throwonhr = pSourcePD.GetStreamDescriptorCount(out cSourceStreams); TRACE(string.Format("Stream count: {0}", cSourceStreams)); // For each stream, create the topology nodes and add them to the topology. for (int i = 0; i < cSourceStreams; i++) { AddBranchToPartialTopology(pTopology, m_hwndVideo, m_pSource, pSourcePD, i); } // Return the IMFTopology pointer to the caller. ppTopology = pTopology; } catch { // If we failed, release the topology SafeRelease(pTopology); throw; } finally { SafeRelease(pSourcePD); } }
/////////////////////////////////////////////////////////////////////// // Name: CreateTopologyBranch // Description: Adds a source and sink to the topology and // connects them. // // pTopology: The topology. // pSource: The media source. // pPD: The source's presentation descriptor. // pSD: The stream descriptor for the stream. // pSink: The media sink. // /////////////////////////////////////////////////////////////////////// static void CreateTopologyBranch( IMFTopology pTopology, IMFMediaSource pSource, // Media source. IMFPresentationDescriptor pPD, // Presentation descriptor. IMFStreamDescriptor pSD, // Stream descriptor. IMFMediaSinkAlt pSink ) { HResult hr; IMFTopologyNode pSourceNode = null; IMFTopologyNode pOutputNode = null; CreateSourceNode(pSource, pPD, pSD, out pSourceNode); try { CreateOutputNode(pSink, 0, out pOutputNode); try { hr = pTopology.AddNode(pSourceNode); MFError.ThrowExceptionForHR(hr); hr = pTopology.AddNode(pOutputNode); MFError.ThrowExceptionForHR(hr); hr = pSourceNode.ConnectOutput(0, pOutputNode, 0); MFError.ThrowExceptionForHR(hr); } finally { if (pOutputNode != null) { Marshal.ReleaseComObject(pOutputNode); } } } finally { if (pSourceNode != null) { Marshal.ReleaseComObject(pSourceNode); } } }
/// <summary> /// Configures the DirectShow graph to play the selected video capture /// device with the selected parameters /// </summary> private void SetupGraph() { /* Clean up any messes left behind */ FreeResources(); Trace.WriteLine("setting up graph 1"); try { Trace.WriteLine("setting up graph 2"); // Create the media session. CreateSession(); Trace.WriteLine("setting up graph 3"); CreateVideoCaptureSource(); // Create a partial topology. IMFTopology pTopology = CreateTopologyFromSource(); Trace.WriteLine("setting up graph 4"); // Set the topology on the media session. int hr = m_pSession.SetTopology(0, pTopology); MFError.ThrowExceptionForHR(hr); //m_pSession.GetClock(out pClock); Trace.WriteLine("setting up graph 5"); COMBase.SafeRelease(pTopology); //Marshal.ReleaseComObject(); } catch (Exception ex) { Marshal.GetHRForException(ex); Trace.WriteLine("SetupGraph Exception " + ex.ToString()); FreeResources(); InvokeMediaFailed(new MediaFailedEventArgs(ex.Message, ex)); } /* Success */ InvokeMediaOpened(); }
private void createSession(string sFilePath) { try { MFError throwonhr = MFExtern.MFCreateMediaSession(null, out m_pSession); // 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(0, pTopology); StartPlayback(); } catch (Exception) { } }
/////////////////////////////////////////////////////////////////////// // Name: BeginEnableContent // Description: Called by the PMP session to start the enable action. ///////////////////////////////////////////////////////////////////////// public HResult BeginEnableContent( IMFActivate pEnablerActivate, IMFTopology pTopo, IMFAsyncCallback pCallback, object punkState ) { // Make sure we *never* leave this entry point with an exception try { Debug.WriteLine("ContentProtectionManager::BeginEnableContent"); if (m_pEnabler != null) { throw new COMException("A previous call is still pending", (int)HResult.E_FAIL); } HResult hr; // Save so we can create an async result later m_pCallback = pCallback; m_punkState = punkState; // Create the enabler from the IMFActivate pointer. object o; hr = pEnablerActivate.ActivateObject(typeof(IMFContentEnabler).GUID, out o); MFError.ThrowExceptionForHR(hr); m_pEnabler = o as IMFContentEnabler; // Notify the application. The application will call DoEnable from the app thread. m_state = Enabler.Ready; // Reset the state. PostMessage(m_hwnd, WM_APP_CONTENT_ENABLER, IntPtr.Zero, IntPtr.Zero); return(HResult.S_OK); } catch (Exception e) { return((HResult)Marshal.GetHRForException(e)); } }
/////////////////////////////////////////////////////////////////////// // Name: CreateVideoBranch // Description: // Adds and connects the nodes downstream from a video source node. // // pTopology: Pointer to the topology. // pSourceNode: Pointer to the source node. // hVideoWindow: Handle to the video window. // clsidTransform: CLSID of an effect transform. ///////////////////////////////////////////////////////////////////////// void CreateVideoBranch( IMFTopology pTopology, IMFTopologyNode pSourceNode, IntPtr hVideoWindow, Guid clsidTransform // GUID_NULL = No effect transform. ) { TRACE("CreateVideoBranch"); IMFTopologyNode pOutputNode = null; IMFActivate pRendererActivate = null; // Create a downstream node. HResult hr = MFExtern.MFCreateTopologyNode(MFTopologyType.OutputNode, out pOutputNode); MFError.ThrowExceptionForHR(hr); try { // Create an IMFActivate object for the video renderer. hr = MFExtern.MFCreateVideoRendererActivate(hVideoWindow, out pRendererActivate); MFError.ThrowExceptionForHR(hr); // Set the IActivate object on the output node. hr = pOutputNode.SetObject(pRendererActivate); MFError.ThrowExceptionForHR(hr); // Add the output node to the topology. hr = pTopology.AddNode(pOutputNode); MFError.ThrowExceptionForHR(hr); // Connect the source to the output. ConnectSourceToOutput(pTopology, pSourceNode, pOutputNode, clsidTransform); } finally { SafeRelease(pOutputNode); SafeRelease(pRendererActivate); } }
/////////////////////////////////////////////////////////////////////// // Name: BeginEnableContent // Description: Called by the PMP session to start the enable action. ///////////////////////////////////////////////////////////////////////// public int BeginEnableContent( IMFActivate pEnablerActivate, IMFTopology pTopo, IMFAsyncCallback pCallback, object punkState ) { // Make sure we *never* leave this entry point with an exception try { Debug.WriteLine("ContentProtectionManager::BeginEnableContent"); if (m_pEnabler != null) { throw new COMException("A previous call is still pending", E_Fail); } int hr; // Save so we can create an async result later m_pCallback = pCallback; m_punkState = punkState; // Create the enabler from the IMFActivate pointer. object o; hr = pEnablerActivate.ActivateObject(typeof(IMFContentEnabler).GUID, out o); MFError.ThrowExceptionForHR(hr); m_pEnabler = o as IMFContentEnabler; // Notify the application. The application will call DoEnable from the app thread. m_state = Enabler.Ready; // Reset the state. PostMessage(m_hwnd, WM_APP_CONTENT_ENABLER, IntPtr.Zero, IntPtr.Zero); return S_Ok; } catch (Exception e) { return Marshal.GetHRForException(e); } }
//////////////////////////////////////////////////////////////////////////////////////// // Name: CPlayer::AddTopologyToSequencer (Private) // Description: // Adds the topology to the sequencer // Parameter: // sURL: [in] File URL // pMediaSource: [in] Pointer to the media source // pTopology: [in] Pointer to the topology // pSegmentId: [out] Receives the segment id returned by the sequencer source ///////////////////////////////////////////////////////////////////////////////////////// private void AddTopologyToSequencer( string sURL, IMFMediaSource pMediaSource, IMFTopology pTopology, out int pSegmentId) { Debug.WriteLine("CPlayer::AddTopologyToSequencer"); if (sURL == null || pMediaSource == null || pTopology == null) { throw new COMException("null pointer", (int)HResult.E_POINTER); } long hnsSegmentDuration = 0; long TopologyID = 0; HResult hr; IMFPresentationDescriptor pPresentationDescriptor; hr = m_pSequencerSource.AppendTopology(pTopology, 0, out pSegmentId); MFError.ThrowExceptionForHR(hr); hr = pTopology.GetTopologyID(out TopologyID); MFError.ThrowExceptionForHR(hr); //create a presentation descriptor hr = pMediaSource.CreatePresentationDescriptor(out pPresentationDescriptor); MFError.ThrowExceptionForHR(hr); //get the segment duration hr = pPresentationDescriptor.GetUINT64(MFAttributesClsid.MF_PD_DURATION, out hnsSegmentDuration); MFError.ThrowExceptionForHR(hr); Debug.Assert(hnsSegmentDuration > 0); //store the segment info: SegmentId, SegmentDuration, TopoID in the linked list. m_Segments.AddNewSegmentEntry(pSegmentId, hnsSegmentDuration, TopologyID, sURL); }
//////////////////////////////////////////////////////////////////////////////////////// // Name: CPlayer::CreateTopology (Private) // Description: // Creates a topology for the media source // Parameter: // pMediaSource: [in] Pointer to the media source // pTopology: [in] Receives the partial topology ///////////////////////////////////////////////////////////////////////////////////////// private void CreateTopology( IMFMediaSource pMediaSource, IMFTopology pTopology) { Debug.WriteLine("CPlayer::CreateTopology"); //The caller needs to pass a valid media source //We need the media source because to set the source node attribute, media source is needed if (pMediaSource == null || pTopology == null) { throw new COMException("null pointer", E_Pointer); } IMFPresentationDescriptor pPresentationDescriptor; //Create Presentation Descriptor for the media source int hr = pMediaSource.CreatePresentationDescriptor(out pPresentationDescriptor); MFError.ThrowExceptionForHR(hr); try { CreateNodesForStream(pPresentationDescriptor, pMediaSource, pTopology); } finally { SafeRelease(pPresentationDescriptor); } }
/////////////////////////////////////////////////////////////////////// // Name: CreateTopologyBranch // Description: Adds a source and sink to the topology and // connects them. // // pTopology: The topology. // pSource: The media source. // pPD: The source's presentation descriptor. // pSD: The stream descriptor for the stream. // pSink: The media sink. // /////////////////////////////////////////////////////////////////////// static void CreateTopologyBranch( IMFTopology pTopology, IMFMediaSource pSource, // Media source. IMFPresentationDescriptor pPD, // Presentation descriptor. IMFStreamDescriptor pSD, // Stream descriptor. IMFMediaSinkAlt pSink ) { int hr; IMFTopologyNode pSourceNode = null; IMFTopologyNode pOutputNode = null; CreateSourceNode(pSource, pPD, pSD, out pSourceNode); try { CreateOutputNode(pSink, 0, out pOutputNode); try { hr = pTopology.AddNode(pSourceNode); MFError.ThrowExceptionForHR(hr); hr = pTopology.AddNode(pOutputNode); MFError.ThrowExceptionForHR(hr); hr = pSourceNode.ConnectOutput(0, pOutputNode, 0); MFError.ThrowExceptionForHR(hr); } finally { if (pOutputNode != null) { Marshal.ReleaseComObject(pOutputNode); } } } finally { if (pSourceNode != null) { Marshal.ReleaseComObject(pSourceNode); } } }
/////////////////////////////////////////////////////////////////////// // Name: CreateTopology // Description: Creates the topology. // // Note: The first audio stream is conntected to the media sink. // Other streams are deselected. /////////////////////////////////////////////////////////////////////// static void CreateTopology(IMFMediaSource pSource, IMFMediaSinkAlt pSink, out IMFTopology ppTopology) { int hr; IMFPresentationDescriptor pPD = null; IMFStreamDescriptor pSD = null; int cStreams = 0; bool fConnected = false; hr = MFExtern.MFCreateTopology(out ppTopology); MFError.ThrowExceptionForHR(hr); hr = pSource.CreatePresentationDescriptor(out pPD); MFError.ThrowExceptionForHR(hr); try { hr = pPD.GetStreamDescriptorCount(out cStreams); MFError.ThrowExceptionForHR(hr); Guid majorType; bool fSelected = false; for (int iStream = 0; iStream < cStreams; iStream++) { hr = pPD.GetStreamDescriptorByIndex(iStream, out fSelected, out pSD); MFError.ThrowExceptionForHR(hr); try { // If the stream is not selected by default, ignore it. if (!fSelected) { continue; } // Get the major media type. GetStreamMajorType(pSD, out majorType); // If it's not audio, deselect it and continue. if (majorType != MFMediaType.Audio) { // Deselect this stream hr = pPD.DeselectStream(iStream); MFError.ThrowExceptionForHR(hr); continue; } // It's an audio stream, so try to create the topology branch. CreateTopologyBranch(ppTopology, pSource, pPD, pSD, pSink); } finally { if (pSD != null) { Marshal.ReleaseComObject(pSD); } } // Set our status flag. fConnected = true; // At this point we have reached the first audio stream in the // source, so we can stop looking (whether we succeeded or failed). break; } } finally { if (pPD != null) { Marshal.ReleaseComObject(pPD); } } // Even if we succeeded, if we didn't connect any streams, it's a failure. // (For example, it might be a video-only source. if (!fConnected) { throw new Exception("No audio streams"); } }
/////////////////////////////////////////////////////////////////////// // Name: CreateTopology // Description: Creates the topology. // // Note: The first audio stream is conntected to the media sink. // Other streams are deselected. /////////////////////////////////////////////////////////////////////// static void CreateTopology(IMFMediaSource pSource, IMFMediaSinkAlt pSink, out IMFTopology ppTopology) { HResult hr; IMFPresentationDescriptor pPD = null; IMFStreamDescriptor pSD = null; int cStreams = 0; bool fConnected = false; hr = MFExtern.MFCreateTopology(out ppTopology); MFError.ThrowExceptionForHR(hr); hr = pSource.CreatePresentationDescriptor(out pPD); MFError.ThrowExceptionForHR(hr); try { hr = pPD.GetStreamDescriptorCount(out cStreams); MFError.ThrowExceptionForHR(hr); Guid majorType; bool fSelected = false; for (int iStream = 0; iStream < cStreams; iStream++) { hr = pPD.GetStreamDescriptorByIndex(iStream, out fSelected, out pSD); MFError.ThrowExceptionForHR(hr); try { // If the stream is not selected by default, ignore it. if (!fSelected) { continue; } // Get the major media type. GetStreamMajorType(pSD, out majorType); // If it's not audio, deselect it and continue. if (majorType != MFMediaType.Audio) { // Deselect this stream hr = pPD.DeselectStream(iStream); MFError.ThrowExceptionForHR(hr); continue; } // It's an audio stream, so try to create the topology branch. CreateTopologyBranch(ppTopology, pSource, pPD, pSD, pSink); } finally { if (pSD != null) { Marshal.ReleaseComObject(pSD); } } // Set our status flag. fConnected = true; // At this point we have reached the first audio stream in the // source, so we can stop looking (whether we succeeded or failed). break; } } finally { if (pPD != null) { Marshal.ReleaseComObject(pPD); } } // Even if we succeeded, if we didn't connect any streams, it's a failure. // (For example, it might be a video-only source. if (!fConnected) { throw new Exception("No audio streams"); } }
/////////////////////////////////////////////////////////////////////// // Name: RunMediaSession // Description: // Queues the specified topology on the media session and runs the // media session until the MESessionEnded event is received. /////////////////////////////////////////////////////////////////////// static void RunMediaSession(IMFTopology pTopology) { int hr; IMFMediaSession pSession; bool bGetAnotherEvent = true; PropVariant varStartPosition = new PropVariant(); hr = MFExtern.MFCreateMediaSession(null, out pSession); MFError.ThrowExceptionForHR(hr); try { hr = pSession.SetTopology(0, pTopology); MFError.ThrowExceptionForHR(hr); while (bGetAnotherEvent) { int hrStatus = 0; IMFMediaEvent pEvent; MediaEventType meType = MediaEventType.MEUnknown; int TopoStatus = (int)MFTopoStatus.Invalid; // Used with MESessionTopologyStatus event. hr = pSession.GetEvent(MFEventFlag.None, out pEvent); MFError.ThrowExceptionForHR(hr); try { hr = pEvent.GetStatus(out hrStatus); MFError.ThrowExceptionForHR(hr); hr = pEvent.GetType(out meType); MFError.ThrowExceptionForHR(hr); if (hrStatus >= 0) { switch (meType) { case MediaEventType.MESessionTopologySet: Debug.WriteLine("MESessionTopologySet"); break; case MediaEventType.MESessionTopologyStatus: // Get the status code. hr = pEvent.GetUINT32(MFAttributesClsid.MF_EVENT_TOPOLOGY_STATUS, out TopoStatus); MFError.ThrowExceptionForHR(hr); switch ((MFTopoStatus)TopoStatus) { case MFTopoStatus.Ready: Debug.WriteLine("MESessionTopologyStatus: MF_TOPOSTATUS_READY"); pSession.Start(Guid.Empty, varStartPosition); break; case MFTopoStatus.Ended: Debug.WriteLine("MESessionTopologyStatus: MF_TOPOSTATUS_ENDED"); break; } break; case MediaEventType.MESessionStarted: Debug.WriteLine("MESessionStarted"); break; case MediaEventType.MESessionEnded: Debug.WriteLine("MESessionEnded"); hr = pSession.Stop(); break; case MediaEventType.MESessionStopped: Debug.WriteLine("MESessionStopped"); Console.WriteLine("Attempting to close the media session."); hr = pSession.Close(); MFError.ThrowExceptionForHR(hr); break; case MediaEventType.MESessionClosed: Debug.WriteLine("MESessionClosed"); bGetAnotherEvent = false; break; default: Debug.WriteLine(string.Format("Media session event: {0}", meType)); break; } } else { Debug.WriteLine(string.Format("HRStatus: {0}", hrStatus)); bGetAnotherEvent = false; } } finally { if (pEvent != null) { Marshal.ReleaseComObject(pEvent); } } } Debug.WriteLine("Shutting down the media session."); hr = pSession.Shutdown(); MFError.ThrowExceptionForHR(hr); } finally { if (pSession != null) { Marshal.ReleaseComObject(pSession); } } }
private static extern int ExternMFCreateTranscodeTopology( [In, MarshalAs(UnmanagedType.Interface)] IMFMediaSource pSrc, [In, MarshalAs(UnmanagedType.LPWStr)] string pwszOutputFilePath, [In, MarshalAs(UnmanagedType.Interface)] IMFTranscodeProfile pProfile, [Out, MarshalAs(UnmanagedType.Interface)] out IMFTopology ppTranscodeTopo);
/////////////////////////////////////////////////////////////////////// // Name: RunMediaSession // Description: // Queues the specified topology on the media session and runs the // media session until the MESessionEnded event is received. /////////////////////////////////////////////////////////////////////// static void RunMediaSession(IMFTopology pTopology) { HResult hr; IMFMediaSession pSession; bool bGetAnotherEvent = true; PropVariant varStartPosition = new PropVariant(); hr = MFExtern.MFCreateMediaSession(null, out pSession); MFError.ThrowExceptionForHR(hr); try { hr = pSession.SetTopology(0, pTopology); MFError.ThrowExceptionForHR(hr); while (bGetAnotherEvent) { HResult hrStatus = 0; IMFMediaEvent pEvent; MediaEventType meType = MediaEventType.MEUnknown; int TopoStatus = (int)MFTopoStatus.Invalid; // Used with MESessionTopologyStatus event. hr = pSession.GetEvent(MFEventFlag.None, out pEvent); MFError.ThrowExceptionForHR(hr); try { hr = pEvent.GetStatus(out hrStatus); MFError.ThrowExceptionForHR(hr); hr = pEvent.GetType(out meType); MFError.ThrowExceptionForHR(hr); if (hrStatus >= 0) { switch (meType) { case MediaEventType.MESessionTopologySet: Debug.WriteLine("MESessionTopologySet"); break; case MediaEventType.MESessionTopologyStatus: // Get the status code. hr = pEvent.GetUINT32(MFAttributesClsid.MF_EVENT_TOPOLOGY_STATUS, out TopoStatus); MFError.ThrowExceptionForHR(hr); switch ((MFTopoStatus)TopoStatus) { case MFTopoStatus.Ready: Debug.WriteLine("MESessionTopologyStatus: MF_TOPOSTATUS_READY"); pSession.Start(Guid.Empty, varStartPosition); break; case MFTopoStatus.Ended: Debug.WriteLine("MESessionTopologyStatus: MF_TOPOSTATUS_ENDED"); break; } break; case MediaEventType.MESessionStarted: Debug.WriteLine("MESessionStarted"); break; case MediaEventType.MESessionEnded: Debug.WriteLine("MESessionEnded"); hr = pSession.Stop(); break; case MediaEventType.MESessionStopped: Debug.WriteLine("MESessionStopped"); Console.WriteLine("Attempting to close the media session."); hr = pSession.Close(); MFError.ThrowExceptionForHR(hr); break; case MediaEventType.MESessionClosed: Debug.WriteLine("MESessionClosed"); bGetAnotherEvent = false; break; default: Debug.WriteLine(string.Format("Media session event: {0}", meType)); break; } } else { Debug.WriteLine(string.Format("HRStatus: {0}", hrStatus)); bGetAnotherEvent = false; } } finally { if (pEvent != null) { Marshal.ReleaseComObject(pEvent); } } } Debug.WriteLine("Shutting down the media session."); hr = pSession.Shutdown(); MFError.ThrowExceptionForHR(hr); } finally { if (pSession != null) { Marshal.ReleaseComObject(pSession); } } }
/////////////////////////////////////////////////////////////////////// // Name: AddBranchToPartialTopology // Description: Adds a topology branch for one stream. // // pTopology: Pointer to the topology object. // hVideoWindow: Handle to the video window (for video streams). // pSource: Media source. // pSourcePD: The source's presentation descriptor. // iStream: Index of the stream to render. // // Pre-conditions: The topology must be created already. // // Notes: For each stream, we must do the following: // 1. Create a source node associated with the stream. // 2. Create an output node for the renderer. // 3. Connect the two nodes. // // Optionally we can also add an effect transform between the source // and output nodes. // // The media session will resolve the topology, so we do not have // to worry about decoders or color converters. ///////////////////////////////////////////////////////////////////////// void AddBranchToPartialTopology( IMFTopology pTopology, IntPtr hVideoWindow, IMFMediaSource pSource, IMFPresentationDescriptor pSourcePD, int iStream) { TRACE("Player::RenderStream"); IMFStreamDescriptor pSourceSD = null; IMFTopologyNode pSourceNode = null; int hr; Guid majorType; bool fSelected = false; // Get the stream descriptor for this stream. hr = pSourcePD.GetStreamDescriptorByIndex(iStream, out fSelected, out pSourceSD); MFError.ThrowExceptionForHR(hr); // First check if the stream is selected by default. If not, ignore it. // More sophisticated applications can change the default selections. if (fSelected) { try { // Create a source node for this stream. CreateSourceStreamNode(pSource, pSourcePD, pSourceSD, out pSourceNode); // Add the source node to the topology. hr = pTopology.AddNode(pSourceNode); MFError.ThrowExceptionForHR(hr); // Get the major media type for the stream. GetStreamType(pSourceSD, out majorType); if (majorType == MFMediaType.Video) { // For video, use the grayscale transform. CreateVideoBranch(pTopology, pSourceNode, hVideoWindow, m_VideoEffect); } else if (majorType == MFMediaType.Audio) { CreateAudioBranch(pTopology, pSourceNode, Guid.Empty); } } finally { // Clean up. SafeRelease(pSourceSD); SafeRelease(pSourceNode); } } }
protected void CreateTopologyFromSource(out IMFTopology ppTopology) { TRACE("CPlayer::CreateTopologyFromSource"); Debug.Assert(m_pSession != null); Debug.Assert(m_pSource != null); IMFTopology pTopology = null; IMFPresentationDescriptor pSourcePD = null; int cSourceStreams = 0; HResult hr; try { // Create a new topology. hr = MFExtern.MFCreateTopology(out pTopology); MFError.ThrowExceptionForHR(hr); // Create the presentation descriptor for the media source. hr = m_pSource.CreatePresentationDescriptor(out pSourcePD); MFError.ThrowExceptionForHR(hr); { // See if there is metadata. If anything fails, // just leave m_pMetadata as null. object o; hr = MFExtern.MFGetService( m_pSource, MFServices.MF_METADATA_PROVIDER_SERVICE, typeof(IMFMetadataProvider).GUID, out o ); if (Succeeded(hr)) { IMFMetadataProvider pMetaProvider = o as IMFMetadataProvider; hr = pMetaProvider.GetMFMetadata( pSourcePD, 0, // Stream id 0 == presentation-level metadata. 0, // Reserved out m_pMetadata); } } // Get the number of streams in the media source. hr = pSourcePD.GetStreamDescriptorCount(out cSourceStreams); MFError.ThrowExceptionForHR(hr); TRACE(string.Format("Stream count: {0}", cSourceStreams)); // For each stream, create the topology nodes and add them to the topology. for (int i = 0; i < cSourceStreams; i++) { AddBranchToPartialTopology(pTopology, m_hwndVideo, m_pSource, pSourcePD, i); } // Return the IMFTopology pointer to the caller. ppTopology = pTopology; } catch { // If we failed, release the topology SafeRelease(pTopology); throw; } finally { SafeRelease(pSourcePD); } }
public static void MFCreateTranscodeTopology( IMFMediaSource mediaSource, string outputFilePath, IMFTranscodeProfile transcodeProfile, out IMFTopology transcodeTopology) { int result = ExternMFCreateTranscodeTopology(mediaSource, outputFilePath, transcodeProfile, out transcodeTopology); if (result < 0) { throw new COMException("Exception from HRESULT: 0x" + result.ToString("X", System.Globalization.NumberFormatInfo.InvariantInfo) + " (MFCreateTranscodeTopology failed)", result); } }
//////////////////////////////////////////////////////////////////////////////////////// // Name: CPlayer::CreateNodesForStream (Private) // Description: // Creates the source and output nodes for a stream and // Adds them to the topology // Connects the source node to the output node // // Parameter: // pPresentationDescriptor: [in] Pointer to the presentation descriptor for the media source // pMediaSource: [in] Pointer to the media source // pTopology: [in] Pointer to the topology // // Notes: For each stream, the app must: // 1. Create a source node associated with the stream. // 2. Create an output node for the renderer. // 3. Connect the two nodes. // The media session will resolve the topology, transform nodes are not required ///////////////////////////////////////////////////////////////////////////////////////// private void CreateNodesForStream( IMFPresentationDescriptor pPresentationDescriptor, IMFMediaSource pMediaSource, IMFTopology pTopology) { if (pPresentationDescriptor == null || pMediaSource == null || pTopology == null) { throw new COMException("null pointer", (int)HResult.E_POINTER); } HResult hr; IMFStreamDescriptor pStreamDescriptor; IMFTopologyNode pSourceNode; IMFTopologyNode pOutputNode; bool fSelected = false; // Get the stream descriptor for the only stream index =0. hr = pPresentationDescriptor.GetStreamDescriptorByIndex(0, out fSelected, out pStreamDescriptor); MFError.ThrowExceptionForHR(hr); try { if (fSelected) { // Create a source node for this stream and add it to the topology. CreateSourceNode(pPresentationDescriptor, pStreamDescriptor, pMediaSource, out pSourceNode); try { hr = pTopology.AddNode(pSourceNode); MFError.ThrowExceptionForHR(hr); // Create the output node for the renderer and add it to the topology. CreateOutputNode(pStreamDescriptor, out pOutputNode); try { hr = pTopology.AddNode(pOutputNode); MFError.ThrowExceptionForHR(hr); // Connect the source node to the output node. hr = pSourceNode.ConnectOutput(0, pOutputNode, 0); MFError.ThrowExceptionForHR(hr); } finally { SafeRelease(pOutputNode); } } finally { SafeRelease(pSourceNode); } } } finally { //clean up SafeRelease(pStreamDescriptor); } }
/////////////////////////////////////////////////////////////////////// // Name: ConnectSourceToOutput // Description: // Connects the source node to the output node. // // pTopology: Pointer to the topology. // pSourceNode: Pointer to the source node. // pOutputNode: Pointer to the output node. // clsidTransform: CLSID of an effect transform. ///////////////////////////////////////////////////////////////////////// void ConnectSourceToOutput( IMFTopology pTopology, IMFTopologyNode pSourceNode, IMFTopologyNode pOutputNode, Guid clsidTransform ) { int hr; if (clsidTransform == Guid.Empty) { // There is no effect specified, so connect the source node // directly to the output node. hr = pSourceNode.ConnectOutput(0, pOutputNode, 0); MFError.ThrowExceptionForHR(hr); } else { IMFTopologyNode pTransformNode = null; object pTransformUnk = null; // Create a transform node. hr = MFExtern.MFCreateTopologyNode(MFTopologyType.TransformNode, out pTransformNode); MFError.ThrowExceptionForHR(hr); try { Type type = Type.GetTypeFromCLSID(clsidTransform); pTransformUnk = Activator.CreateInstance(type); hr = pTransformNode.SetObject(pTransformUnk); MFError.ThrowExceptionForHR(hr); //// Set the CLSID of the transform. //if (SUCCEEDED(hr)) //{ // hr = pTransformNode->SetGUID(MF_TOPONODE_TRANSFORM_OBJECTID, clsidTransform); //} // Add the transform node to the topology. hr = pTopology.AddNode(pTransformNode); MFError.ThrowExceptionForHR(hr); // Connect the source node to the transform node. hr = pSourceNode.ConnectOutput(0, pTransformNode, 0); MFError.ThrowExceptionForHR(hr); // Connect the transform node to the output node. hr = pTransformNode.ConnectOutput(0, pOutputNode, 0); MFError.ThrowExceptionForHR(hr); } finally { SafeRelease(pTransformNode); //SafeRelease(pTransformUnk); } } }
//////////////////////////////////////////////////////////////////////////////////////// // Name: CPlayer::AddTopologyToSequencer (Private) // Description: // Adds the topology to the sequencer // Parameter: // sURL: [in] File URL // pMediaSource: [in] Pointer to the media source // pTopology: [in] Pointer to the topology // pSegmentId: [out] Receives the segment id returned by the sequencer source ///////////////////////////////////////////////////////////////////////////////////////// private void AddTopologyToSequencer( string sURL, IMFMediaSource pMediaSource, IMFTopology pTopology, out int pSegmentId) { Debug.WriteLine("CPlayer::AddTopologyToSequencer"); if (sURL == null || pMediaSource == null || pTopology == null) { throw new COMException("null pointer", E_Pointer); } long hnsSegmentDuration = 0; long TopologyID = 0; int hr; IMFPresentationDescriptor pPresentationDescriptor; hr = m_pSequencerSource.AppendTopology(pTopology, 0, out pSegmentId); MFError.ThrowExceptionForHR(hr); hr = pTopology.GetTopologyID(out TopologyID); MFError.ThrowExceptionForHR(hr); //create a presentation descriptor hr = pMediaSource.CreatePresentationDescriptor(out pPresentationDescriptor); MFError.ThrowExceptionForHR(hr); //get the segment duration hr = pPresentationDescriptor.GetUINT64(MFAttributesClsid.MF_PD_DURATION, out hnsSegmentDuration); MFError.ThrowExceptionForHR(hr); Debug.Assert(hnsSegmentDuration > 0); //store the segment info: SegmentId, SegmentDuration, TopoID in the linked list. m_Segments.AddNewSegmentEntry(pSegmentId, hnsSegmentDuration, TopologyID, sURL); }
/////////////////////////////////////////////////////////////////////// // Name: CreateVideoBranch // Description: // Adds and connects the nodes downstream from a video source node. // // pTopology: Pointer to the topology. // pSourceNode: Pointer to the source node. // hVideoWindow: Handle to the video window. // clsidTransform: CLSID of an effect transform. ///////////////////////////////////////////////////////////////////////// void CreateVideoBranch( IMFTopology pTopology, IMFTopologyNode pSourceNode, IntPtr hVideoWindow, Guid clsidTransform // GUID_NULL = No effect transform. ) { TRACE("CreateVideoBranch"); IMFTopologyNode pOutputNode = null; IMFActivate pRendererActivate = null; // Create a downstream node. int hr = MFExtern.MFCreateTopologyNode(MFTopologyType.OutputNode, out pOutputNode); MFError.ThrowExceptionForHR(hr); try { // Create an IMFActivate object for the video renderer. hr = MFExtern.MFCreateVideoRendererActivate(hVideoWindow, out pRendererActivate); MFError.ThrowExceptionForHR(hr); // Set the IActivate object on the output node. hr = pOutputNode.SetObject(pRendererActivate); MFError.ThrowExceptionForHR(hr); // Add the output node to the topology. hr = pTopology.AddNode(pOutputNode); MFError.ThrowExceptionForHR(hr); // Connect the source to the output. ConnectSourceToOutput(pTopology, pSourceNode, pOutputNode, clsidTransform); } finally { SafeRelease(pOutputNode); SafeRelease(pRendererActivate); } }
//////////////////////////////////////////////////////////////////////////////////////// // Name: CPlayer::CreateNodesForStream (Private) // Description: // Creates the source and output nodes for a stream and // Adds them to the topology // Connects the source node to the output node // // Parameter: // pPresentationDescriptor: [in] Pointer to the presentation descriptor for the media source // pMediaSource: [in] Pointer to the media source // pTopology: [in] Pointer to the topology // // Notes: For each stream, the app must: // 1. Create a source node associated with the stream. // 2. Create an output node for the renderer. // 3. Connect the two nodes. // The media session will resolve the topology, transform nodes are not required ///////////////////////////////////////////////////////////////////////////////////////// private void CreateNodesForStream( IMFPresentationDescriptor pPresentationDescriptor, IMFMediaSource pMediaSource, IMFTopology pTopology) { if (pPresentationDescriptor == null || pMediaSource == null || pTopology == null) { throw new COMException("null pointer", E_Pointer); } int hr; IMFStreamDescriptor pStreamDescriptor; IMFTopologyNode pSourceNode; IMFTopologyNode pOutputNode; bool fSelected = false; // Get the stream descriptor for the only stream index =0. hr = pPresentationDescriptor.GetStreamDescriptorByIndex(0, out fSelected, out pStreamDescriptor); MFError.ThrowExceptionForHR(hr); try { if (fSelected) { // Create a source node for this stream and add it to the topology. CreateSourceNode(pPresentationDescriptor, pStreamDescriptor, pMediaSource, out pSourceNode); try { hr = pTopology.AddNode(pSourceNode); MFError.ThrowExceptionForHR(hr); // Create the output node for the renderer and add it to the topology. CreateOutputNode(pStreamDescriptor, out pOutputNode); try { hr = pTopology.AddNode(pOutputNode); MFError.ThrowExceptionForHR(hr); // Connect the source node to the output node. hr = pSourceNode.ConnectOutput(0, pOutputNode, 0); MFError.ThrowExceptionForHR(hr); } finally { SafeRelease(pOutputNode); } } finally { SafeRelease(pSourceNode); } } } finally { //clean up SafeRelease(pStreamDescriptor); } }
/// <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)); } } }
/// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+= /// <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); } } }
protected void AddBranchToPartialTopology( IMFTopology pTopology, IMFPresentationDescriptor pSourcePD, int iStream ) { TRACE("CPlayer::AddBranchToPartialTopology"); Debug.Assert(pTopology != null); IMFStreamDescriptor pSourceSD = null; IMFTopologyNode pSourceNode = null; IMFTopologyNode pOutputNode = null; bool fSelected = false; try { // Get the stream descriptor for this stream. pSourcePD.GetStreamDescriptorByIndex(iStream, out fSelected, out pSourceSD); // Create the topology branch only if the stream is selected. // Otherwise, do nothing. if (fSelected) { // Create a source node for this stream. CreateSourceStreamNode(pSourcePD, pSourceSD, out pSourceNode); // Create the output node for the renderer. CreateOutputNode(pSourceSD, out pOutputNode); // Add both nodes to the topology. pTopology.AddNode(pSourceNode); pTopology.AddNode(pOutputNode); // Connect the source node to the output node. pSourceNode.ConnectOutput(0, pOutputNode, 0); } } finally { // Clean up. SafeRelease(pSourceSD); SafeRelease(pSourceNode); SafeRelease(pOutputNode); } }
public static extern void MFCreateTopology(out IMFTopology ppTopo);
protected void CreateTopologyFromSource(out IMFTopology ppTopology) { TRACE("CPlayer::CreateTopologyFromSource"); Debug.Assert(m_pSession != null); Debug.Assert(m_pSource != null); IMFTopology pTopology = null; IMFPresentationDescriptor pSourcePD = null; int cSourceStreams = 0; try { // Create a new topology. MFExtern.MFCreateTopology(out pTopology); // Create the presentation descriptor for the media source. m_pSource.CreatePresentationDescriptor(out pSourcePD); // Get the number of streams in the media source. pSourcePD.GetStreamDescriptorCount(out cSourceStreams); TRACE(string.Format("Stream count: {0}", cSourceStreams)); // For each stream, create the topology nodes and add them to the topology. for (int i = 0; i < cSourceStreams; i++) { AddBranchToPartialTopology(pTopology, pSourcePD, i); } // Return the IMFTopology pointer to the caller. ppTopology = pTopology; } catch { // If we failed, release the topology SafeRelease(pTopology); throw; } finally { SafeRelease(pSourcePD); } }
private static HResult BuildTopology(out IMFMediaSinkAlt mediaSink, IMFTopology topology, IMFPresentationDescriptor presentationDescriptor, IMFMediaSource source) { HResult hr = S_OK; mediaSink = null; IMFMediaSinkAlt tempMediaSink = null; IMFStreamDescriptor streamDescriptor = null; IMFTopologyNode sourceNode = null; IMFTopologyNode outputNode = null; bool selected = false; int streamCount = 0; hr = presentationDescriptor.GetStreamDescriptorCount(out streamCount); if (Failed(hr)) { return(hr); } for (int i = 0; i < streamCount; i++) { hr = presentationDescriptor.GetStreamDescriptorByIndex(i, out selected, out streamDescriptor); if (Failed(hr)) { return(hr); } if (selected) { hr = CreateSourceStreamNode(source, streamDescriptor, presentationDescriptor, out sourceNode); if (Failed(hr)) { return(hr); } hr = CreateOutputNode(streamDescriptor, out tempMediaSink, out outputNode); if (Failed(hr)) { mediaSink = null; return(hr); } if (tempMediaSink != null) { mediaSink = tempMediaSink; } hr = topology.AddNode(sourceNode); if (Failed(hr)) { mediaSink = null; return(hr); } hr = topology.AddNode(outputNode); if (Failed(hr)) { mediaSink = null; return(hr); } hr = sourceNode.ConnectOutput(0, outputNode, 0); if (Failed(hr)) { mediaSink = null; return(hr); } } } return(hr); }
public static extern HResult MFCreateTopology( out IMFTopology ppTopo );