ffmpeg: HDR 둥영상을 SDR로 변환

!
경고: 이 글이 작성된 지 365일이 넘었습니다. 글의 정보가 오래되어 부정확할 수 있습니다.

(모바일 사용자들을 위한 경고: 이 글은 파일 크기가 큰 사진들이 첨부되어 있기에 로딩이 느릴 수 있습니다. 사진을 압축/크기 변경하는 것을 고려했습니다만 사진 속 세세한 부분까지 보존하고 싶어 그대로 두었습니다. 만약 사진들이 로드되지 않는다면 컴퓨터에서 글을 읽어보세요. 감사합니다!)

만약 저처럼 미디어를 수집하신다면, HDR (High Dynamic Range, 넓은 다이나믹 레인지)로 찍힌 영화나 둥영상과 같은 컨텐츠를 가지고 있으실 수 있습니다.

그리고 많은 기기들을 보유하고 있으시다면, 거의 대부분의 최신 기기들은 HDR 컨텐츠를 아무 문제 없이 재생할 수 있다는 것을 아실 겁니다. 빠르게 참조하실 수 있도록, 인기가 높은 기기 라인업들이 언제부터 HDR을 지원하기 시작했는지 밑에 나열해두겠습니다:

추가적으로, HDR 재생을 지원하지 않는 기기에서는, 어떤 플랫폼과 둥영상 플레이어(VLC 등)는 HDR 둥영상을 SDR, 즉 Standard Dynamic Range (표준 다이나믹 레인지)로 “톤맵”(이게 무엇인지는 나중에 설명드리겠습니다)하는 것을 허용합니다. 이를 통해 하드웨어를 업그레이드할 필요 없이 HDR 컨텐츠를 재생할 수 있죠.

아쉽게도, HDR 컨텐츠를 무슨 방식으로든 지원하지 않는 기기에서 재생을 시도할 경우 문제가 여럿 생기게 됩니다. 낡은 안드로이드 폰이나 태블릿, 낡은 애플 기기 등 HDR 톤매핑을 지원하는 외부 플레이어를 설치하는 것을 불허하는 기기에서 HDR 컨텐츠를 재생 시, 재생은 되겠지만 둥영상에 문제가 있다는 것을 느끼셨을 겁니다. 색상이 전부 색이 빠진 느낌이 들고, 밝기값이 틀릴 것입니다. 무엇이 문제일까요?

색상 클리핑

시작하기에 앞서, SDR 둥영상들이 사용하는 “색상 영역"을 확인하겠습니다. SDR 둥영상들은 대부분 Rec. 709 색상 영역을 사용하는데, 이 영역은 다음과 같습니다:

rec-709-diagram

< 출처: https://en.wikipedia.org/wiki/Rec._709 >

이와 비교되게, HDR 둥영상들은 Rec. 2020 색상 영역을 사용하는데, 이 영역은 다음과 같습니다:

rec-2020-diagram

< 출처: https://en.wikipedia.org/wiki/Rec._2020 >

콘 모양 안에 검정색으로 된 삼각형이 색상 스펙트럼에서 색상 영역이 나타낼 수 있는 부분을 표시합니다. 위에서 보실 수 있듯이, Rec. 2020이 Rec. 709보다 더 많은 색상을 나타낼 수 있습니다.

이게 문제가 되는 이유를 설명드리자면, Rec. 2020 색상을 제대로 표시하기 위해 하드웨어 (기기와 화면), 플랫폼, 그리고 둥영상 플레이어가 모두 Rec. 2020을 표시하는 것을 (당연히) 지원해야 합니다. 톤매핑이 가능한 하드웨어-플랫폼-소프트웨어 조합에서는, Rec. 709 색상 영역 밖에 있는 색상들이 제대로 지원되는 영역 안으로 “매핑"된 색상 출력을 보실 수 있을 겁니다 (이게 앞서 말씀드린 “톤매핑"의 전부입니다).

하지만 재생 조합(하드웨어-플랫폼-소프트웨어)이 톤매핑을 제대로 지원하지 않는다면, Rec. 709 영역 밖의 색상들은 지원되는 영역 안으로 강제로 맞추어지게 되고 (클리핑이라고도 불립니다), 결과적으로 표시되는 이미지는 회색빛을 띠는 부정확한 색상으로 표시되어 보기에 안 좋습니다.

그러면 이 문제를 어떻게 해결할까요?

해결 방안들

가장 좋은 순으로 몇 가지 해결 방안을 나열했습니다:

  1. HDR을 지원하는 기기로 업그레이드
  2. 실시간 톤매핑을 제공하는 둥영상 플레이어를 사용
  3. 컨텐츠가 SDR 버전으로 제공되는 경우 다시 받기
  4. ffmpeg로 둥영상을 재인코딩

이상적인 세상에서는, 저희 모두 HDR를 지원하는 기기를 사용하겠지만, 이 세상은 유토피아가 아니고 지금 현재 출시되는 기기들 중에서도 HDR에 대한 지원을 부실하게 (또는 아예 안) 하는 경우가 많습니다. HDR 지원 기기만을 고르더라도, 이렇게 기기를 교체하는 것은 가격도 비싸고, 다른 해결 방안이 존재하는 한 예전 기기들을 교체할 충분한 이유가 되지 않습니다. (명확하게 말씀드리자면, 만약 기기를 업그레이드할 예정이었는데 HDR가 수많은 이유 중 하나였다면 업그레이드하셔도 괜챃습니다. 하지만 HDR를 지원하지 않는다는 이유만으로 기기를 교체하시는 경우, 거의 대부분의 기기들은 (특히 컴퓨터들) HDR를 지원하지 않기에, HDR 지원만으로 기기를 업그레이드하시는 것은 바람직하지 않을 겁니다.)

다음으로 가장 좋은 방안은 톤매핑을 지원하는 둥영상 플레이어(예를 들어 VLC)를 사용하는 것입니다. 이는 다른 둥영상 플레이어가 탑재 가능한 데스크탑 운영체제에 적용 가능합니다. 하지만 만약 HDR 지원을 별도로 설치하는 것이 어렵거나 불가능한 기기를 사용한다면 어떻게 해야 할까요?

만약 컨텐츠의 SDR 버전이 존재할 경우 이를 받으실 수도 있습니다. 이 방법을 사용하는 것이 대부분 쉽고 빠른데, 다운로드가 인코드보다 속도 면에서 빠르기 때문입니다. 하지만 HDR 버전만 존재한다면요?

그렇다면 재인코딩밖에 답이 없습니다!

시작하기 전에

다음 섹션들에 작성된 HDR에서 SDR 변환 과정은 현재 삭제된 이 블로그 글(사이트 자체가 삭제된 듯 합니다)에서 발췌된 점을 빠르게 짚고 넘어가고 싶습니다. 아카이브된 버전을 Wayback Machine에서 확인하실 수 있습니다. 이 주제에 대한 블로그 글의 글쓴이, Daniel Stevens께 감사의 말씀 드립니다!

원본

시연을 위해, 유튜브에서 가져온 이 둥영상을 사용하여 HDR에서 SDR로 변환하는 여러 방법을 보여드리려고 합니다. (둥영상을 첨부하기에는 파일이 너무 크기에, 둥영상 중앙에 있는 한 프레임을 기준으로 하겠습니다. 제가 하는 것을 따라서 해 보고 싶으시다면 둥영상을 다운 받으셔서 같은 명령들을 사용하시면 됩니다!)

한 개의 HDR 프레임을 추출하여, 톤매핑 없이 Rec. 709에서 어떻게 보이는지 확인하겠습니다:

ffmpeg -ss 00:01:10.871 -i hdr-original.mp4 -vframes 1 original.png

original

색이 빠진 느낌이 드는데, 예상하던 대로입니다. 그러면 이를 SDR로 제대로 변환하기 위해서는 무슨 명령을 실행해야 할까요?

톤맵 알고리즘

다음은 사용 가능한 여러 톤맵 알고리즘입니다: mobius, hable, 그리고 reinhard가 있습니다. 각각 확인해봅시다!

mobius

똑같은 프레임을 추출한 다음 mobius 톤맵 프리셋 적용:

ffmpeg -ss 00:01:10.871 -i hdr-original.mp4 -vf 'zscale=t=linear:npl=100,format=gbrpf32le,zscale=p=bt709,tonemap=tonemap=mobius,zscale=t=bt709:m=bt709:r=tv,format=yuv420p' -vframes 1 mobius.png

결과물입니다:

mobius

색상이 더 보이는 듯 합니다! 하지만 아직도 뭔가 이상합니다. 색상이 너무 강한 듯 합니다.

나머지 두 알고리즘을 사용해 보겠습니다.

hable

명령:

ffmpeg -ss 00:01:10.871 -i hdr-original.mp4 -vf 'zscale=t=linear:npl=100,format=gbrpf32le,zscale=p=bt709,tonemap=tonemap=hable,zscale=t=bt709:m=bt709:r=tv,format=yuv420p' -vframes 1 hable.png

결과:

hable

원했던 결과물에 꽤 가까운 듯 합니다… 그럼 비교 대상으로…

reinhard

명령:

ffmpeg -ss 00:01:10.871 -i hdr-original.mp4 -vf 'zscale=t=linear:npl=100,format=gbrpf32le,zscale=p=bt709,tonemap=tonemap=reinhard,zscale=t=bt709:m=bt709:r=tv,format=yuv420p' -vframes 1 reinhard.png

결과:

reinhard

위의 사진과 hable간의 차이를 확인하기 어려우실 수 있기에, 비교하는 도구를 밑에 만들어 두었습니다:

(왼쪽에 hable, 오른쪽에 reinhard)

그리고 mobius가 얼마나 채도가 높은지 확인하고 싶으시다면:

(왼쪽에 mobius, 오른쪽에 hable)

(왼쪽에 mobius, 오른쪽에 reinhard)

이제 사용 가능한 프리셋의 설명이 끝났으니, 각 프리셋 안에 조절 가능한 한 값에 대해 설명해 드리겠습니다. 그건 바로…

채도 낮추기 (Desaturation)

ffmpeg의 설명서에서:

이 밝기 레벨을 초과하는 부분들의 채도를 낮춥니다. 값이 높을수록, 더 많은 색상 정보가 보존됩니다. 이 설정값은 밝은 부분의 색상이 부자연스럽게 날아가는 것을 방지하기 위해, 흰색으로 (부드럽게) 변환합니다. 이렇게 하면 범위를 벗어난 색상에 대한 정보를 줄이는 대신, 이미지가 더 자연스럽게 느껴집니다.

기본값인 2.0은 보수적이며 대부분 하늘이나 직사광선이 그대로 비친 표면에 적용합니다. 0.0의 설정값은 이 기능을 비활성화합니다.

이는 Daniel Stevens의 원글에서의 설명과도 일치합니다. 하지만, 그는 0 설정값을 사용하여 이 옵션을 끄는 것을 추천합니다. 하지만 설명서는 “밝은 부분의 색상이 부자연스럽게 날아가는 것"을 방지하는 데 좋기에 이 기능을 켜두는 것이 좋은 것처럼 설명을 합니다.

그러면 채도 낮추기 기능을 0으로 설정한 mobius 프레임을 생성한 후, 원래의 mobius 사진(다시 설명드리지만, 기본값은 2.0입니다. 만약 채도 낮추기 설정값을 적지 않았을 경우, 2.0으로 가정합니다)과 비교해 보겠습니다:

ffmpeg -ss 00:01:10.871 -i hdr-original.mp4 -vf 'zscale=t=linear:npl=100,format=gbrpf32le,zscale=p=bt709,tonemap=tonemap=mobius:desat=0,zscale=t=bt709:m=bt709:r=tv,format=yuv420p' -vframes 1 mobius-desat-0.png

그냥 사진만을 표시하는 것은 별로 의미가 없기에, 다시 비교 슬라이더를 밑에 준비해두었습니다:

(왼쪽에 mobius, 오른쪽에 채도 낮추기 설정값이 0으로 설정된 mobius)

그리고 나머지들은 다음과 같습니다:

ffmpeg -ss 00:01:10.871 -i hdr-original.mp4 -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' -vframes 1 hable-desat-0.png
ffmpeg -ss 00:01:10.871 -i hdr-original.mp4 -vf 'zscale=t=linear:npl=100,format=gbrpf32le,zscale=p=bt709,tonemap=tonemap=reinhard:desat=0,zscale=t=bt709:m=bt709:r=tv,format=yuv420p' -vframes 1 reinhard-desat-0.png

(왼쪽에 hable, 오른쪽에 채도 낮추기 설정값이 0으로 설정된 hable)

(왼쪽에 reinhard, 오른쪽에 채도 낮추기 설정값이 0으로 설정된 reinhard)

다른 값을 시도해보겠습니다. 저는 reinhard 프리셋에서 0.5로 한번 생성하겠습니다만, 만약 다른 프리셋을 원하신다면 명령에서 대치하셔서 실행하시면 됩니다. 그리고 비교 결과는 다음과 같습니다:

(왼쪽에 채도 낮추기 설정값이 0.5로 설정된 reinhard, 오른쪽에 reinhard)

제가 생각하기에는 개인 취향에 따라 갈릴 것 같습니다. 만약 이 설정값이 왜 비활성화되어야 하는지 설명해주신다면 이 섹션을 수정하겠습니다.

그러면, 무슨 프리셋을 사용하여 HDR 둥영상을 SDR로 변환해야 할까요?

(개인적인) 비교와 생각들

위에 실시한 실험을 바탕으로 한 개인적인 생각들을 적어보겠습니다.

일단 mobius 알고리즘은 색상을 변조시키면서 너무 채도를 과하게 입히기 때문에 곧바로 고려 대상에서 제외했습니다. 만약 그렇게 색상이 화려한 것을 좋아하신다면 좋은 선택이 되실 수도 있지만, 제 느낌에는 둥영상의 색상을 너무 이상하게 바꾸기 때문에 사용하기 어려운 것 같습니다.

그러면 hablereinhard가 남습니다. reinhard는 밝은 사진을 생성하는데, (HDR과 SDR 버전이 둘 다 존재하는 컨텐츠를 사용하여 ffmpeg의 출력과 비교하였을 때) hable이 원본 SDR 소스와 가장 비슷했던 것 같습니다. 다시 설명드리지만, 개인 취향에 따라 갈릴 것 같습니다만, 저는 hable이 잘 못하는, 어두운 장면이 잘 보이는 것을 선호하기에 reinhard를 사용할 듯 합니다.

사용 예시

HDR에서 SDR 톤매핑을 적용한 소프트웨어들이 사용하는 알고리즘이 궁금하여 찾아본 결과 다음을 발견했습니다:

실제로 둥영상 변환하기

이제 선호하시는 알고리즘을 정하신 다음, 둥영상 전체를 변환하는 것은 다음과 같이 -ss-vframes 인수들을 제거한 후 사용할 인코더와 같은 인수들을 추가하는 것만큼 쉽습니다:

ffmpeg -i input.mp4 -vf 'zscale=t=linear:npl=100,format=gbrpf32le,zscale=p=bt709,tonemap=tonemap=reinhard,zscale=t=bt709:m=bt709:r=tv,format=yuv420p' -c:v libx264 -preset veryfast -crf 18 -c:a aac -b:a 160k -movflags +faststart output.mp4

결론

모든 상황에 적합한 HDR에서 SDR 톤매핑 해결 방안은 없지만, 위에 적어둔 실험과 설명들은 절차가 어떻게 되는지, 그리고 무엇을 해야 선호하는 알고리즘을 찾을 수 있는지에 대한 이해를 제공할 겁니다.


  1. 아이폰 8/8 플러스 이상의 모든 기종들은 HDR 재생을 지원하지만, 소프트웨어만을 고려하였을때로 한정됩니다. 특정 아이폰(방금 말씀드린 아이폰 8/8 플러스와 “보급형"급 모델인 아이폰 SE 등)들은 하드웨어상에서 실제 HDR를 표시할 수 없습니다↩︎

  2. 엄밀히 따지면, 삼성은 갤럭시 S8/S8+와 노트 8부터 “모바일 HDR” 재생을 지원했습니다. 하지만 HDR10+ 지원은 위에 명시된 기기부터 적용되었습니다. ↩︎ ↩︎

비슷한 게시물

댓글