2009년 9월 1일 화요일

H.264 비디오 압축원리와 하드웨어 구현

요즘 연구실에서 하는 작업은 H.264 Intra Prediction Encoder의 HDL 구현이다.
HDL은 Verilog로 구현하고 있으며, 최종적으로 구현과 검증이 완성되면 칩으로 굽게 될 것이다.
H.264는 ITU-T와 ISO에서 공동으로 완성한 Video Compression 표준이다.

우선, Video Compression이란 말 그대로 영상을 압축하는 것이다.
영상을 압축하지 않으면 파일로 보관하기에도 용량이 너무 크고, HDTV와 같은 실시간 전송은 더더욱 힘들다.
압축하지 않은 영상의 용량이 얼마나 큰지는 다음과 같이 간단히 짐작할 수 있다.
한 pixel을 나타내기 위해서는 3 byte (혹은 24 bit)이 필요하다.
모니터에 직접 전송되는 신호는 YUV 3개 신호인데, Y는 밝기(luminance)를 나타내고, U와 V는 색상(chrominance)를 나타낸다.
Y,U,V 각각 8bit로 구성되기 때문에 2^8 = 256개 값을 분간할 수 있다.
YUV는 RGB(Red Green Blue)로 산술적 변환이 가능하고,
예전 흑백 TV 시절에는 Y값만 사용하다가 나중에 U와 V가 추가된 것이라고 한다.

여튼, 해상도가 1280*1024의 영상이라면, 하나의 frame에 1280KB * 3 = 3.75MB의 용량이 필요하다.
그리고 동영상의 움직임이 자연스러우려면, 초당 30 frame은 있어야 한다고 한다.  (초당 20이면 인간 눈이 끊김을 감지할 수 있다).
그러면 1초의 동영상은 112.5MB, 1분의 동영상은 6750MB = 6.59GB,
2시간 짜리 영화는 791GB라는 계산이 나온다;  이는 현재의 저장 기술, 전송 기술로는 감당할 수 없는 용량이다.

하지만 다시 생각해보면, 한 frame의 1310720개 pixel이 모두 1초에 30번이나 변화하지는 않을 것이다.
또한 한 frame의 1310720개 pixel의 인접 pixel이 모두 완전히 다르지도 않을 것이다.
만약 모두 변화하거나, 다르면 의미 있는 영상이 될 수 없다.
오히려 의미 있는 영상이라면, 대부분의 pixel들은 고정되거나, 주변과 연속성을 가지며, 움직임이 있는 일부, 혹은 사물의 경계에 있는 일부에만 큰 변화가 있다.
좀 더 구체적인 예로, 김연아 선수가 스케이트를 타는 모습을 생각해보자.
스케이트를 타는 빙판은 계속 하얀색이며, 빙판 영역 내에서는 거의 변화를 보이지 않을 것이다.
또한 김연아가 1/30초 동안 앞으로 가다가, 다음 1/30초에는 뒤로 가지 않으므로, 김연아의 움직임에도 규칙성이 있다.
이러한 연속성과 규칙성으로 영상을 예측해서, 그 차분만큼만 encoding 하는 것이 영상 압축이다.
예측이 정확할수록 차분이 작아지고, 압축된 영상의 용량도 작아진다.

H.264는 크게 2가지 방식의 prediction을 한다:

  1. Inter Prediction - ME(Motion Estimation)을 적용하여, 이전 frame과 현재 frame의 motion vector로 다음 frame의 움직임이  어떻게 될지 예측한다.
    ex) 김연아의 움직임
  2. Intra Prediction - 현재 frame 내에서, 영역들의 연속성을 추측한다.
    ex) 빙판 영역의 연속성

H.264 표준이 발표된 것은 2003년이며, 관련 논문들은 이미 여러 편 나와 있다.
현재 연구실에서 진수형을 필두로, 나와 경헌이가 작업하여, 세계에서 가장 빠른; H.264 encoder를 만드는 것이 목표이다.
경헌이가 Inter Prediction 구현을 하고 있고, 나는 Intra Prediction 구현을 하고 있다.

보다 구체적으로 H.264 Intra Prediction은 다음 단계로 구성된다:
한 prediction frame은 16×16 기준이다.

  1. 4×4 block 16개에 대해 9가지 I4 prediction을 적용한다.
  2. 실제 pixel 값과 9개 prediction 값의 차분을 구한다.
  3. 차분을 Hadamard Transform 해서 SATD(Sum of Transformed Differences)를 구한다.
  4. SATD가 가장 작은 mode를 선택해서 그 mode의 차분을 DCT(Discrete Cosine Transform) 한다.
  5. DCT 결과를 Quantization 한다.
  6. Quantization 결과를 Inverse Quantization 한다.
  7. IQ 결과를 IDCT 한다.
  8. IDCT 결과인 reconstructed block을 다음 4×4 block prediction에 활용한다.

이 외에 16×16 block 1개를 4개 I16 prediction을 적용해서, 최종적으로 I4, I16 중 SATD가 작은 mode를 선택한다.  Luma block은 I4, I16을 다 수행하고, 4개 Luma마다 하나 있는 Chroma는 I16과 같은 I8 prediction을 수행한다.  이렇게 얻은 Intra prediction의 SATD가 Intra prediction의 SATD 보다 작으면, Intra의 DCT 결과 (위 5번 결과)를 encoder에 보내서 압축 영상을 생성한다.

이 복잡한 과정에서, Luma I4 prediction만 생각하면 위의 8개 단계가 있다.
이를 C program으로 작성해서, 범용 프로세서에서 처리할 수 있을 것이다.  (실제로 이러한 프로그램은 H.264/AVC JM Reference Software로 제공되고 있다)
하지만 디지털 캠코더와 같이 실시간으로 H.264 encoding을 수행해야 하는 application에서는 범용 프로세서로 요구되는 timing constraint를 만족시킬 수 없다.
ADD를 1 cycle에, MULT를 2 cycle에 처리하는 processor를 가정하더라도, 위 작업들을 직렬로 처리하면 요구 조건 이상의 cycle이 필요하다 (알고리즘에 대한 자세한 계산은 논문에도 있으니 생략;; )
실시간 encoding을 위해서는 H.264 encoding만을 위한 dedicated architecture가 필요하게 된다.
그리고 이 architecture 내에서는 병렬 처리를 위해 물론 여러개의 adder과 multiplier를 활용하겠지만, hardware cost를 줄이기 위해 hardware를 요령껏 재활용해야 한다.

이와 같은 hardware를 Verilog로 설계하고 있다.
한 cycle에 4개 pixel (1개 row)를 처리할 수 있는 I4 mode predictor를 2개 둬서, 4*5=20 cycle에 하나의 4×4 block I4 prediction을 완료할 수 있는 구조로 만들고 있다.  10개 I4 mode 중 9개를 사용하고 비는 하나는 이전 확정된 best mode를 re-predict 하는 데에 사용한다.  block 처리 순서를 잘 조정해서, 다음 4×4 blcok에서 이전 block의 reconstruction이 최대한 필요없도록 해서, 1-2 block, 14-15 block에서만 bubble이 발생해서, (16 + 2) * 20 = 360 cycle에 16×16 block의 I4 prediction을 성공적으로 완료하는 것까지 확인한 단계.ㅎㅎ

이와 같은 설계에서 가장 어려운 부분은 내부적 pipelining이다.
Adder와 mux를 여러개 붙이다 보면 path가 길어져서, 동작 주파수가 낮아진다.  (simulation에서는 신호가 전파되는 시간을 고려하지는 않지만, 물리적으로는 1um를 전파하는데에 1us라도 걸린다.  1Mhz clock에서 1us는 1 cycle time이다.  위 수치들은 실값은 아니고 예시일 뿐이다).  Path를 짧게 하기 위해서는 path가 긴 곳을 flip-flop으로 끊고, 다음 clock의 rising edge에 재전파되도록 해야 한다.  그러면 flip-flop으로 끊기 전과 후는 서로 다른 시간 (혹은 서로 다른 row나 block)의 정보를 가지고 있다.  이것들이 synch를 잘 맞게 하는 것이 골치 아프고, 내가 짠 코드를 내가 이해하기도 어려워진다;;

또한 이러한 synch의 불연속성 때문에, 입력에서 들어와서 차후 단계에서 사용하고자 하는 정보는 그 단계까지 계속 buffering 해 주어야 한다.  입력에서 바로 보내면, 서로 다른 시간의 정보가 엉켜서 안드로메다로 간다;;  문제는 SATD까지 완료해야 mode 선택을 할 수 있고, prediction 값과 차분값이 DCT에서 다시 필요하다는 것이다.  9개 mode를 다 계산하기 전까지 어느 mode가 최선인지 모르기 때문에 전부 다 저장해야 한다;  이러면 이를 저장하기 위한 hardware cost가 지나치게 커진다.  이를 극복하기 위해 best mode를 선택한 후에, 그 mode를 10개 mode 중 남는 공간에 다시 prediction을 하는 기법을 택했다.
Hardware는 사용하든 말든 항상 돌아가기 때문에 100% 사용하지 않으면 그냥 낭비가 된다는 점에 유의해야 한다.  (물론 사용하지 않는 hardware의 power를 끌 수 있으면 power save가 가능하고, 저전력 embedded system 연구실에서는 이러한 연구를 하고 있는 것으로 알고 있다).

아무쪼록 요즘 이러한 일들을 하고 있다.
하면서 배우는 것도 많고, 흥미진진하다 ^^ 

댓글 없음:

댓글 쓰기