HDR 동영상 재생

HDR(High Dynamic Range)은 더 넓은 범위의 색상과 가장 밝은 흰색과 가장 어두운 그림자 사이의 대비를 높여 육안으로 인식하는 것과 더 비슷한 동영상 품질을 제공합니다.

앱에서 HDR 동영상 재생을 설정하여 HDR 동영상 콘텐츠를 미리 보고 재생할 수 있습니다.

이 도움말에서는 앱에 기본 동영상 재생 지원을 이미 추가했다고 가정합니다. 재생에 관한 자세한 내용은 ExoPlayer 문서를 참고하세요.

기기 기본 요건

일부 Android 기기에서는 HDR 재생을 지원하지 않습니다. 앱에서 HDR 동영상 콘텐츠를 재생하기 전에 기기가 다음 기본 요건을 충족하는지 확인합니다.

  • Android 7.0 이상 (API 레이어 24)을 타겟팅합니다.
  • HDR 지원 디코더가 있고 HDR 지원 디스플레이에 액세스할 수 있습니다.

HDR 재생 지원 확인

Display.getHdrCapabilities()를 사용하여 디스플레이의 HDR 기능을 쿼리합니다. 이 메서드는 디스플레이의 지원되는 HDR 프로필과 휘도 범위에 관한 정보를 반환합니다.

다음 코드는 기기가 HLG10 재생을 지원하는지 확인합니다. Android 13부터 HLG10은 기기에서 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");
}

자바

// 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");
}

앱에서 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()

자바

// 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

미디어

  • Media API 참조: Media API에 대해 자세히 알아보세요.
  • ExoPlayer: ExoPlayer 라이브러리로 앱을 설정하는 방법을 알아봅니다.