2011년 12월 22일 목요일

FFMPEG을 가지고 MPEG4 Video 영상 인코딩하기

출처 : http://iamlow.tistory.com/entry/FFMPEG%EC%9D%84-%EA%B0%80%EC%A7%80%EA%B3%A0-MPEG4-Video-%EC%98%81%EC%83%81-%EC%9D%B8%EC%BD%94%EB%94%A9%ED%95%98%EA%B8%B0

여기에는 테스트한 발자취를 남긴다. 따라서 삽질하는 과정도 포함되어 있다.

이 작업을 한 이유는 이전에 작업한 libx264 라이브러리가 안드로이드 플랫폼에서 영상을 인코딩할 때 성능문제가 발생했기 때문이다. 약 6프레임 정도 밖에 나오지 않는다.. 그래서 대체할 코덱을 찾느라고 작업했다.

0. FFmpeg 0.8.2 버전을 가지고 테스트하였고, 예제는 ffmpeg-0.8.2/doc/example/encoding_example.c 파일을 사용하였다.

1. FFmpeg을 가지고 MPEG4 Video 영상을 인코딩 하기 위해 사용한 옵션은 아래와 같다.

249     /* put sample parameters */                                     
255     c->bit_rate         = 300 * 1000;                               
257     /* resolution must be a multiple of two */                      
258     c->width = 352;                                                 
259     c->height = 288;                                                
260     /* frames per second */                                         
261     c->time_base= (AVRational){1,25};                               
262     c->gop_size = 25; /* emit one intra frame every ten frames */   
263     c->pix_fmt = PIX_FMT_YUV420P;

2. H.264와 달리 PTS 값을 매번 설정하지 않고 아래와 같이 설정하면 경고나 오류없이 동작한다.

221     AVFrame *picture;
326     picture->pts = AV_NOPTS_VALUE;

3. 그러나 문제는... CBR 비트레이트 컨트롤이 제대로 안되는 문제가 발생하였다.
   구글링과 삽질을 통하여 옵션을 찾았다. bufsize와 maxrate 옵션을 설정하니 CBR 비트레이트 설정이 가능하였다. (bufsize maxrate 옵션이 무것인지는 인터넷 찾아보면 어렵지 않게 찾을 수 있다.) 이 설정은 영상을 네트워크로 전송할 때와 같은 경우에 쓰면 된다.
   ffmpeg 바이너리를 가지고 아래와 같이 설정하면 된다.

   $ ffmpeg -i example.y4m -vcodec mpeg4 -bufsize 300K -b 300K -maxrate 300K video_300k.mp4
   
4. 테스트 코드에 적용시켜 보았다.

249 /* put sample parameters */ 
250 c->rc_max_rate = 300 * 1000; 
251 c->bit_rate = c->rc_max_rate >> 1; 
252 c->rc_buffer_size = c->rc_max_rate; 
254 /* resolution must be a multiple of two */ 
255 c->width = 352; 
256 c->height = 288; 
257 /* frames per second */ 
258 c->time_base= (AVRational){1,25}; 
259 c->gop_size = 25; /* emit one intra frame every ten frames */ 
260 c->pix_fmt = PIX_FMT_YUV420P; 

   테스트 결과 동작은 하는데.... 아래와 같은 

   [mpeg4 @ 0x90ba020] rc buffer underflow

   메시지가 발생한다... 내가 뭔가 빠뜨린것 같은데... 설정이 부족한거 같다.
   구글링했으나 못찾았다..

   그래서 코드를 뒤졌다..

   $ grep -R "rc buffer underflow" ../../*
../../libavcodec/ratecontrol.c:            av_log(s->avctx, AV_LOG_ERROR, "rc buffer underflow\n");

   뭔가 있다..

  $ vi ../../libavcodec/ratecontrol.c
   
266 int ff_vbv_update(MpegEncContext *s, int frame_size){
267     RateControlContext *rcc= &s->rc_context;
268     const double fps= 1/av_q2d(s->avctx->time_base);
269     const int buffer_size= s->avctx->rc_buffer_size;
270     const double min_rate= s->avctx->rc_min_rate/fps;
271     const double max_rate= s->avctx->rc_max_rate/fps;
272 
273 //printf("%d %f %d %f %f\n", buffer_size, rcc->buffer_index, frame_size, min_rate, max_rate);
274         av_log(s->avctx, AV_LOG_ERROR, "%d %f %d %f %f\n", buffer_size, rcc->buffer_index, frame_size, min_rate, max_rate);
275     if(buffer_size){
276         int left;
277 
278         rcc->buffer_index-= frame_size;
279         if(rcc->buffer_index < 0){
280             av_log(s->avctx, AV_LOG_ERROR, "rc buffer underflow\n");
281             rcc->buffer_index= 0;
282         }

   279 라인에서 rcc->buffer_index 값 때문에 메시지를 찍네..
   buffer_index 값으로 검색 또 해봤다..

66 int ff_rate_control_init(MpegEncContext *s)
.
.
.
127     rcc->buffer_index= s->avctx->rc_initial_buffer_occupancy;

   127 라인에서 avctx->rc_initial_buffer_occupancy 값을 설정하네.. 빙고!!!
   구글링 해보니 rc_max_rate값과 동일하게 설정을 하더라...
   그래서 아래와 같이 설정을 했다.

249     /* put sample parameters */                                     
250     c->rc_max_rate      = 300 * 1000;                               
251     c->bit_rate         = c->rc_max_rate >> 1;                      
252     c->rc_buffer_size   = c->rc_max_rate;                           
253     c->rc_initial_buffer_occupancy = c->rc_max_rate;                
254     /* resolution must be a multiple of two */                      
255     c->width = 352;                                                 
256     c->height = 288;                                                
257     /* frames per second */                                         
258     c->time_base= (AVRational){1,25};                               
259     c->gop_size = 25; /* emit one intra frame every ten frames */   
260     c->pix_fmt = PIX_FMT_YUV420P;                                   
  
   아래 경고 문구가 사라짐..ㅋㅋ 행복하구나..

 [mpeg4 @ 0x90ba020] rc buffer underflow

이렇게 쓰면 될 듯... 이상!!
위 코드를 보면 알겠지만 비트레이트 설정한데로 정확하게 나오지는 않는다.
rc_max_rate와 bit_rate 항목을 알맞게 설정해서 써야한다.

테스트 코드 아래 첨부..



* 성능 테스트 결과
  - 비트레이트가 낮을 수록 성능이 떨어지는 것 같음.
  - rc_initial_buffer_occupancy 값을 어떻게 설정하느냐에 따라 비트레이트가 달라지는 것 같음.
  - [mpeg4 @ 0x8d60020] impossible bitrate constraints, this will fail 이런 메시지가 발생함.
     비트레이트와 최대 비트레이트를 같게 하면 나타남..
  - 테스트 중 낮은 비트레이트를 설정하면   [mpeg4 @ 0x90ba020] rc buffer underflow] 
     메시지가 동일하게 발생함. 비트레이트를 터무니 없게 낮게 설정할 경우 발생하는 것으로 판단됨. CIF 영상에 비트레이트를 100K 로 설정하면 발생하나 QCIF에 비트레이트 100K로 설정하면 정상적으로 영상이 출력됨.
  - 비트레이트를 맞추기 위해서 해상도, 프레임레이트 별로 설정하는 rc_max_rate, rc_buffer_size, rc_initial_buffer_occupancy 값을 테스트하여 표로 만들어서 정리해야 할 것으로 생각됨.

249 /* put sample parameters */ 
250 c->rc_max_rate = 300 * 1000; 
251 c->bit_rate = c->rc_max_rate >> 1; 
252 c->rc_buffer_size = c->rc_max_rate; 
253 c->rc_initial_buffer_occupancy = c->rc_max_rate;      

댓글 없음:

댓글 쓰기