Tutorial: Codieren einer MP4-Datei
In diesem Tutorial erfahren Sie, wie Sie die Transcodierungs-API zum Codieren einer MP4-Datei verwenden, indem Sie H.264 für den Videostream und AAC für den Audiostream verwenden.
- Header und Bibliotheksdateien
- Definieren der Codierungsprofile
- Schreiben der wmain-Funktion
- Codieren der Datei
- Mediensitzungs-Hilfe
- Zugehörige Themen
Header und Bibliotheksdateien
Schließen Sie die folgenden Headerdateien ein.
#include <new>
#include <iostream>
#include <windows.h>
#include <mfapi.h>
#include <Mfidl.h>
#include <shlwapi.h>
Verknüpfen Sie die folgenden Bibliotheksdateien.
#pragma comment(lib, "mfplat")
#pragma comment(lib, "mf")
#pragma comment(lib, "mfuuid")
#pragma comment(lib, "shlwapi")
Definieren der Codierungsprofile
Ein Ansatz für die Codierung besteht in der Definition einer Liste von Zielcodierungsprofilen, die im Voraus bekannt sind. In diesem Tutorial verwenden wir einen relativ einfachen Ansatz und speichern eine Liste der Codierungsformate für H.264-Video und AAC-Audio.
Für H.264 sind die wichtigsten Formatattribute das H.264-Profil, die Bildfrequenz, die Framegröße und die codierte Bitrate. Das folgende Array enthält eine Liste der H.264-Codierungsformate.
struct H264ProfileInfo
{
UINT32 profile;
MFRatio fps;
MFRatio frame_size;
UINT32 bitrate;
};
H264ProfileInfo h264_profiles[] =
{
{ eAVEncH264VProfile_Base, { 15, 1 }, { 176, 144 }, 128000 },
{ eAVEncH264VProfile_Base, { 15, 1 }, { 352, 288 }, 384000 },
{ eAVEncH264VProfile_Base, { 30, 1 }, { 352, 288 }, 384000 },
{ eAVEncH264VProfile_Base, { 29970, 1000 }, { 320, 240 }, 528560 },
{ eAVEncH264VProfile_Base, { 15, 1 }, { 720, 576 }, 4000000 },
{ eAVEncH264VProfile_Main, { 25, 1 }, { 720, 576 }, 10000000 },
{ eAVEncH264VProfile_Main, { 30, 1 }, { 352, 288 }, 10000000 },
};
H.264-Profile werden mithilfe der eAVEncH264VProfile-Enumeration angegeben. Sie können auch die H.264-Ebene angeben, aber der Microsoft Media Foundation H.264 Video Encoder kann die richtige Ebene für einen bestimmten Videostream ableiten. Daher wird empfohlen, die ausgewählte Ebene des Encoders nicht zu überschreiben. Für Interlacing-Inhalte würden Sie auch den Interlace-Modus angeben (siehe Video Interlacing).
Für AAC-Audio sind die wichtigsten Formatattribute die Audiostichprobenrate, die Anzahl der Kanäle, die Anzahl der Bits pro Stichprobe und die codierte Bitrate. Optional können Sie die AAC-Audioprofilebenenanzeige festlegen. Weitere Informationen finden Sie unter AAC Encoder. Das folgende Array enthält eine Liste der AAC-Codierungsformate.
struct AACProfileInfo
{
UINT32 samplesPerSec;
UINT32 numChannels;
UINT32 bitsPerSample;
UINT32 bytesPerSec;
UINT32 aacProfile;
};
AACProfileInfo aac_profiles[] =
{
{ 96000, 2, 16, 24000, 0x29},
{ 48000, 2, 16, 24000, 0x29},
{ 44100, 2, 16, 16000, 0x29},
{ 44100, 2, 16, 12000, 0x29},
};
Hinweis
Die H264ProfileInfo hier definierten Strukturen und sind nicht Teil der Media Foundation AACProfileInfo API.
Schreiben der wmain-Funktion
Der folgende Code zeigt den Einstiegspunkt für die Konsolenanwendung.
int video_profile = 0;
int audio_profile = 0;
int wmain(int argc, wchar_t* argv[])
{
HeapSetInformation(NULL, HeapEnableTerminationOnCorruption, NULL, 0);
if (argc < 3 || argc > 5)
{
std::cout << "Usage:" << std::endl;
std::cout << "input output [ audio_profile video_profile ]" << std::endl;
return 1;
}
if (argc > 3)
{
audio_profile = _wtoi(argv[3]);
}
if (argc > 4)
{
video_profile = _wtoi(argv[4]);
}
HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
if (SUCCEEDED(hr))
{
hr = MFStartup(MF_VERSION);
if (SUCCEEDED(hr))
{
hr = EncodeFile(argv[1], argv[2]);
MFShutdown();
}
CoUninitialize();
}
if (SUCCEEDED(hr))
{
std::cout << "Done." << std::endl;
}
else
{
std::cout << "Error: " << std::hex << hr << std::endl;
}
return 0;
}
Die wmain Funktion führt Folgendes aus:
- Ruft die CoInitializeEx-Funktion auf, um die COM-Bibliothek zu initialisieren.
- Ruft die MFStartup-Funktion auf, um die Media Foundation.
- Ruft die anwendungsdefinierte Funktion
EncodeFileauf. Diese Funktion transcodiert die Eingabedatei in die Ausgabedatei und wird im nächsten Abschnitt gezeigt. - Ruft die MFShutdown-Funktion auf, um die Media Foundation.
- Rufen Sie die CoUninitialize-Funktion auf, um die Initialisierung der COM-Bibliothek zu entfernen.
Codieren der Datei
Der folgende Code zeigt EncodeFile die -Funktion, die die Transcodierung ausführt. Diese Funktion besteht größtenteils aus Aufrufen anderer anwendungsdefinierter Funktionen, die weiter unten in diesem Thema gezeigt werden.
HRESULT EncodeFile(PCWSTR pszInput, PCWSTR pszOutput)
{
IMFTranscodeProfile *pProfile = NULL;
IMFMediaSource *pSource = NULL;
IMFTopology *pTopology = NULL;
CSession *pSession = NULL;
MFTIME duration = 0;
HRESULT hr = CreateMediaSource(pszInput, &pSource);
if (FAILED(hr))
{
goto done;
}
hr = GetSourceDuration(pSource, &duration);
if (FAILED(hr))
{
goto done;
}
hr = CreateTranscodeProfile(&pProfile);
if (FAILED(hr))
{
goto done;
}
hr = MFCreateTranscodeTopology(pSource, pszOutput, pProfile, &pTopology);
if (FAILED(hr))
{
goto done;
}
hr = CSession::Create(&pSession);
if (FAILED(hr))
{
goto done;
}
hr = pSession->StartEncodingSession(pTopology);
if (FAILED(hr))
{
goto done;
}
hr = RunEncodingSession(pSession, duration);
done:
if (pSource)
{
pSource->Shutdown();
}
SafeRelease(&pSession);
SafeRelease(&pProfile);
SafeRelease(&pSource);
SafeRelease(&pTopology);
return hr;
}
Die EncodeFile Funktion führt die folgenden Schritte aus.
- Erstellt eine Medienquelle für die Eingabedatei unter Verwendung der URL oder des Dateipfads der Eingabedatei. (Weitere Informationen finden Sie unter Erstellen der Medienquelle.)
- Ruft die Dauer der Eingabedatei ab. (Weitere Informationen finden Sie unter Get the Source Duration.)
- Erstellen Sie das Transcodierungsprofil. (Weitere Informationen finden Sie unter Erstellen des Transcodierungsprofils.)
- Rufen Sie MFCreateTranscodeTopology auf, um die Teiltranscodierungstopologie zu erstellen.
- Erstellen Sie ein Hilfsobjekt, das die Mediensitzung verwaltet. (Weitere Informationen finden Sie unter Media Session Helper(Mediensitzungs-Hilfe).
- Führen Sie die Codierungssitzung aus, und warten Sie, bis sie abgeschlossen ist. (Siehe Ausführen der Codierungssitzung.)
- Rufen Sie DIE MEDIENQUELLE::Shutdown auf, um die Medienquelle herunter zu fahren.
- Releaseschnittstellenzeer. In diesem Code wird die SafeRelease-Funktion verwendet, um Schnittstellenzeigen zu veröffentlichen. Eine weitere Möglichkeit ist die Verwendung einer intelligenten COM-Zeigerklasse, z. B. CComPtr.
Erstellen der Medienquelle
Die Medienquelle ist das Objekt, das die Eingabedatei liest und analysiert. Um die Medienquelle zu erstellen, übergeben Sie die URL der Eingabedatei an den Quellre resolver. Dies wird im folgenden Code veranschaulicht.
HRESULT CreateMediaSource(PCWSTR pszURL, IMFMediaSource **ppSource)
{
MF_OBJECT_TYPE ObjectType = MF_OBJECT_INVALID;
IMFSourceResolver* pResolver = NULL;
IUnknown* pSource = NULL;
// Create the source resolver.
HRESULT hr = MFCreateSourceResolver(&pResolver);
if (FAILED(hr))
{
goto done;
}
// Use the source resolver to create the media source
hr = pResolver->CreateObjectFromURL(pszURL, MF_RESOLUTION_MEDIASOURCE,
NULL, &ObjectType, &pSource);
if (FAILED(hr))
{
goto done;
}
// Get the IMFMediaSource interface from the media source.
hr = pSource->QueryInterface(IID_PPV_ARGS(ppSource));
done:
SafeRelease(&pResolver);
SafeRelease(&pSource);
return hr;
}
Weitere Informationen finden Sie unter Verwenden des Quellre resolvers.
Get the Source Duration
Obwohl dies nicht erforderlich ist, ist es hilfreich, die Medienquelle für die Dauer der Eingabedatei abfragt. Dieser Wert kann zum Nachverfolgen des Codierungsfortschritts verwendet werden. Die Dauer wird im MF _ PD _ DURATION-Attribut des Präsentationsdeskriptors gespeichert. Rufen Sie den Präsentationsdeskriptor ab, indem Sie DENKMediaSource::CreatePresentationDescriptor aufrufen.
HRESULT GetSourceDuration(IMFMediaSource *pSource, MFTIME *pDuration)
{
*pDuration = 0;
IMFPresentationDescriptor *pPD = NULL;
HRESULT hr = pSource->CreatePresentationDescriptor(&pPD);
if (SUCCEEDED(hr))
{
hr = pPD->GetUINT64(MF_PD_DURATION, (UINT64*)pDuration);
pPD->Release();
}
return hr;
}
Erstellen des Transcodierungsprofils
Das Transcodierungsprofil beschreibt die Codierungsparameter. Weitere Informationen zum Erstellen eines Transcodierungsprofils finden Sie unter Verwenden der Transcodierungs-API. Führen Sie zum Erstellen des Profils die folgenden Schritte aus.
- Rufen Sie MFCreateTranscodeProfile auf, um das leere Profil zu erstellen.
- Erstellen Sie einen Medientyp für den AAC-Audiostream. Fügen Sie sie dem Profil hinzu, indem Sie DENKTranscodeProfile::SetAudioAttributes aufrufen.
- Erstellen Sie einen Medientyp für den H.264-Videostream. Fügen Sie sie dem Profil hinzu, indem Sie DEN WERT FÜRTRANSCODEProfile::SetVideoAttributes aufrufen.
- Rufen Sie MFCreateAttributes auf, um einen Attributspeicher für die Attribute auf Containerebene zu erstellen.
- Legen Sie das MF _ TRANSCODE _ CONTAINERTYPE-Attribut fest. Dies ist das einzige erforderliche Attribut auf Containerebene. Legen Sie für die MP4-Dateiausgabe dieses Attribut auf MFTranscodeContainerType _ MPEG4 fest.
- Rufen Sie ZUM Festlegen der Attribute auf Containerebene DEN WERTBTRANSCODEProfile::SetContainerAttributes auf.
Der folgende Code zeigt diese Schritte.
HRESULT CreateTranscodeProfile(IMFTranscodeProfile **ppProfile)
{
IMFTranscodeProfile *pProfile = NULL;
IMFAttributes *pAudio = NULL;
IMFAttributes *pVideo = NULL;
IMFAttributes *pContainer = NULL;
HRESULT hr = MFCreateTranscodeProfile(&pProfile);
if (FAILED(hr))
{
goto done;
}
// Audio attributes.
hr = CreateAACProfile(audio_profile, &pAudio);
if (FAILED(hr))
{
goto done;
}
hr = pProfile->SetAudioAttributes(pAudio);
if (FAILED(hr))
{
goto done;
}
// Video attributes.
hr = CreateH264Profile(video_profile, &pVideo);
if (FAILED(hr))
{
goto done;
}
hr = pProfile->SetVideoAttributes(pVideo);
if (FAILED(hr))
{
goto done;
}
// Container attributes.
hr = MFCreateAttributes(&pContainer, 1);
if (FAILED(hr))
{
goto done;
}
hr = pContainer->SetGUID(MF_TRANSCODE_CONTAINERTYPE, MFTranscodeContainerType_MPEG4);
if (FAILED(hr))
{
goto done;
}
hr = pProfile->SetContainerAttributes(pContainer);
if (FAILED(hr))
{
goto done;
}
*ppProfile = pProfile;
(*ppProfile)->AddRef();
done:
SafeRelease(&pProfile);
SafeRelease(&pAudio);
SafeRelease(&pVideo);
SafeRelease(&pContainer);
return hr;
}
Um die Attribute für den H.264-Videostream anzugeben, erstellen Sie einen Attributspeicher und legen die folgenden Attribute fest:
| attribute | Beschreibung |
|---|---|
| MF _ _ MT-UNTERTYP | Legen Sie auf MFVideoFormat _ H264 fest. |
| MF _ MT _ _ MPEG2-PROFIL | H.264-Profil. |
| MF _ MT _ FRAME _ SIZE | Framegröße. |
| MF _ MT _ FRAME _ RATE | Bildrate. |
| MF _ MT _ AVG _ BITRATE | Codierte Bitrate. |
Um die Attribute für den AAC-Audiostream anzugeben, erstellen Sie einen Attributspeicher und legen die folgenden Attribute fest:
| attribute | Beschreibung |
|---|---|
| MF _ _ MT-UNTERTYP | Legen Sie auf MFAudioFormat _ AAC fest. |
| MF _ _ MT-AUDIOBEISPIELE _ _ PRO _ SEKUNDE | Rate der Audiostichproben. |
| MF _ _ MT-AUDIOBITS _ _ PRO _ BEISPIEL | Bits pro Audiobeispiel. |
| MF _ MT _ AUDIO _ NUM _ CHANNELS | Anzahl der Audiokanäle. |
| MF _ MT _ AUDIO _ AVG _ BYTES _ PER _ SECOND | Codierte Bitrate. |
| MF MT AUDIO BLOCK ALIGNMENT (MF _ _ MT-AUDIOBLOCKAUSRICHTUNG) _ _ | Auf 1 festlegen. |
| MF _ MT _ AAC _ AUDIO _ PROFILE _ LEVEL _ INDICATION | AAC-Profilebenenanzeige (optional). |
Der folgende Code erstellt die Videostreamattribute.
HRESULT CreateH264Profile(DWORD index, IMFAttributes **ppAttributes)
{
if (index >= ARRAYSIZE(h264_profiles))
{
return E_INVALIDARG;
}
IMFAttributes *pAttributes = NULL;
const H264ProfileInfo& profile = h264_profiles[index];
HRESULT hr = MFCreateAttributes(&pAttributes, 5);
if (SUCCEEDED(hr))
{
hr = pAttributes->SetGUID(MF_MT_SUBTYPE, MFVideoFormat_H264);
}
if (SUCCEEDED(hr))
{
hr = pAttributes->SetUINT32(MF_MT_MPEG2_PROFILE, profile.profile);
}
if (SUCCEEDED(hr))
{
hr = MFSetAttributeSize(
pAttributes, MF_MT_FRAME_SIZE,
profile.frame_size.Numerator, profile.frame_size.Numerator);
}
if (SUCCEEDED(hr))
{
hr = MFSetAttributeRatio(
pAttributes, MF_MT_FRAME_RATE,
profile.fps.Numerator, profile.fps.Denominator);
}
if (SUCCEEDED(hr))
{
hr = pAttributes->SetUINT32(MF_MT_AVG_BITRATE, profile.bitrate);
}
if (SUCCEEDED(hr))
{
*ppAttributes = pAttributes;
(*ppAttributes)->AddRef();
}
SafeRelease(&pAttributes);
return hr;
}
Der folgende Code erstellt die Audiostreamattribute.
HRESULT CreateAACProfile(DWORD index, IMFAttributes **ppAttributes)
{
if (index >= ARRAYSIZE(aac_profiles))
{
return E_INVALIDARG;
}
const AACProfileInfo& profile = aac_profiles[index];
IMFAttributes *pAttributes = NULL;
HRESULT hr = MFCreateAttributes(&pAttributes, 7);
if (SUCCEEDED(hr))
{
hr = pAttributes->SetGUID(MF_MT_SUBTYPE, MFAudioFormat_AAC);
}
if (SUCCEEDED(hr))
{
hr = pAttributes->SetUINT32(
MF_MT_AUDIO_BITS_PER_SAMPLE, profile.bitsPerSample);
}
if (SUCCEEDED(hr))
{
hr = pAttributes->SetUINT32(
MF_MT_AUDIO_SAMPLES_PER_SECOND, profile.samplesPerSec);
}
if (SUCCEEDED(hr))
{
hr = pAttributes->SetUINT32(
MF_MT_AUDIO_NUM_CHANNELS, profile.numChannels);
}
if (SUCCEEDED(hr))
{
hr = pAttributes->SetUINT32(
MF_MT_AUDIO_AVG_BYTES_PER_SECOND, profile.bytesPerSec);
}
if (SUCCEEDED(hr))
{
hr = pAttributes->SetUINT32(MF_MT_AUDIO_BLOCK_ALIGNMENT, 1);
}
if (SUCCEEDED(hr))
{
hr = pAttributes->SetUINT32(
MF_MT_AAC_AUDIO_PROFILE_LEVEL_INDICATION, profile.aacProfile);
}
if (SUCCEEDED(hr))
{
*ppAttributes = pAttributes;
(*ppAttributes)->AddRef();
}
SafeRelease(&pAttributes);
return hr;
}
Beachten Sie, dass die Transcodierungs-API keinen echten Medientyp erfordert, obwohl sie Medientypattribute verwendet. Insbesondere das MF _ MT _ MAJOR _ TYPE-Attribut ist nicht erforderlich, da die Methoden SetVideoAttributes und SetAudioAttributes den Haupttyp implizieren. Es ist jedoch auch gültig, einen tatsächlichen Medientyp an diese Methoden zu übergeben. (Die BESCHRIFTUNGMediaType-Schnittstelle erbt DIE ATTRIBUTE.)
Ausführen der Codierungssitzung
Der folgende Code führt die Codierungssitzung aus. Es wird die Media Session-Hilfsklasse verwendet, die im nächsten Abschnitt gezeigt wird.
HRESULT RunEncodingSession(CSession *pSession, MFTIME duration)
{
const DWORD WAIT_PERIOD = 500;
const int UPDATE_INCR = 5;
HRESULT hr = S_OK;
MFTIME pos;
LONGLONG prev = 0;
while (1)
{
hr = pSession->Wait(WAIT_PERIOD);
if (hr == E_PENDING)
{
hr = pSession->GetEncodingPosition(&pos);
LONGLONG percent = (100 * pos) / duration ;
if (percent >= prev + UPDATE_INCR)
{
std::cout << percent << "% .. ";
prev = percent;
}
}
else
{
std::cout << std::endl;
break;
}
}
return hr;
}
Mediensitzungs-Hilfe
Die Mediensitzung wird im Abschnitt Media Foundation Architektur dieser Dokumentation genauer beschrieben. Die Mediensitzung verwendet ein asynchrones Ereignismodell. In einer GUI-Anwendung sollten Sie auf Sitzungsereignisse reagieren, ohne zu blockieren, dass der UI-Thread auf das nächste Ereignis wartet. Das Tutorial How to Play Unprotected Media Files (Wiedergeben von ungeschützten Mediendateien) zeigt, wie Sie dies in einer Wiedergabeanwendung tun. Für die Codierung ist das Prinzip identisch, aber es sind weniger Ereignisse relevant:
| Event | Beschreibung |
|---|---|
| MESessionEnded | Wird ausgelöst, wenn die Codierung abgeschlossen ist. |
| MESessionClosed | Wird ausgelöst, wenn die METHODE FÜR DIE 100:000-000000000001 abgeschlossen ist. Nachdem dieses Ereignis ausgelöst wurde, ist es sicher, die Mediensitzung herunterfahren. |
Für eine Konsolenanwendung ist es sinnvoll, Ereignisse zu blockieren und auf diese zu warten. Je nach Quelldatei und Codierungseinstellungen kann es einige Zeit dauern, bis die Codierung abgeschlossen ist. Sie können Statusupdates wie folgt erhalten:
- Rufen Sie DIEMEDIASession::GetClock auf, um die Präsentationsuhr zu erhalten.
- Fragen Sie die Uhr für die BENUTZEROBERFLÄCHEPresentationClock-Schnittstelle ab.
- Rufen Sie VORZEIGERDarstellungClock::GetTime auf, um die aktuelle Position zu erhalten.
- Die Position wird in Zeiteinheiten angegeben. Verwenden Sie den Wert , um den prozentsatz abgeschlossenen Wert zu
(100 * position) / durationerhalten.
Hier ist die Deklaration der CSession -Klasse.
class CSession : public IMFAsyncCallback
{
public:
static HRESULT Create(CSession **ppSession);
// IUnknown methods
STDMETHODIMP QueryInterface(REFIID riid, void** ppv);
STDMETHODIMP_(ULONG) AddRef();
STDMETHODIMP_(ULONG) Release();
// IMFAsyncCallback methods
STDMETHODIMP GetParameters(DWORD* pdwFlags, DWORD* pdwQueue)
{
// Implementation of this method is optional.
return E_NOTIMPL;
}
STDMETHODIMP Invoke(IMFAsyncResult *pResult);
// Other methods
HRESULT StartEncodingSession(IMFTopology *pTopology);
HRESULT GetEncodingPosition(MFTIME *pTime);
HRESULT Wait(DWORD dwMsec);
private:
CSession() : m_cRef(1), m_pSession(NULL), m_pClock(NULL), m_hrStatus(S_OK), m_hWaitEvent(NULL)
{
}
virtual ~CSession()
{
if (m_pSession)
{
m_pSession->Shutdown();
}
SafeRelease(&m_pClock);
SafeRelease(&m_pSession);
CloseHandle(m_hWaitEvent);
}
HRESULT Initialize();
private:
IMFMediaSession *m_pSession;
IMFPresentationClock *m_pClock;
HRESULT m_hrStatus;
HANDLE m_hWaitEvent;
long m_cRef;
};
Der folgende Code zeigt die vollständige Implementierung der CSession -Klasse.
HRESULT CSession::Create(CSession **ppSession)
{
*ppSession = NULL;
CSession *pSession = new (std::nothrow) CSession();
if (pSession == NULL)
{
return E_OUTOFMEMORY;
}
HRESULT hr = pSession->Initialize();
if (FAILED(hr))
{
pSession->Release();
return hr;
}
*ppSession = pSession;
return S_OK;
}
STDMETHODIMP CSession::QueryInterface(REFIID riid, void** ppv)
{
static const QITAB qit[] =
{
QITABENT(CSession, IMFAsyncCallback),
{ 0 }
};
return QISearch(this, qit, riid, ppv);
}
STDMETHODIMP_(ULONG) CSession::AddRef()
{
return InterlockedIncrement(&m_cRef);
}
STDMETHODIMP_(ULONG) CSession::Release()
{
long cRef = InterlockedDecrement(&m_cRef);
if (cRef == 0)
{
delete this;
}
return cRef;
}
HRESULT CSession::Initialize()
{
IMFClock *pClock = NULL;
HRESULT hr = MFCreateMediaSession(NULL, &m_pSession);
if (FAILED(hr))
{
goto done;
}
hr = m_pSession->GetClock(&pClock);
if (FAILED(hr))
{
goto done;
}
hr = pClock->QueryInterface(IID_PPV_ARGS(&m_pClock));
if (FAILED(hr))
{
goto done;
}
hr = m_pSession->BeginGetEvent(this, NULL);
if (FAILED(hr))
{
goto done;
}
m_hWaitEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
if (m_hWaitEvent == NULL)
{
hr = HRESULT_FROM_WIN32(GetLastError());
}
done:
SafeRelease(&pClock);
return hr;
}
// Implements IMFAsyncCallback::Invoke
STDMETHODIMP CSession::Invoke(IMFAsyncResult *pResult)
{
IMFMediaEvent* pEvent = NULL;
MediaEventType meType = MEUnknown;
HRESULT hrStatus = S_OK;
HRESULT hr = m_pSession->EndGetEvent(pResult, &pEvent);
if (FAILED(hr))
{
goto done;
}
hr = pEvent->GetType(&meType);
if (FAILED(hr))
{
goto done;
}
hr = pEvent->GetStatus(&hrStatus);
if (FAILED(hr))
{
goto done;
}
if (FAILED(hrStatus))
{
hr = hrStatus;
goto done;
}
switch (meType)
{
case MESessionEnded:
hr = m_pSession->Close();
if (FAILED(hr))
{
goto done;
}
break;
case MESessionClosed:
SetEvent(m_hWaitEvent);
break;
}
if (meType != MESessionClosed)
{
hr = m_pSession->BeginGetEvent(this, NULL);
}
done:
if (FAILED(hr))
{
m_hrStatus = hr;
m_pSession->Close();
}
SafeRelease(&pEvent);
return hr;
}
HRESULT CSession::StartEncodingSession(IMFTopology *pTopology)
{
HRESULT hr = m_pSession->SetTopology(0, pTopology);
if (SUCCEEDED(hr))
{
PROPVARIANT varStart;
PropVariantClear(&varStart);
hr = m_pSession->Start(&GUID_NULL, &varStart);
}
return hr;
}
HRESULT CSession::GetEncodingPosition(MFTIME *pTime)
{
return m_pClock->GetTime(pTime);
}
HRESULT CSession::Wait(DWORD dwMsec)
{
HRESULT hr = S_OK;
DWORD dwTimeoutStatus = WaitForSingleObject(m_hWaitEvent, dwMsec);
if (dwTimeoutStatus != WAIT_OBJECT_0)
{
hr = E_PENDING;
}
else
{
hr = m_hrStatus;
}
return hr;
}