Share via


Tutorial: Schreiben einer WMA-Datei mithilfe von WMContainer-Objekten

In diesem Tutorial wird das Schreiben einer neuen Audiodatei (WMA) veranschaulicht, indem Medieninhalte aus einer unkomprimierten Audiodatei (WAV) extrahiert und dann im ASF-Format komprimiert werden. Der für die Konvertierung verwendete Codierungsmodus ist constant bit rate encoding (CBR). In diesem Modus gibt die Anwendung vor der Codierungssitzung eine Zielbitrate an, die der Encoder erreichen muss.

In diesem Tutorial erstellen Sie eine Konsolenanwendung, die die Eingabe- und Ausgabedateinamen als Argumente verwendet. Die Anwendung ruft die unkomprimierten Medienbeispiele aus einer Wellendateianalyseanwendung ab, die in diesem Tutorial bereitgestellt wird. Diese Beispiele werden zur Konvertierung in das Windows Media Audio 9-Format an den Encoder gesendet. Der Encoder ist für die CBR-Codierung konfiguriert und verwendet die erste Bitrate, die während der Medientypverhandlung verfügbar ist, als Zielbitrate. Die codierten Beispiele werden zur Paketisierung im ASF-Datenformat an den Multiplexer gesendet. Diese Pakete werden in einen Bytestream geschrieben, der das ASF-Datenobjekt darstellt. Nachdem der Datenabschnitt bereit ist, erstellen Sie eine ASF-Audiodatei und schreiben das neue ASF-Headerobjekt, das alle Headerinformationen konsolidiert, und fügen dann den ASF-Datenobjekt-Bytestream an.

Dieses Tutorial enthält die folgenden Abschnitte:

Voraussetzungen

In diesem Tutorial wird Folgendes vorausgesetzt:

  • Sie sind mit der Struktur einer ASF-Datei und den Komponenten vertraut, die von Media Foundation für die Arbeit mit ASF-Objekten bereitgestellt werden. Zu diesen Komponenten gehören ContentInfo, Splitter, Multiplexer und Profile-Objekte. Weitere Informationen finden Sie unter WMContainer ASF-Komponenten.
  • Sie sind mit Windows Media-Encodern und den verschiedenen Codierungstypen, insbesondere CBR, vertraut. Weitere Informationen finden Sie unter Windows Media Encoders .
  • Sie sind mit Medienpuffern und Bytestreams vertraut: Insbesondere Dateivorgänge, die einen Bytedatenstrom verwenden, und schreiben den Inhalt eines Medienpuffers in einen Bytedatenstrom.

Begriff

In diesem Tutorial werden die folgenden Begriffe verwendet:

1. Einrichten des Projekts

  1. Fügen Sie die folgenden Header in Ihre Quelldatei ein:

    #include <new>
    #include <stdio.h>       // Standard I/O
    #include <windows.h>     // Windows headers
    #include <mfapi.h>       // Media Foundation platform
    #include <wmcontainer.h> // ASF interfaces
    #include <mferror.h>     // Media Foundation error codes
    
  2. Link zu den folgenden Bibliotheksdateien:

    • mfplat.lib
    • mf.lib
    • mfuuid.lib
  3. Deklarieren Sie die SafeRelease-Funktion .

  4. Schließen Sie die CWmaEncoder-Klasse in Ihr Projekt ein. Den vollständigen Quellcode dieser Klasse finden Sie unter Encoder-Beispielcode.

2. Deklarieren von Hilfsfunktionen

In diesem Tutorial werden die folgenden Hilfsfunktionen zum Lesen und Schreiben aus einem Bytedatenstrom verwendet.

  • AppendToByteStream: Fügt den Inhalt eines Bytestreams an einen anderen Bytedatenstrom an.
  • WriteBufferToByteStream: Schreibt Daten aus einem Medienpuffer in einen Bytedatenstrom.

Weitere Informationen finden Sie unter IMFByteStream::Write. Der folgende Code zeigt diese Hilfsfunktionen:

//-------------------------------------------------------------------
// AppendToByteStream
//
// Reads the contents of pSrc and writes them to pDest.
//-------------------------------------------------------------------

HRESULT AppendToByteStream(IMFByteStream *pSrc, IMFByteStream *pDest)
{
    HRESULT hr = S_OK;

    const DWORD READ_SIZE = 1024;

    BYTE buffer[READ_SIZE];

    while (1)
    {
        ULONG cbRead;

        hr = pSrc->Read(buffer, READ_SIZE, &cbRead);

        if (FAILED(hr)) { break; }

        if (cbRead == 0)
        {
            break;
        }

        hr = pDest->Write(buffer, cbRead, &cbRead);

        if (FAILED(hr)) { break; }
    }

    return hr;
}
//-------------------------------------------------------------------
// WriteBufferToByteStream
//
// Writes data from a media buffer to a byte stream.
//-------------------------------------------------------------------

HRESULT WriteBufferToByteStream(
    IMFByteStream *pStream,   // Pointer to the byte stream.
    IMFMediaBuffer *pBuffer,  // Pointer to the media buffer.
    DWORD *pcbWritten         // Receives the number of bytes written.
    )
{
    HRESULT hr = S_OK;
    DWORD cbData = 0;
    DWORD cbWritten = 0;
    BYTE *pMem = NULL;

    hr = pBuffer->Lock(&pMem, NULL, &cbData);

    if (SUCCEEDED(hr))
    {
        hr = pStream->Write(pMem, cbData, &cbWritten);
    }

    if (SUCCEEDED(hr))
    {
        if (pcbWritten)
        {
            *pcbWritten = cbWritten;
        }
    }

    if (pMem)
    {
        pBuffer->Unlock();
    }
    return hr;
}

3. Öffnen einer Audiodatei

In diesem Tutorial wird davon ausgegangen, dass Ihre Anwendung unkomprimierte Audiodaten für die Codierung generiert. Zu diesem Zweck werden in diesem Tutorial zwei Funktionen deklariert:

HRESULT OpenAudioFile(PCWSTR pszURL, IMFMediaType **ppAudioFormat);
HRESULT GetNextAudioSample(BOOL *pbEOS, IMFSample **ppSample);

Die Implementierung dieser Funktionen bleibt dem Reader überlassen.

  • Die OpenAudioFile Funktion sollte die durch pszURL angegebene Mediendatei öffnen und einen Zeiger auf einen Medientyp zurückgeben, der einen Audiodatenstrom beschreibt.
  • Die GetNextAudioSample Funktion sollte unkomprimierte PCM-Audiodaten aus der Datei lesen, die von OpenAudioFilegeöffnet wurde. Wenn das Ende der Datei erreicht ist, erhält pbEOS den Wert TRUE. Andernfalls empfängt ppSample ein Medienbeispiel, das den Audiopuffer enthält.

4. Konfigurieren des Encoders

Erstellen Sie als Nächstes den Encoder, konfigurieren Sie ihn so, dass CBR-codierte Datenstrombeispiele erstellt werden, und verhandeln Sie die Eingabe- und Ausgabemedientypen.

In Media Foundation werden Encoder (die IMFTransform-Schnittstelle verfügbar machen) als Media Foundation Transforms (MFT) implementiert.

In diesem Tutorial wird der Encoder in der -Klasse implementiert, die CWmaEncoder einen Wrapper für MFT bereitstellt. Den vollständigen Quellcode dieser Klasse finden Sie unter Encoder-Beispielcode.

Hinweis

Optional können Sie den Codierungstyp als CBR angeben. Standardmäßig ist der Encoder für die Verwendung der CBR-Codierung konfiguriert. Weitere Informationen finden Sie unter Codierung mit konstanter Bitrate. Sie können je nach Codierungstyp zusätzliche Eigenschaften festlegen. Informationen zu den Eigenschaften, die für einen Codierungsmodus spezifisch sind, finden Sie unter Qualitätsbasierte Codierung variabler Bitraten, Codierung mit nicht eingeschränkter variabler Bitrate und Codierung mit eingeschränkter variabler Bitrate.

 

    CWmaEncoder* pEncoder = NULL; //Pointer to the Encoder object.

    hr = OpenAudioFile(sInputFileName, &pInputType);
    if (FAILED(hr))
    {
        goto done;
    }

    // Initialize the WMA encoder wrapper.

    pEncoder = new (std::nothrow) CWmaEncoder();
    if (pEncoder == NULL)
    {
        hr = E_OUTOFMEMORY;
        goto done;
    }

    hr = pEncoder->Initialize();
    if (FAILED(hr))
    {
        goto done;
    }

    hr = pEncoder->SetEncodingType(EncodeMode_CBR);
    if (FAILED(hr))
    {
        goto done;
    }

    hr = pEncoder->SetInputType(pInputType);
    if (FAILED(hr))
    {
        goto done;
    }

5. Erstellen Sie das ASF ContentInfo-Objekt.

Das ASF ContentInfo-Objekt enthält Informationen zu den verschiedenen Headerobjekten der Ausgabedatei.

Erstellen Sie zunächst ein ASF-Profil für den Audiodatenstrom:

  1. Rufen Sie MFCreateASFProfile auf, um ein leeres ASF-Profilobjekt zu erstellen. Das ASF-Profil macht die IMFASFProfile-Schnittstelle verfügbar. Weitere Informationen finden Sie unter Erstellen und Konfigurieren von ASF-Streams.
  2. Rufen Sie das codierte Audioformat aus dem CWmaEncoder -Objekt ab.
  3. Rufen Sie IMFASFProfile::CreateStream auf, um einen neuen Stream für das ASF-Profil zu erstellen. Übergeben Sie einen Zeiger auf die IMFMediaType-Schnittstelle , die das Streamformat darstellt.
  4. Rufen Sie IMFASFStreamConfig::SetStreamNumber auf, um einen Streambezeichner zuzuweisen.
  5. Legen Sie die Parameter "Leaky Bucket" fest, indem Sie das attribut MF_ASFSTREAMCONFIG_LEAKYBUCKET1 für das Streamobjekt festlegen.
  6. Rufen Sie IMFASFProfile::SetStream auf, um den neuen Stream dem Profil hinzuzufügen.

Erstellen Sie nun das ASF ContentInfo-Objekt wie folgt:

  1. Rufen Sie MFCreateASFContentInfo auf, um ein leeres ContentInfo-Objekt zu erstellen.
  2. Rufen Sie IMFASFContentInfo::SetProfile auf, um das ASF-Profil festzulegen.

Diese Schritte sind im folgenden Code dargestellt:

HRESULT CreateASFContentInfo(
    CWmaEncoder* pEncoder,
    IMFASFContentInfo** ppContentInfo
    )
{
    HRESULT hr = S_OK;
    
    IMFASFProfile* pProfile = NULL;
    IMFMediaType* pMediaType = NULL;
    IMFASFStreamConfig* pStream = NULL;
    IMFASFContentInfo* pContentInfo = NULL;

    // Create the ASF profile object.

    hr = MFCreateASFProfile(&pProfile); 
    if (FAILED(hr))
    {
        goto done;
    }

    // Create a stream description for the encoded audio.

    hr = pEncoder->GetOutputType(&pMediaType); 
    if (FAILED(hr))
    {
        goto done;
    }

    hr = pProfile->CreateStream(pMediaType, &pStream); 
    if (FAILED(hr))
    {
        goto done;
    }

    hr = pStream->SetStreamNumber(DEFAULT_STREAM_NUMBER); 
    if (FAILED(hr))
    {
        goto done;
    }

    // Set "leaky bucket" values.

    LeakyBucket bucket;

    hr = pEncoder->GetLeakyBucket1(&bucket);
    if (FAILED(hr))
    {
        goto done;
    }

    hr = pStream->SetBlob(
        MF_ASFSTREAMCONFIG_LEAKYBUCKET1, 
        (UINT8*)&bucket, 
        sizeof(bucket)
        );

    if (FAILED(hr))
    {
        goto done;
    }

    //Add the stream to the profile

    hr = pProfile->SetStream(pStream);
    if (FAILED(hr))
    {
        goto done;
    }

    // Create the ASF ContentInfo object.

    hr = MFCreateASFContentInfo(&pContentInfo); 
    if (FAILED(hr))
    {
        goto done;
    }

    hr = pContentInfo->SetProfile(pProfile); 
    if (FAILED(hr))
    {
        goto done;
    }

    // Return the pointer to the caller.

    *ppContentInfo = pContentInfo;
    (*ppContentInfo)->AddRef();

done:
    SafeRelease(&pProfile);
    SafeRelease(&pStream);
    SafeRelease(&pMediaType);
    SafeRelease(&pContentInfo);
    return hr;
}

6. Erstellen des ASF-Multiplexers

Der ASF-Multiplexer generiert ASF-Datenpakete.

  1. Rufen Sie MFCreateASFMultiplexer auf, um den ASF-Multiplexer zu erstellen.
  2. Rufen Sie IMFASFMultiplexer::Initialize auf, um den Multiplexer zu initialisieren. Übergeben Sie einen Zeiger auf das ASF Content Info-Objekt, das im vorherigen Abschnitt erstellt wurde.
  3. Rufen Sie IMFASFMultiplexer::SetFlags auf, um das flag MFASF_MULTIPLEXER_AUTOADJUST_BITRATE festzulegen. Wenn diese Einstellung verwendet wird, passt der Multiplexer die Bitrate des ASF-Inhalts automatisch an die Merkmale der zu multiplexierten Streams an.
HRESULT CreateASFMux( 
    IMFASFContentInfo* pContentInfo,
    IMFASFMultiplexer** ppMultiplexer
    )
{
    HRESULT hr = S_OK;
    
    IMFMediaType* pMediaType = NULL;
    IMFASFMultiplexer *pMultiplexer = NULL;

    // Create and initialize the ASF Multiplexer object.

    hr = MFCreateASFMultiplexer(&pMultiplexer);
    if (FAILED(hr))
    {
        goto done;
    }

    hr = pMultiplexer->Initialize(pContentInfo);
    if (FAILED(hr))
    {
        goto done;
    }

    // Enable automatic bit-rate adjustment.

    hr = pMultiplexer->SetFlags(MFASF_MULTIPLEXER_AUTOADJUST_BITRATE);
    if (FAILED(hr))
    {
        goto done;
    }

    *ppMultiplexer = pMultiplexer;
    (*ppMultiplexer)->AddRef();

done:
    SafeRelease(&pMultiplexer);
    return hr;
}

7. Generieren neuer ASF-Datenpakete

Generieren Sie als Nächstes ASF-Datenpakete für die neue Datei. Diese Datenpakete stellen das endgültige ASF-Datenobjekt für die neue Datei dar. So generieren Sie neue ASF-Datenpakete:

  1. Rufen Sie MFCreateTempFile auf, um einen temporären Bytestream zu erstellen, der die ASF-Datenpakete enthält.
  2. Rufen Sie die anwendungsdefinierte GetNextAudioSample Funktion auf, um unkomprimierte Audiodaten für den Encoder abzurufen.
  3. Übergeben Sie das nicht komprimierte Audio zur Komprimierung an den Encoder. Weitere Informationen finden Sie unter Verarbeiten von Daten im Encoder.
  4. Rufen Sie IMFASFMultiplexer::P rocessSample auf, um die komprimierten Audiobeispiele zur Paketisierung an den ASF-Multiplexer zu senden.
  5. Rufen Sie die ASF-Pakete aus dem Multiplexer ab, und schreiben Sie sie in den temporären Bytestream. Weitere Informationen finden Sie unter Generieren neuer ASF-Datenpakete.
  6. Wenn Sie das Ende des Quelldatenstroms erreichen, entladen Sie den Encoder, und ziehen Sie die verbleibenden komprimierten Beispiele aus dem Encoder. Weitere Informationen zum Entladen eines MFT finden Sie unter Grundlegendes MFT-Verarbeitungsmodell.
  7. Nachdem alle Beispiele an den Multiplexer gesendet wurden, rufen Sie IMFASFMultiplexer::Flush auf, und ziehen Sie die verbleibenden ASF-Pakete aus dem Multiplexer.
  8. Rufen Sie IMFASFMultiplexer::End auf.

Der folgende Code generiert ASF-Datenpakete. Die Funktion gibt einen Zeiger auf einen Bytestream zurück, der das ASF-Datenobjekt enthält.

HRESULT EncodeData(
    CWmaEncoder* pEncoder, 
    IMFASFContentInfo* pContentInfo,
    IMFASFMultiplexer* pMux, 
    IMFByteStream** ppDataStream) 
{
    HRESULT hr = S_OK;

    IMFByteStream* pStream = NULL;
    IMFSample* pInputSample = NULL;
    IMFSample* pWmaSample = NULL;

    BOOL bEOF = FALSE;

   // Create a temporary file to hold the data stream.
   hr = MFCreateTempFile(
        MF_ACCESSMODE_READWRITE, 
        MF_OPENMODE_DELETE_IF_EXIST,
        MF_FILEFLAGS_NONE,
        &pStream
        );

   if (FAILED(hr))
   {
       goto done;
   }

    BOOL bNeedInput = TRUE;

    while (TRUE)
    {
        if (bNeedInput)
        {
            hr = GetNextAudioSample(&bEOF, &pInputSample);
            if (FAILED(hr))
            {
                goto done;
            }

            if (bEOF)
            {
                // Reached the end of the input file.
                break;
            }

            // Encode the uncompressed audio sample.
            hr = pEncoder->ProcessInput(pInputSample);
            if (FAILED(hr))
            {
                goto done;
            }

            bNeedInput = FALSE;
        }

        if (bNeedInput == FALSE)
        {
            // Get data from the encoder.

            hr = pEncoder->ProcessOutput(&pWmaSample);
            if (FAILED(hr))
            {
                goto done;
            }

            // pWmaSample can be NULL if the encoder needs more input.

            if (pWmaSample)
            {
                hr = pMux->ProcessSample(DEFAULT_STREAM_NUMBER, pWmaSample, 0);
                if (FAILED(hr))
                {
                    goto done;
                }

                //Collect the data packets and write them to a stream
                hr = GenerateASFDataPackets(pMux, pStream);
                if (FAILED(hr))
                {
                    goto done;
                }
            }
            else
            {
                bNeedInput = TRUE;
            }
        }
        
        SafeRelease(&pInputSample);
        SafeRelease(&pWmaSample);
    }

    // Drain the MFT and pull any remaining samples from the encoder.

    hr = pEncoder->Drain();
    if (FAILED(hr))
    {
        goto done;
    }

    while (TRUE)
    {
        hr = pEncoder->ProcessOutput(&pWmaSample);
        if (FAILED(hr))
        {
            goto done;
        }

        if (pWmaSample == NULL)
        {
            break;
        }

        hr = pMux->ProcessSample(DEFAULT_STREAM_NUMBER, pWmaSample, 0);
        if (FAILED(hr))
        {
            goto done;
        }

        //Collect the data packets and write them to a stream
        hr = GenerateASFDataPackets(pMux, pStream);
        if (FAILED(hr))
        {
            goto done;
        }

        SafeRelease(&pWmaSample);
    }

    // Flush the mux and get any pending ASF data packets.
    hr = pMux->Flush();
    if (FAILED(hr))
    {
        goto done;
    }

    hr = GenerateASFDataPackets(pMux, pStream);
    if (FAILED(hr))
    {
        goto done;
    }
    
    // Update the ContentInfo object
    hr = pMux->End(pContentInfo);
    if (FAILED(hr))
    {
        goto done;
    }

    //Return stream to the caller that contains the ASF encoded data.
    *ppDataStream = pStream;
    (*ppDataStream)->AddRef();

done:
    SafeRelease(&pStream);
    SafeRelease(&pInputSample);
    SafeRelease(&pWmaSample);
    return hr;
}

Code für die GenerateASFDataPackets Funktion wird im Thema Generieren neuer ASF-Datenpakete angezeigt.

8. Schreiben der ASF-Datei

Schreiben Sie als Nächstes den ASF-Header in einen Medienpuffer, indem Sie IMFASFContentInfo::GenerateHeader aufrufen. Diese Methode konvertiert Daten, die im ContentInfo-Objekt gespeichert sind, in Binärdaten im ASF-Headerobjektformat. Weitere Informationen finden Sie unter Generieren eines neuen ASF-Headerobjekts.

Nachdem das neue ASF-Headerobjekt generiert wurde, erstellen Sie einen Bytestream für die Ausgabedatei. Schreiben Sie zuerst das Header-Objekt in den Ausgabebytestream. Folgen Sie dem Header-Objekt mit dem im Datenbytestream enthaltenen Datenobjekt.

HRESULT WriteASFFile( 
     IMFASFContentInfo *pContentInfo, 
     IMFByteStream *pDataStream,
     PCWSTR pszFile
     )
{
    HRESULT hr = S_OK;
    
    IMFMediaBuffer* pHeaderBuffer = NULL;
    IMFByteStream* pWmaStream = NULL;

    DWORD cbHeaderSize = 0;
    DWORD cbWritten = 0;

    //Create output file
    hr = MFCreateFile(MF_ACCESSMODE_WRITE, MF_OPENMODE_DELETE_IF_EXIST,
        MF_FILEFLAGS_NONE, pszFile, &pWmaStream);

    if (FAILED(hr))
    {
        goto done;
    }


    // Get the size of the ASF Header Object.
    hr = pContentInfo->GenerateHeader (NULL, &cbHeaderSize);
    if (FAILED(hr))
    {
        goto done;
    }

    // Create a media buffer.
    hr = MFCreateMemoryBuffer(cbHeaderSize, &pHeaderBuffer);
    if (FAILED(hr))
    {
        goto done;
    }

    // Populate the media buffer with the ASF Header Object.
    hr = pContentInfo->GenerateHeader(pHeaderBuffer, &cbHeaderSize);
    if (FAILED(hr))
    {
        goto done;
    }

    // Write the ASF header to the output file.
    hr = WriteBufferToByteStream(pWmaStream, pHeaderBuffer, &cbWritten);
    if (FAILED(hr))
    {
        goto done;
    }

    // Append the data stream to the file.

    hr = pDataStream->SetCurrentPosition(0);
    if (FAILED(hr))
    {
        goto done;
    }

    hr = AppendToByteStream(pDataStream, pWmaStream);

done:
    SafeRelease(&pHeaderBuffer);
    SafeRelease(&pWmaStream);
    return hr;
}

9. Definieren der Entry-Point-Funktion

Nun können Sie die vorherigen Schritte in einer vollständigen Anwendung zusammenfassen. Bevor Sie eines der Media Foundation-Objekte verwenden, initialisieren Sie die Media Foundation-Plattform, indem Sie MFStartup aufrufen. Wenn Sie fertig sind, rufen Sie MFShutdown auf. Weitere Informationen finden Sie unter Initialisieren von Media Foundation.

Der folgende Code zeigt die vollständige Konsolenanwendung. Das Befehlszeilenargument gibt den Namen der zu konvertierenden Datei und den Namen der neuen Audiodatei an.

int wmain(int argc, WCHAR* argv[])
{
    HeapSetInformation(NULL, HeapEnableTerminationOnCorruption, NULL, 0);

    if (argc != 3)
    {
        wprintf_s(L"Usage: %s input.wmv, %s output.wma");
        return 0;
    }

    const WCHAR* sInputFileName = argv[1];    // Source file name
    const WCHAR* sOutputFileName = argv[2];  // Output file name
    
    IMFMediaType* pInputType = NULL;
    IMFASFContentInfo* pContentInfo = NULL;
    IMFASFMultiplexer* pMux = NULL;
    IMFByteStream* pDataStream = NULL;

    CWmaEncoder* pEncoder = NULL; //Pointer to the Encoder object.

    HRESULT hr = CoInitializeEx(
        NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);

    if (FAILED(hr))
    {
        goto done;
    }

    hr = MFStartup(MF_VERSION);
    if (FAILED(hr))
    {
        goto done;
    }

    CWmaEncoder* pEncoder = NULL; //Pointer to the Encoder object.

    hr = OpenAudioFile(sInputFileName, &pInputType);
    if (FAILED(hr))
    {
        goto done;
    }

    // Initialize the WMA encoder wrapper.

    pEncoder = new (std::nothrow) CWmaEncoder();
    if (pEncoder == NULL)
    {
        hr = E_OUTOFMEMORY;
        goto done;
    }

    hr = pEncoder->Initialize();
    if (FAILED(hr))
    {
        goto done;
    }

    hr = pEncoder->SetEncodingType(EncodeMode_CBR);
    if (FAILED(hr))
    {
        goto done;
    }

    hr = pEncoder->SetInputType(pInputType);
    if (FAILED(hr))
    {
        goto done;
    }

    // Create the WMContainer objects.
    hr = CreateASFContentInfo(pEncoder, &pContentInfo);
    if (FAILED(hr))
    {
        goto done;
    }

    hr = CreateASFMux(pContentInfo, &pMux);
    if (FAILED(hr))
    {
        goto done;
    }

    // Convert uncompressed data to ASF format.
    hr = EncodeData(pEncoder, pContentInfo, pMux, &pDataStream);
    if (FAILED(hr))
    {
        goto done;
    }

    // Write the ASF objects to the output file.
    hr = WriteASFFile(pContentInfo, pDataStream, sOutputFileName);

done:
    SafeRelease(&pInputType);
    SafeRelease(&pContentInfo);
    SafeRelease(&pMux);
    SafeRelease(&pDataStream);
    delete pEncoder;

    MFShutdown();
    CoUninitialize();

    if (FAILED(hr))
    {
        wprintf_s(L"Error: 0x%X\n", hr);
    }

    return 0;
} 

WMContainer ASF-Komponenten

ASF-Unterstützung in Media Foundation