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,请使用 MediaCodec
通过 SurfaceView
设置 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 捕获和播放功能的工作应用程序。