Phát video HDR

HDR hay còn gọi là Dải động cao (High Dynamic Range) mang đến nhiều dải màu hơn và có độ tương phản cao hơn giữa màu trắng sáng nhất và bóng tối nhất, giúp chất lượng video gần giống với những gì mắt thường cảm nhận được.

Bạn có thể thiết lập tính năng phát video HDR trong ứng dụng để xem trước và phát lại nội dung video HDR.

Bài viết này giả định rằng bạn đã thêm tính năng hỗ trợ phát video cơ bản vào ứng dụng của mình. Hãy xem tài liệu về ExoPlayer để biết thêm thông tin chi tiết về cách phát.

Điều kiện tiên quyết đối với thiết bị

Không phải thiết bị Android nào cũng hỗ trợ tính năng phát HDR. Trước khi phát lại nội dung video HDR trong ứng dụng, hãy xác định xem thiết bị của bạn có đáp ứng các điều kiện tiên quyết sau đây hay không:

  • Nhắm đến Android 7.0 trở lên (API lớp 24).
  • Có bộ giải mã hỗ trợ HDR và quyền truy cập vào màn hình hỗ trợ HDR.

Kiểm tra xem có hỗ trợ phát HDR không

Sử dụng Display.getHdrCapabilities() để truy vấn chức năng HDR của màn hình. Phương thức này sẽ trả về thông tin về các cấu hình HDR được hỗ trợ và phạm vi độ chói cho màn hình.

Đoạn mã sau đây sẽ kiểm tra xem thiết bị có hỗ trợ tính năng phát HLG10 hay không. Kể từ Android 13, HLG10 là tiêu chuẩn tối thiểu mà các nhà sản xuất thiết bị phải hỗ trợ nếu thiết bị có khả năng phát HDR:

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();
List capabilities = Arrays.stream(list).boxed().collect(Collectors.toList());
if (!capabilities.contains(HDR_TYPE_HLG)) {
 throw new RuntimeException("Display does not support desired HDR type");
}

Thiết lập chế độ phát HDR trong ứng dụng

Nếu ứng dụng của bạn sử dụng ExoPlayer, thì ứng dụng sẽ hỗ trợ phát HDR theo mặc định. Hãy xem bài viết Kiểm tra chế độ hỗ trợ phát HDR để biết các bước tiếp theo.

Nếu ứng dụng của bạn không sử dụng ExoPlayer, hãy thiết lập tính năng phát HDR bằng MediaCodec qua SurfaceView.

Thiết lập MediaCodec bằng SurfaceView

Thiết lập quy trình phát MediaCodec chuẩn bằng SurfaceView. Điều này cho phép bạn hiển thị nội dung video HDR mà không cần xử lý đặc biệt khi phát HDR:

  • MediaCodec: Giải mã nội dung video HDR.
  • SurfaceView: Hiển thị nội dung video HDR.

Đoạn mã sau đây sẽ kiểm tra xem bộ mã hoá và giải mã có hỗ trợ cấu hình HDR hay không, rồi thiết lập MediaCodec bằng SurfaceView:

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();

Để biết thêm về cách triển khai MediaCodec bằng SurfaceView, hãy xem mẫu Máy ảnh trên Android.

Tài nguyên

Để biết thêm thông tin liên quan đến tính năng phát HDR, hãy xem các tài nguyên sau:

HDR

Nội dung nghe nhìn