protected virtual void SetupAudio() { int hr; IEnumFilters enumFilters; hr = _graph.EnumFilters(out enumFilters); DsError.ThrowExceptionForHR(hr); IBaseFilter[] filters = new IBaseFilter[1]; IntPtr fetched = new IntPtr(); while (enumFilters.Next(1, filters, fetched) == 0) { IBaseFilter filter = filters[0] as IBaseFilter; IPin unconnectedPin = DsFindPin.ByConnectionStatus((IBaseFilter)filter, PinConnectedStatus.Unconnected, 0); if (unconnectedPin != null) { PinDirection direction; hr = unconnectedPin.QueryDirection(out direction); DsError.ThrowExceptionForHR(hr); if (direction == PinDirection.Output) { hr = _graph.Render(unconnectedPin); DsError.ThrowExceptionForHR(hr); SetupSampleGrabber(); } } } }
void TestRenderStream() { int hr; IBaseFilter ifilt; // Try using nulls hr = m_icgb2.RenderStream(null, null, m_Source, null, m_Multiplexer); DsError.ThrowExceptionForHR(hr); hr = m_graphBuilder.FindFilterByName("AVI Splitter", out ifilt); DsError.ThrowExceptionForHR(hr); IPin ipin = DsFindPin.ByConnectionStatus(ifilt, PinConnectedStatus.Unconnected, 0); Guid g = DsUtils.GetPinCategory(ipin); // With this setup, there is no valid value for parm1 hr = m_icgb2.RenderStream(null, MediaType.Audio, m_Source, null, m_Multiplexer); DsError.ThrowExceptionForHR(hr); }
private void SetupSampleGrabber() { if (_graph == null) { return; } int hr; //Get directsound filter IBaseFilter directSoundFilter; hr = _graph.FindFilterByName(DEFAULT_AUDIO_RENDERER_NAME, out directSoundFilter); DsError.ThrowExceptionForHR(hr); IPin rendererPinIn = DsFindPin.ByConnectionStatus(directSoundFilter, PinConnectedStatus.Connected, 0); if (rendererPinIn != null) { IPin audioPinOut; hr = rendererPinIn.ConnectedTo(out audioPinOut); DsError.ThrowExceptionForHR(hr); if (audioPinOut != null) { //Disconect audio decoder to directsound renderer hr = audioPinOut.Disconnect(); DsError.ThrowExceptionForHR(hr); hr = _graph.RemoveFilter(directSoundFilter); DsError.ThrowExceptionForHR(hr); //Add Sample Grabber ISampleGrabber sampleGrabber = new SampleGrabber() as ISampleGrabber; hr = sampleGrabber.SetCallback(this, 1); DsError.ThrowExceptionForHR(hr); AMMediaType media; media = new AMMediaType(); media.majorType = MediaType.Audio; media.subType = MediaSubType.PCM; media.formatType = FormatType.WaveEx; hr = sampleGrabber.SetMediaType(media); DsError.ThrowExceptionForHR(hr); IPin sampleGrabberPinIn = DsFindPin.ByDirection((IBaseFilter)sampleGrabber, PinDirection.Input, 0); IPin sampleGrabberPinOut = DsFindPin.ByDirection((IBaseFilter)sampleGrabber, PinDirection.Output, 0); hr = _graph.AddFilter((IBaseFilter)sampleGrabber, "SampleGrabber"); DsError.ThrowExceptionForHR(hr); PinInfo pinInfo; hr = audioPinOut.QueryPinInfo(out pinInfo); DsError.ThrowExceptionForHR(hr); FilterInfo filterInfo; hr = pinInfo.filter.QueryFilterInfo(out filterInfo); DsError.ThrowExceptionForHR(hr); hr = _graph.Connect(audioPinOut, sampleGrabberPinIn); DsError.ThrowExceptionForHR(hr); //Add null renderer NullRenderer nullRenderer = new NullRenderer(); hr = _graph.AddFilter((IBaseFilter)nullRenderer, "NullRenderer"); DsError.ThrowExceptionForHR(hr); IPin nullRendererPinIn = DsFindPin.ByDirection((IBaseFilter)nullRenderer, PinDirection.Input, 0); hr = _graph.Connect(sampleGrabberPinOut, nullRendererPinIn); DsError.ThrowExceptionForHR(hr); _audioEngine.Setup(this.GetSampleGrabberFormat(sampleGrabber)); } } }
/// <summary> /// Builds the DVD DirectShow graph /// </summary> private void BuildGraph() { try { FreeResources(); int hr; /* Create our new graph */ m_graph = (IGraphBuilder) new FilterGraphNoThread(); #if DEBUG m_rot = new DsROTEntry(m_graph); #endif /* We are going to use the VMR9 for now. The EVR does not * seem to work with the interactive menus yet. It should * play Dvds fine otherwise */ var rendererType = VideoRendererType.VideoMixingRenderer9; /* Creates and initializes a new renderer ready to render to WPF */ m_renderer = CreateVideoRenderer(rendererType, m_graph, 2); /* Do some VMR9 specific stuff */ if (rendererType == VideoRendererType.VideoMixingRenderer9) { var mixer = m_renderer as IVMRMixerControl9; if (mixer != null) { VMR9MixerPrefs dwPrefs; mixer.GetMixingPrefs(out dwPrefs); dwPrefs &= ~VMR9MixerPrefs.RenderTargetMask; dwPrefs |= VMR9MixerPrefs.RenderTargetYUV; /* Enable this line to prefer YUV */ //hr = mixer.SetMixingPrefs(dwPrefs); } } /* Create a new DVD Navigator. */ var dvdNav = (IBaseFilter) new DVDNavigator(); /* The DVDControl2 interface lets us control DVD features */ m_dvdControl = dvdNav as IDvdControl2; if (m_dvdControl == null) { throw new Exception("Could not QueryInterface the IDvdControl2 interface"); } /* QueryInterface the DVDInfo2 */ m_dvdInfo = dvdNav as IDvdInfo2; /* If a Dvd directory has been set then use it, if not, let DShow find the Dvd */ if (!string.IsNullOrEmpty(DvdDirectory)) { hr = m_dvdControl.SetDVDDirectory(DvdDirectory); DsError.ThrowExceptionForHR(hr); } /* This gives us the DVD time in Hours-Minutes-Seconds-Frame time format, and other options */ hr = m_dvdControl.SetOption(DvdOptionFlag.HMSFTimeCodeEvents, true); DsError.ThrowExceptionForHR(hr); /* If the graph stops, resume at the same point */ m_dvdControl.SetOption(DvdOptionFlag.ResetOnStop, false); hr = m_graph.AddFilter(dvdNav, "DVD Navigator"); DsError.ThrowExceptionForHR(hr); IPin dvdVideoPin = null; IPin dvdAudioPin = null; IPin dvdSubPicturePin = null; IPin dvdNavPin; int i = 0; /* Loop all the output pins on the DVD Navigator, trying to find which pins are which. * We could more easily find the pins by name, but this is more fun...and more flexible * if we ever want to use a 3rd party DVD navigator that used different pin names */ while ((dvdNavPin = DsFindPin.ByDirection(dvdNav, PinDirection.Output, i)) != null) { var mediaTypes = new AMMediaType[1]; IntPtr pFetched = IntPtr.Zero; IEnumMediaTypes mediaTypeEnum; dvdNavPin.EnumMediaTypes(out mediaTypeEnum); /* Loop over each of the mediaTypes of each pin */ while (mediaTypeEnum.Next(1, mediaTypes, pFetched) == 0) { AMMediaType mediaType = mediaTypes[0]; /* This will be the video stream pin */ if (mediaType.subType == MediaSubType.Mpeg2Video) { /* Keep the ref and we'll work with it later */ dvdVideoPin = dvdNavPin; break; } /* This will be the audio stream pin */ if (mediaType.subType == MediaSubType.DolbyAC3 || mediaType.subType == MediaSubType.Mpeg2Audio) { /* Keep the ref and we'll work with it later */ dvdAudioPin = dvdNavPin; break; } /* This is the Dvd sub picture pin. This generally * shows overlays for Dvd menus and sometimes closed captions */ if (mediaType.subType == DVD_SUBPICTURE_TYPE) { /* Keep the ref and we'll work with it later */ dvdSubPicturePin = dvdNavPin; break; } } mediaTypeEnum.Reset(); Marshal.ReleaseComObject(mediaTypeEnum); i++; } /* This is the windowed renderer. This is *NEEDED* in order * for interactive menus to work with the other VMR9 in renderless mode */ var dummyRenderer = (IBaseFilter) new VideoMixingRenderer9(); var dummyRendererConfig = (IVMRFilterConfig9)dummyRenderer; /* In order for this interactive menu trick to work, the VMR9 * must be set to Windowed. We will make sure the window is hidden later on */ hr = dummyRendererConfig.SetRenderingMode(VMR9Mode.Windowed); DsError.ThrowExceptionForHR(hr); hr = dummyRendererConfig.SetNumberOfStreams(1); DsError.ThrowExceptionForHR(hr); hr = m_graph.AddFilter(dummyRenderer, "Dummy Windowed"); DsError.ThrowExceptionForHR(hr); if (dvdAudioPin != null) { /* This should render out to the default audio device. We * could modify this code here to go out any audio * device, such as SPDIF or another sound card */ hr = m_graph.Render(dvdAudioPin); DsError.ThrowExceptionForHR(hr); } /* Get the first input pin on our dummy renderer */ m_dummyRendererPin = DsFindPin.ByConnectionStatus(dummyRenderer, /* Filter to search */ PinConnectedStatus.Unconnected, 0); /* Get an available pin on our real renderer */ IPin rendererPin = DsFindPin.ByConnectionStatus(m_renderer, /* Filter to search */ PinConnectedStatus.Unconnected, 0); /* Pin index */ /* Connect the pin to the renderer */ hr = m_graph.Connect(dvdVideoPin, rendererPin); DsError.ThrowExceptionForHR(hr); /* Get the next available pin on our real renderer */ rendererPin = DsFindPin.ByConnectionStatus(m_renderer, /* Filter to search */ PinConnectedStatus.Unconnected, 0); /* Pin index */ /* Render the sub picture, which will connect * the DVD navigator to the codec, not the renderer */ hr = m_graph.Render(dvdSubPicturePin); DsError.ThrowExceptionForHR(hr); /* These are the subtypes most likely to be our dvd subpicture */ var preferedSubpictureTypes = new[] { MediaSubType.ARGB4444, MediaSubType.AI44, MediaSubType.AYUV, MediaSubType.ARGB32 }; IPin dvdSubPicturePinOut = null; /* Find what should be the subpicture pin out */ foreach (var guidType in preferedSubpictureTypes) { dvdSubPicturePinOut = FindPinInGraphByMediaType(guidType, /* GUID of the media type being searched for */ PinDirection.Output, m_graph); /* Our current graph */ if (dvdSubPicturePinOut != null) { break; } } if (dvdSubPicturePinOut == null) { throw new Exception("Could not find the sub picture pin out"); } /* Here we connec thte Dvd sub picture pin to the video renderer. * This enables the overlays on Dvd menus and some closed * captions to be rendered. */ hr = m_graph.Connect(dvdSubPicturePinOut, rendererPin); DsError.ThrowExceptionForHR(hr); /* Search for the Line21 out in the graph */ IPin line21Out = FindPinInGraphByMediaType(MediaType.AuxLine21Data, PinDirection.Output, m_graph); if (line21Out == null) { throw new Exception("Could not find the Line21 pin out"); } /* We connect our line21Out out in to the dummy renderer * this is what ultimatly makes interactive DVDs work with * VMR9 in renderless (for WPF) */ hr = m_graph.Connect(line21Out, m_dummyRendererPin); DsError.ThrowExceptionForHR(hr); /* This is the dummy renderers Win32 window. */ m_dummyRenderWindow = dummyRenderer as IVideoWindow; if (m_dummyRenderWindow == null) { throw new Exception("Could not QueryInterface for IVideoWindow"); } ConfigureDummyWindow(); /* Setup our base classes with this filter graph */ SetupFilterGraph(m_graph); /* Sets the NaturalVideoWidth/Height */ //SetNativePixelSizes(m_renderer); } catch (Exception ex) { FreeResources(); InvokeMediaFailed(new MediaFailedEventArgs(ex.Message, ex)); return; } InvokeMediaOpened(); }
private void RenderStreams(IBaseFilter pSource) { int hr; bool bRenderedAudio = false; bool bRenderedVideo = false; IBaseFilter pEVR = (IBaseFilter) new EnhancedVideoRenderer(); IBaseFilter pAudioRenderer = (IBaseFilter) new DSoundRender(); try { // Add the EVR to the graph. hr = m_pGraph.AddFilter(pEVR, "EVR"); DsError.ThrowExceptionForHR(hr); InitializeEVR(pEVR, 1, out m_pDisplay); // Add the DSound Renderer to the graph. hr = m_pGraph.AddFilter(pAudioRenderer, "Audio Renderer"); DsError.ThrowExceptionForHR(hr); ICaptureGraphBuilder2 cgb; cgb = (ICaptureGraphBuilder2) new CaptureGraphBuilder2(); try { hr = cgb.SetFiltergraph(m_pGraph); DsError.ThrowExceptionForHR(hr); // Connect the streams. hr = cgb.RenderStream(null, MediaType.Video, pSource, null, pEVR); DsError.ThrowExceptionForHR(hr); hr = cgb.RenderStream(null, MediaType.Audio, pSource, null, pAudioRenderer); DsError.ThrowExceptionForHR(hr); // If we are using a splitter, the two lines above did nothing. We // ignore the errors from the next 2 statements in case the 2 lines above // *did* do something. hr = cgb.RenderStream(null, null, pSource, null, pEVR); //DsError.ThrowExceptionForHR(hr); hr = cgb.RenderStream(null, null, pSource, null, pAudioRenderer); //DsError.ThrowExceptionForHR(hr); IPin pPin = DsFindPin.ByConnectionStatus(pEVR, PinConnectedStatus.Unconnected, 0); if (pPin == null) { bRenderedVideo = true; } else { Marshal.ReleaseComObject(pPin); } pPin = DsFindPin.ByConnectionStatus(pAudioRenderer, PinConnectedStatus.Unconnected, 0); if (pPin == null) { bRenderedAudio = true; } else { Marshal.ReleaseComObject(pPin); } } finally { Marshal.ReleaseComObject(cgb); } // Remove un-used renderers. if (!bRenderedVideo) { m_pGraph.RemoveFilter(pEVR); // If we removed the EVR, then we also need to release our // pointer to the EVR display interfaace //Marshal.ReleaseComObject(m_pDisplay); m_pDisplay = null; } else { // EVR is still in the graph. Cache the interface pointer. Debug.Assert(pEVR != null); m_pEVR = pEVR; } if (!bRenderedAudio) { m_pGraph.RemoveFilter(pAudioRenderer); } } finally { Marshal.ReleaseComObject(pAudioRenderer); } }