Bagikan melalui


Perender Video Alternatif

[Fitur yang terkait dengan halaman ini, DirectShow, adalah fitur warisan. Ini telah digantikan oleh MediaPlayer, IMFMediaEngine, dan Pengambilan 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 Pengambilan Audio/Video 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.]

Topik ini menjelaskan cara menulis perender video kustom untuk DirectShow.

Catatan

Alih-alih menulis perender video kustom, disarankan agar Anda menulis alokator-presenter plug-in untuk Video Mixing Renderer (VMR) atau Enhanced Video Renderer (EVR). Pendekatan ini akan memberi Anda semua manfaat VMR/EVR, termasuk dukungan untuk DirectX Video Acceleration (DXVA), deinterlacing perangkat keras, dan langkah bingkai, dan kemungkinan akan lebih kuat daripada perender video kustom. Untuk informasi selengkapnya, lihat topik berikut:

 

Menulis Penyaji Alternatif

Microsoft DirectShow menyediakan perender video berbasis jendela; ini juga menyediakan perender layar penuh dalam penginstalan run-time. Anda dapat menggunakan kelas dasar DirectShow untuk menulis perender video alternatif. Agar perender alternatif dapat berinteraksi dengan benar dengan aplikasi berbasis DirectShow, perender harus mematuhi pedoman yang diuraikan dalam artikel ini. Anda dapat menggunakan kelas CBaseRenderer dan CBaseVideoRenderer untuk membantu mengikuti panduan ini saat menerapkan render video alternatif. Karena pengembangan DirectShow yang sedang berlangsung, tinjau implementasi Anda secara berkala untuk memastikan bahwa perender kompatibel dengan versi terbaru DirectShow.

Topik ini membahas banyak pemberitahuan bahwa perender bertanggung jawab untuk menangani. Tinjauan singkat pemberitahuan DirectShow mungkin membantu mengatur tahapan. Pada dasarnya ada tiga jenis pemberitahuan yang terjadi di DirectShow:

  • Pemberitahuan streaming, yang merupakan peristiwa yang terjadi di aliran media dan diteruskan dari satu filter ke filter berikutnya. Ini dapat berupa mulai membersihkan, menghapus akhir, atau pemberitahuan end-of-stream dan dikirim dengan memanggil metode yang sesuai pada pin input filter hilir (misalnya IPin::BeginFlush).
  • Memfilter pemberitahuan grafik, yang merupakan peristiwa yang dikirim dari filter ke Filter Graph Manager seperti EC_COMPLETE. Ini dicapai dengan memanggil metode IMediaEventSink::Notify pada Filter Graph Manager.
  • Pemberitahuan aplikasi, yang diambil dari Filter Graph Manager oleh aplikasi pengontrol. Aplikasi memanggil metode IMediaEvent::GetEvent pada Filter Graph Manager untuk mengambil peristiwa ini. Seringkali, Filter Graph Manager melewati peristiwa yang diterimanya ke aplikasi.

Topik ini membahas tanggung jawab filter perender dalam menangani pemberitahuan aliran yang diterimanya dan dalam mengirim pemberitahuan grafik filter yang sesuai.

Menangani Pemberitahuan End-of-stream dan Flushing

Pemberitahuan end-of-stream dimulai pada filter upstram (seperti filter sumber) saat filter tersebut mendeteksi bahwa filter tersebut tidak dapat mengirim data lagi. Ini diteruskan melalui setiap filter dalam grafik dan akhirnya berakhir di perender, yang bertanggung jawab untuk kemudian mengirim pemberitahuan EC_COMPLETE ke Filter Graph Manager. Perender memiliki tanggung jawab khusus dalam menangani pemberitahuan ini.

Perender menerima pemberitahuan end-of-stream ketika metode IPin::EndOfStream pin inputnya dipanggil oleh filter upstream. Perender harus mencatat pemberitahuan ini dan terus merender data apa pun yang telah diterimanya. Setelah semua data yang tersisa diterima, perender harus mengirim pemberitahuan EC_COMPLETE ke Filter Graph Manager. Pemberitahuan EC_COMPLETE harus dikirim hanya sekali oleh perender setiap kali mencapai akhir aliran. Selain itu, pemberitahuan EC_COMPLETE tidak boleh dikirim kecuali ketika grafik filter berjalan. Oleh karena itu, jika grafik filter dijeda saat filter sumber mengirim pemberitahuan akhir aliran, maka EC_COMPLETE tidak boleh dikirim hingga grafik filter akhirnya dijalankan.

Setiap panggilan ke metode IMemInputPin::Receive atau IMemInputPin::ReceiveMultiple setelah pemberitahuan end-of-stream disinyalir akan ditolak. E_UNEXPECTED adalah pesan kesalahan yang paling tepat untuk dikembalikan dalam kasus ini.

Saat grafik filter dihentikan, pemberitahuan akhir aliran yang di-cache harus dihapus dan tidak ditolak saat berikutnya dimulai. Ini karena Filter Graph Manager selalu menjeda semua filter tepat sebelum menjalankannya sehingga pembilasan yang tepat terjadi. Jadi, misalnya, jika grafik filter dijeda dan pemberitahuan akhir aliran diterima, lalu grafik filter dihentikan, perender tidak boleh mengirim pemberitahuan EC_COMPLETE saat kemudian dijalankan. Jika tidak ada pencarian yang terjadi, filter sumber akan secara otomatis mengirim pemberitahuan end-of-stream lain selama status jeda yang mendahului status eksekusi. Jika, di sisi lain, pencarian telah terjadi saat grafik filter dihentikan, filter sumber mungkin memiliki data untuk dikirim, sehingga tidak akan mengirim pemberitahuan end-of-stream.

Perender video sering bergantung pada pemberitahuan end-of-stream untuk lebih dari pengiriman pemberitahuan EC_COMPLETE . Misalnya, jika streaming telah selesai diputar (yaitu, pemberitahuan end-of-stream dikirim) dan jendela lain diseret melalui jendela perender video, sejumlah pesan jendela WM_PAINT akan dihasilkan. Praktik umum untuk menjalankan perender video adalah menahan diri dari mengecat ulang bingkai saat ini setelah menerima pesan WM_PAINT (berdasarkan asumsi bahwa bingkai lain yang akan digambar akan diterima). Namun, ketika pemberitahuan end-of-stream telah dikirim, perender berada dalam status menunggu; masih berjalan tetapi menyadari bahwa ia tidak akan menerima data tambahan apa pun. Dalam keadaan ini, perender biasanya menggambar area pemutaran menjadi hitam.

Menangani pembilasan adalah komplikasi tambahan untuk perender. Pembilasan dilakukan melalui sepasang metode IPin yang disebut BeginFlush dan EndFlush. Flushing pada dasarnya adalah status tambahan yang harus ditangani oleh perender. Ini ilegal bagi filter sumber untuk memanggil BeginFlush tanpa memanggil EndFlush, jadi mudah-mudahan statusnya pendek dan diskrit; namun, perender harus menangani data atau pemberitahuan yang diterimanya dengan benar selama transisi flush.

Setiap data yang diterima setelah memanggil BeginFlush harus segera ditolak dengan mengembalikan S_FALSE. Selain itu, setiap pemberitahuan end-of-stream yang di-cache juga harus dibersihkan saat perender dibersihkan. Perender biasanya akan dibersihkan sebagai respons terhadap pencarian. Flush memastikan bahwa data lama dibersihkan dari grafik filter sebelum sampel baru dikirim. (Biasanya, pemutaran dua bagian aliran, satu demi satu, paling baik ditangani melalui perintah yang ditangguhkan daripada menunggu satu bagian selesai dan kemudian mengeluarkan perintah pencarian.)

Menangani Perubahan Status dan Penyelesaian Jeda

Filter perender bereaksi sama dengan filter lain dalam grafik filter saat statusnya diubah, dengan pengecualian berikut. Setelah dijeda, perender akan memiliki beberapa data yang diantrekan, siap untuk dirender saat kemudian dijalankan. Saat perender video dihentikan, perender video menyimpan data yang diantrekan ini. Ini adalah pengecualian untuk aturan DirectShow bahwa tidak ada sumber daya yang harus dipegang oleh filter saat grafik filter dihentikan.

Alasan pengecualian ini adalah bahwa dengan menyimpan sumber daya, perender akan selalu memiliki gambar untuk mengecat ulang jendela jika menerima pesan WM_PAINT . Ini juga memiliki gambar untuk memenuhi metode, seperti CBaseControlVideo::GetStaticImage, yang meminta salinan gambar saat ini. Efek lain dari menahan sumber daya adalah bahwa menahan gambar menghentikan alokator dinonaktifkan, yang pada gilirannya membuat perubahan status berikutnya terjadi jauh lebih cepat karena buffer gambar sudah dialokasikan.

Perender video harus merender dan merilis sampel hanya saat berjalan. Saat dijeda, filter mungkin merendernya (misalnya, saat menggambar gambar poster statis di jendela), tetapi tidak boleh melepaskannya. Perender audio tidak akan melakukan penyajian saat dijeda (meskipun mereka dapat melakukan aktivitas lain, seperti menyiapkan perangkat gelombang, misalnya). Waktu di mana sampel harus dirender diperoleh dengan menggabungkan waktu streaming dalam sampel dengan waktu referensi yang diteruskan sebagai parameter ke metode IMediaControl::Run . Perender harus menolak sampel dengan waktu mulai kurang dari atau sama dengan waktu akhir.

Saat aplikasi menjeda grafik filter, grafik filter tidak kembali dari metode IMediaControl::P ause hingga ada data yang diantrekan di perender. Untuk memastikan hal ini, ketika perender dijeda, perender harus mengembalikan S_FALSE jika tidak ada data yang menunggu untuk dirender. Jika memiliki data yang diantrekan, maka data dapat mengembalikan S_OK.

Filter Graph Manager memeriksa semua nilai yang dikembalikan saat menjeda grafik filter, untuk memastikan bahwa perender memiliki data yang diantrekan. Jika satu atau beberapa filter belum siap, Filter Graph Manager akan melakukan polling filter dalam grafik dengan memanggil IMediaFilter::GetState. Metode GetState membutuhkan parameter waktu habis. Filter (biasanya perender) yang masih menunggu data tiba sebelum menyelesaikan perubahan status mengembalikan VFW_S_STATE_INTERMEDIATE jika metode GetState kedaluwarsa. Setelah data tiba di perender, GetState harus segera dikembalikan dengan S_OK.

Dalam status menengah dan selesai, status filter yang dilaporkan akan State_Paused. Hanya nilai yang dikembalikan yang menunjukkan apakah filter benar-benar siap atau tidak. Jika, saat perender menunggu data tiba, filter sumbernya mengirimkan pemberitahuan end-of-stream, maka itu juga harus menyelesaikan perubahan status.

Setelah semua filter benar-benar memiliki data yang menunggu untuk dirender, grafik filter akan menyelesaikan perubahan status jedanya.

Penanganan Penghentian

Perender video harus menangani peristiwa penghentian dengan benar dari pengguna. Ini menyiratkan menyembunyikan jendela dengan benar dan mengetahui apa yang harus dilakukan jika jendela kemudian dipaksa untuk ditampilkan. Selain itu, perender video harus memberi tahu Filter Graph Manager saat jendelanya dihancurkan (atau lebih akurat, ketika perender dihapus dari grafik filter) ke sumber daya gratis.

Jika pengguna menutup jendela video (misalnya dengan menekan ALT+F4), konvensinya adalah menyembunyikan jendela segera dan mengirim pemberitahuan EC_USERABORT ke Filter Graph Manager. Pemberitahuan ini diteruskan ke aplikasi, yang akan menghentikan pemutaran grafik. Setelah mengirim EC_USERABORT, perender video harus menolak sampel tambahan yang dikirimkan ke sana.

Bendera yang dihentikan grafik harus dibiarkan oleh perender hingga kemudian dihentikan, di mana bendera harus diatur ulang sehingga aplikasi dapat mengambil alih tindakan pengguna dan terus memutar grafik jika diinginkan. Jika ALT+F4 ditekan saat video berjalan, jendela akan disembunyikan dan semua sampel lebih lanjut yang dikirimkan akan ditolak. Jika jendela kemudian ditampilkan (mungkin melalui IVideoWindow::p ut_Visible), maka tidak ada pemberitahuan EC_REPAINT yang harus dihasilkan.

Perender video juga harus mengirim pemberitahuan EC_WINDOW_DESTROYED ke grafik filter saat perender video berakhir. Bahkan, yang terbaik adalah menangani ini ketika metode IBaseFilter::JoinFilterGraph perender dipanggil dengan parameter null (menunjukkan bahwa perender akan dihapus dari grafik filter), daripada menunggu sampai jendela video aktual dihancurkan. Mengirim pemberitahuan ini memungkinkan distributor plug-in di Filter Graph Manager meneruskan sumber daya yang bergantung pada fokus jendela ke filter lain, seperti perangkat audio.

Menangani Perubahan Format Dinamis

Dalam beberapa kasus, filter upstream perender mungkin mencoba mengubah format video saat video diputar. Paling sering dekompresor video yang memulai perubahan format dinamis.

Filter upstram yang mencoba mengubah format secara dinamis harus selalu memanggil metode IPin::QueryAccept pada pin input perender. Perender video memiliki kelonggaran tentang jenis perubahan format dinamis apa yang harus didukungnya. Minimal, itu harus memungkinkan filter upstram untuk mengubah palet. Ketika filter upstram mengubah jenis media, filter tersebut melampirkan jenis media ke sampel pertama yang dikirimkan dalam format baru. Jika perender menyimpan sampel dalam antrean untuk penyajian, perenderan tidak boleh mengubah format hingga merender sampel dengan perubahan jenis.

Perender video juga dapat meminta perubahan format dari dekoder. Misalnya, mungkin meminta dekoder untuk menyediakan format yang kompatibel dengan DirectDraw dengan biHeight negatif. Saat perender dijeda, perender harus memanggil QueryAccept pada pin upstram untuk melihat format mana yang dapat disediakan dekoder. Decoder mungkin tidak menghitung semua jenis yang dapat diterimanya, sehingga perender harus menawarkan beberapa jenis bahkan jika dekoder tidak mengiklankannya.

Jika dekoder dapat beralih ke format yang diminta, dekoder akan mengembalikan S_OK dari QueryAccept. Perender kemudian melampirkan jenis media baru ke sampel media berikutnya pada alokator hulu. Agar ini berfungsi, perender harus menyediakan alokator kustom yang mengimplementasikan metode privat untuk melampirkan jenis media ke sampel berikutnya. (Dalam metode privat ini, panggil IMediaSample::SetMediaType untuk mengatur jenis.)

Pin input perender harus mengembalikan alokator kustom perender dalam metode IMemInputPin::GetAllocator . Ambil alih IMemInputPin::NotifyAllocator sehingga gagal jika filter upstream tidak menggunakan alokator perender.

Dengan beberapa dekoder, mengatur biHeight ke angka positif pada jenis YUV menyebabkan dekoder menggambar gambar terbalik. (Ini salah, dan harus dianggap sebagai bug dalam dekoder.)

Setiap kali perubahan format terdeteksi oleh perender video, itu harus mengirim pemberitahuan EC_DISPLAY_CHANGED . Sebagian besar perender video memilih format selama koneksi sehingga format dapat digambar secara efisien melalui GDI. Jika pengguna mengubah mode tampilan saat ini tanpa memulai ulang komputer, perender mungkin menemukan dirinya dengan koneksi format gambar yang buruk dan harus mengirim pemberitahuan ini. Parameter pertama harus berupa pin yang perlu disambungkan kembali. Filter Graph Manager akan mengatur agar grafik filter dihentikan dan pin disambungkan kembali. Selama koneksi ulang berikutnya, perender dapat menerima format yang lebih tepat.

Setiap kali perender video mendeteksi perubahan palet dalam aliran, perender video harus mengirim pemberitahuan EC_PALETTE_CHANGED ke Filter Graph Manager. Perender video DirectShow mendeteksi apakah palet benar-benar telah berubah dalam format dinamis atau tidak. Perender video melakukan ini tidak hanya untuk memfilter jumlah pemberitahuan EC_PALETTE_CHANGED yang dikirim tetapi juga untuk mengurangi jumlah pembuatan palet, penginstalan, dan penghapusan yang diperlukan.

Akhirnya, perender video mungkin juga mendeteksi bahwa ukuran video telah berubah, dalam hal ini, video harus mengirim pemberitahuan EC_VIDEO_SIZE_CHANGED . Aplikasi mungkin menggunakan pemberitahuan ini untuk menegosiasikan ruang dalam dokumen gabungan. Dimensi video aktual tersedia melalui antarmuka kontrol IBasicVideo . Perender DirectShow mendeteksi apakah video benar-benar telah berubah ukuran atau tidak sebelum mengirim peristiwa ini.

Menangani Properti Persisten

Semua properti yang diatur melalui antarmuka IBasicVideo dan IVideoWindow dimaksudkan untuk persisten di seluruh koneksi. Oleh karena itu, memutuskan dan menyambungkan kembali perender tidak akan menunjukkan efek pada ukuran jendela, posisi, atau gaya. Namun, jika dimensi video berubah di antara koneksi, perender harus mengatur ulang persegi panjang sumber dan tujuan ke defaultnya. Posisi sumber dan tujuan diatur melalui antarmuka IBasicVideo .

IBasicVideo dan IVideoWindow menyediakan akses yang cukup ke properti untuk memungkinkan aplikasi menyimpan dan memulihkan semua data dalam antarmuka dalam format persisten. Ini akan berguna untuk aplikasi yang harus menyimpan konfigurasi dan properti grafik filter yang tepat selama sesi pengeditan dan memulihkannya nanti.

Menangani Pemberitahuan EC_REPAINT

Pemberitahuan EC_REPAINT dikirim hanya ketika perender dijeda atau dihentikan. Pemberitahuan ini memberi sinyal ke Filter Graph Manager bahwa perender membutuhkan data. Jika grafik filter dihentikan saat menerima salah satu pemberitahuan ini, grafik filter akan dijeda, menunggu semua filter menerima data (dengan memanggil GetState), lalu menghentikannya lagi. Saat dihentikan, perender video harus berpegang pada gambar sehingga pesan WM_PAINT berikutnya dapat ditangani.

Oleh karena itu, jika perender video menerima pesan WM_PAINT ketika dihentikan atau dijeda, dan tidak memiliki apa pun untuk melukis jendelanya, maka itu harus mengirim EC_REPAINT ke Filter Graph Manager. Jika pemberitahuan EC_REPAINT diterima saat dijeda, Maka Filter Graph Manager memanggil IMediaPosition::p ut_CurrentPosition dengan posisi saat ini (yaitu, mencari ke posisi saat ini). Hal ini menyebabkan filter sumber membersihkan grafik filter dan menyebabkan data baru dikirim melalui grafik filter.

Perender hanya boleh mengirim salah satu pemberitahuan ini pada satu waktu. Oleh karena itu, setelah perender mengirim pemberitahuan, perender harus memastikan tidak ada lagi yang dikirim sampai beberapa sampel dikirimkan. Cara konvensional untuk melakukan ini adalah dengan memiliki bendera untuk menandakan bahwa repaint dapat dikirim, yang dimatikan setelah pemberitahuan EC_REPAINT dikirim. Bendera ini harus diatur ulang setelah data dikirimkan atau ketika pin input dibersihkan, tetapi tidak jika akhir aliran diberi sinyal pada pin input.

Jika perender tidak memantau pemberitahuan EC_REPAINT , perender akan membanjiri Filter Graph Manager dengan permintaan EC_REPAINT (yang relatif mahal untuk diproses). Misalnya, jika perender tidak memiliki gambar untuk digambar, dan jendela lain diseret di jendela perender dalam operasi seret penuh, perender menerima beberapa pesan WM_PAINT . Hanya yang pertama dari ini yang harus menghasilkan pemberitahuan peristiwa EC_REPAINT dari perender ke Filter Graph Manager.

Perender harus mengirim pin inputnya sebagai parameter pertama ke pemberitahuan EC_REPAINT . Dengan melakukan ini, pin output yang terpasang akan dikueri untuk IMediaEventSink, dan jika didukung, pemberitahuan EC_REPAINT akan dikirim ke sana terlebih dahulu. Ini memungkinkan pin output untuk menangani repaint sebelum grafik filter harus disentuh. Ini tidak akan dilakukan jika grafik filter dihentikan, karena tidak ada buffer yang akan tersedia dari alokator perender yang dinonaktifkan.

Jika pin output tidak dapat menangani permintaan dan grafik filter berjalan, maka pemberitahuan EC_REPAINT diabaikan. Pin output harus mengembalikan S_OK dari IMediaEventSink::Notify untuk memberi sinyal bahwa ia berhasil memproses permintaan repaint. Pin output akan dipanggil pada utas pekerja Filter Graph Manager, yang menghindari perender memanggil pin output secara langsung, sehingga memihak masalah kebuntuan. Jika grafik filter dihentikan atau dijeda dan output tidak menangani permintaan, maka pemrosesan default dilakukan.

Menangani Pemberitahuan dalam Mode Full-Screen

Distributor plug-in IVideoWindow (PID) di grafik filter mengelola pemutaran layar penuh. Ini akan menukar perender video untuk perender layar penuh spesialis, meregangkan jendela perender ke layar penuh, atau meminta perender mengimplementasikan pemutaran layar penuh secara langsung. Untuk berinteraksi dalam protokol layar penuh, perender video harus mengirim pemberitahuan EC_ACTIVATE setiap kali jendelanya diaktifkan atau dinonaktifkan. Dengan kata lain, pemberitahuan EC_ACTIVATE harus dikirim untuk setiap pesan WM_ACTIVATEAPP yang diterima perender.

Saat perender digunakan dalam mode layar penuh, pemberitahuan ini mengelola peralihan ke dan keluar dari mode layar penuh tersebut. Penonaktifan jendela biasanya terjadi ketika pengguna menekan ALT+TAB untuk beralih ke jendela lain, yang digunakan perender layar penuh DirectShow sebagai iseng untuk kembali ke mode penyajian umum.

Saat pemberitahuan EC_ACTIVATE dikirim ke Filter Graph Manager saat beralih dari mode layar penuh, Filter Graph Manager mengirimkan pemberitahuan EC_FULLSCREEN_LOST ke aplikasi pengontrol. Aplikasi mungkin menggunakan pemberitahuan ini untuk memulihkan status tombol layar penuh, misalnya. Pemberitahuan EC_ACTIVATE digunakan secara internal oleh DirectShow untuk mengelola pengalihan layar penuh pada iseng dari perender video.

Ringkasan Pemberitahuan

Bagian ini mencantumkan pemberitahuan grafik filter yang dapat dikirim oleh perender.

Notifikasi kejadian Deskripsi
EC_ACTIVATE Dikirim oleh perender video dalam mode penyajian layar penuh untuk setiap pesan WM_ACTIVATEAPP diterima.
EC_COMPLETE Dikirim oleh perender setelah semua data dirender.
EC_DISPLAY_CHANGED Dikirim oleh perender video saat format tampilan berubah.
EC_PALETTE_CHANGED Dikirim setiap kali perender video mendeteksi perubahan palet di aliran.
EC_REPAINT Dikirim oleh perender video yang dihentikan atau dijeda saat pesan WM_PAINT diterima dan tidak ada data untuk ditampilkan. Hal ini menyebabkan Filter Graph Manager menghasilkan bingkai untuk dicat ke layar.
EC_USERABORT Dikirim oleh perender video untuk memberi sinyal penutupan yang diminta pengguna (misalnya, pengguna menutup jendela video).
EC_VIDEO_SIZE_CHANGED Dikirim oleh perender video setiap kali perubahan ukuran video asli terdeteksi.
EC_WINDOW_DESTROYED Dikirim oleh perender video saat filter dihapus atau dihancurkan sehingga sumber daya yang bergantung pada fokus jendela dapat diteruskan ke filter lain.

 

Menulis Perender Video