Delen via


Streamvoorbeelden genereren van een bestaand ASF-gegevensobject

Het ASF-splitsobject object is een WMContainer-laagonderdeel dat het ASF-gegevensobject van een ASF-bestand (Advanced Systems Format) parseert.

Voordat gegevenspakketten worden doorgegeven aan de splitsfunctie, moet de toepassing stromen in de splitsfunctie initialiseren, configureren en selecteren om deze voor te bereiden op het parseringsproces. Zie Het ASF-splitsobject maken en Het ASF-splitsobject configurerenvoor meer informatie.

De methoden die vereist zijn voor het parseren van het ASF-gegevensobject zijn:

De gegevensoffset vinden

Voordat u het parseringsproces start, moet de toepassing het gegevensobject in het ASF-bestand zoeken. Er zijn twee manieren om de offset van het gegevensobject vanaf het begin van het bestand te bepalen:

  • Voordat u het ContentInfo-object hebt geïnitialiseerd, kunt u de methode IMFASFContentInfo::GetHeaderSize aanroepen. Voor deze methode is een buffer vereist die de eerste 30 bytes van de ASF-header bevat. Het retourneert de grootte van de hele header die de offset aangeeft aan het eerste gegevenspakket. Deze waarde bevat ook de headergrootte van het gegevensobject van 50 bytes.

  • Nadat u het Object ContentInfo hebt geïnitialiseerd, kunt u de presentatiedescriptor ophalen door IMFASFContentInfo::GeneratePresentationDescriptoraan te roepen en vervolgens een query uit te voeren op de presentatiedescriptor voor het kenmerk MF_PD_ASF_DATA_START_OFFSET. De waarde van dit kenmerk is de koptekstgrootte.

    Notitie

    Het kenmerk MF_PD_ASF_DATA_LENGTH op de presentatiedescriptor geeft de lengte van het ASF-gegevensobject aan.

     

In beide gevallen is de geretourneerde waarde de grootte van het headerobject plus de grootte van de koptekstsectie van het gegevensobject. Daarom is de resulterende waarde de verschuiving naar het begin van de gegevenspakketten in het ASF-gegevensobject. Wanneer u begint met het verzenden van gegevens naar de splitsverwerker, moeten de gegevens beginnen vanaf deze offset vanaf het begin van het ASF-bestand.

De offsetwaarde wordt doorgegeven als een parameter aan ParseData- waarmee het parseringsproces wordt gestart.

Het gegevensobject is onderverdeeld in gegevenspakketten. Elk gegevenspakket bevat een gegevenspakketheader die pakketparseringsinformatie en de nettoladinggegevens biedt: de werkelijke digitale mediagegevens. In een opzoekscenario wil de toepassing mogelijk dat de splitser begint met parseren op een bepaald gegevenspakket. Hiervoor kunt u de ASF-indexeerfunctie gebruiken om de offset op te halen. De indexeerfunctie retourneert een offsetwaarde die begint bij de pakketgrens. Als u de indexeerfunctie niet gebruikt, moet u ervoor zorgen dat de offset begint aan het begin van de header van het gegevenspakket. Als er een ongeldige offset wordt doorgegeven aan de splitsfunctie, bijvoorbeeld wanneer de waarde niet verwijs naar de pakketgrens, slagen de ParseHeader- en GetNextSample--aanroepen, maar wordt er bij de GetNextSample--aanroep geen steekproeven opgehaald en wordt NULL- ontvangen in de parameter pSample-.

Als de splitster is geconfigureerd om in de omgekeerde richting te parseren, begint de splitster altijd te parseren aan het einde van de mediabuffer die wordt doorgegeven aan ParseData-. Voor omgekeerde parsering in de aanroep naar ParseData-geeft u de offset door in de parameter cbLength, waarmee de lengte van de gegevens wordt opgegeven en cbBufferOffset op nul wordt ingesteld.

Voorbeelden genereren voor ASF-gegevenspakketten

Een toepassing start het parseringsproces door de gegevenspakketten door te geven aan de splitser. De invoer voor de splitser is een reeks mediabuffers die het gehele of fragmenten van het gegevensobject bevatten. De uitvoer van de splitser is een reeks mediavoorbeelden die de pakketgegevens bevatten.

Als u invoergegevens wilt doorgeven aan de splitsfunctie, maakt u een mediabuffer en vult u deze met gegevens uit de sectie Gegevensobject van het ASF-bestand. (Zie Mediabuffersvoor meer informatie over mediabuffers.) Geef vervolgens de mediabuffer door aan de methode IMFASFSplitter::ParseData. U kunt ook het volgende opgeven:

  • De verschuiving in de buffer waar de splitser moet beginnen met parseren. Als de offset nul is, begint parseren aan het begin van de buffer. Zie de sectie 'Het gegevensoffset vinden' in dit onderwerp voor meer informatie over het instellen van het gegevensoffset.
  • De hoeveelheid gegevens die moet worden geparseerd. Als deze waarde nul is, parseert de splitsfunctie totdat deze het einde van de buffer bereikt, zoals opgegeven door de methode IMFMediaBuffer::GetCurrentLength.

De splitser genereert mediavoorbeelden door te verwijzen naar de gegevens in de mediabuffers. De client kan de uitvoervoorbeelden ophalen door IMFASFSplitter::GetNextSample- in een lus aan te roepen totdat er geen gegevens meer zijn om te parseren. Als GetNextSample- de vlag ASF_STATUSFLAGS_INCOMPLETE retourneert in de parameter pdwStatusFlags, betekent dit dat er meer voorbeelden moeten worden opgehaald en dat de toepassing GetNextSample- opnieuw kan aanroepen. Anders roept u ParseData- aan om meer gegevens door te geven aan de splitser. Voor de gegenereerde voorbeelden stelt de splitsfunctie de volgende informatie in:

  • De splitser stelt een tijdstempel in op alle voorbeelden die worden gegenereerd. De voorbeeldtijd vertegenwoordigt de presentatietijd en bevat niet de preroll-tijd. De toepassing kan IMFSample::GetSampleTime aanroepen om de presentatietijd te krijgen, in eenheden van 100 nanoseconden.
  • Als er tijdens het genereren van een steekproef een onderbreking optreedt, stelt de splitser het kenmerk MFSampleExtension_Discontinuity in op het eerste voorbeeld na de onderbreking. Onderbrekingen worden meestal veroorzaakt door verwijderde pakketten op een netwerkverbinding, beschadigde bestandsgegevens of de splitser die van de ene bronstroom naar de andere overschakelt.
  • Voor video controleert de splitser of het voorbeeld een sleutelframe bevat. Als dit het geval is, stelt de splitser het kenmerk MFSampleExtension_CleanPoint in het voorbeeld in.

Als de splitser gegevenspakketten parseert die worden ontvangen van een mediaserver, is het mogelijk dat de pakketlengte variabel is. In dit geval moet de client ParseData- aanroepen voor elk pakket en het kenmerk MFASFSPLITTER_PACKET_BOUNDARY instellen voor elke buffer die naar de splitser wordt verzonden. Dit kenmerk geeft aan de splitter of de mediabuffer het begin van een ASF-pakket bevat. Stel het kenmerk in op TRUE- als de buffer het begin van een nieuw pakket bevat. Als de buffer een vervolg van het vorige pakket bevat, stelt u het kenmerk in op ONWAAR. De buffers kunnen niet meerdere pakketten omvatten.

Voordat nieuwe mediabuffers aan de splitter worden doorgegeven, moet de toepassing IMFASFSplitter::Flushaanroepen. Met deze methode wordt de splitser opnieuw ingesteld en wordt een gedeeltelijk frame gewist dat wacht op voltooiing. Dit is handig in een zoekscenario waarbij de offset zich op een andere locatie bevindt.

Voorbeeld

In het volgende codevoorbeeld ziet u hoe u gegevenspakketten parseert. In dit voorbeeld wordt vanaf het begin van het gegevensobject naar het einde van de stroom geparseerd en wordt informatie weergegeven over de voorbeelden die sleutelframes bevatten. Zie zelfstudie: een ASF-bestand lezenvoor een volledig voorbeeld waarin deze code wordt gebruikt.

// Parse the video stream and display information about the video samples.
//
// The current read position of the byte stream must be at the start of the ASF
// Data Object.

HRESULT DisplayKeyFrames(IMFByteStream *pStream, IMFASFSplitter *pSplitter)
{
    const DWORD cbReadSize = 2048;  // Read size (arbitrary value)

    IMFMediaBuffer *pBuffer = NULL;
    IMFSample *pSample = NULL;

    HRESULT hr = S_OK;
    while (SUCCEEDED(hr))
    {
        // The parser must get a newly allocated buffer each time.
        hr = MFCreateMemoryBuffer(cbReadSize, &pBuffer);
        if (FAILED(hr))
        {
            break;
        }

        // Read data into the buffer.
        hr = ReadFromByteStream(pStream, pBuffer, cbReadSize);
        if (FAILED(hr)) 
        {
            break; 
        }

        // Get the amound of data that was read.
        DWORD cbData;
        hr = pBuffer->GetCurrentLength(&cbData);
        if (FAILED(hr)) 
        { 
            break; 
        }

        if (cbData == 0)
        {
            break; // End of file.
        }

        // Send the data to the ASF splitter.
        hr = pSplitter->ParseData(pBuffer, 0, 0);
        SafeRelease(&pBuffer);
        if (FAILED(hr)) 
        { 
            break; 
        }

        // Pull samples from the splitter.
        DWORD parsingStatus = 0;
        do
        {
            WORD streamID;
            hr = pSplitter->GetNextSample(&parsingStatus, &streamID, &pSample);
            if (FAILED(hr)) 
            { 
                break; 
            }
            if (pSample == NULL)
            {
                // No samples yet. Parse more data.
                break;
            }
            if (IsRandomAccessPoint(pSample))
            {
                DisplayKeyFrame(pSample);
            }
            SafeRelease(&pSample);
            
        } while (parsingStatus & ASF_STATUSFLAGS_INCOMPLETE);
    }
    SafeRelease(&pSample);
    SafeRelease(&pBuffer);
    return hr;
}

ASF-splitter