protected void AddBranchToPartialTopology(IMFTopology pTopology, IMFPresentationDescriptor pSourcePD, int iStream) { int hr; //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. hr = pSourcePD.GetStreamDescriptorByIndex(iStream, out fSelected, out pSourceSD); MFError.ThrowExceptionForHR(hr); // Create the topology branch only if the stream is selected. // Otherwise, do nothing. if (fSelected) { // Create a source node for this stream. pSourceNode = CreateSourceStreamNode(pSourcePD, pSourceSD); // Add both nodes to the topology. hr = pTopology.AddNode(pSourceNode); MFError.ThrowExceptionForHR(hr); // Create the output node for the renderer. pOutputNode = CreateOutputNode(pSourceSD); if (pOutputNode == null) { throw new Exception("Could not create output node"); } 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 { // Clean up. COMBase.SafeRelease(pSourceSD); COMBase.SafeRelease(pSourceNode); COMBase.SafeRelease(pOutputNode); } }
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: CreateAudioBranch // Description: // Adds and connects the nodes downstream from an audio source node. // // pTopology: Pointer to the topology. // pSourceNode: Pointer to the source node. // clsidTransform: CLSID of an effect transform. ///////////////////////////////////////////////////////////////////////// void CreateAudioBranch( IMFTopology pTopology, IMFTopologyNode pSourceNode, Guid clsidTransform // GUID_NULL = No transform. ) { TRACE("CreateAudioBranch"); IMFTopologyNode pOutputNode = null; IMFActivate pRendererActivate = null; // Create a downstream node. MFError throwonhr; throwonhr = MFExtern.MFCreateTopologyNode(MFTopologyType.OutputNode, out pOutputNode); try { // Create an IMFActivate object for the audio renderer. throwonhr = MFExtern.MFCreateAudioRendererActivate(out pRendererActivate); // Set the IActivate object on the output node. throwonhr = pOutputNode.SetObject(pRendererActivate); // Add the output node to the topology. throwonhr = pTopology.AddNode(pOutputNode); ConnectSourceToOutput(pTopology, pSourceNode, pOutputNode, clsidTransform); } finally { // Connect the source to the output. SafeRelease(pOutputNode); SafeRelease(pRendererActivate); } }
/////////////////////////////////////////////////////////////////////// // 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 ) { HResult 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: 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); } } }
/////////////////////////////////////////////////////////////////////// // 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; MFError throwonhr; Guid majorType; bool fSelected = false; // Get the stream descriptor for this stream. throwonhr = pSourcePD.GetStreamDescriptorByIndex(iStream, out fSelected, out pSourceSD); // 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. throwonhr = pTopology.AddNode(pSourceNode); // 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) { if (!m_Audio) { CreateAudioBranch(pTopology, pSourceNode, m_AudioEffect); } } } finally { // Clean up. SafeRelease(pSourceSD); SafeRelease(pSourceNode); } } }
/////////////////////////////////////////////////////////////////////// // 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 ) { MFError throwonhr; if (clsidTransform == Guid.Empty) { // There is no effect specified, so connect the source node // directly to the output node. throwonhr = pSourceNode.ConnectOutput(0, pOutputNode, 0); } else { IMFTopologyNode pTransformNode = null; // Create a transform node. throwonhr = MFExtern.MFCreateTopologyNode(MFTopologyType.TransformNode, out pTransformNode); if (clsidTransform == m_VideoEffect) { m_VideoNode = pTransformNode; } else if (clsidTransform == m_AudioEffect) { m_AudioNode = pTransformNode; } try { // Set the CLSID of the transform. throwonhr = pTransformNode.SetGUID(MFAttributesClsid.MF_TOPONODE_TRANSFORM_OBJECTID, clsidTransform); // Add the transform node to the topology. throwonhr = pTopology.AddNode(pTransformNode); // Connect the source node to the transform node. throwonhr = pSourceNode.ConnectOutput(0, pTransformNode, 0); // Connect the transform node to the output node. throwonhr = pTransformNode.ConnectOutput(0, pOutputNode, 0); } finally { //SafeRelease(pTransformNode); } } }
/////////////////////////////////////////////////////////////////////// // 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: 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); } }
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); } }
/////////////////////////////////////////////////////////////////////// // 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); } } }
/////////////////////////////////////////////////////////////////////// // 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: 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::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); } }
/// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+= /// <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 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); }
/////////////////////////////////////////////////////////////////////// // 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); } } }