/// <summary> /// Checks if the pin connections can be kept, or if a graph rebuilding is necessary. /// </summary> /// <param name="baseFilter">Filter to check</param> /// <returns>True if graph needs to be rebuilt</returns> private static bool GraphNeedsRebuild(IBaseFilter baseFilter) { IEnumPins pinEnum; int hr = baseFilter.EnumPins(out pinEnum); if (hr != 0 || pinEnum == null) { return(true); } IPin[] pins = new IPin[1]; IntPtr ptrFetched = Marshal.AllocCoTaskMem(4); for (; ;) { hr = pinEnum.Next(1, pins, ptrFetched); if (hr != 0 || Marshal.ReadInt32(ptrFetched) == 0) { break; } try { IPin other; if (pins[0].ConnectedTo(out other) == 0 && other != null) { try { PinInfo pinInfo; pins[0].QueryPinInfo(out pinInfo); FilterInfo filterInfo = FilterGraphTools.QueryFilterInfoAndFree(pinInfo.filter); try { if (!QueryConnect(pins[0], other)) { ServiceRegistration.Get <ILogger>().Info("Graph needs a rebuild. Filter: {0}, Pin: {1}", filterInfo.achName, pinInfo.name); return(true); } } finally { FilterGraphTools.FreePinInfo(pinInfo); } } finally { Marshal.ReleaseComObject(other); } } } finally { Marshal.ReleaseComObject(pins[0]); } } Marshal.ReleaseComObject(pinEnum); Marshal.FreeCoTaskMem(ptrFetched); ServiceRegistration.Get <ILogger>().Info("Graph does not need a rebuild"); return(false); }
/// <summary> /// Disconnects all pins of all filters in graph. /// </summary> /// <param name="graphBuilder">IGraphBuilder</param> /// <param name="filter">Current IBaseFilter in graph</param> bool DisconnectAllPins(IGraphBuilder graphBuilder, IBaseFilter filter) { IEnumPins pinEnum; int hr = filter.EnumPins(out pinEnum); if (hr != 0 || pinEnum == null) { return(false); } FilterInfo info = FilterGraphTools.QueryFilterInfoAndFree(filter); ServiceRegistration.Get <ILogger>().Info("Disconnecting all pins from filter {0}", info.achName); bool allDisconnected = true; IntPtr ptrFetched = Marshal.AllocCoTaskMem(4); for (; ;) { IPin[] pins = new IPin[1]; hr = pinEnum.Next(1, pins, ptrFetched); if (hr != 0 || Marshal.ReadInt32(ptrFetched) == 0) { break; } PinInfo pinInfo; pins[0].QueryPinInfo(out pinInfo); if (pinInfo.dir == PinDirection.Output) { if (!DisconnectPin(graphBuilder, pins[0])) { allDisconnected = false; } } FilterGraphTools.FreePinInfo(pinInfo); Marshal.ReleaseComObject(pins[0]); } Marshal.ReleaseComObject(pinEnum); Marshal.FreeCoTaskMem(ptrFetched); return(allDisconnected); }
/// <summary> /// Enumerates streams from video (audio, subtitles). /// </summary> /// <param name="forceRefresh">Force refresh</param> /// <returns><c>true</c> if information has been changed.</returns> protected virtual bool EnumerateStreams(bool forceRefresh) { if (_graphBuilder == null || !_initialized) { return(false); } StreamInfoHandler audioStreams; StreamInfoHandler subtitleStreams; StreamInfoHandler titleStreams; lock (SyncObj) { audioStreams = _streamInfoAudio; subtitleStreams = _streamInfoSubtitles; titleStreams = _streamInfoTitles; } if (forceRefresh || audioStreams == null || subtitleStreams == null || titleStreams == null) { audioStreams = new StreamInfoHandler(); subtitleStreams = new StreamInfoHandler(); titleStreams = new StreamInfoHandler(); // Release stream selectors ReleaseStreamSelectors(); _streamSelectors = FilterGraphTools.FindFiltersByInterface <IAMStreamSelect>(_graphBuilder); foreach (IAMStreamSelect streamSelector in _streamSelectors) { FilterInfo fi = FilterGraphTools.QueryFilterInfoAndFree(((IBaseFilter)streamSelector)); int streamCount; streamSelector.Count(out streamCount); for (int i = 0; i < streamCount; ++i) { IntPtr pp_punk = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(IntPtr))); IntPtr pp_object = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(IntPtr))); IntPtr pp_name = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(IntPtr))); IntPtr pp_groupNumber = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(IntPtr))); IntPtr pp_lcid = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(IntPtr))); IntPtr pp_selectInfoFlags = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(IntPtr))); IntPtr pp_mediaType = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(IntPtr))); int hr = streamSelector.Info(i, pp_mediaType, pp_selectInfoFlags, pp_lcid, pp_groupNumber, pp_name, pp_punk, pp_object); new HRESULT(hr).Throw(); // We get a pointer to pointer for a structure. AMMediaType mediaType = (AMMediaType)Marshal.PtrToStructure(Marshal.ReadIntPtr(pp_mediaType), typeof(AMMediaType)); int groupNumber = Marshal.ReadInt32(pp_groupNumber); int lcid = Marshal.ReadInt32(pp_lcid); string name = Marshal.PtrToStringAuto(Marshal.ReadIntPtr(pp_name)); // If stream does not contain a LCID, try a lookup from stream name. if (lcid == 0) { lcid = LookupLcidFromName(name); } ServiceRegistration.Get <ILogger>().Debug("Stream {4}|{0}: MajorType {1}; Name {2}; PWDGroup: {3}; LCID: {5}", i, mediaType.majorType, name, groupNumber, fi.achName, lcid); StreamInfo currentStream = new StreamInfo(streamSelector, i, name, lcid); switch ((StreamGroup)groupNumber) { case StreamGroup.Video: break; case StreamGroup.Audio: if (mediaType.majorType == MediaType.AnalogAudio || mediaType.majorType == MediaType.Audio) { String streamName = name.Trim(); String streamAppendix; if (!CodecHandler.MediaSubTypes.TryGetValue(mediaType.subType, out streamAppendix)) { streamAppendix = string.Empty; } // if audio information is available via WaveEx format, query the channel count if (mediaType.formatType == FormatType.WaveEx && mediaType.formatPtr != IntPtr.Zero) { WaveFormatEx waveFormatEx = (WaveFormatEx)Marshal.PtrToStructure(mediaType.formatPtr, typeof(WaveFormatEx)); currentStream.ChannelCount = waveFormatEx.nChannels; streamAppendix = String.Format("{0} {1}ch", streamAppendix, currentStream.ChannelCount); } if (!string.IsNullOrEmpty(streamAppendix)) { currentStream.Name = String.Format("{0} ({1})", streamName, streamAppendix); } audioStreams.AddUnique(currentStream); } break; case StreamGroup.Subtitle: { currentStream.IsAutoSubtitle = currentStream.Name.ToLowerInvariant().Contains(FORCED_SUBTITLES); subtitleStreams.AddUnique(currentStream, true); } break; case StreamGroup.VsFilterSubtitle: case StreamGroup.VsFilterSubtitleOptions: case StreamGroup.DirectVobSubtitle: subtitleStreams.AddUnique(currentStream, true); break; case StreamGroup.MatroskaEdition: // This is a MKV Edition handled by Haali splitter titleStreams.AddUnique(currentStream, true); break; } // Free MediaType and references DsUtils.FreeAMMediaType(mediaType); Marshal.FreeHGlobal(pp_punk); Marshal.FreeHGlobal(pp_object); Marshal.FreeHGlobal(pp_name); Marshal.FreeHGlobal(pp_groupNumber); Marshal.FreeHGlobal(pp_lcid); Marshal.FreeHGlobal(pp_selectInfoFlags); Marshal.FreeHGlobal(pp_mediaType); } } SetPreferedAudio_intern(ref audioStreams, false); SetPreferredSubtitle_intern(ref subtitleStreams); lock (SyncObj) { _streamInfoAudio = audioStreams; _streamInfoSubtitles = subtitleStreams; _streamInfoTitles = titleStreams; } return(true); } return(false); }
/// <summary> /// Reconnects all filters in graph. /// </summary> /// <param name="graphBuilder">IGraphBuilder</param> /// <param name="filter">Current IBaseFilter in graph</param> static void ReConnectAll(IGraphBuilder graphBuilder, IBaseFilter filter) { IEnumPins pinEnum; FilterInfo info = FilterGraphTools.QueryFilterInfoAndFree(filter); IntPtr ptrFetched = Marshal.AllocCoTaskMem(4); int hr = filter.EnumPins(out pinEnum); if ((hr == 0) && (pinEnum != null)) { ServiceRegistration.Get <ILogger>().Info("got pins"); IPin[] pins = new IPin[1]; int iFetched; int iPinNo = 0; do { // Get the next pin iPinNo++; hr = pinEnum.Next(1, pins, ptrFetched); // In case of error stop the pin enumeration if (hr != 0) { break; } iFetched = Marshal.ReadInt32(ptrFetched); if (iFetched == 1 && pins[0] != null) { PinInfo pinInfo; hr = pins[0].QueryPinInfo(out pinInfo); if (hr == 0) { ServiceRegistration.Get <ILogger>().Info(" got pin#{0}:{1}", iPinNo - 1, pinInfo.name); FilterGraphTools.FreePinInfo(pinInfo); } else { ServiceRegistration.Get <ILogger>().Info(" got pin:?"); } PinDirection pinDir; pins[0].QueryDirection(out pinDir); if (pinDir == PinDirection.Output) { IntPtr other_ptr; hr = pins[0].ConnectedTo(out other_ptr); if (hr == 0 && other_ptr != IntPtr.Zero) { ServiceRegistration.Get <ILogger>().Info("Reconnecting {0}:{1}", info.achName, pinInfo.name); hr = graphBuilder.Reconnect(pins[0]); if (hr != 0) { ServiceRegistration.Get <ILogger>().Warn("Reconnect failed: {0}:{1}, code: 0x{2:x}", info.achName, pinInfo.name, hr); } IPin other = Marshal.GetObjectForIUnknown(other_ptr) as IPin; PinInfo otherPinInfo; other.QueryPinInfo(out otherPinInfo); ReConnectAll(graphBuilder, otherPinInfo.filter); FilterGraphTools.FreePinInfo(otherPinInfo); Marshal.ReleaseComObject(other); } } Marshal.ReleaseComObject(pins[0]); } else { ServiceRegistration.Get <ILogger>().Info("no pins?"); break; } }while (iFetched == 1); FilterGraphTools.TryRelease(ref pinEnum); Marshal.FreeCoTaskMem(ptrFetched); } }
/// <summary> /// Enumerates streams from video (audio, subtitles). /// </summary> /// <param name="forceRefresh">Force refresh</param> /// <returns><c>true</c> if information has been changed.</returns> protected virtual bool EnumerateStreams(bool forceRefresh) { if (_graphBuilder == null || !_initialized) { return(false); } StreamInfoHandler audioStreams; StreamInfoHandler subtitleStreams; StreamInfoHandler titleStreams; lock (SyncObj) { audioStreams = _streamInfoAudio; subtitleStreams = _streamInfoSubtitles; titleStreams = _streamInfoTitles; } if (forceRefresh || audioStreams == null || subtitleStreams == null || titleStreams == null) { audioStreams = new StreamInfoHandler(); subtitleStreams = new StreamInfoHandler(); titleStreams = new StreamInfoHandler(); // Release stream selectors ReleaseStreamSelectors(); _streamSelectors = FilterGraphTools.FindFiltersByInterface <IAMStreamSelect>(_graphBuilder); foreach (IAMStreamSelect streamSelector in _streamSelectors) { FilterInfo fi = FilterGraphTools.QueryFilterInfoAndFree(((IBaseFilter)streamSelector)); int streamCount; streamSelector.Count(out streamCount); for (int i = 0; i < streamCount; ++i) { AMMediaType mediaType; AMStreamSelectInfoFlags selectInfoFlags; int groupNumber, lcid; string name; object pppunk, ppobject; streamSelector.Info(i, out mediaType, out selectInfoFlags, out lcid, out groupNumber, out name, out pppunk, out ppobject); // If stream does not contain a LCID, try a lookup from stream name. if (lcid == 0) { lcid = LookupLcidFromName(name); } ServiceRegistration.Get <ILogger>().Debug("Stream {4}|{0}: MajorType {1}; Name {2}; PWDGroup: {3}; LCID: {5}", i, mediaType.majorType, name, groupNumber, fi.achName, lcid); StreamInfo currentStream = new StreamInfo(streamSelector, i, name, lcid); switch ((StreamGroup)groupNumber) { case StreamGroup.Video: break; case StreamGroup.Audio: if (mediaType.majorType == MediaType.AnalogAudio || mediaType.majorType == MediaType.Audio) { String streamName = name.Trim(); String streamAppendix; if (!CodecHandler.MediaSubTypes.TryGetValue(mediaType.subType, out streamAppendix)) { streamAppendix = string.Empty; } // if audio information is available via WaveEx format, query the channel count if (mediaType.formatType == FormatType.WaveEx && mediaType.formatPtr != IntPtr.Zero) { WaveFormatEx waveFormatEx = (WaveFormatEx)Marshal.PtrToStructure(mediaType.formatPtr, typeof(WaveFormatEx)); currentStream.ChannelCount = waveFormatEx.nChannels; streamAppendix = String.Format("{0} {1}ch", streamAppendix, currentStream.ChannelCount); } if (!string.IsNullOrEmpty(streamAppendix)) { currentStream.Name = String.Format("{0} ({1})", streamName, streamAppendix); } audioStreams.AddUnique(currentStream); } break; case StreamGroup.Subtitle: case StreamGroup.DirectVobSubtitle: subtitleStreams.AddUnique(currentStream, true); break; case StreamGroup.MatroskaEdition: // This is a MKV Edition handled by Haali splitter titleStreams.AddUnique(currentStream, true); break; } // Free MediaType and references FilterGraphTools.FreeAMMediaType(mediaType); } } lock (SyncObj) { _streamInfoAudio = audioStreams; _streamInfoSubtitles = subtitleStreams; _streamInfoTitles = titleStreams; } return(true); } return(false); }