Membangun Grafik dengan Capture Graph Builder

[Fitur yang terkait dengan halaman ini, DirectShow, adalah fitur warisan. Ini telah digantikan oleh MediaPlayer, IMFMediaEngine, dan Tangkapan Audio/Video di Media Foundation. Fitur-fitur tersebut telah dioptimalkan untuk Windows 10 dan Windows 11. Microsoft sangat menyarankan agar kode baru menggunakan MediaPlayer, IMFMediaEngine dan Audio/Video Capture di Media Foundation alih-alih DirectShow, jika memungkinkan. Microsoft menyarankan agar kode yang ada yang menggunakan API warisan ditulis ulang untuk menggunakan API baru jika memungkinkan.]

Terlepas dari namanya, Capture Graph Builder berguna untuk membangun berbagai jenis grafik filter kustom, tidak hanya menangkap grafik. Artikel ini menyediakan gambaran umum singkat tentang cara menggunakan objek ini.

Capture Graph Builder mengekspos antarmuka ICaptureGraphBuilder2 . Mulailah dengan memanggil CoCreateInstance untuk membuat Capture Graph Builder dan Filter Graph Manager. Kemudian inisialisasi Capture Graph Builder dengan memanggil ICaptureGraphBuilder2::SetFiltergraph dengan pointer ke Filter Graph Manager, sebagai berikut:

IGraphBuilder *pGraph = NULL;
ICaptureGraphBuilder2 *pBuilder = NULL;

// Create the Filter Graph Manager.
HRESULT hr =  CoCreateInstance(CLSID_FilterGraph, NULL,
    CLSCTX_INPROC_SERVER, IID_IGraphBuilder, (void **)&pGraph);

if (SUCCEEDED(hr))
{
    // Create the Capture Graph Builder.
    hr = CoCreateInstance(CLSID_CaptureGraphBuilder2, NULL,
        CLSCTX_INPROC_SERVER, IID_ICaptureGraphBuilder2, 
        (void **)&pBuilder);
    if (SUCCEEDED(hr))
    {
        pBuilder->SetFiltergraph(pGraph);
    }
};

Menyambungkan Filter

Metode ICaptureGraphBuilder2::RenderStream menghubungkan dua atau tiga filter bersama-sama dalam rantai. Umumnya, metode ini berfungsi paling baik ketika setiap filter memiliki tidak lebih dari satu pin input atau pin output dengan jenis yang sama. Diskusi ini dimulai dengan mengabaikan dua parameter pertama RenderStream dan berfokus pada tiga parameter terakhir. Parameter ketiga adalah penunjuk IUnknown , yang dapat menentukan filter (sebagai penunjuk antarmuka IBaseFilter ) atau pin output (sebagai penunjuk antarmuka IPin ). Parameter keempat dan kelima menentukan pointer IBaseFilter . Metode RenderStream menghubungkan ketiga filter dalam rantai. Misalnya, A,B, dan C adalah filter. Asumsikan untuk saat ini bahwa setiap filter memiliki tepat satu pin input dan satu pin output. Panggilan berikut menyambungkan A ke B, lalu B ke C:

'RenderStream(NULL, NULL, A, B, C)'

Semua koneksi "cerdas", yang berarti bahwa filter tambahan ditambahkan ke grafik sesuai kebutuhan. Untuk detailnya, lihat Intelligent Connect. Untuk menyambungkan hanya dua filter, atur nilai tengah ke NULL. Misalnya, panggilan ini menghubungkan A ke C:

'RenderStream(NULL, NULL, A, NULL, C)'

Anda dapat membuat rantai yang lebih panjang dengan memanggil metode dua kali:

'RenderStream(NULL, NULL, A, B, C)' 'RenderStream(NULL, NULL, C, D, E)'

Jika parameter terakhir adalah NULL, metode secara otomatis menemukan perender default. Ini menggunakan Video Renderer untuk video dan DirectSound Renderer untuk audio. Sehingga:

'RenderStream(NULL, NULL, A, NULL, NULL)'

setara dengan

'RenderStream(NULL, NULL, A, NULL, R)'

di mana R adalah perender yang sesuai. Namun, untuk menyambungkan filter Video Mixing Renderer alih-alih Video Renderer, Anda harus menentukannya secara eksplisit.

Jika Anda menentukan filter di parameter ketiga, bukan pin, Anda mungkin perlu menunjukkan pin output mana yang harus digunakan untuk koneksi. Itu adalah tujuan dari dua parameter pertama metode. Parameter pertama hanya berlaku untuk menangkap filter. Ini menentukan GUID yang menunjukkan kategori pin. Untuk daftar lengkap kategori, lihat Menyematkan Kumpulan Properti. Dua kategori berlaku untuk semua filter pengambilan:

  • PIN_CATEGORY_CAPTURE
  • PIN_CATEGORY_PREVIEW

Jika filter tangkapan tidak menyediakan pin terpisah untuk pengambilan dan pratinjau, metode RenderStream menyisipkan filter Smart Tee , yang membagi aliran menjadi aliran tangkapan dan aliran pratinjau. Dari sudut depan aplikasi, Anda cukup memperlakukan semua filter tangkapan sebagai memiliki pin terpisah dan mengabaikan topologi grafik yang mendasar.

Untuk pengambilan file, sambungkan pin pengambilan ke filter mux. Untuk pratinjau langsung, sambungkan pin pratinjau ke perender. Jika Anda mengalihkan dua kategori, grafik mungkin menghilangkan jumlah bingkai yang berlebihan selama pengambilan file; tetapi jika grafik terhubung dengan benar, grafik menghilangkan bingkai pratinjau sesuai kebutuhan untuk mempertahankan throughput pada aliran pengambilan.

Contoh berikut menunjukkan cara menyambungkan kedua aliran:

// Capture to file:
pBuilder->RenderStream(&PIN_CATEGORY_CAPTURE, NULL, pCapFilter, NULL, pMux);
// Preview:
pBuilder->RenderStream(&PIN_CATEGORY_PREVIEW, NULL, pCapFilter, NULL, NULL);

Beberapa filter pengambilan juga mendukung keterangan tertutup, yang ditunjukkan oleh PIN_CATEGORY_VBI. Untuk mengambil keterangan tertutup ke file, render kategori ini ke filter mux. Untuk melihat keterangan tertutup di jendela pratinjau Anda, sambungkan ke perender:

// Capture to file:
pBuilder->RenderStream(&PIN_CATEGORY_VBI, NULL, pCapFilter, NULL, pMux);
// Preview on screen:
pBuilder->RenderStream(&PIN_CATEGORY_VBI, NULL, pCapFilter, NULL, NULL);

Parameter kedua untuk RenderStream mengidentifikasi jenis media, dan biasanya merupakan salah satu dari berikut ini:

  • MEDIATYPE_Audio
  • MEDIATYPE_Video
  • MEDIATYPE_Interleaved (DV)

Anda dapat menggunakan parameter ini setiap kali pin output filter mendukung enumerasi jenis media pilihan. Untuk sumber file, Capture Graph Builder secara otomatis menambahkan filter parser jika diperlukan, lalu mengkueri jenis media di parser. (Misalnya, lihat Mengompresi Ulang File AVI.) Selain itu, jika filter terakhir dalam rantai memiliki beberapa pin input, metode ini mencoba menghitung jenis media mereka. Namun, tidak semua filter mendukung fungsionalitas ini.

Menemukan Antarmuka pada Filter dan Pin

Setelah membuat grafik, Anda biasanya perlu menemukan berbagai antarmuka yang diekspos oleh filter dan pin dalam grafik. Misalnya, filter pengambilan mungkin mengekspos antarmuka IAMDroppedFrames , sementara pin output filter mungkin mengekspos antarmuka IAMStreamConfig .

Cara paling sederhana untuk menemukan antarmuka adalah dengan menggunakan metode ICaptureGraphBuilder2::FindInterface . Metode ini berjalan grafik (filter dan pin) sampai menemukan antarmuka yang diinginkan. Anda dapat menentukan titik awal untuk pencarian, dan Anda dapat membatasi pencarian untuk memfilter hulu atau hilir dari titik awal.

Contoh berikut mencari antarmuka IAMStreamConfig pada pin pratinjau video:

IAMStreamConfig *pConfig = NULL;
HRESULT hr = pBuild->FindInterface(
    &PIN_CATEGORY_PREVIEW, 
    &MEDIATYPE_Video,
    pVCap, 
    IID_IAMStreamConfig, 
    (void**)&pConfig
);
if (SUCCESSFUL(hr))
{
    /* ... */
    pConfig->Release();
}

Catatan

Topik Menemukan Antarmuka pada Filter atau Pin menunjukkan pendekatan alternatif yang menggunakan antarmuka IGraphBuilder alih-alih ICaptureGraphBuilder2. Pendekatan mana yang akan digunakan tergantung pada aplikasi Anda. Jika aplikasi Anda sudah menggunakan ICaptureGraphBuilder2 untuk membangun grafik, maka ICaptureGraphBuilder2::FindInterface adalah pendekatan yang baik. Jika tidak, pertimbangkan untuk menggunakan metode IGraphBuilder .

 

Menemukan Pin

Kurang umum, Anda mungkin perlu menemukan pin individual pada filter, meskipun dalam banyak kasus metode RenderStream dan FindInterface akan menghemat masalah Anda. Jika Anda perlu menemukan pin tertentu pada filter, metode pembantu ICaptureGraphBuilder2::FindPin berguna. Tentukan kategori, jenis media (video atau audio), arah, dan apakah pin harus tidak tersambung.

Misalnya, kode berikut mencari pin pratinjau video yang tidak terhubung pada filter pengambilan:

IPin *pPin = NULL;
hr = pBuild->FindPin(
    pCap,                   // Pointer to the filter to search.
    PINDIR_OUTPUT,          // Search for an output pin.
    &PIN_CATEGORY_PREVIEW,  // Search for a preview pin.
    &MEDIATYPE_Video,       // Search for a video pin.
    TRUE,                   // The pin must be unconnected. 
    0,                      // Return the first matching pin (index 0).
    &pPin);                 // This variable receives the IPin pointer.
if (SUCCESSFUL(hr))
{
    /* ... */
    pPin->Release();
}

Pengambilan Video