Neuer Downloadbereich

Da mein Hoster (1&1) den bestehenden Vertrag ohne Mehrkosten erheblich erweitert hat, stehen mir jetzt 1 GB Web Space zur Verfügung. Daher kann ich auch wieder die alten DVB.NET und VCR.NET Versionen zum direkten Download anbieten. In diesem Zuge habe ich mich entschlossen, http://downloads.psimarron.net als eigenen Downloadbereich anzulegen, den ich in den nächsten Woche mit Inhalt füllen werde – so viel ist es nicht, aber durch den Kleinkram gibt es schon einen gewissen Wildwuchs.

Die neue Site wird keine Homepage bekommen, sondern direkt auf Verzeichnisebene abrufbar sein. Vielleicht (vermutlich aber eher nicht) werde ich mal ein paar (HTML) ReadMe’s ergänzen.

Viel Spaß

Jochen

COM Wars – wenn .NET zu schlau ist…

Im Rahmen von DVB.NET 3.1 möchte ich in einen DirectShow (COM basiert) Filtergraphen eine .NET Klasse einbinden. Die Klasse klemmt sich in den Datenstrom zwischen einen TS Capture Filter und einen Demultiplexer – nicht wirklich ein Problem. Auf der Eingangsseite (Input Pin) der .NET Klasse werden über eine COM Schnittstelle IMemInputPin so genannte Media Samples (IMediaSample) entgegengenommen. Die Klasse macht damit was und gibt sie dann unverändert an die gleichartige Schnittstelle des Demultiplexers an der Ausgangsseite (Output Pin) weiter. Es kommt ein Fehler 0x80040155 (REGDB_E_IIDNOTREG)!

Dieser Fehler ist ein COM Marshalling Fehler. Er bedeutet, dass COM versucht hat, eine Schnittstelle aus einem Apartment in ein anderes zu transferieren, dabei aber keinen Eintrag in der Registery (HKCR\Interface) für die Schnittstelle gefunden hat und die betroffenen COM Klasse auch kein Custom Marshalling anbietet (IMarshal).

Nun gut, was könnte also hier passieren? Der Filtergraph wird im Hauptprogramm, einer Windows Form, angelegt, damit auch alle Filter (COM Komponenten). Der Natur der Sache nach wird dazu ein Single-Threaded-Apartment (STA) verwendet. Durch die Gegebenheiten in einem DirectShow Graphen muss ich allerdings die Weitergabe der Media Samples auf einem eigene Thread machen (sonst blockiert der Graph). Das kann natürlich nie dasselbe Apartment sein, wie das Heimatapartment der Komponenten.

Nun, wie macht Microsoft das? Ein Blick in das DirectShow SDK zeigt, dass in Graphen COM Regeln wohl etwas lockerer gesehen werden. Das Infinite Tee Beispiel von Microsoft nimmt COM Schnittstellen wie sie kommen und nutzt sie ohne eine Marshalling gnadenlos auf einem anderen Thread. Nun gut, machen wir das mit .NET. Geht aber nicht (so einfach)!

Der erste Versuch, die .NET Schnittstelle einfach im anderen Thread zu verwenden, hatten wir oben schon. Auch der Trick, im STA ein Marshal.QueryInterface zu machen, fruchtet nicht. Man erhält hier tatsächlich eine IntPtr auf die COM Schnittstelle zum direkten Zugriff. Packt man diese in dem Worker Thread aber via Marshal.GetObjectFor IUnknown aus, ist .NET wieder so clever, ein Marshalling anzustossen. Böse Falle.

Ok, es geht doch, aber was jetzt kommt ist zumindest verboten 🙂 Also mit Vorsicht geniessen! Das ganz fängt mit folgendem Code Fragment an (da gab es einige Zwischenschritte bis zu genau dieser Lösung, die es tut – Details erspare ich hier mal):


private delegate void MediaSampleSink(IntPtr classPointer, IntPtr[] sampleArray, Int32 sampleCount, out Int32 processed);

private MediaSampleSink m_MemSink = null;
private IntPtr m_MemPin = IntPtr.Zero;

m_MemPin = Marshal.GetComInterfaceForObject(m_Connected, typeof(Interfaces.IMemInputPin));

IntPtr comFunctionTable = Marshal.ReadIntPtr(m_MemPin);
IntPtr receiveMultiple = Marshal.ReadIntPtr(comFunctionTable, 28);

m_MemSink = (MediaSampleSink)Marshal.GetDelegateForFunctionPointer(receiveMultiple, typeof(MediaSampleSink));

Aus der Eingangsadresse des anderen Filters (m_Connected ist der IMemInputPin) wird die COM Schnittstelle ermittelt. Dann relativ trivial die Adresse der Funktionentablle und schließlich die Adresse der 7ten Methode (IMemInputPin:ReceiveMultiple). Der erstellte Delegate berücksichtig dabei, dass bei einem COM Aufruf der zusätzliche, normalerweise unsichtbare, erste Parameter die Adresse des COM Objektes ist.

Nun funktioniert folgender Aufruf wie gewünscht:

IntPtr[] toProcess = ...;
Int32 processed;
m_MemSink(m_MemPin, toProcess, toProcess.Length, out processed);

Wie gesagt: eigentlich werden hier COM Regeln auf das übelste verletzt. Es fragt sich allerdings, ob in einem DirectShow Graphen nicht wirklich andere Regeln gelten, bei denen COM Schnittstellen nur zur Zerlegung in Komponenten verwendet werden, Apartments aber keine Rolle spielen. Müßte ich mal recherchieren – ich hoffe im Moment einfach mal, dass es so ist (zudem alle Microsoft DirectShow Beispiele es auch so handhaben).

Immerhin, ein kleiner Schritt in Richtung DVB.NET 3.1!

Viel Spaß

Jochen

DVB.NET 3.0 Release

Ich habe mich entschlossen, DVB.NET 3.0 freizugeben. Es gibt zwar noch einige Probleme, aber es hält sich im Rahmen. Aus dem internen und externen Beta-Test kam auch nicht mehr viel.

Der nächste Schritt ist jetzt VCR.NET 3.0. Dazu ist zu sagen, dass ich im Moment nicht vorhabe, am aktuellen Release Candidate noch irgendetwas zu verändern! Bei VCR.NET und auch beim Zapping Client geht es mir nur noch darum, die Homepage anzupassen, dann kommt der Deckel ‘drauf. Danach wird es (bis auf Bug-Fixes, die gibt es nach dieser Riesenumstellung trotz des sehr lobenswerten Einsatzes der Beta-Tester [allen voran darkstorm und mrthaler] sicher noch) erst mal eine Entwicklungspause geben. In der nächsten Phase wird dann DVB.NET im Vordergrund stehen.

Bis demnächst

Jochen

Transponderstatistik erstellen bei Verwendung von BDA Karten

Obwohl das im folgenden beschrieben Feature Standard in anderen Anwendungen ist und dort im Allgemeinen auch optisch ansprechend präsentiert wird, ist es doch neu in DVB.NET 3.0 und könnte den einen oder anderen trotz der mageren Darstellung als Textprotokoll interessieren – wohl kaum den Normalanwender, aber es gibt ja auch noch andere Neugierige da draussen.

Wenn DVB.NET 3.0 auf eine DVB Hardware über einen BDA Treiber zugreift (etwa bei der Hauppauge Nova-S Plus oder der TechnoTrend S2-3200), dann geschieht dies über so genannte DirectShow Filter. Für seine Kernaufgaben klinkt sich DVB.NET mit einem eigenen Filter in den Rohdatenstrom (Transport Stream des Senders), zerlegt diesen in seine Bestandteile und verteilt die einzelnen Datenströme gemäß der aktuellen Anforderung.

Wichtig ist, dass der gesamte Datenstrom durch DVB.NET läuft und während der Zerlegung intern einige Zähler mitgeführt werden. Diese Zähler können beim Beenden einer DVB.NET Anwendung in eine Datei geschrieben werden, wodurch man einen interessanten Einblick in die interne Struktur des Rohdatenstroms erhalten kann. Wird die Protokollierung in einer regulären DVB.NET Anwendung (Stream Manager, Quick Record, …) aktiviert, so wird das Protokoll im temporären Verzeichnis des Anwenders angelegt (C:\Documents and Settings\USER\Local Settings\Temp oder ähnliches). Bei einer Aktivierung für VCR.NET wird das temporäre Verzeichnis von Windows verwendet (%SystemRoot%\temp oder ähnliches), da VCR.NET als Windows Dienst unter dem LocalSystem Konto abgearbeitet wird und dieses kein Benutzerprofil besitzt. Man beachte, dass ein Protokolleintrag immer von Anfang bis Ende der Nutzung erfolgt und blind gegenüber Senderwechsel ist. Quick Record ist daher ein eher unüblicher Kandidat zur Erstellung eines Protokolls, VCR.NET schon fast ideal.

Die Aktivierung des Features erfolgt über einen Eintrag in der .NET Konfiguration des DVB.NET Programms, das ein Protokoll anlegen soll (etwa DVBStreamManager.exe.config oder auch JMS.DVBVCR.RecordingService.exe.config). Bei einer Eintragung bitte eine Sicherheitskopie anlegen und sorgfältig vorgehen – ein Fehleintrag kann dazu führen, dass das Programm nicht mehr startet, was beim VCR.NET besonders ärgerlich ist. Nach der Änderung muss das jeweilige Programm neu gestartet werden – auch das gilt besonders für den VCR.NET Windows Dienst. Der Eintrag selbst ist einfach:

<add key=”TSStatistics” value=”True” />

Ist das Erzeugen eines Protokolls aktiv, so wird eine Protokolldatei namens DVBNETTSStatistics.log fortlaufend gefüllt. Grundsätzlich werden die im Folgenden beschriebenen Eintragungen vorgenommen.

Immer, wenn ein Datenstromfilter (Bild, Ton, VideoText, EPG/Programmzeitschrift, PMT/PAT/Sendersuchlauf, …) nicht mehr benötigt wird, wird dessen Nutzung eingetragen:

2007.02.01 22:41:15 [00163] #290081 2376343552 ([8192..8192] 8192)

In eckigen Klammern steht der PID, hinter dem # die Anzahl der übertragenen Pakete (keine TS Pakete) und die Anzahl der übertragenen Bytes. Dahinter in Klammern minimale, maximale und mittlere Paketgröße. DVB.NET 3.0 überträgt Nutzdaten (PES Datenströme) in festen Blöcken von 8 kBytes ohne Rücksicht auf die Paketierung des Datenstroms. Die Weiterverarbeitung innerhalb von DVB.NET ist darauf vorbereitet. Bei Steuerdaten (SI Tabellen) werden tatsächlich immer ganze Tabellen übertragen, da sieht das schon interessanter aus, hier ein paar Zeilen aus meiner letzten Aktualisierung der Programmzeitschrift (PID 18 ist das EPG):

2007.02.03 18:01:07 [00018] #4641 4261011 ([18..4096] 918)
2007.02.03 18:02:09 [00018] #23587 9554622 ([18..3847] 405)
2007.02.03 18:03:10 [00018] #2236 2671201 ([18..4066] 1194)
2007.02.03 18:04:12 [00018] #4091 4208208 ([18..4063] 1028)

Nur am Ende einer DVB.NET Anwendung wird ein Gesamtprotokoll der durch DVB.NET analysierten Daten erstellt. Dieses beginnt immer mit einer Übersicht:

2007.02.01 22:41:17 cb=287822 b=27704594432 s=257372 p=147363495 enc=25321062
2007.02.01 22:41:17 strm=0 tbl=0 sync=5 err=10

Dabei bedeuten: cb=Anzahl der Aufrufe des DVB.NET DirectShow Filters durch das jeweilige BDA Gerät; b=Gesamtzahl der untersuchen Bytes; s=Durch Resynchronisation des Datenstroms (sync) verlorene Bytes; p=Anzahl der TS Pakete (à 188 Bytes); enc=Anzahl der verschlüsselten dadurch verworfenen TS Pakete; strm=Fehler bei der Analyse von PES Datenströmen; tbl=Fehler bei der Analyse von SI Tabellen; sync=Resynchronisationen durch nicht interpretierbare Daten; err=Anzahl der als fehlerhaft markierten und deswegen verworfenen TS Pakete.

Nun folgt für jeden Datenstrom dessen Datenvolumen:

2007.02.01 22:41:17 02047 #44
2007.02.01 22:41:17 00033 #12
2007.02.01 22:41:17 00255 #91
2007.02.01 22:41:17 00035 #9
2007.02.01 22:41:17 01791 #175
2007.02.01 22:41:17 01023 #136
2007.02.01 22:41:17 08191 #16160227

Die Zahl hinter der Uhrzeit ist der PID (dezimal), hinter dem # die Anzahl der zugehörigen TS Pakete. Interessant ist etwa der PID 8191, der nur Fülldaten enthält und letztlich eine Aussage über die verbleibende Datenkapazität im Rohdatenstrom ist.

Ich persönlich war überrascht zu sehen, dass die Rohdatenströme Bitraten von mehr als 30 MBit/s aufweisen (DVB-S). Und dass ich den Eindruck habe, als wenn DVB.NET die Zerlegung mindestens genauso gut kann, wie die Microsoft BDA Komponenten – zumindest was die Laufzeit angeht, funktional wurde diese Lösung gewählt, weil gerade die PSI zerlegung von Microsoft über den MPEG2 Demultiplexer unzureichend funktioniert.

Viel Spaß

Jochen