Poznámka:
Přístup k této stránce vyžaduje autorizaci. Můžete se zkusit přihlásit nebo změnit adresáře.
Přístup k této stránce vyžaduje autorizaci. Můžete zkusit změnit adresáře.
Toto téma popisuje, jak pomocí čtečky zdrojového kódu zpracovávat data médií.
Chcete-li použít čtečku zdroje, postupujte podle těchto základních kroků:
- Vytvořte instanci čtečky zdrojů.
- Zobrazí výčet možných výstupních formátů.
- Nastavte skutečný výstupní formát pro každý datový proud.
- Zpracování dat ze zdroje
Zbývající část tohoto tématu podrobně popisuje tyto kroky.
- Vytvoření zdrojového čteče
- Vyjmenování výstupních formátů
- Nastavení výstupních formátů
- Zpracování mediálních dat
- vyprázdnění datového kanálu
- Získání délky trvání souboru
- Hledání
- rychlost přehrávání
- hardwarová akcelerace
- související témata
Vytvoření čtečky zdroje
Pokud chcete vytvořit instanci čtenáře zdroje, zavolejte jednu z následujících funkcí:
| Funkce | Popis |
|---|---|
|
MFCreateSourceReaderFromURL |
Přebírá jako vstup adresu URL. Tato funkce používá Řešitel zdrojů k vytvoření zdroje médií z adresy URL. |
|
MFCreateSourceReaderFromByteStream |
Přijímá ukazatel na bajtový datový proud. Tato funkce také používá k vytvoření zdroje médií nástroj Source Resolver. |
|
MFCreateSourceReaderFromMediaSource |
Vezme ukazatel na zdroj médií, který už byl vytvořen. Tato funkce je užitečná pro zdroje médií, které nelze vytvořit, jako jsou zařízení pro zachytávání nebo vlastní zdroje médií. |
U mediálních souborů obvykle použijte MFCreateSourceReaderFromURL. Pro zařízení, jako jsou webové kamery, použijte MFCreateSourceReaderFromMediaSource. (Další informace o zařízeních pro zachytávání v Microsoft Media Foundation naleznete v tématu Audio/Video Capture.)
Každá z těchto funkcí akceptuje volitelný ukazatel IMFAttributes, který se používá k nastavení různých voleb na Source Reader, jak je uvedeno v referenčních tématech pro tyto funkce. Chcete-li získat výchozí chování, nastavte tento parametr na NULL. Každá funkce vrátí IMFSourceReader ukazatel jako výstupní parametr. Před voláním některé z těchto funkcí je nutné zavolat funkce CoInitialize(Ex) a MFStartup.
Následující kód vytvoří čtenáře zdroje z adresy URL.
int __cdecl wmain(int argc, __in_ecount(argc) PCWSTR* argv)
{
if (argc < 2)
{
return 1;
}
const WCHAR *pszURL = argv[1];
// Initialize the COM runtime.
HRESULT hr = CoInitializeEx(0, COINIT_MULTITHREADED);
if (SUCCEEDED(hr))
{
// Initialize the Media Foundation platform.
hr = MFStartup(MF_VERSION);
if (SUCCEEDED(hr))
{
// Create the source reader.
IMFSourceReader *pReader;
hr = MFCreateSourceReaderFromURL(pszURL, NULL, &pReader);
if (SUCCEEDED(hr))
{
ReadMediaFile(pReader);
pReader->Release();
}
// Shut down Media Foundation.
MFShutdown();
}
CoUninitialize();
}
}
Vytvoření výčtu výstupních formátů
Každý zdroj médií má alespoň jeden stream. Například videosoubor může obsahovat stream videa a zvukový stream. Formát každého datového proudu je popsán pomocí typu média reprezentovaný rozhraním HFMediaType. Další informace o typech médií naleznete v tématu Typy médií. Abyste porozuměli formátu dat, která získáte od čtenáře zdroje, musíte prozkoumat typ média.
Zpočátku má každý datový proud výchozí formát, který můžete najít voláním MMFSourceReader::GetCurrentMediaType metoda:
Pro každý datový proud nabízí zdroj médií seznam možných typů médií pro daný datový proud. Počet typů závisí na zdroji. Pokud zdroj představuje mediální soubor, obvykle existuje pouze jeden typ na stream. Webová kamera na druhé straně může být schopná streamovat video v několika různých formátech. V takovém případě může aplikace vybrat formát, který se má použít ze seznamu typů médií.
Chcete-li získat jeden z typů médií pro datový proud, zavolejte metodu IMFSourceReader::GetNativeMediaType. Tato metoda má dva parametry indexu: index datového proudu a index do seznamu typů médií pro stream. Pokud chcete vytvořit výčet všech typů datového proudu, navyšte index seznamu a přitom zachováte konstantu indexu streamu. Když index seznamu překročí meze, GetNativeMediaType vrátí MF_E_NO_MORE_TYPES.
HRESULT EnumerateTypesForStream(IMFSourceReader *pReader, DWORD dwStreamIndex)
{
HRESULT hr = S_OK;
DWORD dwMediaTypeIndex = 0;
while (SUCCEEDED(hr))
{
IMFMediaType *pType = NULL;
hr = pReader->GetNativeMediaType(dwStreamIndex, dwMediaTypeIndex, &pType);
if (hr == MF_E_NO_MORE_TYPES)
{
hr = S_OK;
break;
}
else if (SUCCEEDED(hr))
{
// Examine the media type. (Not shown.)
pType->Release();
}
++dwMediaTypeIndex;
}
return hr;
}
Pokud chcete vytvořit výčet typů médií pro každý datový proud, navyšte index streamu. Když index datového proudu přejde mimo hranice, GetNativeMediaType vrátí MF_E_INVALIDSTREAMNUMBER.
HRESULT EnumerateMediaTypes(IMFSourceReader *pReader)
{
HRESULT hr = S_OK;
DWORD dwStreamIndex = 0;
while (SUCCEEDED(hr))
{
hr = EnumerateTypesForStream(pReader, dwStreamIndex);
if (hr == MF_E_INVALIDSTREAMNUMBER)
{
hr = S_OK;
break;
}
++dwStreamIndex;
}
return hr;
}
Nastavení výstupních formátů
Chcete-li změnit výstupní formát, zavolejte metodu IMFSourceReader::SetCurrentMediaType. Tato metoda přebírá index streamu a typ média:
hr = pReader->SetCurrentMediaType(dwStreamIndex, pMediaType);
U typu média závisí na tom, jestli chcete vložit dekodér.
- Pokud chcete získat data přímo ze zdroje bez dekódování, použijte jeden z typů vrácených GetNativeMediaType.
- Pokud chcete datový proud dekódovat, vytvořte nový typ média, který popisuje požadovaný nekomprimovaný formát.
V případě dekodéru vytvořte typ média následujícím způsobem:
- Chcete-li vytvořit nový typ média, zavolejte MFCreateMediaType.
- Nastavte atribut MF_MT_MAJOR_TYPE pro zadání zvuku nebo videa.
- Nastavte atribut MF_MT_SUBTYPE tak, aby určil podtyp dekódovaného formátu. (Viz identifikátory GUID podtypu zvuku a identifikátory GUID podtypu videa .)
- Volání IMFSourceReader::SetCurrentMediaType.
Čtečka zdroje automaticky načte dekodér. Chcete-li získat úplné podrobnosti dekódovaného formátu, zavolejte IMFSourceReader::GetCurrentMediaType po volání SetCurrentMediaType
Následující kód nakonfiguruje stream videa pro RGB-32 a zvukový stream pro zvuk PCM.
HRESULT ConfigureDecoder(IMFSourceReader *pReader, DWORD dwStreamIndex)
{
IMFMediaType *pNativeType = NULL;
IMFMediaType *pType = NULL;
// Find the native format of the stream.
HRESULT hr = pReader->GetNativeMediaType(dwStreamIndex, 0, &pNativeType);
if (FAILED(hr))
{
return hr;
}
GUID majorType, subtype;
// Find the major type.
hr = pNativeType->GetGUID(MF_MT_MAJOR_TYPE, &majorType);
if (FAILED(hr))
{
goto done;
}
// Define the output type.
hr = MFCreateMediaType(&pType);
if (FAILED(hr))
{
goto done;
}
hr = pType->SetGUID(MF_MT_MAJOR_TYPE, majorType);
if (FAILED(hr))
{
goto done;
}
// Select a subtype.
if (majorType == MFMediaType_Video)
{
subtype= MFVideoFormat_RGB32;
}
else if (majorType == MFMediaType_Audio)
{
subtype = MFAudioFormat_PCM;
}
else
{
// Unrecognized type. Skip.
goto done;
}
hr = pType->SetGUID(MF_MT_SUBTYPE, subtype);
if (FAILED(hr))
{
goto done;
}
// Set the uncompressed format.
hr = pReader->SetCurrentMediaType(dwStreamIndex, NULL, pType);
if (FAILED(hr))
{
goto done;
}
done:
SafeRelease(&pNativeType);
SafeRelease(&pType);
return hr;
}
Zpracování mediálních dat
Chcete-li získat mediální data ze zdroje, zavolejte metodu IMFSourceReader::ReadSample, jak je znázorněno v následujícím kódu.
DWORD streamIndex, flags;
LONGLONG llTimeStamp;
hr = pReader->ReadSample(
MF_SOURCE_READER_ANY_STREAM, // Stream index.
0, // Flags.
&streamIndex, // Receives the actual stream index.
&flags, // Receives status flags.
&llTimeStamp, // Receives the time stamp.
&pSample // Receives the sample or NULL.
);
Prvním parametrem je index datového proudu, pro který chcete získat data. Můžete také určit MF_SOURCE_READER_ANY_STREAM, aby bylo možné získat další dostupná data z libovolného datového proudu. Druhý parametr obsahuje volitelné příznaky; seznam těchto položek najdete v části MF_SOURCE_READER_CONTROL_FLAG. Třetí parametr obdrží index datového proudu, který ve skutečnosti vytvoří data. Tyto informace budete potřebovat, pokud nastavíte první parametr na MF_SOURCE_READER_ANY_STREAM. Čtvrtý parametr přijímá příznaky stavu, které označují různé události, ke kterým může dojít při čtení dat, například změny formátu ve streamu. Seznam příznaků stavu můžete najít v části MF_SOURCE_READER_FLAG.
Pokud je zdroj médií schopen vytvořit data pro požadovaný datový proud, poslední parametr ReadSample obdrží ukazatel na MMFSample rozhraní ukázkového objektu média. Ukázku médií použijte k:
- Získejte ukazatel na multimediální data.
- Získejte čas prezentace a ukázkovou dobu trvání.
- Získejte atributy, které popisují prokládání, dominantní pole a další aspekty vzorku.
Obsah mediálních dat závisí na formátu datového proudu. U nekomprimovaného video streamu obsahuje každá ukázka multimédií jeden snímek videa. U nekomprimovaného zvukového streamu obsahuje každá ukázka multimédií posloupnost zvukových snímků.
Metoda ReadSample může vrátit S_OK, aniž by v parametru pSample vrátila ukázku média. Když například dosáhnete konce souboru, ReadSample nastaví příznak MF_SOURCE_READERF_ENDOFSTREAM v dwFlags a nastaví pSample na NULL. V tomto případě metoda ReadSample vrací S_OK, protože nedošlo k žádné chybě, i když parametr pSample je nastaven na NULL. Proto vždy zkontrolujte hodnotu pSample před její dereferencí.
Následující kód ukazuje, jak volat ReadSample ve smyčce a kontrolovat informace vrácené metodou, dokud se nedosáhne konce mediálního souboru.
HRESULT ProcessSamples(IMFSourceReader *pReader)
{
HRESULT hr = S_OK;
IMFSample *pSample = NULL;
size_t cSamples = 0;
bool quit = false;
while (!quit)
{
DWORD streamIndex, flags;
LONGLONG llTimeStamp;
hr = pReader->ReadSample(
MF_SOURCE_READER_ANY_STREAM, // Stream index.
0, // Flags.
&streamIndex, // Receives the actual stream index.
&flags, // Receives status flags.
&llTimeStamp, // Receives the time stamp.
&pSample // Receives the sample or NULL.
);
if (FAILED(hr))
{
break;
}
wprintf(L"Stream %d (%I64d)\n", streamIndex, llTimeStamp);
if (flags & MF_SOURCE_READERF_ENDOFSTREAM)
{
wprintf(L"\tEnd of stream\n");
quit = true;
}
if (flags & MF_SOURCE_READERF_NEWSTREAM)
{
wprintf(L"\tNew stream\n");
}
if (flags & MF_SOURCE_READERF_NATIVEMEDIATYPECHANGED)
{
wprintf(L"\tNative type changed\n");
}
if (flags & MF_SOURCE_READERF_CURRENTMEDIATYPECHANGED)
{
wprintf(L"\tCurrent type changed\n");
}
if (flags & MF_SOURCE_READERF_STREAMTICK)
{
wprintf(L"\tStream tick\n");
}
if (flags & MF_SOURCE_READERF_NATIVEMEDIATYPECHANGED)
{
// The format changed. Reconfigure the decoder.
hr = ConfigureDecoder(pReader, streamIndex);
if (FAILED(hr))
{
break;
}
}
if (pSample)
{
++cSamples;
}
SafeRelease(&pSample);
}
if (FAILED(hr))
{
wprintf(L"ProcessSamples FAILED, hr = 0x%x\n", hr);
}
else
{
wprintf(L"Processed %d samples\n", cSamples);
}
SafeRelease(&pSample);
return hr;
}
Vyprázdnění datového kanálu
Během zpracování dat může dekodér nebo jiná transformace ukládat vstupní vzorky do vyrovnávací paměti. V následujícím diagramu aplikace volá ReadSample a získá ukázku s prezentačním časem rovným t1. Dekodér drží vzorky pro t2 a t3.
Při dalším volání ReadSamplemůže Source Reader dát t4 dekodéru a vrátit t2 aplikaci.
Chcete-li dekódovat všechny vzorky, které jsou aktuálně ve vyrovnávací paměti v dekodéru, aniž byste předali nové vzorky do dekodéru, nastavte MF_SOURCE_READER_CONTROLF_DRAIN příznak v parametru dwControlFlagsReadSample. Pokračujte ve smyčce, dokud readSample nevrátí null ukázkový ukazatel. V závislosti na tom, jak dekodér ukládá vzorky do vyrovnávací paměti, může k tomu dojít okamžitě nebo po několika voláních ReadSample.
Získání doby trvání souboru
Chcete-li získat dobu trvání multimediálního souboru, zavolejte IMFSourceReader::GetPresentationAttribute metodu a požádejte MF_PD_DURATION atribut, jak je znázorněno v následujícím kódu.
HRESULT GetDuration(IMFSourceReader *pReader, LONGLONG *phnsDuration)
{
PROPVARIANT var;
HRESULT hr = pReader->GetPresentationAttribute(MF_SOURCE_READER_MEDIASOURCE,
MF_PD_DURATION, &var);
if (SUCCEEDED(hr))
{
hr = PropVariantToInt64(var, phnsDuration);
PropVariantClear(&var);
}
return hr;
}
Funkce zobrazená zde získá dobu trvání v 100 nanosekundových jednotkách. Vydělte 10 000 000, abyste získali dobu trvání v sekundách.
Hledání
Zdroj médií, který získává data z místního souboru, může obvykle hledat libovolné pozice v souboru. Zařízení pro záznam, jako jsou webové kamery, se obecně nemohou posouvat, protože data jsou živá. Zdroj, který streamuje data přes síť, může být schopen hledat v závislosti na protokolu streamování sítě.
Chcete-li zjistit, zda zdroj médií může vyhledávat, zavolejte IMFSourceReader::GetPresentationAttribute a požádejte o atribut MF_SOURCE_READER_MEDIASOURCE_CHARACTERISTICS, jak ukazuje následující kód:
HRESULT GetSourceFlags(IMFSourceReader *pReader, ULONG *pulFlags)
{
ULONG flags = 0;
PROPVARIANT var;
PropVariantInit(&var);
HRESULT hr = pReader->GetPresentationAttribute(
MF_SOURCE_READER_MEDIASOURCE,
MF_SOURCE_READER_MEDIASOURCE_CHARACTERISTICS,
&var);
if (SUCCEEDED(hr))
{
hr = PropVariantToUInt32(var, &flags);
}
if (SUCCEEDED(hr))
{
*pulFlags = flags;
}
PropVariantClear(&var);
return hr;
}
Tato funkce získá ze zdroje sadu příznaků schopností. Tyto příznaky jsou definovány ve výčtu MFMEDIASOURCE_CHARACTERISTICS. Dva příznaky souvisejí s hledáním:
| Vlajka | Popis |
|---|---|
|
MFMEDIASOURCE_CAN_SEEK |
Zdroj může hledat. |
|
MFMEDIASOURCE_HAS_SLOW_SEEK |
Hledání může trvat dlouhou dobu. Zdroj může například muset před hledáním stáhnout celý soubor. (Neexistuje žádná striktní kritéria pro vrácení tohoto příznaku zdroje.) |
Následující kód testuje příznak MFMEDIASOURCE_CAN_SEEK.
BOOL SourceCanSeek(IMFSourceReader *pReader)
{
BOOL bCanSeek = FALSE;
ULONG flags;
if (SUCCEEDED(GetSourceFlags(pReader, &flags)))
{
bCanSeek = ((flags & MFMEDIASOURCE_CAN_SEEK) == MFMEDIASOURCE_CAN_SEEK);
}
return bCanSeek;
}
Chcete-li hledat, zavolejte IMFSourceReader::SetCurrentPosition tuto metodu, jak je znázorněno v následujícím kódu.
HRESULT SetPosition(IMFSourceReader *pReader, const LONGLONG& hnsPosition)
{
PROPVARIANT var;
HRESULT hr = InitPropVariantFromInt64(hnsPosition, &var);
if (SUCCEEDED(hr))
{
hr = pReader->SetCurrentPosition(GUID_NULL, var);
PropVariantClear(&var);
}
return hr;
}
První parametr poskytuje formát času, který používáte k určení pozice hledání. Pro podporu 100 nanosekundových jednotek jsou vyžadovány všechny zdroje médií ve službě Media Foundation, které jsou označené hodnotou GUID_NULL. Druhý parametr je PROPVARIANT, který obsahuje pozici hledání. U 100 nanosekundových časových jednotek je datový typ LONGLONG.
Mějte na paměti, že ne každý zdroj médií poskytuje přesné vyhledávání po snímcích. Přesnost hledání závisí na několika faktorech, například na intervalu rámce klíče, na tom, jestli mediální soubor obsahuje index a jestli data mají konstantní nebo proměnlivou bitovou rychlost. Proto po vyhledání pozice v souboru neexistuje žádná záruka, že časové razítko u dalšího vzorku přesně odpovídá požadované pozici. Obecně platí, že skutečná pozice nebude pozdější než požadovaná pozice, takže vzorky můžete zahodit, dokud nedosáhnete požadovaného bodu v datovém proudu.
Rychlost přehrávání
I když můžete nastavit rychlost přehrávání pomocí čtečky zdrojového kódu, obvykle to není velmi užitečné z následujících důvodů:
- Čtečka zdrojového kódu nepodporuje zpětné přehrávání, i když zdroj médií ano.
- Aplikace řídí časy prezentace, takže aplikace může implementovat rychlé nebo pomalé přehrávání bez nastavení rychlosti ve zdroji.
- Některé zdroje médií podporují tenčí režimu, kdy zdroj poskytuje méně vzorků – obvykle jen klíčové snímky. Pokud ale chcete vynechat jiné než klíčové snímky, můžete zkontrolovat jednotlivé vzorky na atribut MFSampleExtension_CleanPoint.
Chcete-li nastavit rychlost přehrávání pomocí Source Reader, zavolejte IMFSourceReader::GetServiceForStream metodu, aby získat IMFRateSupport a IMFRateControl rozhraní ze zdroje médií.
Hardwarová akcelerace
Čtečka zdrojového kódu je kompatibilní s technologií Microsoft DirectX Video Acceleration (DXVA) 2.0 pro hardwarově akcelerované dekódování videa. Pokud chcete používat DXVA se čtečkou zdrojů, proveďte následující kroky.
- Vytvořte zařízení Microsoft Direct3D.
- Voláním funkce DXVA2CreateDirect3DDeviceManager9 vytvořte správce zařízení Direct3D. Tato funkce získá ukazatel na rozhraní IDirect3DDeviceManager9.
- Volejte metodu IDirect3DDeviceManager9::ResetDevice ukazatelem na zařízení Direct3D.
- Vytvořte úložiště atributů voláním funkce MFCreateAttributes.
- Vytvořte čtenáře zdroje. Předejte úložiště atributů v pAttributes parametr funkce pro vytvoření.
Když poskytnete zařízení Direct3D, nástroj Source Reader přidělí ukázky videa, které jsou kompatibilní s rozhraním API grafického procesoru DXVA. Pomocí zpracování videa DXVA můžete provádět hardwarovou deinterlaci nebo míchání videa. Další informace naleznete v tématu DXVA Video Processing. Pokud dekodér podporuje DXVA 2.0, použije zařízení Direct3D k provádění hardwarově akcelerovaného dekódování.
Důležitý
Počínaje Windows 8 lze MMFDXGIDeviceManager použít místo IDirect3DDeviceManager9. Pro aplikace pro Windows Store musíte použít MMFDXGIDeviceManager. Další informace najdete v Video API rozhraní Direct3D 11.
Související témata