Tutorial: Codieren einer MP4-Datei
In diesem Tutorial wird gezeigt, wie Sie die Transcode-API verwenden, um eine MP4-Datei zu codieren, wobei H.264 für den Videostream und AAC für den Audiostream verwendet werden.
- Header und Bibliotheksdateien
- Definieren der Codierungsprofile
- Schreiben der wmain-Funktion
- Codieren der Datei
- Mediensitzungshilfsprogramm
- 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 darin, eine Liste von Zielcodierungsprofilen zu definieren, die im Voraus bekannt sind. In diesem Tutorial verfolgen 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 Bildrate, 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 außer Kraft zu setzen. Für interlaced Content würden Sie auch den Interlace-Modus angeben (siehe Video-Interlacing).
Für AAC-Audio sind die wichtigsten Formatattribute die Audio-Samplerate, die Anzahl der Kanäle, die Anzahl der Bits pro Sample und die codierte Bitrate. Optional können Sie die AAC-Audioprofilpegelanzeige 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 AACProfileInfo
sind nicht Teil der Media Foundation-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 Media Foundation zu initialisieren.
- Ruft die anwendungsdefinierte Funktion auf
EncodeFile
. Diese Funktion transcodiert die Eingabedatei in die Ausgabedatei und wird im nächsten Abschnitt angezeigt. - Ruft die MFShutdown-Funktion auf, um Media Foundation herunterzufahren.
- Rufen Sie die CoUninitialize-Funktion auf, um die COM-Bibliothek zu entinitialisieren.
Codieren der Datei
Der folgende Code zeigt EncodeFile
die Funktion, die die Transcodierung ausführt. Diese Funktion besteht hauptsächlich 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. (Siehe Erstellen der Medienquelle.)
- Ruft die Dauer der Eingabedatei ab. (Siehe Abrufen der Quelldauer.)
- Erstellen Sie das Transcodierungsprofil. (Siehe Erstellen des Transcodierungsprofils.)
- Rufen Sie MFCreateTranscodeTopology auf, um die partielle Transcodierungstopologie zu erstellen.
- Erstellen Sie ein Hilfsobjekt, das die Mediensitzung verwaltet. (Siehe Mediensitzungshilfsprogramm).
- Führen Sie die Codierungssitzung aus, und warten Sie, bis sie abgeschlossen ist. (Siehe Ausführen der Codierungssitzung.)
- Rufen Sie IMFMediaSource::Shutdown auf, um die Medienquelle herunterzufahren.
- Freigeben von Schnittstellenzeigern. In diesem Code wird die SafeRelease-Funktion verwendet, um Schnittstellenzeiger freizugeben. Eine weitere Option ist die Verwendung einer COM Smart Pointer-Klasse, 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 Quelllöser. 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 Quellrelösers.
Abrufen der Quelldauer
Obwohl nicht erforderlich, ist es nützlich, die Medienquelle für die Dauer der Eingabedatei abzufragen. Dieser Wert kann verwendet werden, um den Codierungsfortschritt nachzuverfolgen. Die Dauer wird im MF_PD_DURATION-Attribut des Präsentationsdeskriptors gespeichert. Rufen Sie den Präsentationsdeskriptor ab, indem Sie IMFMediaSource::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 es dem Profil hinzu, indem Sie IMFTranscodeProfile::SetAudioAttributes aufrufen.
- Erstellen Sie einen Medientyp für den H.264-Videostream. Fügen Sie es dem Profil hinzu, indem Sie IMFTranscodeProfile::SetVideoAttributes aufrufen.
- Rufen Sie MFCreateAttributes auf, um einen Attributspeicher für die Attribute auf Containerebene zu erstellen.
- Legen Sie das attribut MF_TRANSCODE_CONTAINERTYPE fest. Dies ist das einzige erforderliche Attribut auf Containerebene. Legen Sie für die MP4-Dateiausgabe dieses Attribut auf MFTranscodeContainerType_MPEG4 fest.
- Rufen Sie IMFTranscodeProfile::SetContainerAttributes auf, um die Attribute auf Containerebene festzulegen.
Im folgenden Code werden diese Schritte veranschaulicht.
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 Sie die folgenden Attribute fest:
attribute | Beschreibung |
---|---|
MF_MT_SUBTYPE | Legen Sie auf MFVideoFormat_H264 fest. |
MF_MT_MPEG2_PROFILE | 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 Sie die folgenden Attribute fest:
attribute | Beschreibung |
---|---|
MF_MT_SUBTYPE | Auf MFAudioFormat_AAC festgelegt |
MF_MT_AUDIO_SAMPLES_PER_SECOND | Audio-Abtastrate. |
MF_MT_AUDIO_BITS_PER_SAMPLE | 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 | 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 die MF_MT_MAJOR_TYPE Attribut 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 IMFMediaType-Schnittstelle erbt IMFAttributes.)
Ausführen der Codierungssitzung
Der folgende Code führt die Codierungssitzung aus. Es verwendet die Media Session-Hilfsklasse, 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;
}
Mediensitzungshilfsprogramm
Die Mediensitzung wird im Abschnitt Media Foundation Architecture dieser Dokumentation ausführlicher beschrieben. Die Mediensitzung verwendet ein asynchrones Ereignismodell. In einer GUI-Anwendung sollten Sie auf Sitzungsereignisse reagieren, ohne den UI-Thread zu blockieren, um auf das nächste Ereignis zu warten. Das Tutorial Wiedergeben ungeschützter Mediendateien zeigt, wie Sie dies in einer Wiedergabeanwendung tun. Für die Codierung ist das Prinzip identisch, aber es sind weniger Ereignisse relevant:
Ereignis | Beschreibung |
---|---|
MESessionEnded | Wird ausgelöst, wenn die Codierung abgeschlossen ist. |
MESessionClosed | Wird ausgelöst, wenn die IMFMediaSession::Close-Methode abgeschlossen ist. Nachdem dieses Ereignis ausgelöst wurde, kann die Mediensitzung sicher heruntergefahren werden. |
Für eine Konsolenanwendung ist es sinnvoll, Ereignisse zu blockieren und darauf zu warten. Abhängig von der Quelldatei und den Codierungseinstellungen kann es eine Weile dauern, bis die Codierung abgeschlossen ist. Sie können Statusupdates wie folgt abrufen:
- Rufen Sie IMFMediaSession::GetClock auf, um die Präsentationsuhr abzurufen.
- Fragen Sie die Uhr für die IMFPresentationClock-Schnittstelle ab.
- Rufen Sie IMFPresentationClock::GetTime auf, um die aktuelle Position abzurufen.
- Die Position wird in Zeiteinheiten angegeben. Um den abgeschlossenen Prozentsatz zu erhalten, verwenden Sie den Wert
(100 * position) / duration
.
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;
}
Zugehörige Themen