Google は、黒人コミュニティに対する人種平等の促進に取り組んでいます。取り組みを見る
このページは Cloud Translation API によって翻訳されました。
Switch to English

マルチメディアトンネリング

Androidフレームワーク5.0以降でマルチメディアトンネリングを実装できます。マルチメディアトンネリングはAndroidTVには必要ありませんが、超高精細(4K)コンテンツに最高のエクスペリエンスを提供します。

Android 11以降では、チューナーから直接供給されるオーディオおよびビデオコンテンツを使用してマルチメディアトンネリングを実装できます。 Codec2AudioTrackは、チューナーのHW同期IDを使用できます。これは、プログラムクロックリファレンス(PCR)またはシステムタイムクロック(STC)チャネルに対応している可能性があります。

バックグラウンド

Androidメディアフレームワークは、4つの方法でオーディオ/ビデオコンテンツを処理します。

  • 純粋なソフトウェア(ローカルデコード):アプリケーションプロセッサ(AP)は、特別な加速なしでオーディオをパルスコード変調(PCM)にローカルでデコードします。常にOggVorbisに使用され、圧縮オフロードのサポートがない場合はMP3およびAACに使用されます。
  • 圧縮オーディオオフロードは、圧縮オーディオデータをデジタルシグナルプロセッサ(DSP)に直接送信し、APを可能な限りオフに保ちます。画面をオフにして音楽ファイルを再生するために使用します。
  • 圧縮オーディオパススルーは、圧縮オーディオ(具体的にはAC3およびE-AC3)を、Android TVデバイスでデコードせずに、HDMI経由で外部TVまたはオーディオレシーバーに直接送信します。ビデオ部分は個別に処理されます。
  • マルチメディアトンネリングは、圧縮されたオーディオデータとビデオデータを一緒に送信します。エンコードされたストリームがビデオおよびオーディオデコーダーによって受信されると、フレームワークに戻りません。理想的には、ストリームがAPを中断しないことです。
  • マルチメディアパススルーは、フレームワークを使用せずに、圧縮されたオーディオおよびビデオデータをチューナーからビデオおよびオーディオデコーダーに一緒に送信します。
マルチメディアトンネリングフロー図
図1.マルチメディアトンネリングフロー

アプローチの比較

純粋なソフトウェア圧縮オーディオオフロード圧縮オーディオパススルーマルチメディアトンネリングマルチメディアパススルー
場所をデコードするAP DSPテレビまたはオーディオ/ビデオレシーバー(AVR)テレビまたはAVRテレビまたはAVR
オーディオを処理しますはいはいはいはい番号
ビデオを処理しますはい番号番号はい番号

アプリ開発者向け

作成SurfaceView 、オーディオセッションIDを取得し、インスタンスを作成し、その後AudioTrackMediaCodec再生、ビデオフレームの復号に必要なタイミングおよび構成を提供するために、インスタンスを。

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を使用できます。

  1. SurfaceViewインスタンスを作成します。
    SurfaceView sv = new SurfaceView(mContext);
  2. オーディオセッションIDを取得します。この一意のIDは、オーディオトラック( AudioTrack )の作成に使用されます。これはメディアコーデック( MediaCodec )に渡され、オーディオパスとビデオパスをリンクするためにメディアフレームワークによって使用されます。
    AudioManager am = mContext.getSystemService(AUDIO_SERVICE);
    int audioSessionId = am.generateAudioSessionId()
    // or, for Android 11 or higher
    int avSyncId = tuner.getAvSyncHwId();
  3. 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);
    
  4. ビデオ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. ビデオフレームをデコードします。
    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の順序を切り替えることができます。

コーデック設定前に作成されたオーディオトラックの図
図2.コーデックを構成する前に作成されたオーディオトラック
コーデック構成後に作成されたオーディオトラックの図
図3.コーデック構成後に作成されたオーディオトラック

デバイスメーカー向け

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コンポーネントをトンネル化モードで構成し( bTunneledOMX_TRUE設定することOMX_TRUE )、 AUDIO_HW_AV_SYNCフラグで作成された関連オーディオ出力デバイスをOMXコンポーネント( nAudioHwSync )にnAudioHwSyncます。

コンポーネントがこの構成をサポートしている場合は、サイドバンドハンドルをこのコーデックに割り当て、 pSidebandWindowメンバーを介してpSidebandWindowあります。サイドバンドハンドルは、ハードウェアコンポーザー(HWコンポーザー)がそれを識別できるようにするトンネルレイヤーのIDタグです。コンポーネントがこの構成をサポートしていない場合は、 bTunneledOMX_FALSE設定するbTunneledOMX_FALSEます。

フレームワークは、OMXコンポーネントによって割り当てられたトンネルレイヤー(サイドバンドハンドル)を取得し、それをHWComposerに渡します。このレイヤーのcompositionTypeHWC_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_SYNCget_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個のバッファー( nBufferCountMinnBufferCountActual )を指定する必要があります。

トンネリングされたコンポーネントは、 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を表しています。

オーディオに基づいてビデオフレームを組み合わせたハードウェアコンポーザーの図
4.HW(またはカーネル/ドライバー)シンクロナイザーと連携するHW Composer