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