HDR(ハイ ダイナミック レンジ)は、より広い色域と、最も明るい白と最も暗いシャドウの間のより大きなコントラストを実現し、肉眼で認識する映像品質に近づけます。
HDR 動画コンテンツをプレビューして再生するには、アプリで HDR 動画再生を設定します。
この記事では、基本的な動画再生のサポートをアプリにすでに追加していることを前提としています。再生の詳細については、ExoPlayer のドキュメントをご覧ください。
デバイスの前提条件
すべての Android デバイスが HDR 再生に対応しているわけではありません。アプリで HDR 動画コンテンツを再生する前に、デバイスが次の前提条件を満たしているかどうかを確認します。
- Android 7.0 以降(API レイヤ 24)を対象としています。
- HDR 対応デコーダと HDR 対応ディスプレイへのアクセス権がある。
HDR 再生のサポートを確認する
Display.getHdrCapabilities()
を使用して、ディスプレイの HDR 機能をクエリします。このメソッドは、ディスプレイでサポートされている HDR プロファイルと輝度範囲に関する情報を返します。
次のコードは、デバイスが HLG10 の再生をサポートしているかどうかを確認します。Android 13 以降、デバイスが HDR 再生に対応している場合、デバイス メーカーがサポートする必要がある最低限の規格は HLG10 です。
Kotlin
// Check if display supports the HDR type val capabilities = display?.hdrCapabilities?.supportedHdrTypes ?: intArrayOf() if (!capabilities.contains(HDR_TYPE_HLG)) { throw RuntimeException("Display does not support desired HDR type"); }
Java
// Check if display supports the HDR type int[] list = getDisplay().getHdrCapabilities().getSupportedHdrTypes(); Listcapabilities = Arrays.stream(list).boxed().collect(Collectors.toList()); if (!capabilities.contains(HDR_TYPE_HLG)) { throw new RuntimeException("Display does not support desired HDR type"); }
アプリで HDR 再生を設定する
アプリで ExoPlayer を使用している場合、HDR 再生はデフォルトでサポートされます。次のステップについては、HDR 再生のサポートを確認するをご覧ください。
アプリで ExoPlayer を使用していない場合は、SurfaceView
を介して MediaCodec
を使用して HDR 再生を設定します。
SurfaceView を使用して MediaCodec を設定する
SurfaceView
を使用して、標準の MediaCodec
再生フローを設定します。これにより、HDR 再生用の特別な処理を行わずに HDR 動画コンテンツを表示できます。
MediaCodec
: HDR 動画コンテンツをデコードします。SurfaceView
: HDR 動画コンテンツを表示します。
次のコードは、コーデックが HDR プロファイルをサポートしているかどうかを確認し、SurfaceView
を使用して MediaCodec
を設定します。
Kotlin
// Check if there's a codec that supports the specific HDR profile val list = MediaCodecList(MediaCodecList.REGULAR_CODECS) var format = MediaFormat() /* media format from the container */; format.setInteger(MediaFormat.KEY_PROFILE, MediaCodecInfo.CodecProfileLevel.AV1ProfileMain10) val codecName = list.findDecoderForFormat (format) ?: throw RuntimeException ("No codec supports the format") // Here is a standard MediaCodec playback flow val codec: MediaCodec = MediaCodec.createByCodecName(codecName); val surface: Surface = surfaceView.holder.surface val callback: MediaCodec.Callback = (object : MediaCodec.Callback() { override fun onInputBufferAvailable(codec: MediaCodec, index: Int) { queue.offer(index) } override fun onOutputBufferAvailable( codec: MediaCodec, index: Int, info: MediaCodec.BufferInfo ) { codec.releaseOutputBuffer(index, timestamp) } override fun onError(codec: MediaCodec, e: MediaCodec.CodecException) { // handle error } override fun onOutputFormatChanged( codec: MediaCodec, format: MediaFormat ) { // handle format change } }) codec.setCallback(callback) codec.configure(format, surface, crypto, 0 /* flags */) codec.start() while (/* until EOS */) { val index = queue.poll() val buffer = codec.getInputBuffer(index) buffer?.put(/* write bitstream */) codec.queueInputBuffer(index, offset, size, timestamp, flags) } codec.stop() codec.release()
Java
// Check if there's a codec that supports the specific HDR profile MediaCodecList list = new MediaCodecList(MediaCodecList.REGULAR_CODECS); MediaFormat format = /* media format from the container */; format.setInteger( MediaFormat.KEY_PROFILE, CodecProfileLevel.AV1ProfileMain10); String codecName = list.findDecoderForFormat(format); if (codecName == null) { throw new RuntimeException("No codec supports the format"); } // Below is a standard MediaCodec playback flow MediaCodec codec = MediaCodec.getCodecByName(codecName); Surface surface = surfaceView.getHolder().getSurface(); MediaCodec.Callback callback = new MediaCodec.Callback() { @Override void onInputBufferAvailable(MediaCodec codec, int index) { queue.offer(index); } @Override void onOutputBufferAvailable(MediaCodec codec, int index) { // release the buffer for render codec.releaseOutputBuffer(index, timestamp); } @Override void onOutputFormatChanged(MediaCodec codec, MediaFormat format) { // handle format change } @Override void onError(MediaCodec codec, MediaCodec.CodecException ex) { // handle error } }; codec.setCallback(callback); codec.configure(format, surface, crypto, 0 /* flags */); codec.start(); while (/* until EOS */) { int index = queue.poll(); ByteBuffer buffer = codec.getInputBuffer(index); buffer.put(/* write bitstream */); codec.queueInputBuffer(index, offset, size, timestamp, flags); } codec.stop(); codec.release();
SurfaceView
を使用するその他の MediaCodec
実装については、Android カメラのサンプルをご覧ください。
リソース
HDR の再生について詳しくは、次のリソースをご覧ください。
HDR
- HDR 動画キャプチャ: Camera2 API を使用して HDR 動画キャプチャを設定する方法を学びます。
- GitHub の Camera2Video サンプル: HDR キャプチャと再生機能を備えた動作中のアプリを確認できます。
メディア
- Media API リファレンス: Media API の詳細を確認する。
- ExoPlayer: ExoPlayer ライブラリを使用してアプリを設定する方法を学びます。