Da ich ja gerade aus Unzufriedenheit über die erhältlichen hardware Mediaplayer meine eigene Player-Software für meinen Eigenbau-HTPC schreibe, verbringe ich viel Zeit mit der Suche nach Informationen zu directshow. Das hier ist das Ergebnis einer erfolgreichen Suche ;)
Ich spiele mit Vorliebe MKV’s ab. Und da in letzter Zeit immer mehr MKV’s über Chapter / Kapitel verfügen, möchte ich die natürlich auch “anspringen” können.
Die beim Abspielen involvierten Audio- und Videodecoder wissen von den Kapiteln nichts, das ist Aufgabe des Splitters.
In meinem Fall (wie eigentlich immer) ist das der Haali Media Splitter.
Leider findet man, wann man nicht einem directshow Interface für Chapter sucht, immer wieder Referenzen auf ein Interface namens IChapterInfo.
Dummerweise gibt’s keine Beispiele, nur die Definition des Interfaces. Mangels Erfahrung mit COM bin ich hier nicht weitergekommen.
Aber irgendwann bin ich dann über den Hinweis gestolpert, das der Haali Media Splitter das IExtendedSeeking implementiert und dort die Kapitelinformationen bereit stellt.
Da ich in C# programmiere und die directshow.net Bibliothek benutze, sieht meine Implementation zum Auslesen der Kapitel so aus:
// this sample assumes that this.graphbuilder already refers to the IGraphBuilder interface for a video // chapter names and start times are placed into arrays // look for a filter that supports the IAMExtendedSeeking interface (like Haali splitter) IEnumFilters fEnum; IBaseFilter[] filter = new IBaseFilter[1]; IntPtr fetched = new IntPtr(); hr = this.graphBuilder.EnumFilters(out fEnum); DsError.ThrowExceptionForHR(hr); while(fEnum.Next(1, filter, fetched) == 0) { this.extSeeking = filter[0] as IAMExtendedSeeking; if (this.extSeeking != null) { int chapterCount = 0; this.extSeeking.get_MarkerCount(out chapterCount); for (int c = 0; c < chapterCount; c++) { // Chapter Markers start with 1 !! And I put the data into arrays that also start at 1 hr = this.extSeeking.GetMarkerName(c+1, out this.chapterName[c+1]); DsError.ThrowExceptionForHR(hr); hr = this.extSeeking.GetMarkerTime(c+1, out this.chapterTime[c+1]); DsError.ThrowExceptionForHR(hr); } Marshal.ReleaseComObject(this.extSeeking); } } Marshal.ReleaseComObject(fEnum);
Die beiden Marshal.ReleaseComObject() sind wichtig. Wenn man das extSeeking Interface (und damit auch den Filter) nicht wieder freigibt, äussert sich das in der Praxis so, daß der Haali Media Splitter nicht beendet wird, wenn auf das nächste Video umgeschaltet wird.
Am Ende hat man die Kapitel in den Arrays chapterName[] und chapterTime[] (das erste Kapitel in [1]).
Hilfreich war folgender Link: http://stackoverflow.com/questions/5220691/getting-multiple-video-renderers-in-directshow-net-in-c