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 库设置应用。