2021-05-19

Android 12のマルチメディアで追加された機能について

この時期は WWDC と Google I/O のトピックスを追っかけるのが大変ですね。

今年は各種イベントに登壇する暇もないくらい忙しいので、Android 12 のベータ版がリリースされたということで注目ポイントを紹介します。

android.media

Interfaces

AudioManager.OnCommunicationDeviceChangedListener

接続しているデバイスが変更された時にリスナーが飛ばせるようになりました。

iOS の AVFoundation では、同様なものに AVAudioSession.routeChangeNotification があります。

MediaCodec.OnFirstTunnelFrameReadyListener

MediaCodec では、HDR 映像を再生するときや、GoogleTV で地上波放送などを再生する際に、MediaCodec を通さずに直接 SoC や DSP に出力するモードがあります。これをトンネルモードといいます。

トンネルモードに設定した際に、フレームの準備が出来た際に飛んでくるリスナーが増えました。

Classes

ApplicationMediaCapabilities

Android 12 の新機能として注目されているところなので、ご存知の方も多いとは思いますが、HEVC(H.265)や HDR(HDR10/HDR10+)の動画コンテンツを共有する際に自動的に H.264/AVC にトランスコードできる機能が誕生しました。

iOS では、既に HEIF 画像を JPEG にしたり、HEVC 動画を AVC にしたりする機能はあるのですが、ようやく Android でもサポートされました。

これらを使うには、 media_capabilities.xml と呼ばれるマニフェストファイルを記述するか、コードで記述する必要があります。

 <media-capabilities xmlns:android="http://schemas.android.com/apk/res/android">
    <format android:name="HEVC" supported="true"/>
    <format android:name="HDR10" supported="false"/>
    <format android:name="HDR10Plus" supported="false"/>
 </media-capabilities>

ここにある format で、トランスコードするのかしないのかを決めることが出来ます。上記の例では、HEVC 以外は全てトランスコードする形となります。

この Media Capabilities を AndroidManifest.xml にも記述する必要があります。

<property
    android:name="android.media.PROPERTY_MEDIA_CAPABILITIES"
    android:resource="@xml/media_capabilities" />

これをコードで記述する場合は以下の通りになります。

val mediaCapabilities = ApplicationMediaCapabilities.Builder()
    .addSupportedVideoMimeType(MediaFormat.MIMETYPE_VIDEO_HEVC)
    .addUnsupportedHdrType(MediaFeature.HdrType.HDR10)
    .addUnsupportedHdrType(MediaFeature.HdrType.HDR10_PLUS)
    .build()

基本的には AndroidManifest のほうが優先されますが、コードで書いた方がスッキリするので、ApplicationMediaCapabilities のほうが使う頻度高そうですね。

AudioDescriptor

HDMI や DVI などを刺す際に、EDID(Extended Display Identification Data)と呼ばれるものを使って、ディスプレイ情報などを送っているのですが、そういった拡張データを取得できるようになりました。

ここで注目したいのは、カプセリングです。上記の AudioProfile で詳しい内容についてご紹介します。

AudioProfile

AudioProfile では、カプセル化と呼ばれる新しい概念が誕生しました。

このカプセル化とは、具体的には IEC61937(SPDIF)のことです。S/PDIF とは、音声信号をデジタル転送する規格で、光デジタルが有名ですね。

https://github.com/FFmpeg/FFmpeg/blob/master/libavformat/spdifenc.c

ちなみに、libavcodec にも実装されています。

この AudioProfile では、デジタル転送する際にどの形式がサポートしているか知りたい時に使うものみたいですね。

具体的には、AC3(Dolby)や DTS などの情報が取得できます。

EncoderProfiles

これはカメラを使う時に CamcorderProfile で各種情報が取得することが出来ますが、MediaRecorder でカメラから映像を録画した際に、EncoderProfilesを使うことで、どの出力形式でファイルが出力されるのか詳細に取れるようになりました。

ビットレート情報やコーデック情報、width と height などが取得できるので、出力が事前に予測できるとアプリケーション側で実装しやすくなりますね。

ParameterDescriptor

MediaCodec では、暗号化されたデータを MediaCrypto と一緒に復号化することができるのですが、その際のパラメータ情報を取得することができるみたいです。

MediaCommunicationManager

AndroidX の media2 専用に出てきた謎クラスです。開発者は基本的にこれを使う機会はほぼありません。

ここで出てくるマネージャーは Session2Token を単純に管理するだけなのですが、 Session2Token とは、MediaSession2MediaController2 をつなげるために必要なトークンのことです。

このトークンによって、各セッションをコントロールすることが出来ます。AndroidX の media2 にある session 処理の裏側で使っています。

AndroidX は以前は OS 内部にあまり干渉しないようにみえたのですが、最近は Android との連携が密になっている気がしますね。

MediaDrm.ErrorCodes

待望の機能がようやく実装されました。Android で DRM(Widevine)を使う際には、MediaDrm を使いますが、今までエラー内容があまりにもわかりにくかったため、多くのビデオ技術者は苦労してきたと思います。

しかし、エラーコードが実装されることで、より細かいエラー内容が取れるようになりました。

特に Widevine はデバイスによって保護レベルがサポートされていないので再生できないみたいなことが頻繁にあるので非常に助かりますね。

MediaDrm.LogMessage

MediaDrm でログメッセージがサポートされました。この LogMessage は MediaDrm のイベントについて記録され、getLogMessages で直近のイベントを取得することが出来ます。

デバッグする時や Firebase Crashlytics や Analytics などと連携すると結構便利そうですね。

MediaDrm.PlaybackComponent

DRM のセッション ID とログのセッション ID が取得出来ます。上記の LogMessage で使うためのものだと思います。

MediaFeature.HdrType

HDR のタイプを定義しています。この MediaFeature ですが、MediaFormat でよかった気もしますが、全てのフォーマットに共通するので、あえて MediaFeature に分けられています。

上記で説明した Media Capitabilty で使います。

android.media.mediafx

HapticGenerator

iPhone などでは馴染み深い Haptic Feedback ですが、Android でも最近導入するアプリが増えてきました。

そんな中、HapticGenerator は、再生しながら曲に合わせて Haptic を得られることが出来ます。

これをサポートするには、音声出力する際に Haptic をサポートする必要があるのでハードウェアは限られてきそうですが、リズムに乗りたいときなんかに便利になりそうですね。

Other

ImageDecoder(NDK)

NDK で使われる ImageDecoder API にアニメーション PNG とアニメーション GIF がサポートされました。

おそらく、皆さんは Glide を多く使っていると思いますが、Glide はサードパーティライブラリを多く依存しており、結構大きいライブラリなので、ImageDecoder API に置き換えることで、デコードの高速化及び APK のサイズ削減につながることでしょう。

android.hardware.battery

2021 年になって、ようやく Android のバッテリー情報が取得できるようになりました。

今までは BatteryManager を使う必要があり、これが Intent を使う必要があるため、BroadcastReceiver とかで呼び出していたと思いますが、そんなことはしなくてもそのまま呼び出すことができるようになりました。

さらに getCapacity を使うことで、 0.0f から 1.0f の間で残量も取得出来ます。最大値から除法みたいなこともやらなくてもよくなりました。

これで謎 Extension が消えますね。AndroidS からサポートなのでしばらくは BattryManager と付き合う必要はありそうですが。

android.os.OutcomeReceiver

Android で非同期処理を行う際に、正しく成功したかどうか取得したい場合が多いと思います。

OutcomeReceiver では、非同期処理が失敗した際にエラーをコールバックしてくれ、成功した場合には Result を返してくれるので、地味に便利になりそうです。

android.graphics.RenderEffect

RenderNode にアタッチすることができ、ぼかしやブラーなどのエフェクトを追加できるようになりました。

従来では、OpenGL ES を使う必要があったのですが、OpenGL ES の知識がなくてもエフェクトを追加出来ますね。

android.bluetooth.BluetoothLeAudio

Bluetooth LE Audio プロファイルの情報を詳細に取れるようになりました。