Nuta
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować się zalogować lub zmienić katalog.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
W tym samouczku pokazano, jak za pomocą interfejsu API transkodowania zakodować plik MP4, używając kodeka H.264 dla strumienia wideo i kodeka AAC dla strumienia audio.
- Nagłówki i Pliki Biblioteki
- Definiowanie profilów kodowania
- Napisz funkcję wmain
- Zakoduj plik
- Asystent sesji multimedialnej
- Tematy pokrewne
Nagłówki i pliki biblioteki
Dołącz następujące pliki nagłówkowe.
#include <new>
#include <iostream>
#include <windows.h>
#include <mfapi.h>
#include <Mfidl.h>
#include <shlwapi.h>
Połącz następujące pliki biblioteki.
#pragma comment(lib, "mfplat")
#pragma comment(lib, "mf")
#pragma comment(lib, "mfuuid")
#pragma comment(lib, "shlwapi")
Definiowanie profilów kodowania
Jednym z podejść do kodowania jest zdefiniowanie listy profilów kodowania docelowego, które są znane z wyprzedzeniem. Na potrzeby tego samouczka użyjemy stosunkowo prostego podejścia i zapiszemy listę formatów kodowania dla wideo H.264 i audio AAC.
W przypadku H.264 najważniejsze atrybuty formatu to profil H.264, szybkość klatek, rozmiar ramki i zakodowana szybkość bitów. Poniższa tablica zawiera listę formatów kodowania H.264.
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 },
};
Profile H.264 są określane przy użyciu wyliczenia eAVEncH264VProfile. Można również określić poziom H.264, ale program Microsoft Media Foundation H.264 Video Encoder może uzyskać odpowiedni poziom dla danego strumienia wideo, dlatego zaleca się, aby nie przesłaniać wybranego poziomu kodera. W przypadku zawartości z przeplotem należy również określić tryb przeplotu (zobacz przeplot wideo).
W przypadku dźwięku AAC najważniejsze atrybuty formatu to częstotliwość próbkowania audio, liczba kanałów, liczba bitów na próbkę i zakodowana szybkość bitów. Opcjonalnie można ustawić wskazanie poziomu profilu audio usługi AAC. Aby uzyskać więcej informacji, zobacz AAC Encoder. Poniższa tablica zawiera listę formatów kodowania AAC.
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},
};
Notatka
Zdefiniowane tutaj struktury H264ProfileInfo i AACProfileInfo nie są częścią interfejsu API programu Media Foundation.
Napisz funkcję wmain
Poniższy kod przedstawia punkt wejścia dla aplikacji konsolowej.
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;
}
Funkcja wmain wykonuje następujące czynności:
- Wywołuje funkcję CoInitializeEx w celu zainicjowania biblioteki COM.
- Wywołuje funkcję MFStartup w celu zainicjowania programu Media Foundation.
- Wywołuje funkcję
EncodeFilezdefiniowaną przez aplikację. Ta funkcja transkoduje plik wejściowy do pliku wyjściowego i jest wyświetlana w następnej sekcji. - Wywołuje funkcję MFShutdown , aby zamknąć Media Foundation.
- Wywołaj funkcję CoUninitialize, aby zdeinicjować bibliotekę COM.
Kodowanie pliku
Poniższy kod przedstawia funkcję EncodeFile, która wykonuje transkodowanie. Ta funkcja składa się głównie z wywołań do innych funkcji zdefiniowanych przez aplikację, które są wyświetlane w dalszej części tego tematu.
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;
}
Funkcja EncodeFile wykonuje następujące kroki.
- Tworzy źródło multimediów dla pliku wejściowego przy użyciu adresu URL lub ścieżki pliku wejściowego. (Zobacz Utwórz źródło multimedialne.)
- Pobiera czas trwania pliku wejściowego. (Zobacz Pobierz czas trwania źródła.)
- Utwórz profil transkodowania. (Zobacz Tworzenie profilu transkodowania.)
- Wywołaj MFCreateTranscodeTopology, aby utworzyć częściową topologię transkodu.
- Utwórz obiekt pomocnika, który zarządza sesją multimediów. (Zobacz Asystenta sesji multimediów).
- Uruchom sesję kodowania i poczekaj na jej zakończenie. (Zobacz Uruchom sesję kodowania.)
- Wywołaj IMFMediaSource::Shutdown, aby zamknąć źródło multimediów.
- Zwolnij wskaźniki interfejsu. Ten kod używa funkcji SafeRelease w celu wydania wskaźników interfejsu. Inną opcją jest użycie klasy inteligentnego wskaźnika COM, takiej jak CComPtr.
Tworzenie źródła multimediów
Źródło multimediów to obiekt, który odczytuje i analizuje plik wejściowy. Aby utworzyć źródło multimediów, przekaż adres URL pliku wejściowego do Source Resolver. Poniższy kod pokazuje, jak to zrobić.
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;
}
Aby uzyskać więcej informacji, zobacz Korzystanie z Rozwiązywacza Źródła.
Pobieranie czasu trwania źródła
Chociaż nie jest to wymagane, warto wykonać zapytanie źródła multimediów dotyczące długości pliku wejściowego. Ta wartość może służyć do śledzenia postępu kodowania. Czas trwania jest przechowywany w atrybucie MF_PD_DURATION deskryptora prezentacji. Pobierz deskryptor prezentacji, wywołując IMFMediaSource::CreatePresentationDescriptor.
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;
}
Tworzenie profilu transkodowania
Profil transkodowania opisuje parametry kodowania. Aby uzyskać więcej informacji na temat tworzenia profilu transkodowania, zobacz Using the Transcode API. Aby utworzyć profil, wykonaj następujące kroki.
- Wywołaj MFCreateTranscodeProfile, aby utworzyć pusty profil.
- Utwórz typ nośnika dla strumienia audio AAC. Dodaj go do profilu, wywołując IMFTranscodeProfile::SetAudioAttributes.
- Utwórz typ nośnika dla strumienia wideo H.264. Dodaj go do profilu, wywołując IMFTranscodeProfile::SetVideoAttributes.
- Wywołaj MFCreateAttributes, aby utworzyć magazyn atrybutów dla atrybutów na poziomie kontenera.
- Ustaw atrybut MF_TRANSCODE_CONTAINERTYPE. Jest to jedyny wymagany atrybut na poziomie kontenera. W przypadku pliku wyjściowego MP4 ustaw ten atrybut na MFTranscodeContainerType_MPEG4.
- Wywołaj IMFTranscodeProfile::SetContainerAttributes, aby ustawić atrybuty na poziomie kontenera.
Poniższy kod przedstawia te kroki.
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;
}
Aby określić atrybuty strumienia wideo H.264, utwórz magazyn atrybutów i ustaw następujące atrybuty:
| Atrybut | Opis |
|---|---|
| MF_MT_SUBTYPE | Ustaw wartość MFVideoFormat_H264. |
| MF_MT_MPEG2_PROFILE | Profil H.264. |
| MF_MT_FRAME_SIZE | Rozmiar ramki. |
| MF_MT_FRAME_RATE | Częstotliwość klatek. |
| MF_MT_AVG_BITRATE | Zakodowana szybkość bitów. |
Aby określić atrybuty strumienia audio AAC, utwórz magazyn atrybutów i ustaw następujące atrybuty:
| Atrybut | Opis |
|---|---|
| MF_MT_SUBTYPE | Ustaw wartość MFAudioFormat_AAC |
| MF_MT_AUDIO_SAMPLES_PER_SECOND | Częstotliwość próbkowania audio. |
| MF_MT_AUDIO_BITS_PER_SAMPLE | Bity na próbkę dźwięku. |
| MF_MT_AUDIO_NUM_CHANNELS | Liczba kanałów audio. |
| MF_MT_AUDIO_AVG_BYTES_PER_SECOND | Zakodowana szybkość bitów. |
| MF_MT_AUDIO_BLOCK_ALIGNMENT | Ustaw wartość 1. |
| MF_MT_AAC_AUDIO_PROFILE_LEVEL_INDICATION | Wskazanie poziomu profilu AAC (opcjonalnie). |
Poniższy kod tworzy atrybuty strumienia wideo.
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;
}
Poniższy kod tworzy atrybuty strumienia audio.
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;
}
Należy pamiętać, że interfejs API transkodowania nie wymaga prawdziwego typu nośnika, chociaż wykorzystuje atrybuty typu nośnika. W szczególności atrybut MF_MT_MAJOR_TYPE nie jest wymagany, ponieważ metody SetVideoAttributes i SetAudioAttributes określają główny typ. Jednak ważne jest również przekazanie rzeczywistego formatu mediów do tych metod. (Interfejs IMFMediaType dziedziczy IMFAttributes.)
Uruchamianie sesji kodowania
Poniższy kod uruchamia sesję kodowania. Używa klasy pomocniczej Media Session, która jest pokazana w następnej sekcji.
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;
}
Pomocnik sesji medialnej
Sesja multimediów jest bardziej szczegółowo opisana w sekcji Architektura Media Foundation tej dokumentacji. Sesja multimediów używa asynchronicznego modelu zdarzeń. W aplikacji z graficznym interfejsem użytkownika należy reagować na zdarzenia sesji, nie blokując wątku interfejsu użytkownika podczas oczekiwania na następne zdarzenie. W samouczku How to Play Unprotected Media Files pokazano, jak to zrobić w aplikacji odtwarzania. W przypadku kodowania zasada jest taka sama, ale mniejsza liczba zdarzeń jest istotna:
| Zdarzenie | Opis |
|---|---|
| MESessionEnded | Wywoływane po zakończeniu kodowania. |
| MESessionClosed | Gdy metoda IMFMediaSession::Close zostanie ukończona, zostanie podniesione. Po wystąpieniu tego zdarzenia można bezpiecznie zamknąć sesję multimedialną. |
W przypadku aplikacji konsolowej uzasadnione jest zablokowanie i oczekiwanie na zdarzenia. W zależności od pliku źródłowego i ustawień kodowania może upłynąć trochę czasu, aby ukończyć kodowanie. Aktualizacje postępu można uzyskać w następujący sposób:
- Wywołaj IMFMediaSession::GetClock, aby uzyskać zegar prezentacji.
- Wykonaj zapytanie o zegar dla interfejsuIMFPresentationClock.
- Wywołaj IMFPresentationClock::GetTime, aby uzyskać bieżącą pozycję.
- Pozycja jest podana w jednostkach czasu. Aby uzyskać wartość procentową ukończenia, użyj wartości
(100 * position) / duration.
Oto deklaracja klasy CSession.
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;
};
Poniższy kod przedstawia pełną implementację klasy CSession.
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;
}
Tematy pokrewne