Menulis Sumber Media Kustom

Topik ini menjelaskan cara mengimplementasikan sumber media kustom di Microsoft Media Foundation. Hal ini berisi bagian-bagian berikut:

Membuat Deskriptor Presentasi

Metode IMFMediaSource::CreatePresentationDescriptor mengembalikan salinan deskriptor presentasi sumber. Untuk membuat deskriptor presentasi, Anda harus mengetahui jumlah aliran dalam konten sumber, dan format yang mungkin dari setiap aliran. Untuk setiap aliran, buat deskriptor aliran sebagai berikut:

  1. Membuat array jenis media. Setiap jenis media dalam array mewakili kemungkinan format untuk aliran. Untuk informasi selengkapnya tentang membuat jenis media, lihat Jenis Media.
  2. Panggil MFCreateStreamDescriptor untuk membuat deskriptor aliran. Meneruskan array jenis media. Fungsi mengembalikan penunjuk IMFStreamDescriptor .
  3. Panggil IMFStreamDescriptor::GetMediaTypeHandler untuk mendapatkan penangan jenis media deskriptor aliran.
  4. Panggil IMFMediaTypeHandler::SetCurrentMediaType untuk mengatur format aliran default. Gunakan salah satu jenis media yang Anda buat di langkah 1. Umumnya, Anda harus menggunakan format dengan kualitas tertinggi.
  5. Secara opsional, atur atribut pada deskriptor aliran. Untuk daftar atribut yang berlaku untuk deskriptor streaming, lihat Atribut Deskriptor Aliran.

Sekarang buat deskriptor presentasi:

  1. Panggil MFCreatePresentationDescriptor dan berikan array deskriptor aliran. Fungsi mengembalikan penunjuk IMFPresentationDescriptor .
  2. Pilih pilihan aliran default dengan memanggil IMFPresentationDescriptor::SelectStream untuk memilih satu atau beberapa aliran. Setidaknya satu aliran harus dipilih dalam konfigurasi default.
  3. Secara opsional, atur atribut pada deskriptor presentasi. Untuk daftar atribut yang berlaku untuk deskriptor streaming, lihat Atribut Deskriptor Presentasi.

Anda harus membuat deskriptor presentasi sekali, baik saat startup atau setelah sumber mengurai cukup data sumber untuk menentukan konten. Metode CreatePresentationDescriptor harus mengembalikan salinan deskriptor presentasi. Untuk membuat salinan, panggil IMFPresentationDescriptor::Clone. Mengembalikan salinan mencegah klien mengubah status deskriptor presentasi asli, seperti atribut atau pemilihan aliran. Namun, ketahuilah bahwa Kloning membuat salinan yang dangkal, sehingga klien berpotensi memodifikasi deskriptor aliran yang mendasar.

Memulai Sumber Media

Metode IMFMediaSource::Start memulai sumber media atau mencari posisi baru. Panggilan ke Mulai menyebabkan pencarian ketika status sebelumnya dijeda atau berjalan, dan waktu mulai baru ditentukan. Jika tidak, metode Mulai menyebabkan permulaan. Saat operasi Mulai selesai, kirim peristiwa berikut.

  1. Kirim peristiwa MENewStream untuk setiap aliran baru—yaitu, setiap aliran yang sebelumnya tidak dipilih dan sekarang dipilih. Data peristiwa adalah penunjuk ke aliran.
  2. Kirim peristiwa MEUpdatedStream untuk setiap aliran yang sebelumnya dipilih dan masih dipilih. Data peristiwa adalah penunjuk ke aliran. (Jangan kirim peristiwa untuk aliran yang tidak dipilih.)
  3. Jika sumber mencari, kirim peristiwa MESourceSeeked . Jika tidak, kirim peristiwa MESourceStarted . Data peristiwa adalah waktu mulai yang ditentukan dalam metode Mulai . Untuk peristiwa MESourceStarted, jika waktu mulai VT_EMPTY, atur atribut MF_EVENT_SOURCE_ACTUAL_START pada peristiwa. Nilai atribut adalah waktu mulai aktual.
  4. Untuk setiap aliran, jika sumber mencari, kirim peristiwa MEStreamSeeked . Jika tidak, kirim peristiwa MEStreamStarted . Data peristiwa adalah waktu mulai. (Sumber media dapat mengantre peristiwa pada aliran dengan memanggil metode IMFMediaEventGenerator::QueueEvent aliran.)

Saat aliran tidak dipilih, matikan aliran. Aliran tidak boleh mengantre peristiwa lagi pada saat itu.

Format waktu untuk metode Mulai diberikan dalam parameter pguidTimeFormat . Format waktu standar, yang ditunjukkan oleh GUID_NULL, adalah 100 unit nanodetik. Sumber media harus mendukung format waktu ini.

Mencari

Saat mencari, posisi mulai yang diminta mungkin tidak jatuh pada batas sampel yang tepat. Selain itu, untuk konten terkompresi, posisi mulai mungkin berada di antara bingkai kunci. Aliran harus mengirimkan sampel dari titik awal yang diperlukan untuk menghasilkan sampel yang tidak dikompresi pada posisi mulai yang diminta. Untuk video, itu berarti dimulai dari bingkai kunci sebelumnya. Alur bertanggung jawab untuk menghilangkan bingkai tambahan dari dekoder, sehingga pemutaran dimulai pada waktu yang diminta.

Waktu mulai yang diberikan dalam peristiwa sumber (MESourceStarted, MESourceSeeked, MEStreamStarted, dan MEStreamSeeked) adalah waktu mulai yang diminta (nilai yang diberikan dalam metode Mulai ), terlepas dari posisi mulai aktual.

Misalnya, misalkan beberapa bingkai pertama aliran video memiliki karakteristik berikut:

Sampel 1 2 3 4
Waktu 33 msec 66 msec 100 msec 133 msec
Bingkai kunci? Ya Tidak Tidak Ya

 

Jika metode Mulai dipanggil dengan nilai 100 milidetik, sumber perlu mengeluarkan video mulai dari bingkai 1, bingkai kunci pertama sebelum waktu ini. Peristiwa mulai masih akan menunjukkan 100 milidetik dalam data peristiwa.

Menjeda Sumber Media

Metode IMFMediaSource::P ause menjeda sumber media.

Saat sumber dijeda, aliran dapat membuat sampel baru dan menyimpannya pada antrean, tetapi aliran tidak mengirimkan sampel. Berikut adalah beberapa pengecualian untuk aturan ini:

  • Sumber langsung harus menghilangkan data saat dijeda.
  • Jika sumber mendapatkan data dari jaringan, sumber mungkin menjeda server.

Jika klien memanggil IMFMediaStream::RequestSample saat sumber dijeda, permintaan juga diantrekan hingga sumber dimulai lagi. Permintaan tidak boleh dihilangkan.

Jeda hanya diperbolehkan dari status dimulai. Jika tidak, Jeda harus mengembalikan MF_E_INVALID_STATE_TRANSITION.

Menghasilkan Data Sumber

Media Foundation menggunakan model penarikan, yang berarti bahwa aliran menghasilkan dan mengirimkan sampel sebagai respons terhadap permintaan dari alur. Aliran dapat mengirimkan sampel saat sumber media berjalan dan aliran dipilih. Aliran hanya mengirimkan data saat klien meminta sampel baru.

Permintaan Sampel

Klien meminta sampel baru dengan memanggil IMFMediaStream::RequestSample. Berikut adalah urutan operasi:

  1. Klien memanggil IMFMediaStream::RequestSample. Argumen adalah penunjuk ke objek token opsional yang digunakan klien untuk melacak permintaan. Klien mengimplementasikan token. Token harus mengekspos antarmuka IUnknown . Klien juga dapat meneruskan pointer NULL alih-alih token.

  2. Jika klien memberikan token, aliran media memanggil AddRef pada token dan menempatkan token dalam antrean pertama masuk dan keluar. Metode mengembalikan, dan langkah-langkah yang tersisa terjadi secara asinkron.

  3. Saat lebih banyak data tersedia, aliran media membuat sampel baru. (Langkah ini dijelaskan secara lebih rinci di bagian berikutnya.)

  4. Aliran media menarik token pertama dari antrean.

  5. Jika token bukan NULL, aliran media mengatur atribut MFSampleExtension_Token pada sampel media. Nilai atribut adalah penunjuk ke token.

  6. Aliran media mengirimkan peristiwa MEMediaSample . Data peristiwa adalah penunjuk ke antarmuka IMFSample sampel.

  7. Jika klien memberikan token, aliran media memanggil Rilis pada objek token.

Jika aliran media tidak dapat memenuhi permintaan RequestSample klien, aliran media menarik token dari antrean dan memanggil Rilis pada token, tetapi tidak mengirim peristiwa MEMediaSample .

Klien dapat menggunakan token untuk melacak status permintaan. Ketika klien menerima peristiwa MEMediaSample , klien bisa mendapatkan token dari sampel dan mencocokkannya dengan permintaan asli. Klien juga dapat menggunakan token untuk mendeteksi apakah sumber media menghilangkan permintaan. Jika jumlah referensi token jatuh ke nol dan aliran media tidak mengirim peristiwa MEMediaSample, itu berarti bahwa permintaan dihilangkan.

Langkah-langkah yang tercantum di sini mengasumsikan bahwa metode RequestSample diimplementasikan sebagai operasi asinkron. Jika metode ini sinkron, Anda tidak perlu meletakkan token permintaan pada antrean. Namun, jika menghasilkan data membutuhkan waktu yang signifikan, pendekatan asinkron direkomendasikan—misalnya, jika sumber membaca data dari aliran byte.

Aliran bertanggung jawab untuk menyangga data apa pun yang terakumulasi antara panggilan ke RequestSample.

Saat aliran media mencapai akhir aliran, aliran akan mengirimkan peristiwa MEEndOfStream setelah sampel terakhir. Setelah setiap aliran berakhir, sumber media mengirimkan peristiwa MEEndOfPresentation . Setelah aliran media mengirim peristiwa MEEndOfStream, metode RequestSample mengembalikan MF_E_END_OF_STREAM hingga sumber dimulai ulang.

Mengalokasikan Sampel

Ketika aliran siap untuk mengisi permintaan sampel yang tertunda, aliran akan membuat sampel baru dan menambahkan satu atau beberapa buffer media ke sampel. Untuk informasi selengkapnya tentang membuat buffer media, lihat Buffer Media.

Aliran harus mengatur stempel waktu dan durasi, jika diketahui. Stempel waktu relatif terhadap sumbernya. Dalam kebanyakan kasus, awal konten sesuai dengan stempel waktu nol. Misalnya, jika sumber membaca dari file media, awal file akan memiliki stempel waktu nol.

Stempel waktu pada sampel tidak selalu sama dengan waktu presentasi. Sesi Media diterjemahkan dari waktu sumber ke waktu presentasi. Untuk data terkompresi, aliran harus menghasilkan data mulai dari bingkai kunci terdekat sebelum waktu mulai. Ini memungkinkan dekoder untuk mengirimkan bingkai yang muncul pada waktu mulai yang diminta. (Jika tidak, dekoder perlu menunggu sampai bingkai kunci berikut.)

Jika laju pemutaran lebih cepat atau lebih lambat dari 1,0, alur akan menyesuaikan laju jam presentasi. Sumber tidak menyesuaikan stempel waktu pada sampel.

Sumber dapat mengatur informasi tambahan pada sampel dengan mengatur atribut. Untuk daftar atribut sampel, lihat Atribut Sampel.

Celah dalam Aliran

Jika aliran berisi celah dengan panjang yang signifikan, disarankan agar aliran mengirim peristiwa MEStreamTick . Kejadian ini memberi tahu klien bahwa sampel hilang. Data peristiwa adalah stempel waktu sampel yang hilang, dalam 100 unit nanodetik (VT_I8). Kejadian ini dapat menyimpan komponen hilir dari menunggu sampel yang tidak akan tiba. Aliran dapat mengirim peristiwa MEStreamTick sebanyak yang diperlukan untuk menjangkau kesenjangan dalam aliran.

Mematikan Sumber Media

Ketika klien selesai menggunakan sumber media, klien memanggil IMFMediaSource::Shutdown. Di dalam metode ini, sumber media harus merusak jumlah referensi melingkar. Biasanya, akan ada referensi melingkar antara sumber media dan aliran media.

Jika Anda menggunakan antrean peristiwa untuk mengimplementasikan IMFMediaEventGenerator, panggil IMFMediaEventQueue::Shutdown pada antrean peristiwa. Metode ini mematikan antrean peristiwa dan memberi sinyal kepada pemanggil apa pun yang saat ini menunggu peristiwa.

Setelah dimatikan, semua metode pada MF_E_SHUTDOWN pengembalian sumber, dengan pengecualian metode IUnknown .

Sumber Langsung

Mulai windows 7, Media Foundation secara otomatis mendukung perangkat pengambilan audio dan video. Untuk video, perangkat harus menyediakan minidriver streaming kernel (KS) dalam kategori pengambilan video. Media Foundation menggunakan jalur PnP untuk menghitung perangkat. Untuk audio, Media Foundation menggunakan WINDOWS Multimedia Device (MMDevice) API untuk menghitung perangkat titik akhir audio. Jika perangkat memenuhi kriteria ini, tidak perlu menerapkan sumber media kustom.

Namun, Anda mungkin ingin menerapkan sumber media kustom untuk beberapa jenis perangkat lain atau sumber data langsung lainnya. Hanya ada beberapa perbedaan antara sumber langsung dan sumber media lainnya:

  • Dalam metode IMFMediaSource::GetCharacteristics , kembalikan bendera MFMEDIASOURCE_IS_LIVE .
  • Sampel pertama harus memiliki stempel waktu nol.
  • Peristiwa dan status streaming ditangani sama dengan sumber media, dengan pengecualian status dijeda.
  • Saat dijeda, jangan mengantre sampel. Hilangkan data apa pun yang dihasilkan saat dijeda.
  • Sumber langsung biasanya tidak mendukung pencarian, putar terbalik, atau kontrol laju.

Sumber Media

Tutorial: Menulis Sumber Media Kustom