Androidフレームワーク5.0以降でマルチメディアトンネリングを実装できます。マルチメディアトンネリングはAndroidTVには必要ありませんが、超高精細(4K)コンテンツに最高のエクスペリエンスを提供します。
Android 11以降では、チューナーから直接供給されるオーディオおよびビデオコンテンツを使用してマルチメディアトンネリングを実装できます。 Codec2
とAudioTrack
は、チューナーのHW同期IDを使用できます。これは、プログラムクロックリファレンス(PCR)またはシステムタイムクロック(STC)チャネルに対応している可能性があります。
バックグラウンド
Androidメディアフレームワークは、4つの方法でオーディオ/ビデオコンテンツを処理します。
- 純粋なソフトウェア(ローカルデコード):アプリケーションプロセッサ(AP)は、特別な加速なしでオーディオをパルスコード変調(PCM)にローカルでデコードします。常にOggVorbisに使用され、圧縮オフロードのサポートがない場合はMP3およびAACに使用されます。
- 圧縮オーディオオフロードは、圧縮オーディオデータをデジタルシグナルプロセッサ(DSP)に直接送信し、APを可能な限りオフに保ちます。画面をオフにして音楽ファイルを再生するために使用します。
- 圧縮オーディオパススルーは、圧縮オーディオ(具体的にはAC3およびE-AC3)を、Android TVデバイスでデコードせずに、HDMI経由で外部TVまたはオーディオレシーバーに直接送信します。ビデオ部分は個別に処理されます。
- マルチメディアトンネリングは、圧縮されたオーディオデータとビデオデータを一緒に送信します。エンコードされたストリームがビデオおよびオーディオデコーダーによって受信されると、フレームワークに戻りません。理想的には、ストリームがAPを中断しないことです。
- マルチメディアパススルーは、フレームワークを使用せずに、圧縮されたオーディオおよびビデオデータをチューナーからビデオおよびオーディオデコーダーに一緒に送信します。

アプローチの比較
純粋なソフトウェア | 圧縮オーディオオフロード | 圧縮オーディオパススルー | マルチメディアトンネリング | マルチメディアパススルー | |
---|---|---|---|---|---|
場所をデコードする | AP | DSP | テレビまたはオーディオ/ビデオレシーバー(AVR) | テレビまたはAVR | テレビまたはAVR |
オーディオを処理します | はい | はい | はい | はい | 番号 |
ビデオを処理します | はい | 番号 | 番号 | はい | 番号 |
アプリ開発者向け
作成SurfaceView
、オーディオセッションIDを取得し、インスタンスを作成し、その後AudioTrack
とMediaCodec
再生、ビデオフレームの復号に必要なタイミングおよび構成を提供するために、インスタンスを。
Android 11以降の場合、オーディオセッションIDの代わりに、アプリはチューナーからHW同期IDを取得し、A / V同期のためにAudioTrack
インスタンスとMediaCodec
インスタンスに提供できます。
A / V同期
マルチメディアトンネリングモードでは、オーディオとビデオはマスタークロックで同期されます。
- Android 11以降の場合、チューナーのPCRまたはSTCがA / V同期のマスタークロックになる可能性があります。
- Android 10以下の場合、オーディオクロックはA / V再生に使用されるマスタークロックです。
トンネリングされたビデオMediaCodec
インスタンスとAudioTrack
インスタンスがAudioTrack
インスタンスにリンクされてHW_AV_SYNC
場合、 AudioTrack
から派生した暗黙のクロックは、実際のオーディオまたはビデオフレーム表示タイムスタンプ(PTS)に基づいて、各ビデオフレームとオーディオサンプルが表示されるHW_AV_SYNC
制限します。
API呼び出しフロー
Android 11以降の場合、クライアントはチューナーのHW同期IDを使用できます。
-
SurfaceView
インスタンスを作成します。SurfaceView sv = new SurfaceView(mContext);
- オーディオセッションIDを取得します。この一意のIDは、オーディオトラック(
AudioTrack
)の作成に使用されます。これはメディアコーデック(MediaCodec
)に渡され、オーディオパスとビデオパスをリンクするためにメディアフレームワークによって使用されます。AudioManager am = mContext.getSystemService(AUDIO_SERVICE); int audioSessionId = am.generateAudioSessionId() // or, for Android 11 or higher int avSyncId = tuner.getAvSyncHwId();
- HW A / V同期
AudioAttributes
AudioTrack
してAudioTrack
を作成します。オーディオポリシーマネージャーは、ハードウェアアブストラクションレイヤー(HAL)に
FLAG_HW_AV_SYNC
をサポートするデバイス出力をFLAG_HW_AV_SYNC
、中間ミキサーなしでこの出力に直接接続されたオーディオトラックを作成します。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);
- ビデオ
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);
- ビデオフレームをデコードします。
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;
注:次の2つの図に示すように、このプロセスではステップ3と4の順序を切り替えることができます。


デバイスメーカー向け
OEMは、トンネルビデオ再生をサポートするために、別個のビデオデコーダーOpenMAX IL(OMX)コンポーネントを作成する必要があります。このOMXコンポーネントは、トンネル再生が可能であることをアドバタイズする必要があります( media_codecs.xml
)。
<Feature name=”tunneled-playback” required=”true” />
コンポーネントは、 ConfigureVideoTunnelModeParams
構造を使用するOMX拡張パラメーターOMX.google.android.index.configureVideoTunnelMode
もサポートする必要があります。
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 };
トンネル化されたMediaCodec
作成要求が行われると、フレームワークはOMXコンポーネントをトンネル化モードで構成し( bTunneled
をOMX_TRUE
設定することOMX_TRUE
)、 AUDIO_HW_AV_SYNC
フラグで作成された関連オーディオ出力デバイスをOMXコンポーネント( nAudioHwSync
)にnAudioHwSync
ます。
コンポーネントがこの構成をサポートしている場合は、サイドバンドハンドルをこのコーデックに割り当て、 pSidebandWindow
メンバーを介してpSidebandWindow
あります。サイドバンドハンドルは、ハードウェアコンポーザー(HWコンポーザー)がそれを識別できるようにするトンネルレイヤーのIDタグです。コンポーネントがこの構成をサポートしていない場合は、 bTunneled
をOMX_FALSE
設定するbTunneled
がOMX_FALSE
ます。
フレームワークは、OMXコンポーネントによって割り当てられたトンネルレイヤー(サイドバンドハンドル)を取得し、それをHWComposerに渡します。このレイヤーのcompositionType
はHWC_SIDEBAND
に設定されHWC_SIDEBAND
。 ( hardware/libhardware/include/hardware/hwcomposer.h
参照してください。)
HW Composerは、適切なタイミングでストリームから新しい画像バッファーを受信し(たとえば、関連するオーディオ出力デバイスに同期)、それらを他のレイヤーの現在のコンテンツと合成し、結果の画像を表示します。これは、通常の準備/設定サイクルとは関係なく発生します。準備/設定の呼び出しは、他のレイヤーが変更された場合、またはサイドバンドレイヤーのプロパティ(位置やサイズなど)が変更された場合にのみ発生します。
構成
フレームワーク/av/services/audioflinger/AudioFlinger.cpp
HALは、 HW_AV_SYNC
64ビット整数の文字列10進表現として返します。 ( 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);
フレームワーク/av/services/audioflinger/Threads.cpp
オーディオフレームワークは、HALの出力ストリームを見つけなければならないと、このセッションIDの対応、およびクエリのためのHAL hwAVSyncId
使用set_parameters
。
mOutput->stream->common.set_parameters(&mOutput->stream->common, AUDIO_PARAMETER_STREAM_HW_AV_SYNC=hwAVSyncId);
OMXデコーダー構成
MediaCodec.java
オーディオフレームワークは、このセッションIDに対応するHAL出力ストリームを見つけ、 AUDIO_PARAMETER_STREAM_HW_AV_SYNC
を使用してHALにAUDIO_PARAMETER_STREAM_HW_AV_SYNC
フラグを照会することにより、 audio-hw-sync
AUDIO_PARAMETER_STREAM_HW_AV_SYNC
を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); } // ...
このHW同期IDは、カスタムパラメーターOMX.google.android.index.configureVideoTunnelMode
を使用してOMXトンネルビデオデコーダーに渡されます。
ACodec.cpp
オーディオハードウェア同期IDを取得すると、ACodecはそれを使用してトンネルビデオデコーダーを構成し、トンネルビデオデコーダーが同期するオーディオトラックを認識できるようにします。
// 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
OMXコンポーネントは、上記のconfigureVideoTunnelMode
メソッドによって構成されconfigureVideoTunnelMode
。
// 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
OMXコンポーネントがトンネルモードで構成された後、サイドバンドハンドルがレンダリングサーフェスに関連付けられます。
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; }
次に、最大解像度のヒントが存在する場合は、コンポーネントに送信されます。
// 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); }
サポートの一時停止
Android 5.0以前には、一時停止のサポートは含まれていません。トンネル再生はA / V飢餓によってのみ一時停止できますが、ビデオの内部バッファーが大きい場合(たとえば、OMXコンポーネントに1秒のデータがある場合)、一時停止が応答しないように見えます。
Android 5.1以降では、AudioFlingerは直接(トンネル)オーディオ出力の一時停止と再開をサポートしています。 HALが一時停止/再開を実装している場合、トラックの一時停止/再開はHALに転送されます。
一時停止、フラッシュ、再開の呼び出しシーケンスは、再生スレッドでHAL呼び出しを実行することによって尊重されます(オフロードと同じ)。
Codec2のサポート
Android 11以降の場合、Codec2はトンネル再生をサポートしています。
CCodec.cpp
トンネル再生をサポートするために、Codec2はOMXと同様に機能します。チューナーからのHW同期IDをサポートするために、Codec2は以下のソースから同期IDを探します。
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);
実装の提案
オーディオHAL
Android 11の場合、PCRまたはSTCからのHW同期IDをA / V同期に使用できるため、ビデオのみのストリームがサポートされます。
Android 10以下の場合、トンネルビデオ再生をサポートするデバイスには、 audio_policy.conf
ファイルにフラグFLAG_HW_AV_SYNC
およびAUDIO_OUTPUT_FLAG_DIRECT
持つオーディオ出力ストリームプロファイルが少なくとも1つ必要です。これらのフラグは、オーディオクロックからシステムクロックを設定するために使用されます。
OMX
デバイスメーカーは、トンネルビデオ再生用に個別のOMXコンポーネントを用意する必要があります。メーカーは、安全な再生など、他のタイプのオーディオおよびビデオ再生用に追加のOMXコンポーネントを用意できます。
このコンポーネントは、出力ポートに0個のバッファー( nBufferCountMin
、 nBufferCountActual
)を指定する必要があります。
トンネリングされたコンポーネントは、 OMX.google.android.index.prepareForAdaptivePlayback setParameter
拡張機能も実装する必要があります。
トンネリングされたコンポーネントは、 media_codecs.xml
ファイルでその機能を指定し、トンネリングされた再生機能を宣言する必要があります。また、フレームサイズ、配置、またはビットレートの制限を明確にする必要があります。
<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>
同じOMXコンポーネントを使用してトンネリングと非トンネリングのデコードをサポートする場合は、トンネリングされた再生機能を不要のままにする必要があります。トンネリングされたデコーダーとトンネリングされていないデコーダーの両方に、同じ機能制限があります。
<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>
HWコンポーザー
トンネリング層(持つ層があります場合HWC_SIDEBAND
compositionType
ディスプレイ上に)、層のsidebandStream
OMXビデオコンポーネントによって割り当てられたサイドバンド・ハンドルです。
HW Composerは、デコードされたビデオフレーム(トンネリングされたOMXコンポーネントから)を関連するオーディオトラック( audio-hw-sync
IDを使用)にaudio-hw-sync
ます。新しいビデオフレームが最新になると、HW Composerは、最後の準備/設定呼び出し中に受信したすべてのレイヤーの現在のコンテンツとそれを合成し、結果の画像を表示します。準備/設定の呼び出しは、他のレイヤーが変更された場合、またはサイドバンドレイヤーのプロパティ(位置やサイズなど)が変更された場合にのみ発生します。
図4は、HW(またはカーネル/ドライバー)シンクロナイザーと連携して、ビデオフレーム(7b)と最新のコンポジション(7a)を組み合わせて、オーディオ(7c)に基づいて正しい時間に表示するHWComposerを表しています。
