Google berkomitmen untuk mendorong terwujudnya keadilan ras bagi komunitas Kulit Hitam. Lihat caranya.

Tunneling Multimedia

Anda dapat mengimplementasikan tunneling multimedia dalam kerangka kerja Android 5.0 dan yang lebih tinggi. Meskipun tunneling multimedia tidak diperlukan untuk Android TV, ini memberikan pengalaman terbaik untuk konten definisi ultra-tinggi (4K).

Untuk Android 11 atau lebih tinggi, Anda dapat mengimplementasikan tunneling multimedia dengan konten audio dan video yang diumpankan langsung dari Tuner. Codec2 dan AudioTrack dapat menggunakan ID sinkronisasi HW dari Tuner, yang mungkin sesuai dengan referensi jam program (PCR) atau saluran jam waktu sistem (STC).

Latar Belakang

Kerangka kerja media Android menangani konten audio / video dalam empat cara:

  • Perangkat lunak murni (decoding lokal): Prosesor aplikasi (AP) secara lokal menerjemahkan audio ke modulasi kode-pulsa (PCM) tanpa akselerasi khusus. Selalu digunakan untuk Ogg Vorbis, dan digunakan untuk MP3 dan AAC bila tidak ada dukungan pembongkaran terkompresi.
  • Audio offload terkompresi mengirimkan data audio terkompresi langsung ke prosesor sinyal digital (DSP) dan mematikan AP sebanyak mungkin. Gunakan untuk memutar file musik dengan layar mati.
  • Passthrough audio terkompresi mengirimkan audio terkompresi (khususnya AC3 dan E-AC3) langsung melalui HDMI ke TV eksternal atau penerima audio, tanpa mendekodekannya di perangkat Android TV. Porsi video ditangani secara terpisah.
  • Tunneling multimedia mengirimkan data audio dan video terkompresi secara bersamaan. Saat streaming yang dienkode diterima oleh decoder video dan audio, itu tidak kembali ke framework. Idealnya, aliran tidak mengganggu AP.
  • Multimedia passthrough mengirimkan data audio dan video terkompresi bersama-sama dari Tuner ke video dan decoder audio tanpa melibatkan framework.
Diagram Alir Tunneling Multimedia
Gambar 1. Alur tunneling multimedia

Perbandingan pendekatan

Perangkat lunak murni Pembongkaran audio terkompresi Passthrough audio terkompresi Tunneling multimedia Passthrough multimedia
Lokasi decode AP DSP TV atau penerima audio / video (AVR) TV atau AVR TV atau AVR
Menangani audio Iya Iya Iya Iya tidak
Menangani video Iya tidak tidak Iya tidak

Untuk pengembang aplikasi

Buat instance SurfaceView , dapatkan ID sesi audio, lalu buat AudioTrack dan MediaCodec untuk memberikan pengaturan waktu dan konfigurasi yang diperlukan untuk pemutaran dan decoding bingkai video.

Untuk Android 11 atau lebih tinggi, sebagai alternatif untuk ID sesi audio, aplikasi bisa mendapatkan ID sinkronisasi HW dari Tuner dan memberikannya ke AudioTrack dan MediaCodec untuk sinkronisasi A / V.

Sinkronisasi A / V

Dalam mode kanalisasi multimedia, audio dan video disinkronkan pada jam utama.

  • Untuk Android 11 atau lebih tinggi, PCR atau STC dari Tuner mungkin menjadi jam utama untuk sinkronisasi A / V.
  • Untuk Android 10 atau lebih rendah, jam audio adalah jam utama yang digunakan untuk pemutaran A / V.

Jika instance MediaCodec video MediaCodec dan instance AudioTrack ditautkan ke instance HW_AV_SYNC di AudioTrack , jam implisit yang diturunkan dari HW_AV_SYNC membatasi kapan setiap frame video dan sampel audio disajikan, berdasarkan stempel waktu presentasi frame (PTS) audio atau video yang sebenarnya.

Alur panggilan API

Untuk Android 11 atau lebih tinggi, klien dapat menggunakan ID sinkronisasi HW dari Tuner.

  1. Buat instance SurfaceView .
    SurfaceView sv = new SurfaceView(mContext);
  2. Dapatkan ID sesi audio. ID unik ini digunakan dalam membuat trek audio ( AudioTrack ). Ini diteruskan ke codec media ( MediaCodec ) dan digunakan oleh kerangka media untuk menautkan jalur audio dan video.
    AudioManager am = mContext.getSystemService(AUDIO_SERVICE);
    int audioSessionId = am.generateAudioSessionId()
    // or, for Android 11 or higher
    int avSyncId = tuner.getAvSyncHwId();
  3. Buat AudioTrack dengan HW A / V sync AudioAttributes .

    Manajer kebijakan audio meminta lapisan abstraksi perangkat keras (HAL) untuk keluaran perangkat yang mendukung FLAG_HW_AV_SYNC , dan membuat trek audio yang langsung terhubung ke keluaran ini tanpa mixer perantara.

    AudioAttributes.Builder aab = new AudioAttributes.Builder();
    aab.setUsage(AudioAttributes.USAGE_MEDIA);
    aab.setContentType(AudioAttributes.CONTENT_TYPE_MOVIE);
    aab.setFlag(AudioAttributes.FLAG_HW_AV_SYNC);
    
    // or, for Android 11 or higher
    new tunerConfig = TunerConfiguration(0, avSyncId);
    aab.setTunerConfiguration(tunerConfig);
    
    AudioAttributes aa = aab.build();
    AudioTrack at = new AudioTrack(aa);
    
  4. Buat instance MediaCodec video dan konfigurasikan untuk pemutaran video MediaCodec .
    // retrieve codec with tunneled video playback feature
    MediaFormat mf = MediaFormat.createVideoFormat(“video/hevc”, 3840, 2160);
    mf.setFeatureEnabled(CodecCapabilities.FEATURE_TunneledPlayback, true);
    MediaCodecList mcl = new MediaCodecList(MediaCodecList.ALL_CODECS);
    String codecName = mcl.findDecoderForFormat(mf);
    if (codecName == null) {
      return FAILURE;
    }
    // create codec and configure it
    mf.setInteger(MediaFormat.KEY_AUDIO_SESSION_ID, audioSessionId);
    
    // or, for Android 11 or higher
    mf.setInteger(MediaFormat.KEY_HARDWARE_AV_SYNC_ID, avSyncId);
    
    MediaCodec mc = MediaCodec.createCodecByName(codecName);
    mc.configure(mf, sv.getSurfaceHolder().getSurface(), null, 0);
    
  5. Dekode bingkai video.
    mc.start();
     for (;;) {
       int ibi = mc.dequeueInputBuffer(timeoutUs);
       if (ibi >= 0) {
         ByteBuffer ib = mc.getInputBuffer(ibi);
         // fill input buffer (ib) with valid data
         ...
         mc.queueInputBuffer(ibi, ...);
       }
       // no need to dequeue explicitly output buffers. The codec
       // does this directly to the sideband layer.
     }
     mc.stop();
     mc.release();
     mc = null;

Catatan: Anda dapat mengganti urutan langkah 3 dan 4 dalam proses ini, seperti yang terlihat pada dua gambar di bawah ini.

Diagram trek audio yang dibuat sebelum konfigurasi codec
Gambar 2. Trek audio dibuat sebelum konfigurasi codec
Diagram trek audio yang dibuat setelah konfigurasi codec
Gambar 3. Trek audio dibuat setelah konfigurasi codec

Untuk produsen perangkat

OEM harus membuat komponen OpenMAX IL (OMX) dekoder video terpisah untuk mendukung pemutaran video terowongan. Komponen OMX ini harus mengiklankan bahwa ia mampu melakukan pemutaran terowongan (di media_codecs.xml ).

<Feature name=”tunneled-playback” required=”true” />

Komponen juga harus mendukung parameter diperpanjang OMX OMX.google.android.index.configureVideoTunnelMode yang menggunakan struktur ConfigureVideoTunnelModeParams .

struct ConfigureVideoTunnelModeParams {
    OMX_U32 nSize;              // IN
    OMX_VERSIONTYPE nVersion;   // IN
    OMX_U32 nPortIndex;         // IN
    OMX_BOOL bTunneled;         // IN/OUT
    OMX_U32 nAudioHwSync;       // IN
    OMX_PTR pSidebandWindow;    // OUT
};

Saat permintaan pembuatan MediaCodec dibuat, framework akan mengonfigurasi komponen OMX dalam mode bTunneled (dengan menyetel bTunneled ke OMX_TRUE ) dan meneruskan perangkat output audio terkait yang dibuat dengan flag AUDIO_HW_AV_SYNC ke komponen OMX (di nAudioHwSync ).

Jika komponen mendukung konfigurasi ini, komponen harus mengalokasikan pegangan sideband ke codec ini dan meneruskannya kembali melalui anggota pSidebandWindow . Pegangan sideband adalah tag ID untuk lapisan terowongan yang memungkinkan Hardware Composer (HW Composer) mengidentifikasinya. Jika komponen tidak mendukung konfigurasi ini, itu harus menyetel bTunneled ke OMX_FALSE .

Kerangka kerja mengambil lapisan terowongan (pegangan pita samping) yang dialokasikan oleh komponen OMX dan meneruskannya ke Komposer HW. compositionType lapisan ini disetel ke HWC_SIDEBAND . (Lihat hardware/libhardware/include/hardware/hwcomposer.h .)

Komposer HW bertanggung jawab untuk menerima buffer gambar baru dari aliran pada waktu yang tepat (misalnya, disinkronkan ke perangkat keluaran audio terkait), menggabungkannya dengan konten saat ini dari lapisan lain, dan menampilkan gambar yang dihasilkan. Ini terjadi terlepas dari siklus persiapan / set normal. Panggilan siapkan / set terjadi hanya saat lapisan lain berubah, atau saat properti lapisan pita samping (seperti posisi atau ukuran) berubah.

Konfigurasi

frameworks / av / services / audioflinger / AudioFlinger.cpp

HAL mengembalikan HW_AV_SYNC ID sebagai representasi desimal string karakter dari integer 64-bit. (Lihat frameworks/av/services/audioflinger/AudioFlinger.cpp .)

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);

frameworks / av / services / audioflinger / Threads.cpp

Framework audio harus menemukan aliran keluaran HAL yang sesuai dengan ID sesi ini, dan meminta HAL untuk hwAVSyncId menggunakan set_parameters .

mOutput->stream->common.set_parameters(&mOutput->stream->common,
AUDIO_PARAMETER_STREAM_HW_AV_SYNC=hwAVSyncId);

Konfigurasi decoder OMX

MediaCodec.java

Kerangka audio yang menemukan HAL output stream yang sesuai untuk ID sesi ini dan mengambil audio-hw-sync ID dengan query HAL untuk AUDIO_PARAMETER_STREAM_HW_AV_SYNC bendera menggunakan get_parameters .

// Retrieve HW AV sync audio output device from Audio Service
// in MediaCodec.configure()
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);
}

// ...

ID sinkronisasi HW ini diteruskan ke dekoder video terowongan OMX menggunakan parameter khusus OMX.google.android.index.configureVideoTunnelMode .

ACodec.cpp

Setelah Anda mendapatkan ID sinkronisasi perangkat keras audio, ACodec menggunakannya untuk mengonfigurasi dekoder video yang disalurkan sehingga dekoder video yang disalurkan mengetahui trek audio mana yang akan disinkronkan.

// Assume you're going to use tunneled video rendering.
// Configure OMX component in tunneled mode and grab sideband handle (sidebandHandle) from OMX
// component.

native_handle_t* sidebandHandle;

// Configure OMX component in tunneled mode
status_t err = mOMX->configureVideoTunnelMode(mNode, kPortIndexOutput,
        OMX_TRUE, audioHwSync, &sidebandHandle);

OMXNodeInstance.cpp

Komponen OMX dikonfigurasi dengan metode configureVideoTunnelMode atas.

// paraphrased

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;

ACodec.cpp

Setelah komponen OMX dikonfigurasi dalam mode terowongan, pegangan pita samping dikaitkan dengan permukaan rendering.

  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; }

Kemudian petunjuk resolusi maksimal, jika ada, dikirim ke komponen.

// Configure max adaptive playback resolution - as for any other video decoder
int32_t maxWidth = 0, maxHeight = 0;
if (msg->findInt32("max-width", &maxWidth) &&
    msg->findInt32("max-height", &maxHeight)) {
    err = mOMX->prepareForAdaptivePlayback(
              mNode, kPortIndexOutput, OMX_TRUE, maxWidth, maxHeight);
}

Jeda dukungan

Android 5.0 dan lebih rendah tidak menyertakan dukungan jeda. Anda hanya dapat menjeda pemutaran tunneled dengan A / V kelaparan, tetapi jika buffer internal untuk video besar (misalnya, ada 1 detik data di komponen OMX), jeda tersebut akan terlihat tidak responsif.

Di Android 5.1 dan lebih tinggi, AudioFlinger mendukung jeda dan melanjutkan untuk keluaran audio langsung (terowongan). Jika HAL mengimplementasikan pause / resume, track pause / resume diteruskan ke HAL.

Pause, flush, resume call sequence dilakukan dengan menjalankan panggilan HAL di thread pemutaran (sama seperti offload).

Dukungan Codec2

Untuk Android 11 atau lebih tinggi, Codec2 mendukung pemutaran terowongan.

CCodec.cpp

Untuk mendukung pemutaran terowongan, Codec2 bekerja mirip dengan OMX. Untuk mendukung ID sinkronisasi HW dari Tuner, Codec2 mencari ID sinkronisasi dari sumber di bawah ini.

sp<ANativeWindow> nativeWindow = static_cast<ANativeWindow *>(surface.get());
int32_t audioHwSync = 0;
if (!msg->findInt32("hw-av-sync-id", &audioHwSync)) {
       if (!msg->findInt32("audio-hw-sync", &audioHwSync)) {
       }
}
err = configureTunneledVideoPlayback(comp, audioHwSync, nativeWindow);

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 streaming keluaran audio dengan tanda FLAG_HW_AV_SYNC dan AUDIO_OUTPUT_FLAG_DIRECT dalam file audio_policy.conf -nya. Bendera ini digunakan untuk menyetel jam sistem dari jam audio.

OMX

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 ini harus menetapkan 0 buffer ( nBufferCountMin , nBufferCountActual ) pada port outputnya.

Komponen terowongan juga harus menerapkan ekstensi OMX.google.android.index.prepareForAdaptivePlayback setParameter .

Komponen terowongan harus menentukan kemampuannya dalam file media_codecs.xml dan mendeklarasikan fitur pemutaran terowongan. Ini juga harus menjelaskan batasan apa pun pada ukuran bingkai, keselarasan, atau kecepatan bit.


    <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 tunneled dan non-tunneled, maka fitur pemutaran tunneled harus dibiarkan tidak diperlukan. Baik dekoder terowongan maupun non-terowongan kemudian memiliki batasan kemampuan yang sama.

    <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 HW

Ketika ada lapisan terowongan (lapisan dengan HWC_SIDEBAND compositionType ) pada tampilan, sidebandStream lapisan adalah pegangan HWC_SIDEBAND dialokasikan oleh komponen video OMX.

Komposer HW menyinkronkan bingkai video yang didekodekan (dari komponen OMX terowongan) ke trek audio terkait (dengan audio-hw-sync ID). Ketika bingkai video baru menjadi saat ini, HW Composer menggabungkannya dengan konten saat ini dari semua lapisan yang diterima selama panggilan persiapan / setel terakhir, dan menampilkan gambar yang dihasilkan. Panggilan persiapkan / setel hanya terjadi saat lapisan lain berubah, atau saat properti lapisan sideband (seperti posisi atau ukuran) berubah.

Gambar 4 menunjukkan Komposer HW yang bekerja dengan sinkronisasi HW (atau kernel / driver), untuk menggabungkan bingkai video (7b) dengan komposisi terbaru (7a) untuk ditampilkan pada waktu yang tepat, berdasarkan audio (7c).

Diagram komposer perangkat keras yang menggabungkan bingkai video berdasarkan audio
Gambar 4. Komposer HW bekerja dengan sinkronisasi HW (atau kernel / driver)