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 anschließend im ASF-Format komprimiert werden. Der für die Konvertierung verwendete Codierungsmodus ist Die Codierung der konstanten Bitrate (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 Wavedatei-Analyseanwendung ab, die in diesem Tutorial bereitgestellt wird. Diese Beispiele werden an den Encoder gesendet, um sie in Windows Media Audio 9-Format zu konvertieren. Der Encoder ist für die CBR-Codierung konfiguriert und verwendet die erste Bitrate, die während der Medientypaushandlung 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 BYTE-Datenstrom des ASF-Datenobjekts an.
Dieses Tutorial enthält die folgenden Abschnitte:
- Voraussetzungen
- Terminologie
- 1. Einrichten der Project
- 2. Deklarieren von Hilfsfunktionen
- 3. Öffnen einer Audiodatei
- 4. Konfigurieren des Encoders
- 5. Erstellen Sie das ASF ContentInfo-Objekt.
- 6. Erstellen des ASF-Multiplexers
- 7. Generieren neuer ASF-Datenpakete
- 8. Schreiben der ASF-Datei
- 9. Definieren der Entry-Point Funktion
- Zugehörige Themen
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 Profilobjekte. Weitere Informationen finden Sie unter WMContainer ASF Components.
- Sie sind mit den Windows Media Encoder 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 Bytestream verwenden und den Inhalt eines Medienpuffers in einen Bytestream schreiben.
Begriff
In diesem Tutorial werden die folgenden Begriffe verwendet:
- Quellmedientyp: Medientypobjekt, macht DIEMEDIAType-Schnittstelle verfügbar, die den Inhalt der Eingabedatei beschreibt.
- Audioprofil: Profilobjekt, macht die IMFASFProfile-Schnittstelle verfügbar, die nur Audiostreams der Ausgabedatei enthält.
- Streambeispiel: Medienbeispiel, verfügbar macht DIEZsample-Schnittstelle verfügbar und stellt die Mediendaten der Eingabedatei dar, die vom Encoder in einem komprimierten Zustand erhalten wurden.
- ContentInfo-Objekt: Das ASF ContentInfo-Objektmacht die IMFASFContentInfo-Schnittstelle verfügbar, die das ASF-Headerobjekt der Ausgabedatei darstellt.
- Datenbytedatenstrom: Bytestreamobjekt, macht DIEBYTEStream-Schnittstelle verfügbar, die den gesamten ASF-Datenobjektteil der Ausgabedatei darstellt.
- Datenpaket: Medienbeispiel, verfügbar macht DIESAMple-Schnittstelle verfügbar, die vom ASF-Multiplexer generiert wird; stellt ein ASF-Datenpaket dar, das in den Daten bytestream geschrieben wird.
- Ausgabebytestream: Bytestreamobjekt, macht DIEBYTESTREAM-Schnittstelle verfügbar, die den Inhalt der Ausgabedatei enthält.
1. Einrichten der Project
Schließen 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 codesLink zu den folgenden Bibliotheksdateien:
- mfplat.lib
- mf.lib
- mfuuid.lib
Deklarieren Sie die SafeRelease-Funktion.
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 Bytestream verwendet.
AppendToByteStream: Fügt den Inhalt eines Bytestreams an einen anderen Bytestream an.- WriteBufferToByteStream: Schreibt Daten aus einem Medienpuffer in einen Bytestream.
Weitere Informationen finden Sie unter DURCHBYTEStream::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
OpenAudioFileFunktion sollte die von pszURL angegebene Mediendatei öffnen und einen Zeiger auf einen Medientyp zurückgeben, der einen Audiostream beschreibt. - Die
GetNextAudioSampleFunktion sollte unkomprimierte PCM-Audiodaten aus der Datei lesen, die von geöffnetOpenAudioFilewurde. Wenn das Ende der Datei erreicht ist, empfängt 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 Streambeispiele erstellt werden, und handeln Sie die Eingabe- und Ausgabemedientypen aus.
In Media Foundation werden Encoder (die DIET-Schnittstelle verfügbar machen) als Media Foundation Transforms (MFT) implementiert.
In diesem Tutorial wird der Encoder in der -Klasse CWmaEncoder implementiert, die einen Wrapper für MFT bietet. 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 Constant Bit Rate Encoding. Sie können je nach Codierungstyp zusätzliche Eigenschaften festlegen. Informationen zu den eigenschaften, die für einen Codierungsmodus spezifisch sind, finden Sie unter Quality-Based Variable Bit Rate Encoding, Unconstrained Variable Bit Rate Encodingund Peak-Constrained Variable Bit Rate Encoding.
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 Audiostream:
- 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 Creating and Configuring ASF Streams.
- Das codierte Audioformat wird aus dem -Objekt
CWmaEncoderentfernt. - Rufen Sie IMFASFProfile::CreateStream auf, um einen neuen Stream für das ASF-Profil zu erstellen. Übergeben Sie einen Zeiger auf die BESCHRIFTUNGMediaType-Schnittstelle, die das Streamformat darstellt.
- Rufen Sie IMFASFStreamConfig::SetStreamNumber auf, um einen Streambezeichner zu zuweisen.
- Legen Sie die Parameter "Leaky Bucket" fest, indem Sie das MF _ ASFSTREAMCONFIG _ LEAKYBUCKET1-Attribut für das Streamobjekt festlegen.
- Rufen Sie IMFASFProfile::SetStream auf, um dem Profil den neuen Stream hinzuzufügen.
Erstellen Sie nun das ASF ContentInfo-Objekt wie folgt:
- Rufen Sie MFCreateASFContentInfo auf, um ein leeres ContentInfo-Objekt zu erstellen.
- Rufen Sie IMFASFContentInfo::SetProfile auf, um das ASF-Profil zu festlegen.
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.
- Rufen Sie MFCreateASFMultiplexer auf, um den ASF-Multiplexer zu erstellen.
- Rufen Sie IMFASFMultiplexer::Initialize auf, um den Multiplexer zu initialisieren. Übergeben Sie einen Zeiger auf das ASF-Inhaltsinformationsobjekt, das im vorherigen Abschnitt erstellt wurde.
- Rufen Sie IMFASFMultiplexer::SetFlags auf, um das MFASF _ MULTIPLEXER _ AUTOADJUST _ BITRATE-Flag festlegen. Wenn diese Einstellung verwendet wird, passt der Multiplexer die Bitrate des ASF-Inhalts automatisch an die Merkmale der Datenströme an, die multiplexiert werden.
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 bilden das endgültige ASF-Datenobjekt für die neue Datei. So generieren Sie neue ASF-Datenpakete:
- Rufen Sie MFCreateTempFile auf, um einen temporären Bytestream für die ASF-Datenpakete zu erstellen.
- Rufen Sie die anwendungsdefinierte
GetNextAudioSampleFunktion auf, um unkomprimierte Audiodaten für den Encoder abzurufen. - Übergeben Sie die unkomprimierten Audiodaten zur Komprimierung an den Encoder. Weitere Informationen finden Sie unter Verarbeiten von Daten im Encoder.
- Rufen Sie IMFASFMultiplexer::P rocessSample auf, um die komprimierten Audiobeispiele zur Paketisierung an den ASF-Multiplexer zu senden.
- Abrufen der ASF-Pakete aus dem Multiplexer und Schreiben in den temporären Bytestream. Weitere Informationen finden Sie unter Generieren neuer ASF-Datenpakete.
- Wenn Sie das Ende des Quelldatenstroms erreichen, entladen Sie den Encoder, und ziehen Sie die verbleibenden komprimierten Stichproben vom Encoder. Weitere Informationen zum Entladen eines MFT finden Sie unter Grundlegendes MFT-Verarbeitungsmodell.
- Nachdem alle Beispiele an den Multiplexer gesendet wurden, rufen Sie IMFASFMultiplexer::Flush auf, und pullen Sie die verbleibenden ASF-Pakete aus dem Multiplexer.
- Rufen Sie IMFASFMultiplexer::Endauf.
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-Datenpaketegezeigt.
8. Schreiben der ASF-Datei
Schreiben Sie als Nächstes den ASF-Header in einen Medienpuffer, indem Sie IMFASFContentInfo::GenerateHeaderaufrufen. Diese Methode konvertiert im ContentInfo-Objekt gespeicherte Daten 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 Headerobjekt in den Ausgabe-Bytestream. Folgen Sie dem Headerobjekt mit dem Datenobjekt, das im Daten-Bytestream enthalten ist.
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 zusammenfügen. Bevor Sie eines der Media Foundation -Objekte verwenden, initialisieren Sie die Media Foundation-Plattform, indem Sie MFStartupaufrufen. Wenn Sie fertig sind, rufen Sie MFShutdown auf. Weitere Informationen finden Sie unter Initialisieren 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;
}