[H264] 영상 업로드 실패 사태 분석 - 2. YUV 색공간과 영상 압축
앞선 반성과 함께, 도대체 왜 그럼 YUV 공간이 홀수 해상도를 지원하지 않는가에 대해 더 파보다가 알게 된 사실들. 사실 3년 전 이 회사로 이직해 오면서 영상 다룰 일이 많아, 예전부터 자주 들었던 개념이 많았는데(특히나 이전 팀에 있을 때는 더더욱), 그 때는 하나도 이해가 안 되다가 이번 사태를 계기로 조금씩 이해가 되어 정리해 보고자 한다.
색공간
색을 표현하는 방식이다. 시스템마다 같은 색을 표현하더라도 어떤 정보를 조합해서 표현할 것인가가 달라지는데, 그 때 사용되는 개념이다. 대표적인 색공간으로 RGB, YUV가 있다.
- RGB: Red, Green, Blue
- 빨강, 초록, 파랑 세 가지 빛을 섞어서 색을 만듦
(255, 0, 0): 빨간색
- 모니터, 카메라, 이미지 파일에서 주로 사용
- 특히 모니터, 디스플레이 등 인간 눈이 바로 보는 하드웨어의 표준 색공간은 RGB
- 장점: 직관적이고 하드웨어에서 바로 사용 가능
- 단점: 세 채널 모두 원본 픽셀 크기이기 때문에, 파일 크기가 큼
- 빨강, 초록, 파랑 세 가지 빛을 섞어서 색을 만듦
- YUV (또는 YCbCr)
- Y: 밝기 (Luminance)
- 원본 해상도 그대로 사용
- U/V (또는 Cb/Cr): 색상 정보 (Chrominance)
- 색상을 원본 픽셀 크기에서 압축
- 혹시 이렇게 색상 정보를 압축하면, 원본의 정보가 손실되는 것 아닐까 생각할 수 있는데, 사실이긴 하나, 큰 문제가 되지 않는다고 함
- 과학적으로 인간의 눈은 밝기 변화에 민감하나, 색상 변화에는 둔감함
- 따라서, 색상 정보를 줄여도 화질 차이를 거의 느끼지 못함
- (상술한 특징으로부터 비롯되어) 영상 압축, 방송 표준에서 자주 사용
- 장점: 색상 정보를 압축하기 때문에, RGB 색공간으로 표현할 때에 비해 파일 크기 대폭 감소
- 단점: RGB로 변환하는 과정 필요
- Y: 밝기 (Luminance)
- 기타 색공간: CMYK, HSV/HSL, …
YUV 색공간
YUV 색공간에서도, 압축 과정에서 픽셀을 어떻게 샘플링하느냐에 따라, 방식이 나뉜다.
- 4:4:4: Y, U, V 모두 원본 크기 (압축 안 함, 고품질)
- 4:2:2: U, V를 가로만 절반 (방송용)
- 4:2:0: U, V를 가로/세로 모두 절반 (유튜브, 넷플릭스 등 일반 영상)
H.264와 YUV 색공간
H.264 코덱에서는 정확히는 YUV 색공간 중에서도 YUV 4:2:0 방식을 택하고 있다. 당연히, 픽셀 크기를 가로 세로 모두 절반으로 압축하기 때문에, 압축 효율이 월등히 좋다. 1920x1080 영상 한 프레임을 기준으로 살펴 보자.
- RGB: 약 6,220,800 개의 픽셀을 저장해야 함
- R: 1920x1080 = 2,073,600 픽셀
- G: 1920x1080 = 2,073,600 픽셀
- B: 1920x1080 = 2,073,600 픽셀
- YUV 4:2:0: U, V의 색상 정보를 압축할 수 있어, RGB 방식보다 약 절반 정도 되는 3,110,400 개의 픽셀만 저장하면 됨
- Y: 1920x1080 = 2,073,600 픽셀
- U: 960x540 = 518,400 픽셀 (절반)
- V: 960x540 = 518,400 픽셀 (절반)
이렇게 압축 효율이 좋은데, 과학적으로 인간이 색상 정보를 줄여도 화질 차이를 거의 느끼지 못한다고 하니, 당연히 YUV를 쓰는 게 이득이다.
영상의 인코딩과 디코딩
우리가 영상을 보기 위해서는, 아래와 같은 인코딩, 디코딩 과정이 필요하다. 즉, 우리가 일반적으로 카메라에서 받은 영상을 저장할 때는 압축을 위해 인코딩하고, 영상을 열어서 직접 볼 때는 압축된 영상을 디코딩해서 봐야 하는 것이다.

- 인코딩 = 영상의 압축
- 카메라/캡처: 센서가 빛을 받아 RGB로 변환
- RGB → YUV: 색공간 변환 (FFmpeg/libx264 인코더가 자동 처리)
- YUV 4:2:0: 색상 정보를 절반으로 줄임 (500GB → 250GB 상당)
- 압축: libx264가 중복 정보 제거 (250GB → 2-4GB)
- 저장: MP4 파일로 저장
- 디코딩 = 영상 재생
- 파일 읽기: 하드디스크, SSD에서 로드
- 압축 해제: libx264 디코더가 YUV 데이터 복원
- YUV → RGB: 하드웨어 단에서 변환. 특히 요즘에는 GPU를 이용한 하드웨어 단에서의 초고속 변환이 가능함
실제로 이전 팀에서 영상 미디어 플레이를 위해 Intel CPU QSV 기능을 이용하자 디코딩 성능이 매우 향상되었고, NVIDIA GPU 하드웨어에서는 nvdec을 이용했더니 더 향상되었다는 말을 들었는데, 그게 이 과정에서 적용되는 말이었다. 이제야 이해해 버렸다.
- 출력: 모니터가 RGB 신호를 받아 픽셀 표시
색공간 변환
카메라나 우리가 사용하는 TV, 모니터 등 디스플레이는 RGB 색공간을 사용한다고 했다. 그러니까, 당연히 인코딩과 디코딩 과정 모두에서 색공간 변환이 일어날 것임을 추측할 수 있다. 그러나, 사용자 입장에서 우리는 이걸 몰라도 된다. 하드웨어와 소프트웨어 단에서 알아서 자동으로 처리되기 때문이다.
- 인코딩
- 카메라, 화면 캡처: RGB로 촬영
- ffmpeg, 인코더 등: RGB → YUV 변환 (자동)
- libx264: YUV 데이터 압축해서 파일에 저장
- 디코딩
- 영상 플레이어, 브라우저: 파일 읽어서 YUV 데이터 복원
- GPU, 비디오 디코더: YUV → RGB 변환 (자동)
- 모니터: RGB 신호 받아서 화면에 표시
- 이 과정에서 영상을 처리하는 주체들은 다음과 같다.
- 영상 플레이어: VLC, YouTube, Windows Media Player, 곰플레이어, 팟플레이어, …
- 영상 처리 도구: ffmpeg
- GPU: 하드웨어 가속으로 초고속 변환, 요즘은 전용 칩이 있음
- 카메라: 센서 raw 데이터 → RGB → YUV
이 모든 과정이 알아서 처리되어 우리가 지금 이렇게 유튜브도 보고, TV 영상도 본다니. 정말 알고 보면 놀라운 기술의 세계다.
변환 오버헤드
그리고 누누이 말하듯, 이렇게 변환하는 과정에서 오버헤드가 있음에도 불구하고 색 공간을 변환하는 건, 크기 절약으로 얻는 이점이 변환 오버헤드에 비해 압도적으로 크기 때문이다. 위에서 1920x1080 한 프레임을 기준으로 픽셀 양을 계산해 봤는데, 이제는 1시간 짜리 24FPS 영상을 예로 들어 계산해 보자.
- RGB 사용 시, 1920 x 1080 x 3채널 x 24fps x 3600초 = 약 500GB (무압축)
- 한 프레임의 픽셀 수 = 1920 × 1080 = 2,073,600 픽셀
- R, G, B 각 3채널 적용: 2,073,600 픽셀 × 3채널 (R, G, B) = 6,220,800 픽셀
- 각 픽셀을 1바이트로 저장: 6,220,800 값 × 1바이트 = 6,220,800 바이트
- 각 색상 값은 0~255의 범위를 가지기 때문에, 1바이트를 사용해야 함
- 따라서 한 프레임의 용량은 약 5.93MB 6,220,800 바이트 ÷ 1024 = 6,075 KB 6,075 KB ÷ 1024 = 5.93 MB
- 24FPS 1초 분량 영상의 용량: 5.93 MB × 24프레임 = 142.32 MB
- 1시간 분량 영상의 용량은 약 500.34GB
- 142.32 MB × 3,600초 = 512,352 MB
- 512,352 MB ÷ 1024 = 500.34 GB
- YUV 사용 시, RGB 영상 대비 절반 크기
- 한 프레임의 데이터 양은 약 3.11MB
- Y (밝기): 1920 × 1080 = 2,073,600 바이트
- U (색상): 960 × 540 = 518,400 바이트 (가로/세로 각각 절반)
- V (색상): 960 × 540 = 518,400 바이트 (가로/세로 각각 절반)
- 1시간 분량의 영상은 약 262GB
- 3,110,400 바이트 × 24fps × 3600초 = 268,738,560,000 바이트 = 268,738 MB = 262 GB
- 한 프레임의 데이터 양은 약 3.11MB
그냥 단순 산술 계산으로 500GB가 나온다고 했는데, 이게 얼마나 미친 크기냐면. 압축 안 한 2시간 짜리 HD 영화 한 편을 보려면, 1TB의 하드 디스크가 있어야 하는 크기다. 영화 한 편 저장해서 보겠다고 회사에서나 지원해 줄 법한(?) 하드디스크를 장착하고 있어야 하는 것(…). 그럼 넷플릭스 같은 스트리밍 서비스로 받아서 보면 되지 않느냐고 한데, 이건 더 충격적이다. 100Mbps 인터넷으로는 11시간(…)이 걸리는 속도고, 1Gbps 인터넷을 쓰더라도 1시간이 넘게 걸린다.
그러니 오버헤드 따위야, 무시할 수 있음이 체감된다. 색공간의 변환은 한 번만 발생하고, 게다가 요즘 같이 하드웨어가 빵빵한 때는 GPU가 알아서 빠르게 다 해주니 그냥 무시되는 수준이라고 봐도 무방하다. 그에 비해, 이걸 변환하지 않고 저장한다면, 저장 공간만 10~100배가 더 필요해 질 것이며, 이걸 네트워크로 전송한다고 가정해 보면? 대역폭도 그만큼 잡아 먹어야 되는데, 아주 끔찍하다.
코덱의 필요성
색공간 변환 뿐 아니라, 코덱 적용해서 압축 시 엄청난 일이 벌어진다. H.264는 공간 압축, 시간 압축, 모션 예측, 엔트로피 코딩 등 다양한 기법을 도입해서 영상을 압축해 버리는데, 그 결과가 가히 놀랄만한 수준이다.
- 일반적인 H.264 압축률
- 저품질: 100:1 압축
- 중품질: 80:1 압축
- 고품질: 60:1 압축
- 최종 파일 크기
- YUV 4:2:0 무압축: 262GB
- 저품질: 262/100 = 2.62GB
- 중품질: 262/80 = 3.28GB
- 고품질: 262/60 = 4.37GB
결과적으로, 아래와 같은 흐름으로 인코딩과 디코딩이 이루어진다.
인코딩 과정:
RGB (원본) YUV 변환 압축() 최종 파일
500 GB ────► 250 GB ────► 2-4 GB ────► 💾
(50% 절감) (99% 압축)
디코딩 과정:
파일 읽기 압축 해제 YUV→RGB 화면 출력
💾 2-4 GB ────► 250 GB ────► 500 GB ────► 🖥️
(메모리상에서만 일시적 존재)
카메라의 물리적 한계
사실 이 과정에서 근본적으로 궁금한 게 있다. 애초에 카메라에서 그럼 YUV 색공간을 사용하면 되지, 왜 RGB를 사용하는가? 그것은 카메라의 물리적 한계 때문이라고 한다.
- 카메라에서 영상을 저장할 때, 이미지 센서를 사용하는데, 그 이미지센서가 물리적으로 R, G, B 중 하나의 색만 측정할 수 있음
- 이미지 센서는 빛의 강도만 감지할 수 있을 뿐 색을 구분하지 못하기 때문에,
- 센서 위에 색깔을 구분하기 위한 물리적 필터를 부착하는데,
- 그것이 R, G, B 중 하나만 부착되어 있어, 각 픽셀 당 R, G, B 중 하나의 색만 측정이 가능한데,
- 주변 픽셀 정보를 이용해서 나머지 색을 추정한다(즉, 빨강 픽셀 위치에서 주변의 초록, 파랑 값을 보간해서 추정하는 방식)고 하는데,
- 어쨌거나 저쨌거나, 물리적으로 RGB 색공간을 이용할 수 밖에 없는 구조이다.
- 그러면 왜 YUV 센서를 만들지 않을까?
- 애초에 빛의 파장 자체를 YUV 색공간이 사용하는 Y, U, V로 분리하는 것 자체가 기술적으로 불가능함
- RGB를 이용해 Y를 계산하고, 그 이후에 U, V를 계산해야 함
- Y 필터: RGB를 혼합해야 계산할 수 있음
- U 필터: B-Y를 계산해야 함
- V 필터: R-Y를 계산해야 함
- 그런데, 가능하다고 하더라도, 굳이 그렇게 할 이유가 없기도 함
- 모니터, 디스플레이 기본 색공간이 다 RGB고,
- 사진 편집, 이미지 처리 등도 다 RGB로 진행하고,
- YUV는 압축, 전송 효율성을 위해 고안된 것이니,
- 기술적으로 가능하더라도 효용성이 크지 않은데?
- 애초에 빛의 파장 자체를 YUV 색공간이 사용하는 Y, U, V로 분리하는 것 자체가 기술적으로 불가능함
더 깊은 것은, 더 이상 파보지 않아도 될 것 같다(…). 결론적으로, 아래와 같은 흐름이라고만 기억해 두자.
물리 세계의 빛
↓
RGB 필터 (물리적 한계로 RGB만 가능)
↓
RGB 센서 데이터
↓
소프트웨어 변환 → YUV (압축 효율)
↓
저장/전송
↓
소프트웨어 변환 → RGB (디스플레이 출력)
역사적 배경
그렇다면 이제 진짜로 마지막으로 궁금한 게 있다. 애초에 그럼 YUV가 나왔다는 건, GPU 하드웨어 가속이 되니까 가능했던 걸까? 변환 과정 오버헤드가 GPU 가속으로 인해, 더 빨라졌고, CPU로 변환하면 문제가 될 것 같은데.
YUV의 역사:
1950년대 ─────► 2003년 ─────► 2006-2008년 ─────► 현재
│ │ │ │
TV 방송 H.264 GPU 가속 필수 기능
(GPU 없음) (CPU 디코딩) (선택 사항) (거의 표준)
결론적으로, 역사는 정반대라고 한다. YUV는 GPU보다 훨씬 더 먼저 나왔고, H.264가 제정된 초기에는 CPU로 디코딩했다고 한다. 다만, 문제가 된 것은 HD 영상이 등장하면서부터라고. SD 영상까지만 해도, CPU로 디코딩하는 데에 크게 문제가 없었다고 한다.
- 1950년대: YUV 등장, 흑백 TV → 컬러 TV 전환 시대
- 기존 흑백 TV와 호환되어야 했음
- Y(밝기)만 쓰면 흑백, Y+UV 쓰면 컬러
- GPU는 존재조차 하지 않던 시절
- 1990년대: 디지털 비디오 시대
- MPEG-1 (1993): VCD, 352x240
- MPEG-2 (1995): DVD, 720x480/576
- 영상 해상도 자체가 낮기 때문에, CPU로 충분히 디코딩 가능
- 2003년: H.264 표준 제정
- 초기에는 CPU 디코딩만 가능
- 주류 해상도: SD(480p/576p)
위와 같은 흐름이었는데, HD 화질의 영상이 등장하며 CPU 디코딩만으로 부하가 감당되지 않기 시작했다고 한다.
- 프레임 드랍
- 과다 발열
- 영상 디코딩 시 다른 작업 자체가 불가 그렇게, 전용 하드웨어의 필요성이 대두되고, GPU가 등장하며 GPU 하드웨어 가속이란 것도 더 활발하게 발전하기 시작했다는 것!
뭐라고 끝을 맺어야 할지 모르겠는데. 뭐, 반성으로부터 시작된 알고 보면 놀라고도 신비한 영상 세계 기술 탐방 이야기!였다. 끗~
댓글남기기