Penerowongan multimedia memungkinkan data video terkompresi untuk disalurkan melalui dekoder video perangkat keras langsung ke layar, tanpa diproses oleh kode aplikasi atau kode kerangka kerja Android. Kode khusus perangkat di bawah tumpukan Android menentukan bingkai video mana yang akan dikirim ke layar dan waktu pengirimannya dengan membandingkan stempel waktu presentasi bingkai video dengan salah satu jenis jam internal berikut:
Untuk pemutaran video on-demand di Android 5 atau lebih tinggi, jam
AudioTrack
disinkronkan dengan stempel waktu presentasi audio yang diteruskan oleh aplikasiUntuk pemutaran siaran langsung di Android 11 atau lebih tinggi, jam referensi program (PCR) atau jam waktu sistem (STC) yang digerakkan oleh tuner
Latar belakang
Pemutaran video tradisional di Android memberi tahu aplikasi ketika bingkai video terkompresi telah didekodekan. Aplikasi kemudian melepaskan bingkai video yang didekodekan ke tampilan untuk dirender pada waktu jam sistem yang sama dengan bingkai audio yang sesuai, mengambil contoh AudioTimestamps
historis untuk menghitung waktu yang tepat.
Karena pemutaran video terowongan melewati kode aplikasi dan mengurangi jumlah proses yang bekerja pada video, pemutaran video terowongan dapat memberikan rendering video yang lebih efisien bergantung pada penerapan OEM. Ini juga dapat memberikan irama dan sinkronisasi video yang lebih akurat ke jam yang dipilih (PRC, STC, atau audio) dengan menghindari masalah pengaturan waktu yang disebabkan oleh potensi ketidaksesuaian antara waktu permintaan Android untuk merender video, dan waktu vsync perangkat keras yang sebenarnya. Namun, penerowongan juga dapat mengurangi dukungan untuk efek GPU seperti sudut buram atau membulat di jendela gambar-dalam-gambar (PiP), karena buffer melewati tumpukan grafis Android.
Diagram berikut menunjukkan bagaimana tunneling menyederhanakan proses pemutaran video.
Gambar 1. Perbandingan proses pemutaran video tradisional dan terowongan
Untuk pengembang aplikasi
Karena sebagian besar pengembang aplikasi berintegrasi dengan perpustakaan untuk implementasi pemutaran, dalam banyak kasus implementasi hanya memerlukan konfigurasi ulang perpustakaan tersebut untuk pemutaran terowongan. Untuk penerapan pemutar video terowongan tingkat rendah, gunakan petunjuk berikut.
Untuk pemutaran video on-demand di Android 5 atau lebih tinggi:
Buat contoh
SurfaceView
.Buat instans
audioSessionId
.Buat instans
AudioTrack
danMediaCodec
dengan instansaudioSessionId
yang dibuat pada langkah 2.Antrean data audio ke
AudioTrack
dengan stempel waktu presentasi untuk bingkai audio pertama dalam data audio.
Untuk pemutaran siaran langsung di Android 11 atau lebih tinggi:
Buat contoh
SurfaceView
.Dapatkan instance
avSyncHwId
dariTuner
.Buat instans
AudioTrack
danMediaCodec
dengan instansavSyncHwId
yang dibuat pada langkah 2.
Alur panggilan API ditampilkan dalam cuplikan kode berikut:
aab.setContentType(AudioAttributes.CONTENT_TYPE_MOVIE);
// configure for audio clock sync
aab.setFlag(AudioAttributes.FLAG_HW_AV_SYNC);
// or, for tuner clock sync (Android 11 or higher)
new tunerConfig = TunerConfiguration(0, avSyncId);
aab.setTunerConfiguration(tunerConfig);
if (codecName == null) {
return FAILURE;
}
// configure for audio clock sync
mf.setInteger(MediaFormat.KEY_AUDIO_SESSION_ID, audioSessionId);
// or, for tuner clock sync (Android 11 or higher)
mf.setInteger(MediaFormat.KEY_HARDWARE_AV_SYNC_ID, avSyncId);
Perilaku pemutaran video berdasarkan permintaan
Karena pemutaran video sesuai permintaan yang disalurkan terkait secara implisit dengan pemutaran AudioTrack
, perilaku pemutaran video yang disalurkan mungkin bergantung pada perilaku pemutaran audio.
Di sebagian besar perangkat, secara default, bingkai video tidak dirender hingga pemutaran audio dimulai. Namun, aplikasi mungkin perlu merender bingkai video sebelum memulai pemutaran audio, misalnya, untuk menunjukkan kepada pengguna posisi video saat ini saat mencari.
Untuk memberi sinyal bahwa bingkai video antrean pertama harus dirender segera setelah didekodekan, setel parameter
PARAMETER_KEY_TUNNEL_PEEK
ke1
. Ketika bingkai video terkompresi diurutkan ulang dalam antrean (seperti ketika ada bingkai B ), ini berarti bingkai video pertama yang ditampilkan harus selalu berupa bingkai-I.Jika Anda tidak ingin bingkai video antrean pertama dirender hingga pemutaran audio dimulai, setel parameter ini ke
0
.Jika parameter ini tidak disetel, OEM akan menentukan perilaku perangkat.
Ketika data audio tidak disediakan ke
AudioTrack
dan buffernya kosong (audio underrun), pemutaran video terhenti hingga lebih banyak data audio ditulis karena jam audio tidak lagi berjalan.Selama pemutaran, diskontinuitas yang tidak dapat diperbaiki oleh aplikasi mungkin muncul di stempel waktu presentasi audio. Jika hal ini terjadi, OEM akan memperbaiki kesenjangan negatif dengan menghentikan frame video saat ini, dan kesenjangan positif dengan menghapus frame video atau memasukkan frame audio senyap (tergantung pada penerapan OEM). Posisi bingkai
AudioTimestamp
tidak bertambah untuk bingkai audio senyap yang disisipkan.
Untuk produsen perangkat
Konfigurasi
OEM harus membuat dekoder video terpisah untuk mendukung pemutaran video terowongan. Dekoder ini harus menyatakan bahwa ia mampu melakukan pemutaran terowongan di file media_codecs.xml
:
<Feature name="tunneled-playback" required="true"/>
Ketika instans MediaCodec
yang disalurkan dikonfigurasi dengan ID sesi audio, ia menanyakan AudioFlinger
untuk ID HW_AV_SYNC
ini:
if (entry.getKey().equals(MediaFormat.KEY_AUDIO_SESSION_ID)) {
int sessionId = 0;
try {
sessionId = (Integer)entry.getValue();
}
catch (Exception e) {
throw new IllegalArgumentException("Wrong Session ID Parameter!");
}
keys[i] = "audio-hw-sync";
values[i] = AudioSystem.getAudioHwSyncForSession(sessionId);
}
Selama kueri ini, AudioFlinger
mengambil ID HW_AV_SYNC
dari perangkat audio utama dan mengaitkannya secara internal dengan ID sesi audio:
audio_hw_device_t *dev = mPrimaryHardwareDev->hwDevice();
char *reply = dev->get_parameters(dev, AUDIO_PARAMETER_HW_AV_SYNC);
AudioParameter param = AudioParameter(String8(reply));
int hwAVSyncId;
param.getInt(String8(AUDIO_PARAMETER_HW_AV_SYNC), hwAVSyncId);
Jika instans AudioTrack
telah dibuat, ID HW_AV_SYNC
diteruskan ke aliran output dengan ID sesi audio yang sama. Jika belum dibuat, ID HW_AV_SYNC
diteruskan ke aliran keluaran selama pembuatan AudioTrack
. Hal ini dilakukan oleh thread pemutaran :
mOutput->stream->common.set_parameters(&mOutput->stream->common, AUDIO_PARAMETER_STREAM_HW_AV_SYNC, hwAVSyncId);
ID HW_AV_SYNC
, baik terkait dengan aliran output audio atau konfigurasi Tuner
, diteruskan ke komponen OMX atau Codec2 sehingga kode OEM dapat mengaitkan codec dengan aliran output audio atau aliran tuner yang sesuai.
Selama konfigurasi komponen, komponen OMX atau Codec2 harus mengembalikan pegangan sideband yang dapat digunakan untuk mengaitkan codec dengan lapisan Hardware Composer (HWC). Saat aplikasi mengaitkan suatu permukaan dengan MediaCodec
, pengendali sideband ini diteruskan ke HWC melalui SurfaceFlinger
, yang mengonfigurasi lapisan tersebut sebagai lapisan sideband .
err = native_window_set_sideband_stream(nativeWindow.get(), sidebandHandle);
if (err != OK) {
ALOGE("native_window_set_sideband_stream(%p) failed! (err %d).", sidebandHandle, err);
return err;
}
HWC bertanggung jawab untuk menerima buffer gambar baru dari output codec pada waktu yang tepat, baik disinkronkan ke aliran output audio terkait atau jam referensi program tuner, menggabungkan buffer dengan konten lapisan lain saat ini, dan menampilkan gambar yang dihasilkan. Hal ini terjadi secara independen dari siklus persiapan dan pengaturan normal. Panggilan persiapan dan pengaturan hanya terjadi ketika lapisan lain berubah, atau ketika properti lapisan pita samping (seperti posisi atau ukuran) berubah.
Ya ampun
Komponen dekoder yang disalurkan harus mendukung hal berikut:
Menyetel parameter tambahan
OMX.google.android.index.configureVideoTunnelMode
, yang menggunakan strukturConfigureVideoTunnelModeParams
untuk meneruskan IDHW_AV_SYNC
yang terkait dengan perangkat output audio.Mengonfigurasi parameter
OMX_IndexConfigAndroidTunnelPeek
yang memberi tahu codec untuk merender atau tidak merender bingkai video pertama yang didekodekan, terlepas dari apakah pemutaran audio telah dimulai.Mengirim peristiwa
OMX_EventOnFirstTunnelFrameReady
ketika frame video terowongan pertama telah didekodekan dan siap untuk dirender.
Implementasi AOSP mengonfigurasi mode terowongan di ACodec
melalui OMXNodeInstance
seperti yang ditunjukkan dalam cuplikan kode berikut:
OMX_INDEXTYPE index;
OMX_STRING name = const_cast<OMX_STRING>(
"OMX.google.android.index.configureVideoTunnelMode");
OMX_ERRORTYPE err = OMX_GetExtensionIndex(mHandle, name, &index);
ConfigureVideoTunnelModeParams tunnelParams;
InitOMXParams(&tunnelParams);
tunnelParams.nPortIndex = portIndex;
tunnelParams.bTunneled = tunneled;
tunnelParams.nAudioHwSync = audioHwSync;
err = OMX_SetParameter(mHandle, index, &tunnelParams);
err = OMX_GetParameter(mHandle, index, &tunnelParams);
sidebandHandle = (native_handle_t*)tunnelParams.pSidebandWindow;
Jika komponen mendukung konfigurasi ini, komponen tersebut harus mengalokasikan pegangan sideband ke codec ini dan meneruskannya kembali melalui anggota pSidebandWindow
sehingga HWC dapat mengidentifikasi codec terkait. Jika komponen tidak mendukung konfigurasi ini, komponen harus disetel bTunneled
ke OMX_FALSE
.
Kodek2
Di Android 11 atau lebih tinggi, Codec2
mendukung pemutaran terowongan. Komponen decoder harus mendukung hal berikut:
Mengonfigurasi
C2PortTunneledModeTuning
, yang mengonfigurasi mode terowongan dan meneruskanHW_AV_SYNC
yang diambil dari perangkat output audio atau konfigurasi tuner.Meminta
C2_PARAMKEY_OUTPUT_TUNNEL_HANDLE
, untuk mengalokasikan dan mengambil pegangan sideband untuk HWC.Menangani
C2_PARAMKEY_TUNNEL_HOLD_RENDER
saat dipasang keC2Work
, yang menginstruksikan codec untuk mendekode dan memberi sinyal penyelesaian pekerjaan, namun tidak merender buffer output hingga 1) codec kemudian diinstruksikan untuk merendernya atau 2) pemutaran audio dimulai.Menangani
C2_PARAMKEY_TUNNEL_START_RENDER
, yang memerintahkan codec untuk segera merender frame yang ditandai denganC2_PARAMKEY_TUNNEL_HOLD_RENDER
, meskipun pemutaran audio belum dimulai.Biarkan
debug.stagefright.ccodec_delayed_params
tidak dikonfigurasi (disarankan). Jika Anda mengonfigurasinya, setel kefalse
.
Implementasi AOSP mengonfigurasi mode terowongan di CCodec
melalui C2PortTunnelModeTuning
, seperti yang ditunjukkan dalam cuplikan kode berikut:
if (msg->findInt32("audio-hw-sync", &tunneledPlayback->m.syncId[0])) {
tunneledPlayback->m.syncType =
C2PortTunneledModeTuning::Struct::sync_type_t::AUDIO_HW_SYNC;
} else if (msg->findInt32("hw-av-sync-id", &tunneledPlayback->m.syncId[0])) {
tunneledPlayback->m.syncType =
C2PortTunneledModeTuning::Struct::sync_type_t::HW_AV_SYNC;
} else {
tunneledPlayback->m.syncType =
C2PortTunneledModeTuning::Struct::sync_type_t::REALTIME;
tunneledPlayback->setFlexCount(0);
}
c2_status_t c2err = comp->config({ tunneledPlayback.get() }, C2_MAY_BLOCK,
failures);
std::vector<std::unique_ptr<C2Param>> params;
c2err = comp->query({}, {C2PortTunnelHandleTuning::output::PARAM_TYPE},
C2_DONT_BLOCK, ¶ms);
if (c2err == C2_OK && params.size() == 1u) {
C2PortTunnelHandleTuning::output *videoTunnelSideband =
C2PortTunnelHandleTuning::output::From(params[0].get());
return OK;
}
Jika komponen mendukung konfigurasi ini, komponen tersebut harus mengalokasikan pegangan sideband ke codec ini dan meneruskannya kembali melalui C2PortTunnelHandlingTuning
sehingga HWC dapat mengidentifikasi codec terkait.
Audio HAL
Untuk pemutaran video berdasarkan permintaan, Audio HAL menerima stempel waktu presentasi audio sejalan dengan data audio dalam format big-endian di dalam header yang terdapat di awal setiap blok data audio yang ditulis aplikasi:
struct TunnelModeSyncHeader {
// The 32-bit data to identify the sync header (0x55550002)
int32 syncWord;
// The size of the audio data following the sync header before the next sync
// header might be found.
int32 sizeInBytes;
// The presentation timestamp of the first audio sample following the sync
// header.
int64 presentationTimestamp;
// The number of bytes to skip after the beginning of the sync header to find the
// first audio sample (20 bytes for compressed audio, or larger for PCM, aligned
// to the channel count and sample size).
int32 offset;
}
Agar HWC merender bingkai video secara sinkron dengan bingkai audio yang sesuai, Audio HAL harus mengurai header sinkronisasi dan menggunakan stempel waktu presentasi untuk menyinkronkan ulang jam pemutaran dengan rendering audio. Untuk menyinkronkan ulang saat audio terkompresi diputar, Audio HAL mungkin perlu menguraikan metadata di dalam data audio terkompresi untuk menentukan durasi pemutarannya.
Jeda dukungan
Android 5 atau lebih rendah tidak menyertakan dukungan jeda. Anda dapat menjeda pemutaran terowongan hanya dengan kelaparan A/V, namun jika buffer internal untuk video besar (misalnya, ada satu detik data dalam komponen OMX), hal ini membuat jeda terlihat tidak responsif.
Di Android 5.1 atau lebih tinggi, AudioFlinger
mendukung jeda dan melanjutkan untuk output audio langsung (terowongan). Jika HAL menerapkan jeda dan lanjutkan, jalur jeda dan lanjutkan diteruskan ke HAL.
Urutan panggilan jeda, siram, lanjutkan dipatuhi dengan mengeksekusi panggilan HAL di thread pemutaran (sama seperti offload).
Saran implementasi
Audio HAL
Untuk Android 11, ID sinkronisasi HW dari PCR atau STC dapat digunakan untuk sinkronisasi A/V, sehingga streaming video saja didukung.
Untuk Android 10 atau lebih rendah, perangkat yang mendukung pemutaran video terowongan harus memiliki setidaknya satu profil aliran output audio dengan flag FLAG_HW_AV_SYNC
dan AUDIO_OUTPUT_FLAG_DIRECT
di file audio_policy.conf
nya. Bendera ini digunakan untuk mengatur jam sistem dari jam audio.
Ya ampun
Produsen perangkat harus memiliki komponen OMX terpisah untuk pemutaran video terowongan (produsen dapat memiliki komponen OMX tambahan untuk jenis pemutaran audio dan video lainnya, seperti pemutaran aman). Komponen terowongan harus:
Tentukan 0 buffer (
nBufferCountMin
,nBufferCountActual
) pada port outputnya.Terapkan ekstensi
OMX.google.android.index.prepareForAdaptivePlayback setParameter
.Tentukan kemampuannya dalam file
media_codecs.xml
dan nyatakan fitur pemutaran terowongan. Ini juga harus memperjelas segala batasan pada ukuran frame, penyelarasan, atau bitrate. Contohnya ditunjukkan di bawah ini:<MediaCodec name="OMX.OEM_NAME.VIDEO.DECODER.AVC.tunneled" type="video/avc" > <Feature name="adaptive-playback" /> <Feature name="tunneled-playback" required=”true” /> <Limit name="size" min="32x32" max="3840x2160" /> <Limit name="alignment" value="2x2" /> <Limit name="bitrate" range="1-20000000" /> ... </MediaCodec>
Jika komponen OMX yang sama digunakan untuk mendukung decoding yang disalurkan dan tidak disalurkan, maka fitur pemutaran yang disalurkan harus dibiarkan sebagai tidak diperlukan. Baik decoder tunneled maupun nontunneled memiliki batasan kemampuan yang sama. Contohnya ditunjukkan di bawah ini:
<MediaCodec name="OMX._OEM\_NAME_.VIDEO.DECODER.AVC" type="video/avc" >
<Feature name="adaptive-playback" />
<Feature name="tunneled-playback" />
<Limit name="size" min="32x32" max="3840x2160" />
<Limit name="alignment" value="2x2" />
<Limit name="bitrate" range="1-20000000" />
...
</MediaCodec>
Komposer Perangkat Keras (HWC)
Ketika ada lapisan terowongan (lapisan dengan HWC_SIDEBAND
compositionType
) pada tampilan, sidebandStream
lapisan tersebut adalah pengendali sideband yang dialokasikan oleh komponen video OMX.
HWC menyinkronkan bingkai video yang didekodekan (dari komponen OMX yang disalurkan) ke trek audio terkait (dengan ID audio-hw-sync
). Ketika frame video baru menjadi terkini, HWC menggabungkannya dengan konten terkini dari semua lapisan yang diterima selama panggilan persiapan atau pengaturan terakhir, dan menampilkan gambar yang dihasilkan. Panggilan persiapan atau pengaturan hanya terjadi ketika lapisan lain berubah, atau ketika properti lapisan pita samping (seperti posisi atau ukuran) berubah.
Gambar berikut menunjukkan HWC yang bekerja dengan sinkronisasi perangkat keras (atau kernel atau driver), untuk menggabungkan frame video (7b) dengan komposisi terbaru (7a) untuk ditampilkan pada waktu yang tepat, berdasarkan audio (7c).
Gambar 2. Sinkronisasi perangkat keras (atau kernel atau driver) HWC