/// <summary> /// Stellt die Verbindung zur properitären Schnittstelle her. /// </summary> /// <param name="tuner">Der Filter zur Hardware.</param> protected virtual void Open(TypedComIdentity <IBaseFilter> tuner) { // Connect once if (m_Device != IntPtr.Zero) { return; } // Attach to the tuner output pin to get the hardware index using (var pinRef = tuner.GetSinglePin(PinDirection.Output)) using (var pin = pinRef.MarshalToManaged()) { // Get the information var info = pin.Object.GetMediumArray(); if (info.Length < 1) { throw new InvalidOperationException("no information on attached Hardware"); } // Try to connect m_Device = bdaapiOpenHWIdx(1, info[0].Parameter1); if (m_Device.ToInt64() == -1) { m_Device = IntPtr.Zero; } if (m_Device == IntPtr.Zero) { throw new InvalidOperationException(string.Format("could not connect to properitary API ({0} Media reported, primary Medium is {1} ({2}, {3}))", info.Length, info[0].MediumIdentifier, info[0].Parameter1, info[0].Parameter2)); } } }
/// <summary> /// Erzeugt einen neuen Pin. /// </summary> /// <param name="filter">Zugehöriger Filter.</param> /// <param name="name">Der eigene Name.</param> /// <param name="mediaType">Das zu verwendende Datenformat.</param> public OutputPin(TypedComIdentity <IBaseFilter> filter, string name, MediaType mediaType) { // Remember m_Types = new MediaType[] { mediaType }; m_Filter = filter; m_Name = name; }
/// <summary> /// Ermittelt zu einem Filter einen ausgangsseitigen Steuerknoten der Topologie. /// </summary> /// <typeparam name="T">Die Art der benötigten Schnittstelle.</typeparam> /// <param name="filter">Ein Filter.</param> /// <param name="nodeType">Die Art des Knotens.</param> /// <returns>Der gewünschte Knoten.</returns> public static T GetOutputControlNode <T>(this TypedComIdentity <IBaseFilter> filter, uint nodeType) where T : class { // Validate if (filter == null) { throw new ArgumentNullException("filter"); } // Attach to alternate interface using (var instance = filter.MarshalToManaged()) { // Change type var topology = instance.Object as IBDATopology; if (topology == null) { return(null); } // Load var node = topology.GetControlNode(0, 1, nodeType); var result = node as T; // Cleanup if (result == null) { BDAEnvironment.Release(ref node); } // Report return(result); } }
/// <summary> /// Stellt die Verbindung zur properitären Schnittstelle her. /// </summary> /// <param name="tuner">Der Filter zur Hardware.</param> protected override void Open(TypedComIdentity <IBaseFilter> tuner) { // Did it all if (m_CIOpen) { return; } // Forward base.Open(tuner); // Process var error = bdaapiOpenCIWithoutPointer(Device); if (APIErrorCodes.Success != error) { throw new DVBException(error.ToString()); } // Remember m_CIOpen = true; // Just wait a bit if (m_OpenDelay > 0) { Thread.Sleep(m_OpenDelay); } }
/// <summary> /// Versucht den DVB.NET Datenstrom direkt mit dem zugehörigen Decoder zu verbinden. /// </summary> /// <param name="decoder">Ein manuell angelegter Decoder.</param> /// <param name="source">Der zu verwendende Ausgang.</param> /// <param name="mediaType">Das verwendete Format.</param> /// <returns>Gesetzt, wenn die Verbindung aufgebaut wurde.</returns> private bool TryDirectConnect(TypedComIdentity <IBaseFilter> decoder, OutputPin source, MediaType mediaType) { // In normal cases we should directly connect to the filter so try var connected = false; // Try manual connect decoder.InspectAllPins(p => p.QueryDirection() == PinDirection.Input, pin => { // Skip on error try { // Get the raw interface for the media type var type = mediaType.GetReference(); // Process using (var iFace = ComIdentity.Create <IPin>(pin)) source.Connect(iFace.Interface, type); // Did it connected = true; } catch (Exception) { } // First pin only - even if it can not be used! return(false); }); // Failed if (!connected) { return(false); } // Find the output of the decoder and render it decoder.InspectAllPins(p => p.QueryDirection() == PinDirection.Output, pin => { // Create helper using (var pinWrapper = ComIdentity.Create <IPin>(pin)) DirectShowObject.Render(pinWrapper.Interface); // Did it return(false); }); // Report return(connected); }
/// <summary> /// Erzeugt einen neuen Endpunkt. /// </summary> /// <param name="filter">Der zugehörige Filter.</param> /// <param name="createTIF">Gesetzt, wenn eine BDA Komponente eingebunden werden soll.</param> public InputPin(TypedComIdentity <IBaseFilter> filter, bool createTIF) { // Remember m_Filter = filter; // Create types m_Types = new[] { BDAEnvironment.TransportStreamMediaType1, BDAEnvironment.TransportStreamMediaType2 }; // Create optional output pins if (createTIF) { m_TIF = new OutputPin(m_Filter, "TIF", m_Types[0]); } }
/// <summary> /// Erzeugt eine neue Instanz. /// </summary> /// <typeparam name="DataType">Die Art der Daten.</typeparam> /// <param name="interface">Die zu verwendende Schnittstelle.</param> /// <returns>Eine neue Zugriffsinstanz.</returns> public static IKsPropertySet <DataType> Create <DataType>(IntPtr @interface) where DataType : struct { // None if (@interface == null) { return(null); } // Try to access the interface var com = ComIdentity.TryQueryInterface(@interface, typeof(IKsPropertySet)); if (com == IntPtr.Zero) { return(null); } // Be safe try { // Create the wrapper using (var typed = new TypedComIdentity <IKsPropertySet>(com)) { // No longer needed to release com = IntPtr.Zero; // Create wrapper var wrapper = typed.MarshalToManaged(); try { // Safe process return(new Typed <DataType>(wrapper)); } catch { // Cleanup wrapper.Dispose(); // Forward throw; } } } finally { // Cleanup BDAEnvironment.Release(ref com); } }
/// <summary> /// Verbindet diesen Ausgang mit dem Eingang eines beliebigen Filters. /// </summary> /// <param name="receiver">Der Filter, der die erzeugten Daten verarbeiten soll.</param> /// <param name="mediaType">Die Art der zu verwendenden Daten.</param> public void Connect(TypedComIdentity <IBaseFilter> receiver, MediaType mediaType) { // Attach to the one input pin var to = receiver.GetSinglePin(PinDirection.Input); try { // Process Connect(to.Interface, mediaType.GetReference()); } finally { // Cleanup BDAEnvironment.Release(ref to); } }
/// <summary> /// Legt die Speicherverwaltung fest. /// </summary> /// <param name="allocator">Die zu verwendende Speicherverwaltung.</param> public void SetMemAllocator(TypedComIdentity <IMemAllocator> allocator) { // Nothing to do if (allocator == null) { return; } if (m_MemPin == IntPtr.Zero) { return; } if (m_NotifySink == null) { return; } // Forward m_NotifySink(m_MemPin, allocator.Interface, false); }
/// <summary> /// Stellt die Verbindung zur properitären Schnittstelle her. /// </summary> /// <param name="tuner">Der Filter zur Hardware.</param> protected override void Open( TypedComIdentity<IBaseFilter> tuner ) { // Did it all if (m_CIOpen) return; // Forward base.Open( tuner ); // Process var error = bdaapiOpenCIWithoutPointer( Device ); if (APIErrorCodes.Success != error) throw new DVBException( error.ToString() ); // Remember m_CIOpen = true; // Just wait a bit if (m_OpenDelay > 0) Thread.Sleep( m_OpenDelay ); }
/// <summary> /// Ermittelt einen einzelnen Endpunkt. /// </summary> /// <param name="filter">Der zu betrachtende Filter.</param> /// <param name="direction">Die zu untersuchende Seite des Filters.</param> /// <returns>Eine Referenz auf den gewünschten Endpunkt.</returns> /// <exception cref="ArgumentNullException">Es wurde kein Filter angegeben.</exception> /// <exception cref="InvalidOperationException">Der angegeben Endpunkt existiert nicht.</exception> public static TypedComIdentity <IPin> GetSinglePin(this TypedComIdentity <IBaseFilter> filter, PinDirection direction) { // Validate if (filter == null) { throw new ArgumentNullException("filter"); } // Result to use TypedComIdentity <IPin> result = null; // Use helper to check all of it filter.InspectAllPins(p => p.QueryDirection() == direction, p => { // At most one hit is allowed if (result != null) { // Cleanup result.Dispose(); // Report error throw new InvalidOperationException(Properties.Resources.Exception_DuplicateEndpoint); } // Remember the first one result = ComIdentity.Create(p); }); // Ups if (result != null) { return(result); } else { throw new InvalidOperationException(Properties.Resources.Exception_NoEndpoint); } }
/// <summary> /// Stellt die Verbindung zur properitären Schnittstelle her. /// </summary> /// <param name="tuner">Der Filter zur Hardware.</param> protected virtual void Open( TypedComIdentity<IBaseFilter> tuner ) { // Connect once if (m_Device != IntPtr.Zero) return; // Attach to the tuner output pin to get the hardware index using (var pinRef = tuner.GetSinglePin( PinDirection.Output )) using (var pin = pinRef.MarshalToManaged()) { // Get the information var info = pin.Object.GetMediumArray(); if (info.Length < 1) throw new InvalidOperationException( "no information on attached Hardware" ); // Try to connect m_Device = bdaapiOpenHWIdx( 1, info[0].Parameter1 ); if (m_Device.ToInt64() == -1) m_Device = IntPtr.Zero; if (m_Device == IntPtr.Zero) throw new InvalidOperationException( string.Format( "could not connect to properitary API ({0} Media reported, primary Medium is {1} ({2}, {3}))", info.Length, info[0].MediumIdentifier, info[0].Parameter1, info[0].Parameter2 ) ); } }
/// <summary> /// Meldet einen Filter in Graphen an. /// </summary> /// <param name="name">Der Name des Filters.</param> /// <param name="filter">Die Verwaltungsinstanz des Filters.</param> private void AddFilter(string name, TypedComIdentity <IBaseFilter> filter) { // Test if (string.IsNullOrEmpty(name)) { throw new ArgumentNullException("name"); } if (filter == null) { throw new ArgumentNullException("filter"); } // Test if (m_Graph == null) { throw new InvalidOperationException("not initialized"); } // Forward to COM m_Graph.AddFilter(filter.Interface, name); // Remember m_Filters.Add(name, filter); }
/// <summary> /// Beendet die Nutzung dieser Instanz endgültig. /// </summary> public void Dispose() { // Cleanup using (m_Instance) m_Instance = null; }
/// <summary> /// Fügt eine Instanz zur Verwaltung hinzu. /// </summary> /// <param name="pin">Die zu verwaltende Instanz.</param> public void Add( TypedComIdentity<IPin> pin ) { // Remember m_Pins.Add( pin ); }
/// <summary> /// Untersucht alle Endpunkte eines Filters. /// </summary> /// <param name="filter">Der zu betrachtende Filter.</param> /// <param name="selector">Optional eine Auswahlfunktion.</param> /// <param name="action">Optional eine Aktion, die pro Endpunkt ausgeführt werden soll.</param> /// <exception cref="ArgumentNullException">Es wurde kein Filter angegeben.</exception> public static void InspectAllPins(this TypedComIdentity <IBaseFilter> filter, Predicate <IPin> selector, Action <IPin> action) { // Forward filter.InspectAllPins(selector, pin => { action(pin); return(true); }); }
/// <summary> /// Meldet einen Filter in Graphen an. /// </summary> /// <param name="name">Der Name des Filters.</param> /// <param name="filter">Die Verwaltungsinstanz des Filters.</param> private void AddFilter( string name, TypedComIdentity<IBaseFilter> filter ) { // Test if (string.IsNullOrEmpty( name )) throw new ArgumentNullException( "name" ); if (filter == null) throw new ArgumentNullException( "filter" ); // Test if (m_Graph == null) throw new InvalidOperationException( "not initialized" ); // Forward to COM m_Graph.AddFilter( filter.Interface, name ); // Remember m_Filters.Add( name, filter ); }
/// <summary> /// Versucht den DVB.NET Datenstrom direkt mit dem zugehörigen Decoder zu verbinden. /// </summary> /// <param name="decoder">Ein manuell angelegter Decoder.</param> /// <param name="source">Der zu verwendende Ausgang.</param> /// <param name="mediaType">Das verwendete Format.</param> /// <returns>Gesetzt, wenn die Verbindung aufgebaut wurde.</returns> private bool TryDirectConnect( TypedComIdentity<IBaseFilter> decoder, OutputPin source, MediaType mediaType ) { // In normal cases we should directly connect to the filter so try var connected = false; // Try manual connect decoder.InspectAllPins( p => p.QueryDirection() == PinDirection.Input, pin => { // Skip on error try { // Get the raw interface for the media type var type = mediaType.GetReference(); // Process using (var iFace = ComIdentity.Create<IPin>( pin )) source.Connect( iFace.Interface, type ); // Did it connected = true; } catch (Exception) { } // First pin only - even if it can not be used! return false; } ); // Failed if (!connected) return false; // Find the output of the decoder and render it decoder.InspectAllPins( p => p.QueryDirection() == PinDirection.Output, pin => { // Create helper using (var pinWrapper = ComIdentity.Create<IPin>( pin )) DirectShowObject.Render( pinWrapper.Interface ); // Did it return false; } ); // Report return connected; }
/// <summary> /// Untersucht alle Endpunkte eines Filters. /// </summary> /// <param name="filter">Der zu betrachtende Filter.</param> /// <param name="selector">Optional eine Auswahlfunktion.</param> /// <param name="action">Optional eine Aktion, die pro Endpunkt ausgeführt werden soll.</param> /// <exception cref="ArgumentNullException">Es wurde kein Filter angegeben.</exception> public static void InspectAllPins(this TypedComIdentity <IBaseFilter> filter, Predicate <IPin> selector, Func <IPin, bool> action) { // Validate if (filter == null) { throw new ArgumentNullException("filter"); } // Attach to the instance using (var filterInstance = filter.MarshalToManaged()) { // Attach to all pins var pins = filterInstance.Object.EnumPins(); try { // Process all for (; ;) { using (var array = new COMArray(1)) { // Load uint count = 0; if (pins.Next(1, array.Address, ref count) != 0) { break; } // Load object if (count != 1) { continue; } // Load the one var pin = array.GetObject <IPin>(0); try { // Check predicate if (selector != null) { if (!selector(pin)) { continue; } } // Execute if (action != null) { if (!action(pin)) { return; } } } finally { // Cleanup BDAEnvironment.Release(ref pin); } } } } finally { // Cleanup BDAEnvironment.Release(ref pins); } } }
/// <summary> /// Ermittelt die Demodulatorschnittstelle aus der BDA Topologie des Filters. /// </summary> /// <param name="filter">Der zu verwendende Filter.</param> /// <returns>Die Schnittstelle auf den Demodulator, sofern vorhanden.</returns> public static IBDADigitalDemodulator GetDigitalDemodulator(this TypedComIdentity <IBaseFilter> filter) { // Forward return(filter.GetOutputControlNode <IBDADigitalDemodulator>(1)); }
/// <summary> /// Ermittelt die Schnittstelle mit den Signalinformationen aus der BDA Topologie des Filters. /// </summary> /// <param name="filter">Der zu verwendende Filter.</param> /// <returns>Die Schnittstelle auf die Signalinformationen, sofern vorhanden.</returns> public static IBDASignalStatistics GetSignalStatistics(this TypedComIdentity <IBaseFilter> filter) { // Forward return(filter.GetOutputControlNode <IBDASignalStatistics>(0)); }
/// <summary> /// Untersucht alle Endpunkte eines Filters. /// </summary> /// <param name="filter">Der zu betrachtende Filter.</param> /// <param name="action">Optional eine Aktion, die pro Endpunkt ausgeführt werden soll.</param> /// <exception cref="ArgumentNullException">Es wurde kein Filter angegeben.</exception> public static void InspectAllPins(this TypedComIdentity <IBaseFilter> filter, Action <IPin> action) { // Forward filter.InspectAllPins(null, action); }
/// <summary> /// Erzeugt einen neuen Live Pin. /// </summary> /// <param name="filter">Der zugehörige Filter.</param> /// <param name="name">Der Name des Pins.</param> /// <param name="mediaType">Der Datentyp, der durch den Pin fließt.</param> public LivePin( TypedComIdentity<IBaseFilter> filter, string name, MediaType mediaType ) : base( filter, name, mediaType ) { }
/// <summary> /// Erzeugt einen Graphen und startet ihn. /// </summary> /// <param name="location">Der Ursprung, über den die Quellgruppe empfangen wird.</param> /// <param name="group">Die gewünschte Quellgruppe.</param> /// <exception cref="ArgumentException">Es wurden nicht alle Parameter gesetzt.</exception> public void Create( GroupLocation location, SourceGroup group ) { // Get rid of it Destroy(); // Create new graph builder var graph = Activator.CreateInstance( Type.GetTypeFromCLSID( BDAEnvironment.GraphBuilderClassIdentifier ) ); try { // Convert interface m_Graph = (IMediaFilter) graph; } catch { // Cleanup BDAEnvironment.Release( ref graph ); // Forward throw; } // See if we should register the graph m_ExternalRegistration = BDASettings.RegisterBDAGRaph( m_Graph, false ); // Attach to alternate interface var builder = (IGraphBuilder) m_Graph; // Check log var logFile = BDASettings.BDALogPath; if (logFile != null) { // Open path m_LogFile = new FileStream( logFile.FullName, FileMode.Create, FileAccess.Write, FileShare.Read ); // Enable logging on graph builder builder.SetLogFile( m_LogFile.SafeFileHandle ); } // Start with network provider NetworkProvider = AddFilter( "Network Provider", BDAEnvironment.GetNetworkProviderMoniker( DVBType ) ); // Initialize provider Tune( location, group ); // Always create the tuner if (TunerInformation != null) TunerFilter = AddFilter( "Tuner", TunerInformation ); else throw new ArgumentException( Properties.Resources.Exception_MissingTuner, "Tuner" ); // Optionally create capture if (CaptureInformation != null) CaptureFilter = AddFilter( "Capture", CaptureInformation ); // Add additional filter foreach (var additionalFilter in AdditionalFilterInformations) if (additionalFilter == null) throw new ArgumentNullException( "AdditionalFilters" ); else AdditionalFilters.Add( AddFilter( additionalFilter.DisplayName, additionalFilter ) ); // Connect network provider to streaming instance Connect( NetworkProvider, CaptureFilter ?? TunerFilter ); // Initialize provider Tune( location, group ); // Create the primary filter and add it AddFilter( "TS", TransportStreamAnalyser = new InputFilter() ); // Connect device output for analysis Connect( CaptureFilter ?? TunerFilter, TransportStreamAnalyser ); // Create the demultiplexer - needed to keep the infrastructure alive using (var demux = AddFilter( "TIF", BDAEnvironment.MicrosoftDemultiplexerMoniker )) { // Connect to the dedicated pin of our analyser TransportStreamAnalyser.DataManager.TIFConnector.Connect( demux, BDAEnvironment.TransportStreamMediaType1 ); // Pins to remove var remove = new List<string>(); // Prepare the demultiplexer pins demux.InspectAllPins( pin => { // See if this is the SI pin bool isSectionPin = false; pin.InspectAllMediaTypes( type => { // Check major if (!type.MajorType.Equals( BDAEnvironment.DataFormatTypeSections )) return true; // Check minor isSectionPin = type.SubType.Equals( BDAEnvironment.DataFormatSubtypeSI ); // Report return !isSectionPin; } ); // Check the mode if (isSectionPin) { // Connect using (var comPin = ComIdentity.Create( pin )) builder.Render( comPin.Interface ); // Load connection data IntPtr tifIn = IntPtr.Zero; if (pin.ConnectedTo( ref tifIn ) < 0) throw new InvalidOperationException( Properties.Resources.Exception_TIF ); // Reconstruct var tifPin = Marshal.GetObjectForIUnknown( tifIn ); try { // Request pin context var info = new PinInfo(); ((IPin) tifPin).QueryPinInfo( ref info ); // Request from pin m_TIF = info.GetAndDisposeFilter(); } finally { // Cleanup BDAEnvironment.Release( ref tifPin ); } } else if (pin.QueryDirection() == PinDirection.Output) { // Prepare to kill remove.Add( pin.QueryId() ); } } ); // Prepare to remove all unconnected pins if (remove.Count > 0) using (var demuxInstance = demux.MarshalToManaged()) { // Change type var mpeg2 = (IMpeg2Demultiplexer) demuxInstance.Object; // Remove all foreach (var id in remove) mpeg2.DeleteOutputPin( id ); } } // Install the PMT watchdog TransportStreamAnalyser.DataManager.TSParser.PMTFound += ProcessPMT; }
/// <summary> /// Erzeugt einen neuen Filter. /// </summary> /// <param name="name">Der Name des Filters.</param> /// <param name="filter">Der bereits geladene Filter.</param> /// <returns>Die COM Schnittstelle des neuen Filters.</returns> /// <exception cref="ArgumentNullException">Es wurde kein Filter angegeben.</exception> private void AddFilter( string name, TypedComIdentity<IBaseFilter> filter ) { // Validate if (filter == null) throw new ArgumentNullException( "filter" ); // Process ((IGraphBuilder) m_Graph).AddFilter( filter.Interface, name ); }
/// <summary> /// Verbindet zwei Filter. Es wird erwartet, dass jeweils ein einziger Ein-/Ausgang existiert. /// </summary> /// <param name="from">Der Filter, der die Daten produziert.</param> /// <param name="to">Der Filter, der die Daten entgegennimmt.</param> private void Connect( TypedComIdentity<IBaseFilter> from, TypedComIdentity<IBaseFilter> to ) { // Attach to pins using (var fromPin = from.GetSinglePin( PinDirection.Output )) using (var toPin = to.GetSinglePin( PinDirection.Input )) ((IGraphBuilder) m_Graph).Connect( fromPin.Interface, toPin.Interface ); }
/// <summary> /// Initialisiert eine neue Instanz. /// </summary> /// <param name="instance">Die zu verwaltende Instanz eines COM Objektes.</param> public Typed(TypedComIdentity <IKsPropertySet> .Incarnation instance) { // Remember m_Instance = instance; }
/// <summary> /// Fügt eine Instanz zur Verwaltung hinzu. /// </summary> /// <param name="pin">Die zu verwaltende Instanz.</param> public void Add(TypedComIdentity <IPin> pin) { // Remember m_Pins.Add(pin); }
/// <summary> /// Beendet den Graphen und gibt alle damit verbundenen Ressourcen frei. /// </summary> public void Destroy() { // Disable decryption callback Interlocked.Exchange( ref m_PMTSink, null ); // Pipelines DecryptionPipeline.Terminate(); SignalPipeline.Terminate(); TunePipeline.Terminate(); // External registration using (m_ExternalRegistration) m_ExternalRegistration = null; // Extra filters var additionalFilters = AdditionalFilters.ToArray(); // Reset AdditionalFilters.Clear(); // Filter foreach (var additionalFilter in additionalFilters) if (additionalFilter != null) additionalFilter.Dispose(); using (m_TIF) m_TIF = null; using (TransportStreamAnalyser) TransportStreamAnalyser = null; using (CaptureFilter) CaptureFilter = null; using (TunerFilter) TunerFilter = null; using (NetworkProvider) NetworkProvider = null; // The graph itself if (m_Graph != null) try { // Done with it m_Graph.Stop(); } catch (Exception e) { // For now we ignore all errors during shutdown Trace.WriteLine( e.Message ); } finally { // Get rid of it BDAEnvironment.Release( ref m_Graph ); } // Log file using (var logFile = m_LogFile) { // Forget m_LogFile = null; // Make sure that we have written it all out if (logFile != null) logFile.Flush(); } }
/// <summary> /// Ermittelt die Schnittstelle zur Feineinstellung der Quellgruppenanwahl aus der BDA Topologie des Filters. /// </summary> /// <param name="filter">Der zu verwendende Filter.</param> /// <returns>Die Schnittstelle für die Feineinstellungen, sofern vorhanden.</returns> public static IBDAFrequencyFilter GetFrequencyFilter(this TypedComIdentity <IBaseFilter> filter) { // Forward return(filter.GetOutputControlNode <IBDAFrequencyFilter>(0)); }