private void RenderStreams(DirectShowLib.IBaseFilter pSource, bool enableReclock, bool enableMadvr, bool enableMadvrExclusiveMode, bool enableXySubFilter) { int hr; _filterGraph = m_graph as DirectShowLib.IFilterGraph2; if (_filterGraph == null) { throw new Exception("Could not QueryInterface for the IFilterGraph2"); } // Add audio renderer var useDefaultRenderer = true; if (enableReclock) { try { _reclockAudioRenderer = new ReclockAudioRenderer(); var aRenderer = _reclockAudioRenderer as DirectShowLib.IBaseFilter; if (aRenderer != null) { hr = m_graph.AddFilter(aRenderer, "Reclock Audio Renderer"); DsError.ThrowExceptionForHR(hr); useDefaultRenderer = false; } } catch (Exception ex) { _logger.ErrorException("Error adding reclock filter", ex); } } if (useDefaultRenderer) { _defaultAudioRenderer = new DefaultAudioRenderer(); var aRenderer = _defaultAudioRenderer as DirectShowLib.IBaseFilter; if (aRenderer != null) { m_graph.AddFilter(aRenderer, "Default Audio Renderer"); } } if (_item.IsVideo) { var xySubFilterSucceeded = false; var madVrSucceded = false; //add the video renderer first so we know whether to enable DXVA2 in "Auto" mode. if (enableMadvr) { try { _madvr = _urCom.GetObject(typeof(MadVR).GUID, true);// new MadVR(); var vmadvr = _madvr as DirectShowLib.IBaseFilter; if (vmadvr != null) { hr = m_graph.AddFilter(vmadvr, "MadVR Video Renderer"); DsError.ThrowExceptionForHR(hr); try { MadVRSettings msett = new MadVRSettings(_madvr); bool smoothMotion = msett.GetBool("smoothMotionEnabled"); if (smoothMotion != _mbtConfig.Configuration.InternalPlayerConfiguration.VideoConfig.UseMadVrSmoothMotion) msett.SetBool("smoothMotionEnabled", _mbtConfig.Configuration.InternalPlayerConfiguration.VideoConfig.UseMadVrSmoothMotion); if (string.Compare(msett.GetString("smoothMotionMode"), _mbtConfig.Configuration.InternalPlayerConfiguration.VideoConfig.MadVrSmoothMotionMode, true) != 0) { bool success = msett.SetString("smoothMotionMode", _mbtConfig.Configuration.InternalPlayerConfiguration.VideoConfig.MadVrSmoothMotionMode); } } catch (Exception ex) { _logger.ErrorException("Error configuring madVR", ex); } madVrSucceded = true; } } catch (Exception ex) { _logger.ErrorException("Error adding MadVR filter", ex); } } // Add video renderer if (!madVrSucceded) { _mPEvr = (DirectShowLib.IBaseFilter)new EnhancedVideoRenderer(); hr = m_graph.AddFilter(_mPEvr, "EVR"); DsError.ThrowExceptionForHR(hr); //we only need 2 input pins on the EVR if LAV Video isn't used for DVDs, but it doesn't hurt to have them InitializeEvr(_mPEvr, _isDvd ? 2 : 1); } // Load xySubFilter if configured and if madvr succeeded if (enableXySubFilter && (madVrSucceded || _customEvrPresenterLoaded)) { try { _xySubFilter = _urCom.GetObject(typeof(XySubFilter).GUID, true);//new XySubFilter(); var vxySubFilter = _xySubFilter as DirectShowLib.IBaseFilter; if (vxySubFilter != null) { hr = m_graph.AddFilter(vxySubFilter, "xy-SubFilter"); DsError.ThrowExceptionForHR(hr); } xySubFilterSucceeded = true; } catch (Exception ex) { _logger.ErrorException("Error adding xy-SubFilter filter", ex); } } // Fallback to xyVsFilter if (!xySubFilterSucceeded && enableXySubFilter) { try { _xyVsFilter = new XYVSFilter(); var vxyVsFilter = _xyVsFilter as DirectShowLib.IBaseFilter; if (vxyVsFilter != null) { hr = m_graph.AddFilter(vxyVsFilter, "xy-VSFilter"); DsError.ThrowExceptionForHR(hr); } } catch (Exception ex) { _logger.ErrorException("Error adding xy-VSFilter filter", ex); } } try { _lavvideo = _urCom.GetObject(typeof(LAVVideo).GUID, true);//new LAVVideo(); var vlavvideo = _lavvideo as DirectShowLib.IBaseFilter; if (vlavvideo != null) { hr = m_graph.AddFilter(vlavvideo, "LAV Video Decoder"); DsError.ThrowExceptionForHR(hr); ILAVVideoSettings vsett = vlavvideo as ILAVVideoSettings; if (vsett != null) { //we only want to set it for MB hr = vsett.SetRuntimeConfig(true); DsError.ThrowExceptionForHR(hr); LAVHWAccel configuredMode = VideoConfigurationUtils.GetHwaMode(_mbtConfig.Configuration.InternalPlayerConfiguration.VideoConfig, _customEvrPresenterLoaded); LAVHWAccel testme = vsett.GetHWAccel(); if (testme != configuredMode) { hr = vsett.SetHWAccel(configuredMode); DsError.ThrowExceptionForHR(hr); } foreach (string c in DirectShowPlayer.GetLAVVideoCodecs()) { LAVVideoCodec codec = (LAVVideoCodec)Enum.Parse(typeof(LAVVideoCodec), c); bool isEnabled = vsett.GetFormatConfiguration(codec); if (_mbtConfig.Configuration.InternalPlayerConfiguration.VideoConfig.EnabledCodecs.Contains(c)) { if (!isEnabled) { _logger.Debug("Enable support for: {0}", c); hr = vsett.SetFormatConfiguration(codec, true); DsError.ThrowExceptionForHR(hr); } } else if (isEnabled) { _logger.Debug("Disable support for: {0}", c); hr = vsett.SetFormatConfiguration(codec, false); DsError.ThrowExceptionForHR(hr); } } foreach (string hwaCodec in DirectShowPlayer.GetLAVVideoHwaCodecs()) { LAVVideoHWCodec codec = (LAVVideoHWCodec)Enum.Parse(typeof(LAVVideoHWCodec), hwaCodec); bool hwaIsEnabled = vsett.GetHWAccelCodec(codec); if (_mbtConfig.Configuration.InternalPlayerConfiguration.VideoConfig.HwaEnabledCodecs.Contains(hwaCodec)) { if (!hwaIsEnabled) { _logger.Debug("Enable HWA support for: {0}", hwaCodec); hr = vsett.SetHWAccelCodec(codec, true); DsError.ThrowExceptionForHR(hr); } } else if (hwaIsEnabled) { _logger.Debug("Disable HWA support for: {0}", hwaCodec); hr = vsett.SetHWAccelCodec(codec, false); DsError.ThrowExceptionForHR(hr); } } if (!vsett.GetDVDVideoSupport()) { _logger.Debug("Enable DVD support."); hr = vsett.SetDVDVideoSupport(true); DsError.ThrowExceptionForHR(hr); } int hwaRes = vsett.GetHWAccelResolutionFlags(); if (hwaRes != _mbtConfig.Configuration.InternalPlayerConfiguration.VideoConfig.HwaResolution) { _logger.Debug("Change HWA resolution support from {0} to {1}.", hwaRes, _mbtConfig.Configuration.InternalPlayerConfiguration.VideoConfig.HwaResolution); hr = vsett.SetHWAccelResolutionFlags(VideoConfigurationUtils.GetHwaResolutions(_mbtConfig.Configuration.InternalPlayerConfiguration.VideoConfig)); DsError.ThrowExceptionForHR(hr); } hr = vsett.SetTrayIcon(_mbtConfig.Configuration.InternalPlayerConfiguration.VideoConfig.ShowTrayIcon); DsError.ThrowExceptionForHR(hr); } } } catch (Exception ex) { _logger.ErrorException("Error adding LAV Video filter", ex); } } try { _lavaudio = _urCom.GetObject(typeof(LAVAudio).GUID, true);// new LAVAudio(); var vlavaudio = _lavaudio as DirectShowLib.IBaseFilter; if (vlavaudio != null) { _logger.Debug("Add LAVAudio to the graph."); hr = m_graph.AddFilter(vlavaudio, "LAV Audio Decoder"); DsError.ThrowExceptionForHR(hr); ILAVAudioSettings asett = vlavaudio as ILAVAudioSettings; if (asett != null) { _logger.Debug("Enable LAVAudio Runtime Config"); //we only want to set it for MB hr = asett.SetRuntimeConfig(true); DsError.ThrowExceptionForHR(hr); foreach (string c in DirectShowPlayer.GetLAVAudioCodecs()) { LAVAudioCodec codec = (LAVAudioCodec)Enum.Parse(typeof(LAVAudioCodec), c); bool isEnabled = asett.GetFormatConfiguration(codec); if (_mbtConfig.Configuration.InternalPlayerConfiguration.AudioConfig.EnabledCodecs.Contains(c)) { if (!isEnabled) { _logger.Debug("Enable support for: {0}", c); hr = asett.SetFormatConfiguration(codec, true); DsError.ThrowExceptionForHR(hr); } } else if (isEnabled) { _logger.Debug("Disable support for: {0}", c); hr = asett.SetFormatConfiguration(codec, false); DsError.ThrowExceptionForHR(hr); } } //enable/disable bitstreaming if ((_mbtConfig.Configuration.InternalPlayerConfiguration.AudioConfig.AudioBitstreaming & BitstreamChoice.SPDIF) == BitstreamChoice.SPDIF) { _logger.Debug("Enable LAVAudio S/PDIF bitstreaming"); hr = asett.SetBitstreamConfig(LAVBitstreamCodec.AC3, true); DsError.ThrowExceptionForHR(hr); hr = asett.SetBitstreamConfig(LAVBitstreamCodec.DTS, true); DsError.ThrowExceptionForHR(hr); } if ((_mbtConfig.Configuration.InternalPlayerConfiguration.AudioConfig.AudioBitstreaming & BitstreamChoice.HDMI) == BitstreamChoice.HDMI) { _logger.Debug("Enable LAVAudio HDMI bitstreaming"); hr = asett.SetBitstreamConfig(LAVBitstreamCodec.EAC3, true); DsError.ThrowExceptionForHR(hr); hr = asett.SetBitstreamConfig(LAVBitstreamCodec.TRUEHD, true); DsError.ThrowExceptionForHR(hr); hr = asett.SetBitstreamConfig(LAVBitstreamCodec.DTSHD, true); DsError.ThrowExceptionForHR(hr); } if (_mbtConfig.Configuration.InternalPlayerConfiguration.AudioConfig.Delay > 0) { _logger.Debug("Set LAVAudio audio delay: {0}", _mbtConfig.Configuration.InternalPlayerConfiguration.AudioConfig.Delay); hr = asett.SetAudioDelay(true, _mbtConfig.Configuration.InternalPlayerConfiguration.AudioConfig.Delay); DsError.ThrowExceptionForHR(hr); } _logger.Debug("Set LAVAudio auto AV Sync: {0}", _mbtConfig.Configuration.InternalPlayerConfiguration.AudioConfig.EnableAutoSync); hr = asett.SetAutoAVSync(_mbtConfig.Configuration.InternalPlayerConfiguration.AudioConfig.EnableAutoSync); DsError.ThrowExceptionForHR(hr); _logger.Debug("Set LAVAudio Expand61: {0}", _mbtConfig.Configuration.InternalPlayerConfiguration.AudioConfig.Expand61); hr = asett.SetExpand61(_mbtConfig.Configuration.InternalPlayerConfiguration.AudioConfig.Expand61); DsError.ThrowExceptionForHR(hr); _logger.Debug("Set LAVAudio ExpandMono: {0}", _mbtConfig.Configuration.InternalPlayerConfiguration.AudioConfig.ExpandMono); hr = asett.SetExpandMono(_mbtConfig.Configuration.InternalPlayerConfiguration.AudioConfig.ExpandMono); DsError.ThrowExceptionForHR(hr); _logger.Debug("Set LAVAudio ConvertToStandardLayout: {0}", _mbtConfig.Configuration.InternalPlayerConfiguration.AudioConfig.ConvertToStandardLayout); hr = asett.SetOutputStandardLayout(_mbtConfig.Configuration.InternalPlayerConfiguration.AudioConfig.ConvertToStandardLayout); DsError.ThrowExceptionForHR(hr); _logger.Debug("Set LAVAudio audio EnableDRC: {0}", _mbtConfig.Configuration.InternalPlayerConfiguration.AudioConfig.EnableDRC); hr = asett.SetDRC(_mbtConfig.Configuration.InternalPlayerConfiguration.AudioConfig.EnableDRC, _mbtConfig.Configuration.InternalPlayerConfiguration.AudioConfig.DRCLevel); DsError.ThrowExceptionForHR(hr); _logger.Debug("Set LAVAudio audio ShowTrayIcon: {0}", _mbtConfig.Configuration.InternalPlayerConfiguration.AudioConfig.ShowTrayIcon); hr = asett.SetTrayIcon(_mbtConfig.Configuration.InternalPlayerConfiguration.AudioConfig.ShowTrayIcon); DsError.ThrowExceptionForHR(hr); bool mixingEnabled = asett.GetMixingEnabled(); if (mixingEnabled != _mbtConfig.Configuration.InternalPlayerConfiguration.AudioConfig.EnablePCMMixing) { _logger.Debug("Set LAVAudio EnablePCMMixing: {0}", _mbtConfig.Configuration.InternalPlayerConfiguration.AudioConfig.EnablePCMMixing); hr = asett.SetMixingEnabled(!mixingEnabled); DsError.ThrowExceptionForHR(hr); } if (_mbtConfig.Configuration.InternalPlayerConfiguration.AudioConfig.EnablePCMMixing) { _logger.Debug("Set LAVAudio MixingSetting: {0}", _mbtConfig.Configuration.InternalPlayerConfiguration.AudioConfig.MixingSetting); LAVAudioMixingFlag amf = (LAVAudioMixingFlag)_mbtConfig.Configuration.InternalPlayerConfiguration.AudioConfig.MixingSetting; hr = asett.SetMixingFlags(amf); DsError.ThrowExceptionForHR(hr); _logger.Debug("Set LAVAudio MixingEncoding: {0}", _mbtConfig.Configuration.InternalPlayerConfiguration.AudioConfig.MixingEncoding); LAVAudioMixingMode amm = (LAVAudioMixingMode)Enum.Parse(typeof(LAVAudioMixingMode), _mbtConfig.Configuration.InternalPlayerConfiguration.AudioConfig.MixingEncoding); hr = asett.SetMixingMode(amm); DsError.ThrowExceptionForHR(hr); _logger.Debug("Set LAVAudio MixingLayout: {0}", _mbtConfig.Configuration.InternalPlayerConfiguration.AudioConfig.MixingLayout); LAVAudioMixingLayout aml = (LAVAudioMixingLayout)Enum.Parse(typeof(LAVAudioMixingLayout), _mbtConfig.Configuration.InternalPlayerConfiguration.AudioConfig.MixingLayout); hr = asett.SetMixingLayout(aml); DsError.ThrowExceptionForHR(hr); _logger.Debug("Set LAVAudio LfeMixingLevel: {0} CenterMixingLevel: {1} SurroundMixingLevel: {2}", _mbtConfig.Configuration.InternalPlayerConfiguration.AudioConfig.LfeMixingLevel, _mbtConfig.Configuration.InternalPlayerConfiguration.AudioConfig.CenterMixingLevel, _mbtConfig.Configuration.InternalPlayerConfiguration.AudioConfig.SurroundMixingLevel); int lfe, center, surround; //convert to the # that LAV Audio expects lfe = (int)(_mbtConfig.Configuration.InternalPlayerConfiguration.AudioConfig.LfeMixingLevel * 10000.01); center = (int)(_mbtConfig.Configuration.InternalPlayerConfiguration.AudioConfig.CenterMixingLevel * 10000.01); surround = (int)(_mbtConfig.Configuration.InternalPlayerConfiguration.AudioConfig.SurroundMixingLevel * 10000.01); hr = asett.SetMixingLevels(center, surround, lfe); DsError.ThrowExceptionForHR(hr); } for (int i = 0; i < (int)LAVBitstreamCodec.NB; i++) { LAVBitstreamCodec codec = (LAVBitstreamCodec)i; bool isEnabled = asett.GetBitstreamConfig(codec); _logger.Log(LogSeverity.Debug, "{0} bitstreaming: {1}", codec, isEnabled); } } } } catch (Exception ex) { _logger.ErrorException("Error adding LAV Audio filter", ex); } DirectShowLib.IEnumPins pEnum; hr = pSource.EnumPins(out pEnum); DsError.ThrowExceptionForHR(hr); DirectShowLib.IPin[] pins = { null }; /* Counter for how many pins successfully rendered */ var pinsRendered = 0; /* Loop over each pin of the source filter */ while (pEnum.Next(1, pins, IntPtr.Zero) == 0) { //explicitly build graph to avoid unwanted filters worming their way in List<Guid> mediaTypes = GetPinMediaTypes(pins[0]); bool needsRender = true; for (int m = 0; m < mediaTypes.Count; m++) { DirectShowLib.IPin decIn = null; DirectShowLib.IPin decOut = null; DirectShowLib.IPin rendIn = null; try { if (mediaTypes[m] == DirectShowLib.MediaType.Video && _lavvideo != null) { decIn = DsFindPin.ByDirection((DirectShowLib.IBaseFilter)_lavvideo, PinDirection.Input, 0); if (decIn != null) { hr = _filterGraph.ConnectDirect(pins[0], decIn, null); DsError.ThrowExceptionForHR(hr); decOut = DsFindPin.ByDirection((DirectShowLib.IBaseFilter)_lavvideo, PinDirection.Output, 0); if (_xyVsFilter != null) { //insert xyVsFilter b/w LAV Video and the renderer rendIn = DsFindPin.ByName((DirectShowLib.IBaseFilter)_xyVsFilter, "Video"); if (decOut != null && rendIn != null) { hr = _filterGraph.ConnectDirect(decOut, rendIn, null); DsError.ThrowExceptionForHR(hr); CleanUpInterface(decOut); CleanUpInterface(rendIn); //grab xyVsFilter's output pin so it can be connected to the renderer decOut = DsFindPin.ByDirection((DirectShowLib.IBaseFilter)_xyVsFilter, PinDirection.Output, 0); } } if (_madvr != null) { rendIn = DsFindPin.ByDirection((DirectShowLib.IBaseFilter)_madvr, PinDirection.Input, 0); } else { rendIn = DsFindPin.ByDirection((DirectShowLib.IBaseFilter)_mPEvr, PinDirection.Input, 0); } if (decOut != null && rendIn != null) { hr = _filterGraph.ConnectDirect(decOut, rendIn, null); DsError.ThrowExceptionForHR(hr); needsRender = false; break; } } } else if (mediaTypes[m] == DirectShowLib.MediaType.Audio && _lavaudio != null) { decIn = DsFindPin.ByDirection((DirectShowLib.IBaseFilter)_lavaudio, PinDirection.Input, 0); if (decIn != null) { hr = _filterGraph.ConnectDirect(pins[0], decIn, null); DsError.ThrowExceptionForHR(hr); decOut = DsFindPin.ByDirection((DirectShowLib.IBaseFilter)_lavaudio, PinDirection.Output, 0); if (_reclockAudioRenderer != null) { rendIn = DsFindPin.ByDirection((DirectShowLib.IBaseFilter)_reclockAudioRenderer, PinDirection.Input, 0); } else { rendIn = DsFindPin.ByDirection((DirectShowLib.IBaseFilter)_defaultAudioRenderer, PinDirection.Input, 0); } if (decOut != null && rendIn != null) { hr = _filterGraph.ConnectDirect(decOut, rendIn, null); DsError.ThrowExceptionForHR(hr); needsRender = false; break; } } } else if (mediaTypes[m] == new Guid("E487EB08-6B26-4be9-9DD3-993434D313FD") /*DirectShowLib.MediaType.Subtitle*/ && (_xySubFilter != null || _xyVsFilter != null)) { if (_xySubFilter != null) { rendIn = DsFindPin.ByDirection((DirectShowLib.IBaseFilter)_xySubFilter, PinDirection.Input, 0); } else { rendIn = DsFindPin.ByName((DirectShowLib.IBaseFilter)_xyVsFilter, "Input"); } if (rendIn != null) { hr = _filterGraph.ConnectDirect(pins[0], rendIn, null); DsError.ThrowExceptionForHR(hr); needsRender = false; break; } } } finally { CleanUpInterface(decIn); CleanUpInterface(decOut); CleanUpInterface(rendIn); } } if (needsRender) { if (_filterGraph.RenderEx(pins[0], AMRenderExFlags.RenderToExistingRenderers, IntPtr.Zero) >= 0) pinsRendered++; } else pinsRendered++; Marshal.ReleaseComObject(pins[0]); } Marshal.ReleaseComObject(pEnum); if (pinsRendered == 0) { throw new Exception("Could not render any streams from the source Uri"); } _logger.Debug("Completed RenderStreams with {0} pins.", pinsRendered); if (_item.IsVideo) { SetVideoWindow(enableMadvrExclusiveMode); if(_mPEvr != null) SetEvrVppMode(_mPEvr); } }
private void RenderStreams(DirectShowLib.IBaseFilter pSource, bool enableMadvr, bool enableMadvrExclusiveMode, bool enableXySubFilter) { int hr; _filterGraph = m_graph as DirectShowLib.IFilterGraph2; if (_filterGraph == null) { throw new Exception("Could not QueryInterface for the IFilterGraph2"); } var useDefaultRenderer = true; DirectShowLib.IEnumPins pEnum; hr = pSource.EnumPins(out pEnum); DsError.ThrowExceptionForHR(hr); DirectShowLib.IPin[] pins = {null}; /* Counter for how many pins successfully rendered */ var pinsRendered = 0; /* Loop over each pin of the source filter */ while (pEnum.Next(1, pins, IntPtr.Zero) == 0) { //explicitly build graph to avoid unwanted filters worming their way in List<Guid> mediaTypes = GetPinMediaTypes(pins[0]); bool needsRender = true; for (int m = 0; m < mediaTypes.Count; m++) { DirectShowLib.IPin decIn = null; DirectShowLib.IPin decOut = null; DirectShowLib.IPin rendIn = null; try { if (mediaTypes[m] == DirectShowLib.MediaType.Video) { #region Video //add the video renderer first so we know whether to enable DXVA2 in "Auto" mode. if (enableMadvr) { try { _madvr = _playerWrapper.PrivateCom.GetObject(typeof(MadVR).GUID, true); // new MadVR(); var vmadvr = _madvr as DirectShowLib.IBaseFilter; if (vmadvr != null) { hr = m_graph.AddFilter(vmadvr, "MadVR Video Renderer"); DsError.ThrowExceptionForHR(hr); try { MadVRSettings msett = new MadVRSettings(_madvr); bool smoothMotion = msett.GetBool("smoothMotionEnabled"); if (smoothMotion != _mbtConfig.Configuration.InternalPlayerConfiguration.VideoConfig .UseMadVrSmoothMotion) msett.SetBool("smoothMotionEnabled", _mbtConfig.Configuration.InternalPlayerConfiguration.VideoConfig .UseMadVrSmoothMotion); if ( string.Compare(msett.GetString("smoothMotionMode"), _mbtConfig.Configuration.InternalPlayerConfiguration.VideoConfig .MadVrSmoothMotionMode, true) != 0) { bool success = msett.SetString("smoothMotionMode", _mbtConfig.Configuration.InternalPlayerConfiguration.VideoConfig .MadVrSmoothMotionMode); } MFNominalRange levels = (MFNominalRange)_mbtConfig.Configuration.InternalPlayerConfiguration.VideoConfig.NominalRange; //string madVrLevelInitial = msett.GetString("levels"); //switch (levels) //{ // case MFNominalRange.MFNominalRange_0_255: // msett.SetString("levels", "PC Levels"); // break; // case MFNominalRange.MFNominalRange_16_235: // msett.SetString("levels", "TV Levels"); // break; //} //string madVrLevel = msett.GetString("levels"); //if (string.Compare(madVrLevel, madVrLevelInitial, false) != 0) // _logger.Debug("Changed madVR levels from {0} to {1}", madVrLevelInitial, madVrLevel); } catch (Exception ex) { _logger.ErrorException("Error configuring madVR", ex); } } } catch (Exception ex) { _logger.ErrorException("Error adding MadVR filter", ex); } } else // Add default video renderer { _mPEvr = (DirectShowLib.IBaseFilter)new EnhancedVideoRenderer(); hr = m_graph.AddFilter(_mPEvr, "EVR"); DsError.ThrowExceptionForHR(hr); //we only need 2 input pins on the EVR if LAV Video isn't used for DVDs, but it doesn't hurt to have them InitializeEvr(_mPEvr, _isDvd ? 2 : 1); } try { _lavvideo = _playerWrapper.PrivateCom.GetObject(typeof(LAVVideo).GUID, true); //new LAVVideo(); var vlavvideo = _lavvideo as DirectShowLib.IBaseFilter; if (vlavvideo != null) { hr = m_graph.AddFilter(vlavvideo, "LAV Video Decoder"); DsError.ThrowExceptionForHR(hr); ILAVVideoSettings vsett = vlavvideo as ILAVVideoSettings; if (vsett != null) { //we only want to set it for MB hr = vsett.SetRuntimeConfig(true); DsError.ThrowExceptionForHR(hr); _logger.Debug("GPU Model: {0}", VideoConfigurationUtils.GpuModel); LAVHWAccel configuredMode = VideoConfigurationUtils.GetHwaMode( _mbtConfig.Configuration.InternalPlayerConfiguration.VideoConfig, _customEvrPresenterLoaded); LAVHWAccel testme = vsett.GetHWAccel(); _logger.Debug("Current HWA Mode: {0} Desired Mode: {1}", testme, configuredMode); if (testme != configuredMode) { hr = vsett.SetHWAccel(configuredMode); DsError.ThrowExceptionForHR(hr); } foreach (string c in DirectShowPlayer.GetLAVVideoCodecs()) { LAVVideoCodec codec = (LAVVideoCodec)Enum.Parse(typeof(LAVVideoCodec), c); bool isEnabled = vsett.GetFormatConfiguration(codec); if ( _mbtConfig.Configuration.InternalPlayerConfiguration.VideoConfig.EnabledCodecs .Contains(c)) { if (!isEnabled) { _logger.Debug("Enable support for: {0}", c); hr = vsett.SetFormatConfiguration(codec, true); DsError.ThrowExceptionForHR(hr); } } else if (isEnabled) { _logger.Debug("Disable support for: {0}", c); hr = vsett.SetFormatConfiguration(codec, false); DsError.ThrowExceptionForHR(hr); } } foreach (string hwaCodec in DirectShowPlayer.GetLAVVideoHwaCodecs()) { LAVVideoHWCodec codec = (LAVVideoHWCodec)Enum.Parse(typeof(LAVVideoHWCodec), hwaCodec); bool hwaIsEnabled = vsett.GetHWAccelCodec(codec); if ( _mbtConfig.Configuration.InternalPlayerConfiguration.VideoConfig.HwaEnabledCodecs .Contains(hwaCodec)) { if (!hwaIsEnabled) { _logger.Debug("Enable HWA support for: {0}", hwaCodec); hr = vsett.SetHWAccelCodec(codec, true); DsError.ThrowExceptionForHR(hr); } } else if (hwaIsEnabled) { _logger.Debug("Disable HWA support for: {0}", hwaCodec); hr = vsett.SetHWAccelCodec(codec, false); DsError.ThrowExceptionForHR(hr); } } if (!vsett.GetDVDVideoSupport()) { _logger.Debug("Enable DVD support."); hr = vsett.SetDVDVideoSupport(true); DsError.ThrowExceptionForHR(hr); } int hwaRes = vsett.GetHWAccelResolutionFlags(); if (hwaRes != _mbtConfig.Configuration.InternalPlayerConfiguration.VideoConfig.HwaResolution && _mbtConfig.Configuration.InternalPlayerConfiguration.VideoConfig.HwaResolution > 0) { _logger.Debug("Change HWA resolution support from {0} to {1}.", hwaRes, _mbtConfig.Configuration.InternalPlayerConfiguration.VideoConfig.HwaResolution); hr = vsett.SetHWAccelResolutionFlags( VideoConfigurationUtils.GetHwaResolutions( _mbtConfig.Configuration.InternalPlayerConfiguration.VideoConfig)); DsError.ThrowExceptionForHR(hr); } hr = vsett.SetTrayIcon( _mbtConfig.Configuration.InternalPlayerConfiguration.VideoConfig.ShowTrayIcon); DsError.ThrowExceptionForHR(hr); } } decIn = DsFindPin.ByDirection((DirectShowLib.IBaseFilter)_lavvideo, PinDirection.Input, 0); if (decIn != null) { hr = _filterGraph.ConnectDirect(pins[0], decIn, null); DsError.ThrowExceptionForHR(hr); decOut = DsFindPin.ByDirection((DirectShowLib.IBaseFilter)_lavvideo, PinDirection.Output, 0); if (enableXySubFilter) //this flag indicates whether we should handle subtitle rendering { var xySubFilterSucceeded = false; // Load xySubFilter if configured and if madvr succeeded if (enableMadvr || _customEvrPresenterLoaded) { try { _xySubFilter = _playerWrapper.PrivateCom.GetObject(typeof(XySubFilter).GUID, true); //new XySubFilter(); var vxySubFilter = _xySubFilter as DirectShowLib.IBaseFilter; if (vxySubFilter != null) { hr = m_graph.AddFilter(vxySubFilter, "xy-SubFilter"); DsError.ThrowExceptionForHR(hr); } xySubFilterSucceeded = true; } catch (Exception ex) { _logger.ErrorException("Error adding xy-SubFilter filter", ex); } } // Fallback to xyVsFilter if (!xySubFilterSucceeded) { try { _xyVsFilter = _playerWrapper.PrivateCom.GetObject(typeof(XYVSFilter).GUID, true); //new XYVSFilter(); var vxyVsFilter = _xyVsFilter as DirectShowLib.IBaseFilter; if (vxyVsFilter != null) { hr = m_graph.AddFilter(vxyVsFilter, "xy-VSFilter"); DsError.ThrowExceptionForHR(hr); } } catch (Exception ex) { _logger.ErrorException("Error adding xy-VSFilter filter", ex); } } if (_xyVsFilter != null) //If using VSFilter { //insert xyVsFilter b/w LAV Video and the renderer rendIn = DsFindPin.ByName((DirectShowLib.IBaseFilter)_xyVsFilter, "Video"); //connect it to VSFilter if (decOut != null && rendIn != null) { hr = _filterGraph.ConnectDirect(decOut, rendIn, null); DsError.ThrowExceptionForHR(hr); CleanUpInterface(rendIn); CleanUpInterface(decOut); rendIn = null; decOut = null; } //grab xyVsFilter's output pin so it can be connected to the renderer decOut = DsFindPin.ByDirection((DirectShowLib.IBaseFilter)_xyVsFilter, PinDirection.Output, 0); } } if (_madvr != null) { rendIn = DsFindPin.ByDirection((DirectShowLib.IBaseFilter)_madvr, PinDirection.Input, 0); } else { rendIn = DsFindPin.ByDirection((DirectShowLib.IBaseFilter)_mPEvr, PinDirection.Input, 0); } if (decOut != null && rendIn != null) { hr = _filterGraph.ConnectDirect(decOut, rendIn, null); DsError.ThrowExceptionForHR(hr); needsRender = false; break; } } } catch (Exception ex) { _logger.ErrorException("Error adding LAV Video filter", ex); } #endregion } else if (mediaTypes[m] == DirectShowLib.MediaType.Audio) { #region Audio //we have an audio pin so add a renderer and decoder switch (_mbtConfig.Configuration.InternalPlayerConfiguration.AudioConfig.Renderer) { case AudioRendererChoice.Reclock: try { _reclockAudioRenderer = new ReclockAudioRenderer(); var aRenderer = _reclockAudioRenderer as DirectShowLib.IBaseFilter; if (aRenderer != null) { hr = m_graph.AddFilter(aRenderer, "Reclock Audio Renderer"); DsError.ThrowExceptionForHR(hr); useDefaultRenderer = false; _logger.Debug("Added reclock audio renderer"); } } catch (Exception ex) { _logger.ErrorException("Error adding reclock filter", ex); } break; case AudioRendererChoice.WASAPI: try { _wasapiAR = _playerWrapper.PrivateCom.GetObject(typeof(MPAudioFilter).GUID, true); var aRenderer = _wasapiAR as DirectShowLib.IBaseFilter; if (aRenderer != null) { hr = m_graph.AddFilter(aRenderer, "WASAPI Audio Renderer"); DsError.ThrowExceptionForHR(hr); useDefaultRenderer = false; _logger.Debug("Added WASAPI audio renderer"); IMPAudioRendererConfig arSett = aRenderer as IMPAudioRendererConfig; if (arSett != null) { arSett.SetInt(MPARSetting.WASAPI_MODE, (int)AUDCLNT_SHAREMODE.EXCLUSIVE); arSett.SetBool(MPARSetting.WASAPI_EVENT_DRIVEN, _mbtConfig.Configuration.InternalPlayerConfiguration.AudioConfig.UseWasapiEventMode); _logger.Debug("Set WASAPI use event mode: {0}", _mbtConfig.Configuration.InternalPlayerConfiguration.AudioConfig.UseWasapiEventMode); arSett.SetString(MPARSetting.SETTING_AUDIO_DEVICE, _mbtConfig.Configuration.InternalPlayerConfiguration.AudioConfig.AudioDevice); _logger.Debug("Set WASAPI audio device: {0}", _mbtConfig.Configuration.InternalPlayerConfiguration.AudioConfig.AudioDevice); SpeakerConfig sc = SpeakerConfig.Stereo; //use stereo for maxium compat Enum.TryParse<SpeakerConfig>(_mbtConfig.Configuration.InternalPlayerConfiguration.AudioConfig.SpeakerLayout, out sc); arSett.SetInt(MPARSetting.SPEAKER_CONFIG, (int)sc); _logger.Debug("Set WASAPI speaker config: {0}", sc); //audSett.SetSpeakerMatchOutput(true); arSett.SetBool(MPARSetting.ALLOW_BITSTREAMING, true); arSett.SetInt(MPARSetting.USE_FILTERS, _mbtConfig.Configuration.InternalPlayerConfiguration.AudioConfig.WasapiARFilters); _logger.Debug("Set WASAPI filter config: {0}", _mbtConfig.Configuration.InternalPlayerConfiguration.AudioConfig.WasapiARFilters); AC3Encoding a3 = (AC3Encoding)_mbtConfig.Configuration.InternalPlayerConfiguration.AudioConfig.Ac3EncodingMode; arSett.SetInt(MPARSetting.AC3_ENCODING, (int)a3); _logger.Debug("Set WASAPI AC3 encoding: {0}", a3); arSett.SetBool(MPARSetting.ENABLE_TIME_STRETCHING, _mbtConfig.Configuration.InternalPlayerConfiguration.AudioConfig.EnableTimeStretching); _logger.Debug("Set WASAPI use time stretching: {0}", _mbtConfig.Configuration.InternalPlayerConfiguration.AudioConfig.EnableTimeStretching); arSett.SetInt(MPARSetting.OUTPUT_BUFFER_LENGTH, _mbtConfig.Configuration.InternalPlayerConfiguration.AudioConfig.OutputBufferSize); _logger.Debug("Set WASAPI buffer: {0}", _mbtConfig.Configuration.InternalPlayerConfiguration.AudioConfig.OutputBufferSize); } } } catch (Exception ex) { _logger.ErrorException("Error adding WASAPI audio filter", ex); } break; } if (useDefaultRenderer) { AddDefaultAudioRenderer(); } try { _lavaudio = _playerWrapper.PrivateCom.GetObject(typeof(LAVAudio).GUID, true); // new LAVAudio(); var vlavaudio = _lavaudio as DirectShowLib.IBaseFilter; if (vlavaudio != null) { _logger.Debug("Add LAVAudio to the graph."); hr = m_graph.AddFilter(vlavaudio, "LAV Audio Decoder"); DsError.ThrowExceptionForHR(hr); ILAVAudioSettings asett = vlavaudio as ILAVAudioSettings; if (asett != null) { _logger.Debug("Enable LAVAudio Runtime Config"); //we only want to set it for MB hr = asett.SetRuntimeConfig(true); DsError.ThrowExceptionForHR(hr); foreach (string c in DirectShowPlayer.GetLAVAudioCodecs()) { LAVAudioCodec codec = (LAVAudioCodec)Enum.Parse(typeof(LAVAudioCodec), c); bool isEnabled = asett.GetFormatConfiguration(codec); if ( _mbtConfig.Configuration.InternalPlayerConfiguration.AudioConfig.EnabledCodecs.Contains( c)) { if (!isEnabled) { _logger.Debug("Enable support for: {0}", c); hr = asett.SetFormatConfiguration(codec, true); DsError.ThrowExceptionForHR(hr); } } else if (isEnabled) { _logger.Debug("Disable support for: {0}", c); hr = asett.SetFormatConfiguration(codec, false); DsError.ThrowExceptionForHR(hr); } } //enable/disable bitstreaming if ((_mbtConfig.Configuration.InternalPlayerConfiguration.AudioConfig.AudioBitstreaming & BitstreamChoice.SPDIF) == BitstreamChoice.SPDIF) { _logger.Debug("Enable LAVAudio S/PDIF bitstreaming"); hr = asett.SetBitstreamConfig(LAVBitstreamCodec.AC3, true); DsError.ThrowExceptionForHR(hr); hr = asett.SetBitstreamConfig(LAVBitstreamCodec.DTS, true); DsError.ThrowExceptionForHR(hr); } if ((_mbtConfig.Configuration.InternalPlayerConfiguration.AudioConfig.AudioBitstreaming & BitstreamChoice.HDMI) == BitstreamChoice.HDMI) { _logger.Debug("Enable LAVAudio HDMI bitstreaming"); hr = asett.SetBitstreamConfig(LAVBitstreamCodec.EAC3, true); DsError.ThrowExceptionForHR(hr); hr = asett.SetBitstreamConfig(LAVBitstreamCodec.TRUEHD, true); DsError.ThrowExceptionForHR(hr); hr = asett.SetBitstreamConfig(LAVBitstreamCodec.DTSHD, true); DsError.ThrowExceptionForHR(hr); } if (_mbtConfig.Configuration.InternalPlayerConfiguration.AudioConfig.Delay > 0) { _logger.Debug("Set LAVAudio audio delay: {0}", _mbtConfig.Configuration.InternalPlayerConfiguration.AudioConfig.Delay); hr = asett.SetAudioDelay(true, _mbtConfig.Configuration.InternalPlayerConfiguration.AudioConfig.Delay); DsError.ThrowExceptionForHR(hr); } _logger.Debug("Set LAVAudio auto AV Sync: {0}", _mbtConfig.Configuration.InternalPlayerConfiguration.AudioConfig.EnableAutoSync); hr = asett.SetAutoAVSync( _mbtConfig.Configuration.InternalPlayerConfiguration.AudioConfig.EnableAutoSync); DsError.ThrowExceptionForHR(hr); _logger.Debug("Set LAVAudio Expand61: {0}", _mbtConfig.Configuration.InternalPlayerConfiguration.AudioConfig.Expand61); hr = asett.SetExpand61(_mbtConfig.Configuration.InternalPlayerConfiguration.AudioConfig.Expand61); DsError.ThrowExceptionForHR(hr); _logger.Debug("Set LAVAudio ExpandMono: {0}", _mbtConfig.Configuration.InternalPlayerConfiguration.AudioConfig.ExpandMono); hr = asett.SetExpandMono( _mbtConfig.Configuration.InternalPlayerConfiguration.AudioConfig.ExpandMono); DsError.ThrowExceptionForHR(hr); _logger.Debug("Set LAVAudio ConvertToStandardLayout: {0}", _mbtConfig.Configuration.InternalPlayerConfiguration.AudioConfig.ConvertToStandardLayout); hr = asett.SetOutputStandardLayout( _mbtConfig.Configuration.InternalPlayerConfiguration.AudioConfig.ConvertToStandardLayout); DsError.ThrowExceptionForHR(hr); _logger.Debug("Set LAVAudio audio EnableDRC: {0}", _mbtConfig.Configuration.InternalPlayerConfiguration.AudioConfig.EnableDRC); hr = asett.SetDRC(_mbtConfig.Configuration.InternalPlayerConfiguration.AudioConfig.EnableDRC, _mbtConfig.Configuration.InternalPlayerConfiguration.AudioConfig.DRCLevel); DsError.ThrowExceptionForHR(hr); _logger.Debug("Set LAVAudio audio ShowTrayIcon: {0}", _mbtConfig.Configuration.InternalPlayerConfiguration.AudioConfig.ShowTrayIcon); hr = asett.SetTrayIcon( _mbtConfig.Configuration.InternalPlayerConfiguration.AudioConfig.ShowTrayIcon); DsError.ThrowExceptionForHR(hr); bool mixingEnabled = asett.GetMixingEnabled(); if (mixingEnabled != _mbtConfig.Configuration.InternalPlayerConfiguration.AudioConfig.EnablePCMMixing) { _logger.Debug("Set LAVAudio EnablePCMMixing: {0}", _mbtConfig.Configuration.InternalPlayerConfiguration.AudioConfig.EnablePCMMixing); hr = asett.SetMixingEnabled(!mixingEnabled); DsError.ThrowExceptionForHR(hr); } if (_mbtConfig.Configuration.InternalPlayerConfiguration.AudioConfig.EnablePCMMixing) { _logger.Debug("Set LAVAudio MixingSetting: {0}", _mbtConfig.Configuration.InternalPlayerConfiguration.AudioConfig.MixingSetting); LAVAudioMixingFlag amf = (LAVAudioMixingFlag) _mbtConfig.Configuration.InternalPlayerConfiguration.AudioConfig.MixingSetting; hr = asett.SetMixingFlags(amf); DsError.ThrowExceptionForHR(hr); _logger.Debug("Set LAVAudio MixingEncoding: {0}", _mbtConfig.Configuration.InternalPlayerConfiguration.AudioConfig.MixingEncoding); LAVAudioMixingMode amm = (LAVAudioMixingMode) Enum.Parse(typeof(LAVAudioMixingMode), _mbtConfig.Configuration.InternalPlayerConfiguration.AudioConfig.MixingEncoding); hr = asett.SetMixingMode(amm); DsError.ThrowExceptionForHR(hr); _logger.Debug("Set LAVAudio MixingLayout: {0}", _mbtConfig.Configuration.InternalPlayerConfiguration.AudioConfig.MixingLayout); LAVAudioMixingLayout aml = (LAVAudioMixingLayout) Enum.Parse(typeof(LAVAudioMixingLayout), _mbtConfig.Configuration.InternalPlayerConfiguration.AudioConfig.MixingLayout); hr = asett.SetMixingLayout(aml); DsError.ThrowExceptionForHR(hr); _logger.Debug( "Set LAVAudio LfeMixingLevel: {0} CenterMixingLevel: {1} SurroundMixingLevel: {2}", _mbtConfig.Configuration.InternalPlayerConfiguration.AudioConfig.LfeMixingLevel, _mbtConfig.Configuration.InternalPlayerConfiguration.AudioConfig.CenterMixingLevel, _mbtConfig.Configuration.InternalPlayerConfiguration.AudioConfig.SurroundMixingLevel); int lfe, center, surround; //convert to the # that LAV Audio expects lfe = (int) (_mbtConfig.Configuration.InternalPlayerConfiguration.AudioConfig.LfeMixingLevel * 10000.01); center = (int) (_mbtConfig.Configuration.InternalPlayerConfiguration.AudioConfig.CenterMixingLevel * 10000.01); surround = (int) (_mbtConfig.Configuration.InternalPlayerConfiguration.AudioConfig .SurroundMixingLevel * 10000.01); hr = asett.SetMixingLevels(center, surround, lfe); DsError.ThrowExceptionForHR(hr); } for (int i = 0; i < (int)LAVBitstreamCodec.NB; i++) { LAVBitstreamCodec codec = (LAVBitstreamCodec)i; bool isEnabled = asett.GetBitstreamConfig(codec); _logger.Log(LogSeverity.Debug, "{0} bitstreaming: {1}", codec, isEnabled); } } } } catch (Exception ex) { _logger.ErrorException("Error adding LAV Audio filter", ex); } decIn = DsFindPin.ByDirection((DirectShowLib.IBaseFilter)_lavaudio, PinDirection.Input, 0); if (decIn != null) { hr = _filterGraph.ConnectDirect(pins[0], decIn, null); if (hr < 0) //LAV cannot handle this audio type { _logger.Warn("LAV Audio could not decode audio media type."); } else { //DsError.ThrowExceptionForHR(hr); decOut = DsFindPin.ByDirection((DirectShowLib.IBaseFilter)_lavaudio, PinDirection.Output, 0); } rendIn = DsFindPin.ByDirection(AudioRenderer, PinDirection.Input, 0); if (decOut != null && rendIn != null) { hr = _filterGraph.ConnectDirect(decOut, rendIn, null); if (hr == -2004287474 && _wasapiAR != null) //AUDCLNT_E_EXCLUSIVE_MODE_NOT_ALLOWED { IMPAudioRendererConfig arSett = _wasapiAR as IMPAudioRendererConfig; if (arSett != null) { arSett.SetInt(MPARSetting.WASAPI_MODE, (int)AUDCLNT_SHAREMODE.SHARED); _logger.Warn("WASAPI AR failed to connected in exclusive mode, check device properties"); hr = _filterGraph.ConnectDirect(decOut, rendIn, null); } } DsError.ThrowExceptionForHR(hr); needsRender = false; break; } } #endregion } else if (mediaTypes[m] == SubtitleMediaType /*DirectShowLib.MediaType.Subtitle*/) { #region subtitles if (_xySubFilter != null) { rendIn = DsFindPin.ByDirection((DirectShowLib.IBaseFilter)_xySubFilter, PinDirection.Input, 0); } else if(_xyVsFilter != null) { rendIn = DsFindPin.ByName((DirectShowLib.IBaseFilter)_xyVsFilter, "Input"); } if (rendIn != null) { hr = _filterGraph.ConnectDirect(pins[0], rendIn, null); DsError.ThrowExceptionForHR(hr); needsRender = false; break; } #endregion } else if (mediaTypes[m] == DvdSubpictureMediaType) { #region DVD Subpicture if (_lavvideo != null) { rendIn = DsFindPin.ByName((DirectShowLib.IBaseFilter)_lavvideo, "Subtitle Input"); if (rendIn != null) { hr = _filterGraph.ConnectDirect(pins[0], rendIn, null); DsError.ThrowExceptionForHR(hr); needsRender = false; break; } } #endregion } } finally { CleanUpInterface(decIn); CleanUpInterface(decOut); CleanUpInterface(rendIn); } } if (needsRender) { if (_filterGraph.RenderEx(pins[0], AMRenderExFlags.RenderToExistingRenderers, IntPtr.Zero) >= 0) pinsRendered++; } else pinsRendered++; Marshal.ReleaseComObject(pins[0]); } Marshal.ReleaseComObject(pEnum); if (pinsRendered == 0) { throw new Exception("Could not render any streams from the source Uri"); } _logger.Debug("Completed RenderStreams with {0} pins.", pinsRendered); if (_item.IsVideo) { SetVideoWindow(enableMadvrExclusiveMode); if (_mPEvr != null) SetEvrVppMode(_mPEvr); } }
private void AddMadVr() { int hr = 0; try { _madvr = URCOMLoader.Instance.GetObject(typeof(MadVR).GUID, true); // new MadVR(); var vmadvr = _madvr as DirectShowLib.IBaseFilter; if (vmadvr != null) { hr = _graph.AddFilter(vmadvr, "MadVR Video Renderer"); DsError.ThrowExceptionForHR(hr); try { MadVRSettings msett = new MadVRSettings(_madvr); bool smoothMotion = msett.GetBool("smoothMotionEnabled"); if (smoothMotion != _mbtConfig.Configuration.InternalPlayerConfiguration.VideoConfig .UseMadVrSmoothMotion) msett.SetBool("smoothMotionEnabled", _mbtConfig.Configuration.InternalPlayerConfiguration.VideoConfig .UseMadVrSmoothMotion); if ( string.Compare(msett.GetString("smoothMotionMode"), _mbtConfig.Configuration.InternalPlayerConfiguration.VideoConfig .MadVrSmoothMotionMode, true) != 0) { bool success = msett.SetString("smoothMotionMode", _mbtConfig.Configuration.InternalPlayerConfiguration.VideoConfig .MadVrSmoothMotionMode); } MFNominalRange levels = (MFNominalRange)_mbtConfig.Configuration.InternalPlayerConfiguration.VideoConfig.NominalRange; //string madVrLevelInitial = msett.GetString("levels"); //switch (levels) //{ // case MFNominalRange.MFNominalRange_0_255: // msett.SetString("levels", "PC Levels"); // break; // case MFNominalRange.MFNominalRange_16_235: // msett.SetString("levels", "TV Levels"); // break; //} //string madVrLevel = msett.GetString("levels"); //if (string.Compare(madVrLevel, madVrLevelInitial, false) != 0) // _logger.Debug("Changed madVR levels from {0} to {1}", madVrLevelInitial, madVrLevel); } catch (Exception ex) { _logger.ErrorException("Error configuring madVR", ex); } } } catch (Exception ex) { _logger.ErrorException("Error adding MadVR filter", ex); } }