Not
Åtkomst till den här sidan kräver auktorisering. Du kan prova att logga in eller ändra kataloger.
Åtkomst till den här sidan kräver auktorisering. Du kan prova att ändra kataloger.
I det här avsnittet beskrivs hur du använder Källläsare för att bearbeta mediedata.
Följ dessa grundläggande steg om du vill använda källläsaren:
- Skapa en instans av källläsaren.
- Räkna upp möjliga utdataformat.
- Ange det faktiska utdataformatet för varje ström.
- Bearbeta data från källan.
Resten av det här avsnittet beskriver de här stegen i detalj.
- Skapa källläsaren
- Lista utdataformat
- Ställa in utdataformat
- Bearbetning av mediedata
- Tömmer datapipeline
- Hämta filens varaktighet
- söker
- uppspelningshastighet
- maskinvaruacceleration
- Relaterade ämnen
Skapa källläsaren
Om du vill skapa en instans av källläsaren anropar du någon av följande funktioner:
| Funktion | Beskrivning |
|---|---|
|
MFCreateSourceReaderFromURL |
Tar en URL som indata. Den här funktionen använder Source Resolver för att skapa en mediekälla från URL:en. |
|
MFCreateSourceReaderFromByteStream |
Tar en pekare till en byteström. Den här funktionen använder också Källlösaren för att skapa mediekällan. |
|
MFCreateSourceReaderFromMediaSource |
Tar en pekare till en mediekälla som redan har skapats. Den här funktionen är användbar för mediekällor som Källlösaren inte kan skapa, till exempel avbildningsenheter eller anpassade mediekällor. |
För mediefiler använder du vanligtvis MFCreateSourceReaderFromURL. För enheter, till exempel webbkameror, använder du MFCreateSourceReaderFromMediaSource. (Mer information om inspelningsenheter i Microsoft Media Foundation finns i Audio/Video Capture.)
Var och en av dessa funktioner tar en valfri IMFAttributes pekare, som används för att ange olika alternativ på källläsaren, enligt beskrivningen i referensavsnitten för dessa funktioner. För att få standardbeteendet anger du den här parametern till NULL-. Varje funktion returnerar en IMFSourceReader- pekare som en utdataparameter. Du måste anropa funktionen CoInitialize(Ex) och MFStartup innan du anropar någon av dessa funktioner.
Följande kod skapar källläsaren från en 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();
}
}
Räkna upp utdataformat
Varje mediekälla har minst en strömning. En videofil kan till exempel innehålla en videoström och en ljudström. Formatet för varje ström beskrivs med hjälp av en medietyp som representeras av IMFMediaType- gränssnitt. Mer information om medietyper finns i Medietyper. Du måste undersöka medietypen för att förstå formatet på de data som du får från källläsaren.
Till en början har varje ström ett standardformat som du kan hitta genom att anropa metoden IMFSourceReader::GetCurrentMediaType:
För varje ström erbjuder mediekällan en lista över möjliga medietyper för strömmen. Antalet typer beror på källan. Om källan representerar en mediefil finns det vanligtvis bara en typ per dataström. En webbkamera kan å andra sidan strömma video i flera olika format. I så fall kan programmet välja vilket format som ska användas i listan över medietyper.
Om du vill hämta en av medietyperna för en ström anropar du metoden IMFSourceReader::GetNativeMediaType. Den här metoden tar två indexparametrar: Dataströmmens index och ett index i listan över medietyper för strömmen. För att räkna upp alla typer för en ström, öka listindexet medan strömindexet hålls konstant. När listindexet hamnar utanför gränserna returnerar GetNativeMediaTypeMF_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;
}
Om du vill räkna upp medietyperna för varje ström ökar du strömindexet. När indexet för dataströmmen hamnar utanför gränserna returnerar GetNativeMediaTypeMF_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;
}
Ange utdataformat
Om du vill ändra utdataformatet anropar du metoden IMFSourceReader::SetCurrentMediaType. Den här metoden tar strömindexet och en medietyp:
hr = pReader->SetCurrentMediaType(dwStreamIndex, pMediaType);
För medietypen beror det på om du vill infoga en avkodare.
- Om du vill hämta data direkt från källan utan att avkoda dem använder du någon av de typer som returneras av GetNativeMediaType.
- Om du vill avkoda strömmen skapar du en ny medietyp som beskriver önskat okomprimerat format.
När det gäller avkodaren skapar du medietypen på följande sätt:
- Anropa MFCreateMediaType för att skapa en ny medietyp.
- Ange attributet MF_MT_MAJOR_TYPE för att ange ljud eller video.
- Ange attributet MF_MT_SUBTYPE för att ange undertypen för avkodningsformatet. (Se GUID för ljudundertyp och videoundertyp.)
- Anropa IMFSourceReader::SetCurrentMediaType.
Källläsaren läser automatiskt in avkodaren. Om du vill få fullständig information om det avkodade formatet anropar du IMFSourceReader::GetCurrentMediaType efter anropet till SetCurrentMediaType
Följande kod konfigurerar videoströmmen för RGB-32 och ljudströmmen för PCM-ljud.
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;
}
Bearbeta mediedata
Om du vill hämta mediedata från källan anropar du metoden IMFSourceReader::ReadSample, enligt följande kod.
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.
);
Den första parametern är indexet för dataströmmen som du vill hämta data för. Du kan också ange MF_SOURCE_READER_ANY_STREAM för att hämta nästa tillgängliga data från valfri ström. Den andra parametern innehåller valfria flaggor. se MF_SOURCE_READER_CONTROL_FLAG för en lista över dessa. Den tredje parametern tar emot indexet för dataströmmen som faktiskt producerar data. Du behöver den här informationen om du anger den första parametern till MF_SOURCE_READER_ANY_STREAM. Den fjärde parametern tar emot statusflaggor som anger olika händelser som kan inträffa när data läss, till exempel formatändringar i strömmen. En lista över statusflaggor finns i MF_SOURCE_READER_FLAG.
Om mediekällan kan producera data för den begärda dataströmmen tar den sista parametern i ReadSample emot en pekare till IMFSample- gränssnittet för medieprovobjektet. Använd medieexemplet för att:
- Hämta en pekare till mediedata.
- Hämta presentationens tid och exempelvaraktighet.
- Hämta attribut som beskriver sammanflätning, fältdominans och andra aspekter av exemplet.
Innehållet i mediedata beror på dataströmmens format. För en okomprimerad videoström innehåller varje medieexempel en enda videoram. För en okomprimerad ljudström innehåller varje medieexempel en sekvens med ljudramar.
Metoden ReadSample kan returnera S_OK och ändå inte returnera ett medieexempel i parametern pSample. När du till exempel når slutet av filen anger ReadSample flaggan MF_SOURCE_READERF_ENDOFSTREAM i dwFlags och anger pSample till NULL. I det här fallet returnerar metoden ReadSampleS_OK eftersom inget fel har inträffat, även om parametern pSample är inställd på NULL-. Kontrollera därför alltid värdet för pSample innan du avrefererar det.
Följande kod visar hur du anropar ReadSample- i en loop och kontrollerar informationen som returneras av metoden tills slutet av mediefilen har nåtts.
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;
}
Tömma dataledningen
Under databearbetningen kan en avkodare eller annan transformering buffra inmatningsprover. I följande diagram anropar programmet ReadSample och får ett prov med en presentationstid som är lika med t1. Avkodaren innehåller exempel för t2 och t3.
Vid nästa anrop till ReadSamplekan källläsaren ge t4 till avkodaren och returnera t2- till programmet.
Om du vill avkoda alla exempel som för närvarande är buffrade i avkodaren, utan att skicka några nya exempel till avkodaren, anger du flaggan MF_SOURCE_READER_CONTROLF_DRAIN i parametern dwControlFlags för ReadSample. Fortsätt att göra detta i en loop tills ReadSample returnerar en NULL- exempelpekare. Beroende på hur avkodaren buffrar exempel kan det inträffa omedelbart eller efter flera anrop till ReadSample.
Hämta filvaraktighet
Om du vill hämta varaktigheten för en mediefil anropar du IMFSourceReader::GetPresentationAttribute-metoden och begär attributet MF_PD_DURATION enligt följande kod.
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;
}
Funktionen som visas här hämtar varaktigheten i enheter om 100 nanosekunder. Dividera med 10 000 000 för att få varaktigheten i sekunder.
Söker
En mediekälla som hämtar data från en lokal fil kan vanligtvis söka efter godtyckliga positioner i filen. Inspelningsenheter som webbkameror kan vanligtvis inte söka eftersom data är live. En källa som strömmar data över ett nätverk kanske kan söka, beroende på protokollet för nätverksströmning.
Du kan ta reda på om en mediekälla kan söka genom att anropa IMFSourceReader::GetPresentationAttribute och begära attributet MF_SOURCE_READER_MEDIASOURCE_CHARACTERISTICS enligt följande kod:
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;
}
Den här funktionen hämtar en uppsättning funktionsflaggor från källan. Dessa flaggor definieras i uppräkningen MFMEDIASOURCE_CHARACTERISTICS. Två flaggor relaterar till att söka:
| Flagga | Beskrivning |
|---|---|
|
MFMEDIASOURCE_CAN_SEEK |
Källan kan söka. |
|
MFMEDIASOURCE_HAS_SLOW_SEEK |
Att söka kan ta lång tid att slutföra. Källan kan till exempel behöva ladda ned hela filen innan den kan söka. (Det finns inga strikta kriterier för att en källa ska returnera den här flaggan.) |
Följande kodtest för flaggan 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;
}
Om du vill söka anropar du metoden IMFSourceReader::SetCurrentPosition, enligt följande kod.
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;
}
Den första parametern ger tidsformatet som du använder för att ange sökpositionen. Alla mediekällor i Media Foundation måste ha stöd för 100 nanosekunder, vilket anges av värdet GUID_NULL. Den andra parametern är en PROPVARIANT- som innehåller sökpositionen. För tidsenheter på 100 nanosekunder är datatypen LONGLONG.
Tänk på att inte alla mediekällor ger ram-exakt sökning. Noggrannheten i sökningen beror på flera faktorer, till exempel nyckelramsintervallet, om mediefilen innehåller ett index och om data har en konstant eller variabel bithastighet. När du försöker hitta en position i en fil finns det därför ingen garanti för att tidsstämpeln för nästa exempel exakt matchar den begärda positionen. I allmänhet kommer den faktiska positionen inte att vara senare än den begärda positionen, så du kan ta bort exempel tills du når önskad punkt i strömmen.
Uppspelningshastighet
Även om du kan ange uppspelningshastigheten med hjälp av källläsaren är det vanligtvis inte särskilt användbart av följande skäl:
- Källläsaren stöder inte omvänd uppspelning, även om mediekällan gör det.
- Programmet styr presentationstiderna så att programmet kan implementera snabb eller långsam uppspelning utan att ange källans hastighet.
- Vissa mediekällor stöder läge för gallring, där källan levererar färre prover, vanligtvis bara nyckelbilderna. Men om du vill utelämna icke-nyckelramar kan du kontrollera varje prov för attributet MFSampleExtension_CleanPoint.
Om du vill ange uppspelningshastigheten med hjälp av källläsaren anropar du metoden IMFSourceReader::GetServiceForStream för att hämta metoden IMFRateSupport och IMFRateControl-gränssnitt från mediekällan.
Maskinvaruacceleration
Källläsaren är kompatibel med Microsoft DirectX Video Acceleration (DXVA) 2.0 för maskinvaruaccelererad videodekodning. Utför följande steg för att använda DXVA med källläsaren.
- Skapa en Microsoft Direct3D-enhet.
- Anropa funktionen DXVA2CreateDirect3DDeviceManager9 för att skapa Direct3D-enhetshanteraren. Den här funktionen hämtar en pekare till gränssnittet IDirect3DDeviceManager9.
- Anropa metoden IDirect3DDeviceManager9::ResetDevice med en pekare till Direct3D-enheten.
- Skapa ett attributarkiv genom att anropa funktionen MFCreateAttributes.
- Skapa källläsaren. Skicka attributarkivet i pAttributes parametern för skapandefunktionen.
När du tillhandahåller en Direct3D-enhet allokerar källläsaren videoexempel som är kompatibla med DXVA-videoprocessor-API:et. Du kan använda DXVA-videobearbetning för att utföra maskinvaru-deinterlacing eller videoblandning. Mer information finns i DXVA Video Processing. Om avkodaren dessutom stöder DXVA 2.0 använder den Direct3D-enheten för att utföra maskinvaruaccelererad avkodning.
Viktig
Från och med Windows 8 kan IMFDXGIDeviceManager användas i stället för IDirect3DDeviceManager9. För Windows Store-appar måste du använda IMFDXGIDeviceManager. Mer information finns i Direct3D 11 Video-API:er.
Relaterade ämnen