Een bronfilter schrijven voor DirectShow
[De functie die is gekoppeld aan deze pagina, DirectShow, is een verouderde functie. Het is vervangen door MediaPlayer, IMFMediaEngineen Audio/Video Capture in Media Foundation. Deze functies zijn geoptimaliseerd voor Windows 10 en Windows 11. Microsoft raadt ten zeerste aan om nieuwe code te gebruiken MediaPlayer, IMFMediaEngine en Audio/Video Capture in Media Foundation in plaats van DirectShow, indien mogelijk. Microsoft stelt voor dat bestaande code die gebruikmaakt van de verouderde API's, indien mogelijk opnieuw worden geschreven om de nieuwe API's te gebruiken.]
In dit onderwerp wordt beschreven hoe u een aangepast bronfilter schrijft voor DirectShow.
Notitie
In dit onderwerp worden alleen pushbronnen beschreven; Er worden geen pull-bronnen beschreven, zoals het filter voor Asynchrone lezer of splitsfilters die verbinding maken met pull-bronnen. Zie gegevensstroom voor filterontwikkelaarsvoor het onderscheid tussen push- en pull- bronnen.
Het DirectShow Streaming-model
Wanneer u een bronfilter schrijft, is het belangrijk om te begrijpen dat een pushbron niet hetzelfde is als een livebron. Een livebron haalt gegevens op uit een externe bron, zoals een camera of een netwerkstream. Over het algemeen kan een livebron de binnenkomende snelheid van gegevens niet beheren. Als de downstreamfilters de gegevens niet snel genoeg verbruiken, moet de bron voorbeelden verwijderen.
Maar een pushbron hoeft geen livebron te zijn. Een pushbron kan bijvoorbeeld gegevens lezen uit een lokaal bestand. In dat geval bepalen de downstream rendererfilters hoe snel ze de gegevens uit de bron verbruiken, op basis van de referentieklok en de voorbeeldtijdstempels. Het bronfilter levert zo snel mogelijk voorbeelden, maar de werkelijke gegevensstroom wordt beperkt door de renderers. De mechanismen voor het beperken van de gegevensstroom worden beschreven in gegevensstroom voor filterontwikkelaars.
Elke uitvoerpin op het bronfilter maakt een thread met de naam streamingthread. De pin levert voorbeelden op de streaming-thread. Normaal gesproken vindt alle decodering, verwerking en rendering plaats op deze thread, hoewel sommige downstreamfilters extra threads kunnen maken om hun uitvoervoorbeelden in de wachtrij te plaatsen.
De streaming-thread voert een lus uit met de volgende structuur:
until (stopped)
1. Get a media sample from the allocator.
2. Fill the sample with data.
3. Time stamp the sample.
4. Deliver the sample downstream.
Als er geen voorbeelden beschikbaar zijn, blokkeert stap 1 totdat een voorbeeld beschikbaar is. Stap 4 kan ook blokkeren; bijvoorbeeld, het kan blokkeren terwijl de grafiek is onderbroken.
De lus wordt zo snel mogelijk uitgevoerd, maar wordt beperkt door hoe snel het rendererfilter elk voorbeeld weergeeft. Ervan uitgaande dat de filtergrafiek een verwijzingsklok heeft, wordt de snelheid bepaald door de presentatietijden op de voorbeelden. Als er geen verwijzingsklok is, verbruikt de renderer zo snel mogelijk voorbeelden.
CSource en CSourceStream gebruiken
De DirectShow-basisklassen bevatten twee klassen die pushbronnen ondersteunen: CSource- en CSourceStream-.
- CSource- is de basisklasse voor het filter en implementeert de IBaseFilter-interface.
- CSourceStream is de basisklasse voor de uitvoerpinnen en implementeert de IPin interface.
Uitvoerpinnen
Een bronfilter kan meer dan één uitvoerpin hebben. Maak in de constructormethode van uw filter een of meer pinnen die zijn afgeleid van CSourceStream (één pin per uitvoerstroom). U hoeft geen aanwijzers op te slaan op de pinnen; de spelden voegen zichzelf automatisch toe aan het filter wanneer ze worden gemaakt.
Uitvoerindelingen
De uitvoerpin verwerkt de indelingsonderhandelingen met de volgende CSourceStream methoden:
Methode | Beschrijving |
---|---|
GetMediaType | Haalt een mediatype uit de output-pin. De speld moet ten minste één mediatype voorstellen, omdat het downstreamfilter mogelijk geen typen voorstelt. In de meeste gevallen is het downstreamfilter een decoder of een renderer, afhankelijk van of het bronfilter gecomprimeerde of niet-gecomprimeerde gegevens levert. Een rendererfilter vereist meestal een volledig mediatype, met alle indelingsgegevens die nodig zijn om de stream weer te geven. Voor een decoder is de hoeveelheid informatie die vereist is in het mediatype, sterk afhankelijk van de coderingsindeling. |
CheckMediaType | Controleert of de uitvoerpin een bepaald mediatype accepteert. Het overschrijven van deze methode is optioneel, afhankelijk van hoe u GetMediaType-implementeert. |
De methode GetMediaType is overbelast:
- GetMediaType (1) gebruikt één parameter, een aanwijzer naar een CMediaType--object.
- GetMediaType (2) gebruikt een indexvariabele en een aanwijzer naar een CMediaType--object.
Als de uitvoerpin van het bronfilter exact één media-indeling ondersteunt, moet u (1) overschrijven om het CMediaType--object met die indeling te initialiseren. Laat de standaard implementatie van (2) staan en laat ook de standaard implementatie van CheckMediaType.
Als de pin meer dan één indeling ondersteunt, schrijf (2) over. Initialiseer het CMediaType-object op basis van de waarde van de indexvariabele. De speld moet de notaties retourneren als een geordende lijst. In dit geval moet u ook de CheckMediaType- overschrijven om het mediatype te controleren op basis van uw lijst met indelingen.
Voor niet-gecomprimeerde video-indelingen moet u er rekening mee houden dat het downstreamfilter video-indelingen met verschillende stapwaarden kan voorstellen. Uw filter moet elke geldige stapgrootte accepteren. Zie BITMAPINFOHEADERvoor meer informatie.
U moet ook de pure virtuele methode CBaseOutputPin::DecideBufferSize overschrijven. Gebruik deze methode om de grootte van de voorbeeldbuffers in te stellen.
Streaming
De klasse CSourceStream maakt de streamingthread voor de pin. De threadprocedure wordt geïmplementeerd in de methode CSourceStream::DoBufferProcessingLoop. Met deze methode wordt de pure virtuele CSourceStream::FillBuffer methode aangeroepen, die door de afgeleide klasse moet worden overschreven. Bij deze methode vult de pin de buffer met gegevens. Als uw filter bijvoorbeeld ongecomprimeerde video levert, kunt u hier de videoframes tekenen.
De basisklasse start en stopt automatisch de threadlus op de juiste momenten, wanneer het filter pauzeert of stopt. Als dit gebeurt, roept de CSourceStream--klasse een aantal methoden aan om uw afgeleide klasse op de hoogte te brengen:
U kunt deze methoden overschrijven als u speciale verwerking moet toevoegen. Anders retourneren de standaard implementaties gewoon S_OK.
Op zoek naar
Als u een bronfilter met één uitvoerpin hebt, kunt u de CSourceSeeking klasse gebruiken als uitgangspunt voor het implementeren van zoeken. De pincodeklasse overnemen van zowel CSourceStream- als CSourceSeeking-.
Notitie
CSourceSeeking- wordt niet aanbevolen voor een filter met meer dan één uitvoerpin. Het belangrijkste probleem is dat slechts één pin zou moeten reageren op zoekverzoeken. Normaal gesproken is hiervoor communicatie tussen de spelden en het filter vereist.
De CSourceSeeking klasse beheert de afspeelsnelheid, begintijd, stoptijd en duur. De afgeleide klasse moet de initiële stoptijd en duur instellen. Wanneer een van deze waarden wordt gewijzigd, wordt de methode CSourceSeeking::ChangeRate, CSourceSeeking::ChangeStartof CSourceSeeking::ChangeStop methode aangeroepen. De methoden zijn allemaal pure virtuele methoden. De afgeleide pinklasse overschrijft deze methoden om het volgende te doen:
- Roep IPin::BeginFlush aan op de downstream-pin. Dit zorgt ervoor dat downstreamfilters steekproeven vrijgeven die ze vasthouden en nieuwe steekproeven weigeren.
- Roep CSourceStream::Stop om de streamingthread te stoppen. Het bronfilter onderbreekt het produceren van nieuwe gegevens.
- Roep IPin::EndFlush aan op de downstream pin. Dit geeft de downstreamfilters aan om nieuwe gegevens te accepteren.
- Roep IPin::NewSegment aan met de nieuwe begin- en eindtijden en -snelheid.
- Stel de eigenschap discontinuity in op het volgende voorbeeld.
Zie Ondersteuning zoeken in een bronfiltervoor meer informatie.
Als uw filter het zoeken ondersteunt, is de streampositie nu onafhankelijk van de presentatietijd. Na een zoekbewerking worden tijdstempels opnieuw ingesteld op nul. De algemene formule voor tijdstempels is:
- voorbeeld van begintijd = verstreken tijd / afspeelsnelheid
- voorbeeldeindtijd = voorbeeld van begintijd + (tijd per frame / afspeelsnelheid)
waarbij tijdsverloop verwijst naar de tijd die is verstreken sinds het filter is gestart of sinds de laatste zoekopdracht.
Tijdnotaties voor zoeken
Zoekopdrachten bevinden zich standaard in eenheden van 100 nanoseconden. Uw bronfilter kan ondersteuning bieden voor extra tijdnotaties, zoals zoeken op framenummer. Elk tijdformaat wordt geïdentificeerd door een GUID; zie GUID's voor tijdnotatie.
Als u extra tijdnotaties wilt ondersteunen, moet u de volgende methoden implementeren op uw uitvoerpin:
- IMediaSeeking::ConvertTimeFormat
- IMediaSeeking::GetTimeFormat
- IMediaSeeking::IsFormatSupported
- IMediaSeeking::IsUsingTimeFormat
- IMediaSeeking::QueryPreferredFormat
- IMediaSeeking::SetTimeFormat
Als de toepassing een nieuwe tijdnotatie instelt, worden alle positieparameters in de IMediaSeeking--methoden geïnterpreteerd in termen van de nieuwe tijdnotatie. Als de tijdnotatie bijvoorbeeld frames is, moet de methode IMediaSeeking::GetDuration de duur in frames retourneren.
In de praktijk ondersteunen weinig DirectShow-filters extra tijdnotaties en daardoor maken weinig DirectShow-toepassingen gebruik van deze mogelijkheid.