Not
Bu sayfaya erişim yetkilendirme gerektiriyor. Oturum açmayı veya dizinleri değiştirmeyi deneyebilirsiniz.
Bu sayfaya erişim yetkilendirme gerektiriyor. Dizinleri değiştirmeyi deneyebilirsiniz.
Bu konuda, medya verilerini işlemek için Kaynak Okuyucu nasıl kullanılacağı açıklanmaktadır.
Kaynak Okuyucu'yı kullanmak için şu temel adımları izleyin:
- Kaynak Okuyucu'nun bir örneğini oluşturun.
- Olası çıkış biçimlerini numaralandırın.
- Her akış için gerçek çıkış biçimini ayarlayın.
- Kaynaktan verileri işleme.
Bu konunun geri kalanında bu adımlar ayrıntılı olarak açıklanmaktadır.
- Kaynak Okuyucu Oluşturma
- Çıkış Biçimlerini Numaralandırma
- Çıkış Biçimlerini Ayarlama
- Medya Verilerini İşleme
- Veri İşlem Hattını Boşaltma
- Dosya Süresini Alma
- Arayış
- Oynatma Hızı
- donanım hızlandırma
- İlgili konular
Kaynak Okuyucu oluşturma
Kaynak Okuyucu'nun bir örneğini oluşturmak için aşağıdaki işlevlerden birini çağırın:
| Fonksiyon | Açıklama |
|---|---|
|
MFCreateSourceReaderFromURL |
Giriş olarak bir URL alır. Bu işlev, URL'den bir medya kaynağı oluşturmak için Kaynak Çözümleyicisi kullanır. |
|
MFCreateSourceReaderFromByteStream |
Bayt akışına bir işaretçi tutar. Bu işlev, medya kaynağını oluşturmak için Kaynak Çözümleyici'yi de kullanır. |
|
MFCreateSourceReaderFromMediaSource |
Önceden oluşturulmuş bir medya kaynağına işaretçi alır. Bu işlev, Yakalama cihazları veya özel medya kaynakları gibi Kaynak Çözümleyici'nin oluşturamadığı medya kaynakları için kullanışlıdır. |
Medya dosyaları için genellikle MFCreateSourceReaderFromURLkullanın. Web kameraları gibi cihazlar için MFCreateSourceReaderFromMediaSourcekullanın. (Microsoft Media Foundation'da cihazları yakalama hakkında daha fazla bilgi için bkz. Ses/Video Yakalama.)
Bu işlevlerin her biri, bu işlevlerin başvuru konularında açıklandığı gibi Kaynak Okuyucu'da çeşitli seçenekleri ayarlamak için kullanılan isteğe bağlı bir IMFAttributes işaretçisi alır. Varsayılan davranışı almak için bu parametreyi null olarak ayarlayın. Her işlev çıkış parametresi olarak bir IMFSourceReader işaretçisi döndürür. Bu işlevlerden herhangi birini çağırmadan önce CoInitialize(Ex) ve MFStartup işlevini çağırmanız gerekir.
Aşağıdaki kod bir URL'den Kaynak Okuyucu oluşturur.
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();
}
}
Çıkış Biçimlerini Numaralandırma
Her medya kaynağının en az bir akışı bulunur. Örneğin, bir video dosyası bir video akışı ve bir ses akışı içerebilir. Her akışın biçimi, IMFMediaType arabirimi tarafından temsil edilen bir medya türü kullanılarak açıklanır. Medya türleri hakkında daha fazla bilgi için bkz. Medya Türleri. Kaynak Okuyucu'dan edindiğiniz verilerin biçimini anlamak için medya türünü incelemeniz gerekir.
Başlangıçta, her akışın varsayılan biçimi vardır ve bu biçimi IMFSourceReader::GetCurrentMediaType yöntemini çağırarak bulabilirsiniz:
Her akış için medya kaynağı, bu akış için olası medya türlerinin listesini sunar. Tür sayısı kaynağa bağlıdır. Kaynak bir medya dosyasını temsil ederse, genellikle akış başına yalnızca bir tür vardır. Öte yandan web kamerası birkaç farklı biçimde video akışı yapabilir. Bu durumda, uygulama medya türleri listesinden hangi biçimin kullanılacağını seçebilir.
Bir akışın medya türlerinden birini almak için IMFSourceReader::GetNativeMediaType yöntemini çağırın. Bu yöntem iki dizin parametresi alır: Akışın dizini ve akış için medya türleri listesinde bir dizin. Bir akışın tüm türlerini numaralandırmak için, akış dizini sabitini koruyarak liste dizinini artırın. Liste dizini sınırların dışına çıktığında GetNativeMediaType, MF_E_NO_MORE_TYPESdöndürür.
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;
}
Her akışın medya türlerini numaralandırmak için akış dizinini artırın. Akış dizini sınırları aştığında GetNativeMediaType, MF_E_INVALIDSTREAMNUMBERdeğerini döndürür.
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;
}
Çıkış Biçimlerini Ayarlama
Çıkış biçimini değiştirmek için IMFSourceReader::SetCurrentMediaType yöntemini çağırın. Bu yöntem akış dizinini ve bir medya türünü alır:
hr = pReader->SetCurrentMediaType(dwStreamIndex, pMediaType);
Medya türü için kod çözücü eklemek isteyip istemediğinize bağlıdır.
- Kodu çözmeden doğrudan kaynaktan veri almak için getNativeMediaTypetarafından döndürülen türlerden birini kullanın.
- Akışın kodunu çözmek için, istenen sıkıştırılmamış biçimi açıklayan yeni bir medya türü oluşturun.
Kod çözücü söz konusu olduğunda medya türünü aşağıdaki gibi oluşturun:
- Yeni bir medya türü oluşturmak için MFCreateMediaTypeçağırın.
- Ses veya video belirtmek için MF_MT_MAJOR_TYPE özniteliğini ayarlayın.
- Kod çözme biçiminin alt türünü belirtmek için MF_MT_SUBTYPE özniteliğini ayarlayın. (Bkz. Ses Alt Türü GUID'leri ve Video Alt Türü GUID'leri.)
- Çağrı IMFSourceReader::SetCurrentMediaType.
Kaynak Okuyucu, kod çözücüsün otomatik olarak yüklenmesini sağlayacaktır. Kodu çözülen biçimin tüm ayrıntılarını almak için, SetCurrentMediaTypeçağrısını yaptıktan sonra IMFSourceReader::GetCurrentMediaType çağırın.
Aşağıdaki kod RGB-32 için video akışını ve PCM sesi için ses akışını yapılandırıyor.
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;
}
Medya Verilerini İşleme
Kaynaktan medya verileri almak için aşağıdaki kodda gösterildiği gibi IMFSourceReader::ReadSample yöntemini çağırın.
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.
);
İlk parametre, veri almak istediğiniz akışın dizinidir. Ayrıca herhangi bir akıştan sonraki kullanılabilir verileri almak için MF_SOURCE_READER_ANY_STREAM belirtebilirsiniz. İkinci parametre isteğe bağlı bayraklar içerir; Bunların listesi için bkz. MF_SOURCE_READER_CONTROL_FLAG. Üçüncü parametre, verileri gerçekten üreten akışın dizinini alır. İlk parametreyi MF_SOURCE_READER_ANY_STREAMolarak ayarlarsanız bu bilgilere ihtiyacınız olacaktır. Dördüncü parametre, akıştaki biçim değişiklikleri gibi verileri okurken gerçekleşebilecek çeşitli olayları gösteren durum bayrakları alır. Durum bayraklarının listesi için bkz. MF_SOURCE_READER_FLAG.
Medya kaynağı istenen akış için veri üretebiliyorsa, ReadSample son parametresi, medya örnek nesnesinin IMFSample arabirimine bir işaretçi alır. Medya örneğini kullanarak:
- Medya verilerine bir işaretçi alın.
- Sunu süresini ve örnek süresini alın.
- Araya girme, alan hakimiyeti ve örneğin diğer yönlerini açıklayan öznitelikleri alın.
Medya verilerinin içeriği akışın biçimine bağlıdır. Sıkıştırılmamış bir video akışı için her medya örneği tek bir video çerçevesi içerir. Sıkıştırılmamış bir ses akışı için her medya örneği bir dizi ses çerçevesi içerir.
ReadSample yöntemi S_OK döndürebilir ancak pSample parametresinde bir medya örneği döndüremez. Örneğin, dosyanın sonuna ulaştığınızda, ReadSampledwFlags'de MF_SOURCE_READERF_ENDOFSTREAM bayrağını ayarlar ve pSample'i NULLolarak atanır. Bu durumda, pSample parametresi NULLolarak ayarlanmış olsa da hiçbir hata oluşmadığı için ReadSample yöntemi S_OK döndürür. Bu nedenle, dereferans etmeden önce her zaman pSample değerini denetleyin.
Aşağıdaki kod, bir döngüde ReadSample çağırmayı ve medya dosyasının sonuna ulaşılana kadar yöntemi tarafından döndürülen bilgileri denetlemeyi gösterir.
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;
}
Veri İşlem Hattını Boşaltma
Veri işleme sırasında kod çözücü veya başka bir dönüşüm giriş örneklerini arabelleğe alabilir. Aşağıdaki diyagramda uygulama, ReadSample çağırır ve sunu süresi t1olan bir örnek alır. Kod çözücü, t2 ve t3için örnekler tutuyor.
ReadSamplesonraki çağrısında, Kaynak Okuyucu kod çözücüye t4 verebilir ve uygulamaya t2 döndürebilir.
Kod çözücüde arabelleğe alınmış olan tüm örneklerin kodunu kod çözücüye yeni örnekler geçirmeden çözmek istiyorsanız dwControlFlags parametresinde MF_SOURCE_READER_CONTROLF_DRAIN bayrağını ReadSampleayarlayın. ReadSample bir NULL örnek işaretçisi döndürene kadar bu işlemi bir döngüde yapmaya devam edin. Kod çözücünün örnekleri nasıl arabelleğe aldığına bağlı olarak, ReadSampleiçin yapılan birkaç çağrıdan hemen gerçekleşebilir veya sonra.
Dosya Süresini Alma
Medya dosyasının süresini almak için IMFSourceReader::GetPresentationAttribute yöntemini çağırın ve aşağıdaki kodda gösterildiği gibi MF_PD_DURATION özniteliğini isteyin.
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;
}
Burada gösterilen işlev, süreyi 100 nanosaniye cinsinden alır. Süreyi saniye cinsinden almak için 10.000.000'e bölün.
Aranıyor
Yerel bir dosyadan veri alan bir medya kaynağı genellikle dosyada rastgele konumlar bulmaya çalışır. Veriler canlı olduğundan web kameraları gibi yakalama cihazları genellikle arama yapamaz. Ağ üzerinden veri akışı sağlayan bir kaynak, ağ akış protokolüne bağlı olarak arama yapabilir.
Bir medya kaynağının arama yapıp yapamayacağını öğrenmek için, aşağıdaki kodda gösterildiği gibi IMFSourceReader::GetPresentationAttribute çağırın ve MF_SOURCE_READER_MEDIASOURCE_CHARACTERISTICS özniteliğini isteyin.
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;
}
Bu işlev, kaynaktan bir dizi yetenek bayrağı alır. Bu bayraklar MFMEDIASOURCE_CHARACTERISTICS numaralandırmasında tanımlanır. arama ile ilgili iki bayrak vardır:
| Bayrak | Açıklama |
|---|---|
|
MFMEDIASOURCE_CAN_SEEK |
Kaynak arayabilir. |
|
MFMEDIASOURCE_HAS_SLOW_SEEK |
Aramanın tamamlanması uzun sürebilir. Örneğin, kaynağın aramadan önce dosyanın tamamını indirmesi gerekebilir. Kaynağın bu bayrağı döndürmesi için kesin ölçüt yoktur. |
Aşağıdaki kod, MFMEDIASOURCE_CAN_SEEK bayrağını test eder.
BOOL SourceCanSeek(IMFSourceReader *pReader)
{
BOOL bCanSeek = FALSE;
ULONG flags;
if (SUCCEEDED(GetSourceFlags(pReader, &flags)))
{
bCanSeek = ((flags & MFMEDIASOURCE_CAN_SEEK) == MFMEDIASOURCE_CAN_SEEK);
}
return bCanSeek;
}
Aramak için, aşağıdaki kodda gösterildiği gibi IMFSourceReader::SetCurrentPosition yöntemini çağırın.
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;
}
İlk parametre, arama konumunu belirtmek için kullandığınız saat biçimini verir. Media Foundation'daki tüm medya kaynaklarının GUID_NULLdeğeriyle belirtilen 100 nanosaniyelik birimleri desteklemesi gerekir. İkinci parametre, arama konumunu içeren bir PROPVARIANT'dır. 100 nanosaniyelik zaman birimleri için veri türü LONGLONG.
Her medya kaynağının çerçeve doğru arama sağlamadığını unutmayın. Aramanın doğruluğu anahtar kare aralığı, medya dosyasının dizin içerip içermediği ve verilerin sabit veya değişken bit hızına sahip olup olmadığı gibi çeşitli faktörlere bağlıdır. Bu nedenle, bir dosyadaki konumu aradıktan sonra, sonraki örnekteki zaman damgasının istenen konumla tam olarak eşleşeceğinin garantisi yoktur. Genel olarak, gerçek konum istenen konumdan daha geç olmayacaktır, bu nedenle akışta istenen noktaya ulaşana kadar örnekleri atabilirsiniz.
Oynatma Hızı
Kayıttan yürütme hızını Kaynak Okuyucu kullanarak ayarlayabilmenize rağmen, aşağıdaki nedenlerden dolayı yapmak genellikle çok kullanışlı değildir:
- Kaynak Okuyucu, medya kaynağı desteklese bile ters oynatmayı desteklemez.
- Uygulama sunu sürelerini denetler, böylece uygulama kaynakta hızı ayarlamadan hızlı veya yavaş yürütme gerçekleştirebilir.
- Bazı medya kaynakları inceltme modunu destekler; bu modda, kaynak genellikle yalnızca anahtar kareleri içeren daha az örnek sunar. Ancak, anahtar olmayan çerçeveleri bırakmak istiyorsanız, her örneği MFSampleExtension_CleanPoint özniteliği için de kontrol edebilirsiniz.
Kaynak Okuyucu kullanarak kayıttan yürütme hızını ayarlamak için IMFSourceReader::GetServiceForStream yöntemini çağırarak medya kaynağından IMFRateSupport ve IMFRateControl arabirimlerini alın.
Donanım Hızlandırma
Kaynak Okuyucu, donanım hızlandırmalı video kod çözme için Microsoft DirectX Video Acceleration (DXVA) 2.0 ile uyumludur. DXVA'yı Kaynak Okuyucu ile kullanmak için aşağıdaki adımları uygulayın.
- Microsoft Direct3D cihazı oluşturun.
- Direct3D cihaz yöneticisini oluşturmak için DXVA2CreateDirect3DDeviceManager9 işlevini çağırın. Bu işlev, IDirect3DDeviceManager9 arabirimine bir pointer edinir.
- IDirect3DDeviceManager9::ResetDevice yöntemini Direct3D cihazına yönelik bir işaretçiyle çağırın.
- MFCreateAttributes işlevini çağırarak bir öznitelik deposu oluşturun.
- Kaynak Okuyucuyu oluşturun. Oluşturma işlevinin pAttributes parametresinde öznitelik depolama alanını geçirin.
Direct3D cihazı sağladığınızda, Kaynak Okuyucu DXVA video işlemci API'siyle uyumlu video örnekleri ayırır. Donanım ayrıştırma veya video karıştırma gerçekleştirmek için DXVA video işlemeyi kullanabilirsiniz. Daha fazla bilgi için bkz. DXVA Video İşleme. Ayrıca, kod çözücü DXVA 2.0'ı destekliyorsa, donanım hızlandırmalı kod çözme gerçekleştirmek için Direct3D cihazını kullanır.
Önemli
Windows 8'den başlayarak, IDirect3DDeviceManager9yerineIMFDXGIDeviceManager kullanılabilir. Windows Mağazası uygulamaları için IMFDXGIDeviceManagerkullanmanız gerekir. Daha fazla bilgi için Direct3D 11 Video API'lerine bakın.
İlgili konular