ffmpeg vs hdr

Hermaeus Mora ·

왼쪽 이미지는 h.265 -> h.264로 인코딩한 비디오 프레임을 추출한 것이고, 오른쪽 이미지는 h.264 비디오 프레임을 추출한 것이다.

아래는 ffprobe로 뽑은 두 비디오의 메타데이터이다.

// h.265 -> h.264
{
      \"index\": 0,
  \"codec_name\": \"h264\",
  \"codec_long_name\": \"H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10\",
  \"profile\": \"High 10\",
  \"codec_type\": \"video\",
  \"codec_tag_string\": \"avc1\",
  \"codec_tag\": \"0x31637661\",
  \"width\": 1080,
  \"height\": 1920,
  \"coded_width\": 1080,
  \"coded_height\": 1920,
  \"closed_captions\": 0,
  \"film_grain\": 0,
  \"has_b_frames\": 2,
  \"sample_aspect_ratio\": \"N/A\",
  \"display_aspect_ratio\": \"N/A\",
  \"pix_fmt\": \"yuv420p10le\",
  \"level\": 40,
  \"color_range\": \"tv\",
  \"color_space\": \"bt2020nc\",
  \"color_transfer\": \"smpte2084\",
  \"color_primaries\": \"bt2020\",
  \"chroma_location\": \"left\",
  \"field_order\": \"progressive\",
  \"refs\": 1,
  \"is_avc\": \"true\",
  \"nal_length_size\": 4,
  \"id\": \"0x1\",
  \"r_frame_rate\": \"30/1\",
  \"avg_frame_rate\": \"30/1\",
  \"time_base\": \"1/15360\",
  \"start_pts\": 0,
  \"start_time\": 0,
  \"duration_ts\": 194560,
  \"duration\": 12.666667,
  \"bit_rate\": 1958891,
  \"max_bit_rate\": \"N/A\",
  \"bits_per_raw_sample\": 10,
  \"nb_frames\": 380,
  \"nb_read_frames\": \"N/A\",
  \"nb_read_packets\": \"N/A\",
  \"extradata_size\": 51,
  \"tags\": {
        \"language\": \"eng\",
    \"handler_name\": \"VideoHandle\",
    \"vendor_id\": \"[0][0][0][0]\",
    \"encoder\": \"Lavc59.37.100 libx264\"
  }
}
// h.264
{
      \"index\": 0,
  \"codec_name\": \"h264\",
  \"codec_long_name\": \"H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10\",
  \"profile\": \"High\",
  \"codec_type\": \"video\",
  \"codec_tag_string\": \"avc1\",
  \"codec_tag\": \"0x31637661\",
  \"width\": 720,
  \"height\": 1280,
  \"coded_width\": 720,
  \"coded_height\": 1280,
  \"closed_captions\": 0,
  \"film_grain\": 0,
  \"has_b_frames\": 2,
  \"sample_aspect_ratio\": \"N/A\",
  \"display_aspect_ratio\": \"N/A\",
  \"pix_fmt\": \"yuv420p\",
  \"level\": 31,
  \"color_range\": \"unknown\",
  \"color_space\": \"unknown\",
  \"color_transfer\": \"unknown\",
  \"color_primaries\": \"unknown\",
  \"chroma_location\": \"left\",
  \"field_order\": \"progressive\",
  \"refs\": 1,
  \"is_avc\": \"true\",
  \"nal_length_size\": 4,
  \"id\": \"0x1\",
  \"r_frame_rate\": \"24/1\",
  \"avg_frame_rate\": \"24/1\",
  \"time_base\": \"1/12288\",
  \"start_pts\": 0,
  \"start_time\": 0,
  \"duration_ts\": 156160,
  \"duration\": 12.708333,
  \"bit_rate\": 1912296,
  \"max_bit_rate\": \"N/A\",
  \"bits_per_raw_sample\": 8,
  \"nb_frames\": 305,
  \"nb_read_frames\": \"N/A\",
  \"nb_read_packets\": \"N/A\",
  \"extradata_size\": 46,
  \"tags\": {
        \"language\": \"und\",
    \"handler_name\": \"VideoHandler\",
    \"vendor_id\": \"[0][0][0][0]\",
    \"encoder\": \"Lavc59.37.100 libx264\"
  }
}

h.265 코덱을 h.264로 변환해도 hdr 속성들을 그대로 가지고 있는 것을 확인할 수 있다.

{
      \"color_transfer\": \"smpte2084\",
  \"color_primaries\": \"bt2020\"
}

smpte2084는 hdr용 휘도(1000니트 이상)에 대응하기 위한 감마 곡선을 뜻하고, bt2020은 hdr용 색역을 의미한다. (감마와 HDR의 관계 참고)

ffmpeg이 hdr 프레임을 추출하는 과정에서 문제가 생긴 것으로 판단해서 npm을 뒤적거리다 같은 사례를 발견했다.

위의 사례를 참조해서 hdr비디오의 경우 프레임 추출 옵션에 다음 파라미터를 추가했더니 해결되었다.

-vf zscale=t=linear:npl=100,format=gbrpf32le,zscale=p=bt709,tonemap=tonemap=hable:desat=0,zscale=t=bt709:m=bt709:r=tv,format=yuv420p

색역을 bt2020 -> bt709로 다운그레이드해서 프레임을 추출하는 방법으로 보인다. 크롬 브라우저에서 bt2020 색역대를 지원하지 않는 것이 아닐까..

추가적으로.. 관련해서 레딧을 뒤져보니 크롬 및 여타 브라우저에서 hdr색역대를 지원하지 않고 있다고 한다. chrome://flags에서 force color profilehdr10으로 바꾸면 가능하다는 코멘트가 있다.