/// <summary> /// Erzeugt einen Filter und vermerkt ihn. /// </summary> /// <param name="name">Der Name des Filters.</param> /// <param name="moniker">Der eindeutige Name des Filters.</param> private void AddFilter(string name, string moniker) { // Test if (string.IsNullOrEmpty(name)) { throw new ArgumentNullException("name"); } if (string.IsNullOrEmpty(moniker)) { throw new ArgumentNullException("moniker"); } // Create var filter = ComIdentity.Create <IBaseFilter>(moniker); try { // Process AddFilter(name, filter); } catch { // Cleanup filter.Dispose(); // Forward throw; } }
/// <summary> /// Meldet, dass nun eine Verbindung zu einem anderen Endpunkt festgelegt wurde. /// </summary> /// <param name="connector">Ein anderer Endpunkt.</param> /// <param name="mediaType">Die Art der Daten, die zwischen den Endpunkten ausgetauscht werden.</param> public void ReceiveConnection(IntPtr connector, IntPtr mediaType) { // Free Disconnect(); // Remember if (connector != null) { Marshal.AddRef(connector); } m_Connected = connector; // Clone the media type m_ConnectType.Dispose(); m_ConnectType = new MediaType(mediaType); // Attach to raw COM interface m_MemPin = ComIdentity.QueryInterface(m_Connected, typeof(IMemInputPin)); // Get the delegate for the calls - dirty but we have to avoid automatic marshalling inside the graph IntPtr comFunctionTable = Marshal.ReadIntPtr(m_MemPin); IntPtr receiveSingle = Marshal.ReadIntPtr(comFunctionTable, 24); IntPtr notifyAllocator = Marshal.ReadIntPtr(comFunctionTable, 16); m_MemSink = (MediaSampleSink)Marshal.GetDelegateForFunctionPointer(receiveSingle, typeof(MediaSampleSink)); m_NotifySink = (NotifyAllocatorSink)Marshal.GetDelegateForFunctionPointer(notifyAllocator, typeof(NotifyAllocatorSink)); }
/// <summary> /// Entschlüsselt eine einzelne Quelle. /// </summary> /// <param name="service">Die Informationen zur Quelle.</param> /// <param name="graph">Der zu verwendende Graph.</param> public void Decrypt(ushort service, DataGraph graph) { // Check COM interface var controlPtr = ComIdentity.QueryInterface(graph.AdditionalFilters[m_filterIndex].Interface, typeof(KsControl.Interface)); if (controlPtr != IntPtr.Zero) { using (var control = new KsControl(controlPtr)) control.SetServices(service); } }
/// <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 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> /// Wird zur eigentlichen Steuerung der Entschlüsselung aufgerufen. /// </summary> /// <param name="pmt">Die Informationen zur Quelle.</param> /// <param name="reset">Gesetzt, um einen Neustart der Entschlüsselung zu erzwingen.</param> private void Decrypt(EPG.Tables.PMT pmt, bool reset) { // Check the interface var setPtr = ComIdentity.QueryInterface(m_DataGraph.TunerFilter.Interface, typeof(KsPropertySetFireDTV.Interface)); if (setPtr == IntPtr.Zero) { return; } // Process using (var propertySet = new KsPropertySetFireDTV(setPtr)) try { // Load property identifier var propSetId = PropertySetId; var supported = propertySet.QuerySupported(ref propSetId, BDAProperties.SendCA); if ((PropertySetSupportedTypes.Set & supported) != PropertySetSupportedTypes.Set) { return; } // Process reset if (reset) { propertySet.Send(CACommand.CreateReset()); } else if (pmt == null) { propertySet.Send(CACommand.StopDecryption()); } else { propertySet.Send(CACommand.CreateDecrypt(pmt)); } } catch { // Forward if not resetting if (pmt != null) { throw; } } }
/// <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> /// Lädt einen bestimmten Decoderfilter, sofern explicit konfiguriert. /// </summary> /// <param name="moniker">Der eindeutige Name des Filters.</param> /// <param name="forType">Die Art des Filters - nur zur Benennung im Graphen verwendet.</param> /// <param name="processor">Optionale Verarbeitungsmethode für den neuen Filter.</param> private void LoadDecoder(string moniker, string forType, Action <TypedComIdentity <IBaseFilter> > processor = null) { // Not set if (string.IsNullOrEmpty(moniker)) { return; } // Check it var name = string.Format("{0}Decoder", forType); // Process using (var decoder = ComIdentity.Create <IBaseFilter>(moniker)) { // Create DirectShowObject.AddFilter(decoder.Interface, name); // Call helper if (processor != null) { processor(decoder); } } }
/// <summary> /// Aktiviert die Entschlüsselung einer Quelle. /// </summary> /// <param name="token">Informationen zur gewählten Quelle.</param> public PipelineResult Decrypt(DataGraph.DecryptToken token) { // Load graph if (token != null) { m_dataGraph = token.Pipeline.Graph; } // Get unique call identifier var callIdentifier = Interlocked.Increment(ref m_changeCounter); // See if we can do anything if (m_dataGraph == null) { return(PipelineResult.Continue); } if (m_filterIndex < 0) { return(PipelineResult.Continue); } if (m_filterIndex >= m_dataGraph.AdditionalFilters.Count) { return(PipelineResult.Continue); } // Deactivate if CAM reset is forbidden var sources = (token == null) ? null : token.Sources; var noSources = (sources == null) || (sources.Length < 1); if ((noSources && (m_suppress != SuppressionMode.Complete)) || !m_hasBeenReset) { lock (m_deviceAccess) { // Check COM interface var controlPtr = ComIdentity.QueryInterface(m_dataGraph.AdditionalFilters[m_filterIndex].Interface, typeof(KsControl.Interface)); if (controlPtr == IntPtr.Zero) { return(PipelineResult.Continue); } // Process using (var control = new KsControl(controlPtr)) { // Report if (BDASettings.BDATraceSwitch.Enabled) { Trace.WriteLine(Properties.Resources.Trace_ResetCAM, BDASettings.BDATraceSwitch.DisplayName); } // Reset the CAM control.Reset(); // We did it once m_hasBeenReset = true; } } } // Start processor token.WaitForPMTs( (pmt, first) => { // See if we are still allowed to process and do so lock (m_deviceAccess) { // No longer current if (Thread.VolatileRead(ref m_changeCounter) != callIdentifier) { return(false); } // Try reset if (!first) { if (m_disableOnChange) { Decrypt(0, m_dataGraph); } } // Wait for it if (m_changeDelay > 0) { Thread.Sleep(m_changeDelay); } // Regular Decrypt(pmt.ProgramNumber, m_dataGraph); } // Next return(true); }, sources); // Next return(PipelineResult.Continue); }
/// <summary> /// Erzeugt den zugehörigen Filter. /// </summary> /// <returns>Der gewünschte Filter.</returns> /// <exception cref="NotSupportedException">Der angeforderte Filter existiert.</exception> public TypedComIdentity <IBaseFilter> CreateFilter() { // Create system device enumerator var devEnum = (ICreateDevEnum)Activator.CreateInstance(System.Type.GetTypeFromCLSID(BDAEnvironment.SystemDeviceEnumeratorClassIdentifier)); try { // Helper var category = Category; // Get the enumerator IEnumMoniker monikers; if (devEnum.CreateClassEnumerator(ref category, out monikers, 0) >= 0) { if (monikers != null) { try { // Process all for (; ;) { using (var array = new COMArray(1)) { // Load uint count; if (monikers.Next(1, array.Address, out count) != 0) { break; } if (count != 1) { break; } // Load object var moniker = array.GetObject <IMoniker>(0); try { // Check name if (string.Equals(Moniker, moniker.ReadProperty("DevicePath"))) { // Create the instance var iid = new Guid("56a86895-0ad4-11ce-b03a-0020af0ba770"); var filter = moniker.BindToObject(null, null, ref iid); // Report safely try { // Construct return(ComIdentity.Create((IBaseFilter)filter)); } catch { // Cleanup BDAEnvironment.Release(ref filter); // Forward throw; } } } finally { // Release BDAEnvironment.Release(ref moniker); } } } } finally { // Cleanup BDAEnvironment.Release(ref monikers); } } } } finally { // Back to COM BDAEnvironment.Release(ref devEnum); } // Not found throw new NotSupportedException(string.Format(Properties.Resources.Exception_BadFilter, this)); }
/// <summary> /// Erzuegt den Anzeigegraphen. /// </summary> /// <param name="mpeg4">Gesetzt für H.264 Bildinformationen - ansonsten wird MPEG-2 erwartet.</param> /// <param name="ac3">Gesetzt für AC3 Toninformationen - ansonsten wird MP2 erwartet.</param> public void Show(bool mpeg4, bool ac3) { // Startup bool firstCall = PrepareShow(); // Leave fullscreen before stopping graph bool fullscreen = FullScreen; if (fullscreen) { FullScreen = false; } // Stop the graph Stop(); // Forget the clock DisposeClock(); // Remove all filters not created by us var noRemove = new HashSet <IntPtr>(m_Filters.Values.Select(f => f.Interface)); ((IFilterGraph)m_Graph).InspectFilters(filter => { // Create report structure var info = new FilterInfo(); // Load it filter.QueryFilterInfo(ref info); // Forget about graph BDAEnvironment.Release(ref info.Graph); // Process using raw interfaces using (var id = ComIdentity.Create(filter)) if (!noRemove.Contains(id.Interface)) { try { // Repoert if (DirectShowTraceSwitch.Enabled) { Trace.WriteLine(string.Format(Properties.Resources.Trace_RemoveFilter, info.Name), DirectShowTraceSwitch.DisplayName); } // Process DirectShowObject.RemoveFilter(id.Interface); } catch (Exception e) { // Report Trace.WriteLine(string.Format(Properties.Resources.Trace_Exception_RemoveFilter, info.Name, e.Message), DirectShowTraceSwitch.DisplayName); } } }); // Create media types var videoType = CreateVideoType(mpeg4, UseCyberlink); var audioType = CreateAudioType(ac3); // Configure injection pins InjectorFilter.SetAudioType(audioType); InjectorFilter.SetVideoType(videoType); // Helper var audioConnected = false; var videoConnected = false; // Pre-loaded decoders LoadDecoder(mpeg4 ? H264Decoder : MPEG2Decoder, mpeg4 ? "HDTV-Video" : "SDTV-Video", decoder => videoConnected = TryDirectConnect(decoder, InjectorFilter.VideoPin, videoType)); LoadDecoder(ac3 ? AC3Decoder : MP2Decoder, ac3 ? "AC3-Audio" : "MP2-Audio", decoder => audioConnected = TryDirectConnect(decoder, InjectorFilter.AudioPin, audioType)); // Create display if (!audioConnected) { DirectShowObject.Render(InjectorFilter.AudioPin.Interface); } if (!videoConnected) { DirectShowObject.Render(InjectorFilter.VideoPin.Interface); } // Show for the first time var vmr = VMR; if (firstCall) { if (vmr != null) { if (m_VideoWindow != null) { // Respect window settings vmr.ClippingWindow = m_VideoWindow; vmr.AdjustSize(m_VideoWindow); } } } // Use it m_Clock = new NoMarshalComObjects.ReferenceClock(Activator.CreateInstance(Type.GetTypeFromCLSID(Constants.CLSID_SystemClock)), true); // Attach to graph GraphAsFilter.SetSyncSource(m_Clock.ComInterface); // Time to restart the graph Run(); // Reinstall volume if (m_LastVolume.HasValue) { Volume = m_LastVolume.Value; } // Reinstall picture parameters if (m_PictureParameters != null) { if (vmr != null) { m_PictureParameters.Update(vmr); } } // Back to full screen mode if (fullscreen) { FullScreen = true; } }