WebRTC di Android: cara mengaktifkan penyandian perangkat keras pada banyak perangkat

Untuk panggilan video di Badoo, kami menggunakan standar WebRTC dan codec H.264. Jika Anda meyakini dokumentasinya, codec ini akan berfungsi tanpa masalah pada perangkat Android apa pun sejak Android 5.0. Namun dalam praktiknya, semuanya ternyata tidak begitu. Pada artikel ini, saya akan berbicara tentang fitur menerapkan pengkodean perangkat keras untuk codec H.264 di WebRTC dan bagaimana membuatnya bekerja pada lebih banyak perangkat.



Kenapa H.264?


Ketika terhubung melalui WebRTC, semua perangkat yang berpartisipasi dalam sesi mengirimkan berbagai parameter komunikasi, termasuk video dan audio codec. Jika perangkat mendukung banyak codec (misalnya, VP8 dan H.264), codec prioritas untuk platform terdaftar terlebih dahulu. Data ini digunakan selama tahap rekonsiliasi di WebRTC, setelah itu hanya codec yang didukung oleh semua perangkat yang tersisa. Contoh data tersebut dengan dekripsi dapat dilihat dalam dokumen ini .

Dalam hal panggilan video, jika salah satu perangkat tidak mendukung codec H.264, kedua perangkat dapat beralih, misalnya, ke codec VP8, yang tidak bergantung pada implementasi perangkat keras pada perangkat. Tetapi aplikasi kami tersedia di berbagai gadget, termasuk smartphone dari generasi sebelumnya. Oleh karena itu, untuk komunikasi video, kami ingin menggunakan penyandian perangkat keras kapan pun memungkinkan: itu mengurangi beban prosesor dan tidak memakan baterai terlalu banyak, yang sangat penting untuk gadget yang sudah ketinggalan zaman. Dukungan encoding perangkat keras H.264 diimplementasikan pada sejumlah besar perangkat, tidak seperti VP8 yang sama .

Dukungan H.264 di Android


Jika Anda yakin deskripsi dukungan untuk format multimedia , pengodean ulang Profil Dasar H.264 akan berfungsi pada semua perangkat Android, dan pengodean - dimulai dengan Android 3.0. Di Badoo, kami mendukung perangkat yang dimulai dengan Android 5.0, jadi kami seharusnya tidak memiliki masalah. Tapi itu tidak begitu sederhana: bahkan di gadget dengan versi kelima, kami menemukan sejumlah besar fitur.

Dengan apa itu bisa terkoneksi?

Seperti yang Anda ketahui, saat mengembangkan perangkat baru di Android, produsen mana pun harus lulus Suite Tes Kompatibilitas. Ini berjalan pada PC yang terhubung ke perangkat, dan hasilnya harus dikirim ke Google untuk mengkonfirmasi bahwa perangkat tersebut memenuhi persyaratan OS Android dari versi yang ditentukan. Baru setelah itu gadget bisa dirilis ke pasaran.

Kami tertarik pada tes multimedia dalam rangkaian tes ini, dan lebih khusus lagi, video encoding dan decoding. Saya memutuskan untuk memikirkan tes EncodeDecodeTest , MediaCodecTest , DecoderTest dan EncoderTest , karena semuanya ada di semua versi Android sejak 4.3. Grafik jumlah baris kode dalam tes ini terlihat seperti ini:



Sebelum versi 4.3, sebagian besar tes ini sama sekali tidak ada, dan peningkatan yang signifikan jatuh pada versi 5 dan 7. Oleh karena itu, kita dapat mengatakan bahwa sebelum versi Android 4.3 Google tidak memeriksa kepatuhan perangkat dengan spesifikasi untuk encoding dan decoding video, tetapi dalam versi 5.0 meningkatkan pemeriksaan ini.

Tampaknya ini menunjukkan bahwa mulai dari versi 5.0 dengan pengkodean semuanya harus berurutan. Tapi, mengingat pengalaman saya sebelumnya dengan decoding video streaming di Android, saya yakin itu tidak. Sudah cukup untuk melihat sejumlah topik tentang pengkodean dalam grup Google -webrtc .

File sumber WebRTC, yang berada dalam domain publik, membantu kami mencari jebakan. Mari kita pertimbangkan secara lebih detail.

Dukungan H.264 di WebRTC


Mari kita mulai dengan HardwareVideoEncoderFactory .

Ada metode dengan nama berbicara isHardwareSupportedInCurrentSdkH264:

private boolean isHardwareSupportedInCurrentSdkH264(MediaCodecInfo info) {
  // First, H264 hardware might perform poorly on this model.
  if (H264_HW_EXCEPTION_MODELS.contains(Build.MODEL)) {
    return false;
  }
  String name = info.getName();
  // QCOM H264 encoder is supported in KITKAT or later.
  return (name.startsWith(QCOM_PREFIX) && Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT)
      // Exynos H264 encoder is supported in LOLLIPOP or later.
      || (name.startsWith(EXYNOS_PREFIX)
             && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP);
}

Seperti yang dapat kita lihat, dukungan untuk pengkodean perangkat keras pada Android hanya diterapkan untuk chipset Qualcomm dan Exynos. Mengapa tidak ada dukungan untuk chipset lain dalam implementasi WebRTC standar? Kemungkinan besar, ini disebabkan oleh kekhasan implementasi produsen perangkat keras codec. Dan seringkali dimungkinkan untuk mengidentifikasi fitur-fitur ini hanya pada produksi, karena tidak selalu mungkin untuk menemukan perangkat tertentu.

Semua deskripsi codec pada perangkat disimpan dalam file media_codecs.xml. Di sini, misalnya, adalah file ini untuk Pixel XL dan untuk HUAWEI P8 lite . Ketika Anda menerima daftar codec menggunakan metode getCodecInfos () dari objek MediaCodecList, file ini diuraikan - dan codec yang disimpan di dalamnya dikembalikan. Operasi ini dan pengisian yang benar dari file ini oleh pabrikan tercakup dalam uji CTS.MediaCodecListTest , yang juga meningkat dari 160 baris kode di Android 4.3 menjadi 740 baris di Android 10.

Di Badoo, kami mengubah kode metode isHardwareSupportedInCurrentSdkH264, menolak daftar codec "putih" dan menggantinya dengan daftar kode program "hitam" yang tercantum dalam WebRTC:

static final String[] SOFTWARE_IMPLEMENTATION_PREFIXES = {"OMX.google.", "OMX.SEC."};

Tetapi Anda tidak bisa hanya mengambil dan menerapkan dukungan untuk semua codec tanpa memperhatikan fitur pabrikan. Dari nama-nama topik yang dikhususkan untuk pengkodean perangkat keras pada Android dalam grup diskusi-webrtc , kita dapat memahami bahwa dalam hal ini kita pasti akan menemukan kesalahan. Pada dasarnya, mereka muncul pada tahap konfigurasi codec.

Opsi konfigurasi codec


Inisialisasi codec untuk encoding adalah sebagai berikut:

MediaCodec mediaCodec = createByCodecName(codecName);
MediaFormat format = MediaFormat.createVideoFormat(mime, width, height);
format.setInteger(MediaFormat.KEY_BIT_RATE, targetBitrateBps);
format.setInteger(MediaFormat.KEY_BITRATE_MODE, VIDEO_ControlRateConstant);
format.setInteger(MediaFormat.KEY_COLOR_FORMAT, colorFormat);
format.setInteger(MediaFormat.KEY_FRAME_RATE, targetFps);
format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, keyFrameIntervalSec);
mediaCodec.configure(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);

Sangat mudah untuk membuat kesalahan dalam beberapa parameter ini, yang akan membuat pengecualian ketika mengkonfigurasi codec dan mengganggu aplikasi. Juga, ketika bekerja dengan codec, Anda mungkin perlu menyesuaikan bitrate-nya tergantung pada berbagai faktor, karena codec itu sendiri salah. Untuk ini, di WebRTC, kelas BaseBitrateAdjuster bertanggung jawab , yang memiliki dua keturunan:


Oleh karena itu, untuk setiap codec, Anda harus memilih mekanisme penyesuaian bitrate Anda sendiri. Mari kita pertimbangkan secara lebih rinci fitur pengaturan parameter inisialisasi untuk codec perangkat keras.

Resolusi aliran


Setelah menerima objek MediaCodecInfo untuk codec, Anda dapat memeriksa codec lebih detail dengan mendapatkan kemampuannya di kelas CodecCapabilities . Dari mereka, Anda dapat mengetahui apakah codec mendukung resolusi dan frame rate yang dipilih. Jika mendukung parameter ini, mereka dapat diatur dengan aman.

Namun, terkadang aturan ini tidak berfungsi. Kita dihadapkan dengan fakta bahwa codec dengan awalan "OMX.MARVELL." disandikan salah, menunjukkan garis-garis hijau di tepi layar jika resolusi aliran berbeda dari 4: 3. Pada saat yang sama, codec itu sendiri mengklaim bahwa resolusi dan frame rate yang dipilih didukung.

Mode kecepatan bit


Mode standar untuk semua codec video adalah bitrate konstan. Namun, begitu kami harus menggunakan bitrate variabel:

format.setInteger(MediaFormat.KEY_BITRATE_MODE, VIDEO_ControlRateVariable);

Ini terjadi pada perangkat Lenovo A1000 dengan chipset Spreadtrum (sekarang Unisoc) dimulai dengan awalan "OMX.sprd.". Pencarian di Internet membawa kami ke pos berusia enam tahun di Firefox OS yang menjelaskan masalah ini dan bagaimana menyelesaikannya.

Format warna


Saat menggunakan codec dalam mode byte-buffer, Anda harus memilih format yang benar. Ini biasanya dilakukan menggunakan fungsi dari bentuk berikut:

@Nullable
static Integer selectColorFormat(int[] supportedColorFormats, CodecCapabilities capabilities) {
  for (int supportedColorFormat : supportedColorFormats) {
    for (int codecColorFormat : capabilities.colorFormats) {
      if (codecColorFormat == supportedColorFormat) {
        return codecColorFormat;
      }
    }
  }
  return null;
}

Secara kasar, format warna pertama yang didukung selalu dipilih.

Namun, dalam kasus codec HUAWEI dimulai dengan awalan "OMX.IMG.TOPAZ.", "OMX.hisi." dan “OMX.k3.”, itu tidak berhasil, dan setelah pencarian yang panjang kami menemukan solusinya: tidak peduli format apa yang dikembalikan oleh codec ini, Anda perlu menggunakan format COLOR_FormatYUV420SemiPlanar . Utas membantu kami untuk mencari tahu ini di satu forum Cina.

Penyesuaian Bitrate


Kode WebRTC standar berisi yang berikut ini :

private BitrateAdjuster createBitrateAdjuster(VideoCodecMimeType type, String codecName) {
  if (codecName.startsWith(EXYNOS_PREFIX)) {
    if (type == VideoCodecMimeType.VP8) {
        // Exynos VP8 encoders need dynamic bitrate adjustment.
        return new DynamicBitrateAdjuster();
      } else {
        // Exynos VP9 and H264 encoders need framerate-based bitrate adjustment.
        return new FramerateBitrateAdjuster();
    }
  }
  // Other codecs don't need bitrate adjustment.
  return new BaseBitrateAdjuster();
}

Seperti yang Anda lihat dari kode ini, untuk semua chipset kecuali Exynos, penyesuaian bitrate dimatikan. Tetapi ini hanya berlaku untuk Qualcomm, karena hanya Exynos dan Qualcomm yang didukung dalam kode standar. Setelah bereksperimen dengan berbagai nilai pengaturan ini, dan juga mencari di Internet, kami menemukan bahwa untuk codec dengan awalan "OMX.MTK." itu juga perlu dihidupkan. Hal ini juga diperlukan untuk melakukan ini untuk codec HUAWEI dimulai dengan awalan "OMX.IMG.TOPAZ.", "OMX.hisi." atau "OMX.k3.". Hal ini disebabkan oleh fakta bahwa codec ini tidak menggunakan cap waktu frame untuk mengatur bitrate, dengan asumsi bahwa semua frame datang dengan frekuensi yang sama yang ditetapkan ketika mengkonfigurasi codec.

Sebagai kesimpulan, saya akan memberikan daftar codec yang kami terima untuk perangkat di Android 5.0 dan 5.1. Kami tertarik pada mereka terutama karena pada versi Android yang lebih baru situasinya membaik dan codec non-standar menjadi lebih kecil.

Ini bisa dilihat pada grafik di bawah ini. Skala logaritmik lebih baik untuk menunjukkan kasus langka.


Seperti yang dapat kita lihat, sebagian besar perangkat memiliki chipset Spreadtrum, MediaTek, HUAWEI dan MARVELL - sehingga perubahan kami membantu menghidupkan penyandian perangkat keras pada gadget ini.

Hasil


Meskipun kami berasumsi bahwa beberapa perangkat akan mengalami masalah saat bekerja dengan H.264, Android kembali dapat mengejutkan kami. Seperti yang dapat kita lihat dari statistik pengguna Badoo, masih ada banyak perangkat di tangan pengguna pada 2014-2016, yang tidak mereka inginkan atau tidak dapat perbarui. Dan meskipun situasi dengan rilis pembaruan Android untuk perangkat baru sudah jauh lebih baik daripada beberapa tahun yang lalu, pangsa gadget generasi sebelumnya menurun cukup lambat dan harus dipertahankan untuk beberapa waktu.

Sekarang WebRTC sedang dikembangkan secara aktif oleh Google karena penggunaannya dalam proyek Stadia (inilah videonyadengan perincian tentang topik ini), sehingga akan menjadi lebih baik dan lebih baik dan, kemungkinan besar, akan menjadi standar untuk menerapkan komunikasi video. Saya harap artikel ini akan membantu Anda memahami fitur bekerja dengan H.264 di WebRTC dan menggunakannya dalam proyek Anda.

All Articles