Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
In diesem Lernprogramm wird gezeigt, wie Sie die Transcode-API verwenden, um eine MP4-Datei mit H.264 für den Videostream und AAC für den Audiostream zu codieren.
- Kopfzeilen und Bibliotheksdateien
- Definieren der Codierungsprofile
- Schreiben der wmain-Funktion
- Codieren der Datei
- Mediensitzungshilfsprogramm
- Verwandte Themen
Kopfzeilen und Bibliotheksdateien
Fügen 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 Lernprogramm gehen wir relativ einfach vor und speichern eine Liste von Codierungsformaten für H.264-Video und AAC-Audio.
Bei 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-Aufzählung 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. Bei Interlaced-Inhalten würden Sie auch den Interlacemodus angeben (siehe Video-Interlacing).
Bei AAC-Audio sind die wichtigsten Formatattribute die Audio-Samplerate, die Anzahl der Kanäle, die Anzahl der Bits pro Beispiel und die codierte Bitrate. Optional können Sie die Anzeige der AAC-Audioprofilebene 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 hier definierten H264ProfileInfo
- und AACProfileInfo
-Strukturen sind nicht Teil der Media Foundation-API.
Schreiben Sie die 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 folgende Aktionen 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
EncodeFile
Funktion auf. 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 deinitialisieren.
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 mithilfe der URL oder des Dateipfads der Eingabedatei. (Siehe Erstellen der Medienquelle.)
- Ruft die Dauer der Eingabedatei ab. (Siehe Abrufen der Quelldauer.)
- Erstellen Sie das Transkodierungsprofil. (Siehe Erstellen des Transcodierungsprofils.)
- Rufen Sie MFCreateTranscodeTopology auf, um die partielle Transcodierungstopologie zu erstellen.
- Erstellen Sie ein Hilfsobjekt, das die Mediensitzung verwaltet. (Siehe Media Session Helper).
- 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.
- Schnittstellenzeiger freigeben. Dieser Code verwendet die SafeRelease-Funktion , um Schnittstellenzeiger freizugeben. Eine weitere Option 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 Quelllöser. Der folgende Code zeigt, wie dies funktioniert.
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 Using the Source Resolver.
Ermitteln 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;
}
Transcodierungsprofil erstellen
Das Transcodierungsprofil beschreibt die Codierungsparameter. Weitere Informationen zum Erstellen eines Transcodierungsprofils finden Sie unter Verwenden der Transcode-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 zum Profil hinzu, indem Sie IMFTranscodeProfile::SetAudioAttributes aufrufen.
- Erstellen Sie einen Medientyp für den H.264-Videostream. Fügen Sie es zum 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:
Merkmal | BESCHREIBUNG |
---|---|
MF_MT_SUBTYPE | Auf MFVideoFormat_H264 festgelegt. |
MF_MT_MPEG2_PROFILE | H.264-Profil. |
MF_MT_FRAME_SIZE | Rahmengröß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:
Merkmal | BESCHREIBUNG |
---|---|
MF_MT_SUBTYPE | Auf MFAudioFormat_AAC festlegen |
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 festgelegt. |
MF_MT_AAC_AUDIO_PROFILE_LEVEL_INDICATION | AAC-Profil-Ebenenanzeige (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 Audio-Stream-Attribute.
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 ist das MF_MT_MAJOR_TYPE Attribut nicht erforderlich, da die Methoden SetVideoAttributes und SetAudioAttributes den Haupttyp bedeuten. Es ist jedoch auch zulässig, einen tatsächlichen Medientyp an diese Methoden zu übergeben. (Die IMFMediaType-Schnittstelle erbt IMFAttributes.)
Codierungssitzung starten
Der folgende Code führt die Codierungssitzung aus. Sie verwendet die Hilfsklasse "Media Session", die im nächsten Abschnitt angezeigt 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 Media Foundation Architecture-Abschnitt 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 Lernprogramm zum Wiedergeben ungeschützter Mediendateien zeigt, wie dies in einer Wiedergabeanwendung geschieht. Bei der Codierung ist das Prinzip identisch, aber weniger Ereignisse sind 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, ist es sicher, die Mediensitzung zu beenden. |
Für eine Konsolenanwendung ist es sinnvoll, Ereignisse zu blockieren und auf Ereignisse zu warten. Je nach Quelldatei und den Codierungseinstellungen kann es eine Weile dauern, bis die Codierung abgeschlossen ist. Sie können Statusaktualisierungen wie folgt abrufen:
- Rufen Sie IMFMediaSession::GetClock auf, um die Präsentationsuhr abzurufen.
- Abfrage der Uhr für die IMFPresentationClock-Schnittstelle .
- 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
.
Dies 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