Запутался в x264 и кодировании видеокадров

Я создал тестовый драйвер для кодирования серии снятых мною изображений. Я использую libx264 и основываю свой драйвер на ответе этого парня:

ссылка StackOverflow

В моем случае я начинаю с чтения изображения JPG, преобразования в YUV и повторной передачи одного и того же кадра в цикле кодировщику x264.

Я ожидал, что, поскольку кадр тот же, выход кодировщика будет очень маленьким и постоянным.

Вместо этого я обнаружил, что полезная нагрузка NAL варьируется от нескольких байтов до нескольких КБ, а также сильно различается в зависимости от частоты кадров, которую я указываю в параметрах кодировщика.

Очевидно, я не понимаю кодирование видео. Почему размер вывода так сильно различается?

int main() 
{
  Image image(WIDTH, HEIGHT);
  image.FromJpeg("frame-1.jpg");

  unsigned char *data = image.GetRGB();

  x264_param_t param;

  x264_param_default_preset(&param, "fast", "zerolatency");
  param.i_threads = 1;
  param.i_width = WIDTH;
  param.i_height = HEIGHT;
  param.i_fps_num = FPS;
  param.i_fps_den = 1;

  // Intra refres:
  param.i_keyint_max = FPS;
  param.b_intra_refresh = 1;

  //Rate control:
  param.rc.i_rc_method = X264_RC_CRF;
  param.rc.f_rf_constant = FPS-5;
  param.rc.f_rf_constant_max = FPS+5;

  //For streaming:
  param.b_repeat_headers = 1;
  param.b_annexb = 1;

  x264_param_apply_profile(&param, "baseline");

  // initialize the encoder
  x264_t* encoder = x264_encoder_open(&param);
  x264_picture_t pic_in, pic_out;
  x264_picture_alloc(&pic_in, X264_CSP_I420, WIDTH, HEIGHT);
  // X264 expects YUV420P data use libswscale 
  // (from ffmpeg) to convert images to the right format
  struct SwsContext* convertCtx =
        sws_getContext(WIDTH, HEIGHT, PIX_FMT_RGB24, WIDTH, HEIGHT,
                       PIX_FMT_YUV420P, SWS_FAST_BILINEAR,
                       NULL, NULL, NULL);

  // encoding is as simple as this then, for each frame do:
  // data is a pointer to your RGB structure
  int srcstride = WIDTH*3; //RGB stride is just 3*width
  sws_scale(convertCtx, &data, &srcstride, 0, HEIGHT,
            pic_in.img.plane, pic_in.img.i_stride);
  x264_nal_t* nals;
  int i_nals;
  int frame_size =
        x264_encoder_encode(encoder, &nals, &i_nals, &pic_in, &pic_out);

  int max_loop=15;
  int this_loop=1;

  while (frame_size >= 0 && --max_loop)
  {
      cout << "------------" << this_loop++ << "-----------------\n";
      cout << "Frame size = " << frame_size << endl;
      cout << "output has " << pic_out.img.i_csp << " colorspace\n";
      cout << "output has " << pic_out.img.i_plane << " # img planes\n";

      cout << "i_nals = " << i_nals << endl;
      for (int n=0; n<i_nals; n++)
        cout << "nal[" << n << "] payload size = "
             << nals[n].i_payload << endl;



      // clean this input frame and grab another
      x264_picture_clean(&pic_in);
      x264_picture_alloc(&pic_in, X264_CSP_I420, WIDTH, HEIGHT);
      sws_scale(convertCtx, &data, &srcstride, 0, HEIGHT,
                pic_in.img.plane, pic_in.img.i_stride);


      frame_size=
        x264_encoder_encode(encoder, &nals, &i_nals, &pic_in, &pic_out);
  }

  delete [] data;
  return 0;
}

Мое исходное изображение JPG, которое я читаю, имеет размер 320x240 и занимает примерно 9 КБ на диске. Результат запуска того же изображения через кодировщик выглядит следующим образом:

x264 [warning]: ref > 1 + intra-refresh is not supported
x264 [info]: using cpu capabilities: MMX2 SSE2Fast SSSE3 FastShuffle SSE4.2 AVX
x264 [info]: profile Constrained Baseline, level 1.3 
------------1-----------------
Frame size = 17412
output has 3 colorspace
output has 2 # img planes
i_nals = 4 
nal[0] payload size = 26
nal[1] payload size = 8 
nal[2] payload size = 610 
nal[3] payload size = 16768
------------2-----------------
Frame size = 11
output has 3 colorspace
output has 2 # img planes
i_nals = 1 
nal[0] payload size = 11
------------3-----------------
Frame size = 11
output has 3 colorspace
output has 2 # img planes
i_nals = 1 
nal[0] payload size = 11
------------4-----------------
Frame size = 16
output has 3 colorspace
output has 2 # img planes
i_nals = 1 
nal[0] payload size = 16
------------5-----------------
Frame size = 104 
output has 3 colorspace
output has 2 # img planes
i_nals = 1 
nal[0] payload size = 104 
------------6-----------------
Frame size = 973 
output has 3 colorspace
output has 2 # img planes
i_nals = 1
nal[0] payload size = 973
------------7-----------------
Frame size = 4576
output has 3 colorspace
output has 2 # img planes
i_nals = 1
nal[0] payload size = 4576
------------8-----------------
Frame size = 4040
output has 3 colorspace
output has 2 # img planes
i_nals = 1
nal[0] payload size = 4040
------------9-----------------
Frame size = 3917
output has 3 colorspace
output has 2 # img planes
i_nals = 1
nal[0] payload size = 3917
------------10-----------------
Frame size = 3799
output has 3 colorspace
output has 2 # img planes
i_nals = 1
nal[0] payload size = 3799
------------11-----------------
Frame size = 2454
output has 3 colorspace
output has 2 # img planes
i_nals = 1
nal[0] payload size = 2454
------------12-----------------
Frame size = 1641
output has 3 colorspace
output has 3 colorspace
output has 2 # img planes
i_nals = 1
nal[0] payload size = 1641
------------13-----------------
Frame size = 1121
output has 3 colorspace
output has 2 # img planes
i_nals = 1
nal[0] payload size = 1121
------------14-----------------
Frame size = 247
output has 3 colorspace
output has 2 # img planes
i_nals = 1
nal[0] payload size = 247

Если я установлю FPS на 10 вместо 30, размер вывода резко изменится:

x264 [warning]: ref > 1 + intra-refresh is not supported
x264 [info]: using cpu capabilities: MMX2 SSE2Fast SSSE3 FastShuffle SSE4.2 AVX
x264 [info]: profile Constrained Baseline, level 1.1 
------------1-----------------
Frame size = 60120
output has 3 colorspace
output has 2 # img planes
i_nals = 4 
nal[0] payload size = 25
nal[1] payload size = 9 
nal[2] payload size = 609 
nal[3] payload size = 59477
------------2-----------------
Frame size = 10
output has 3 colorspace
output has 2 # img planes
i_nals = 1 
nal[0] payload size = 10
------------3-----------------
Frame size = 151 
output has 3 colorspace
output has 2 # img planes
i_nals = 1 
nal[0] payload size = 151 
------------4-----------------
Frame size = 2329
output has 3 colorspace
output has 2 # img planes
i_nals = 1 
nal[0] payload size = 2329
------------5-----------------
Frame size = 1466
output has 3 colorspace
output has 2 # img planes
i_nals = 1 
nal[0] payload size = 1466
------------6-----------------
Frame size = 539 
output has 3 colorspace
output has 2 # img planes
i_nals = 1
nal[0] payload size = 539
------------7-----------------
Frame size = 311
output has 3 colorspace
output has 2 # img planes
i_nals = 1
nal[0] payload size = 311
------------8-----------------
Frame size = 291
output has 3 colorspace
output has 2 # img planes
i_nals = 1
nal[0] payload size = 291
------------9-----------------
Frame size = 302
output has 3 colorspace
output has 2 # img planes
i_nals = 1
nal[0] payload size = 302
------------10-----------------
Frame size = 287
output has 3 colorspace
output has 2 # img planes
i_nals = 1
nal[0] payload size = 287
------------11-----------------
Frame size = 11937
output has 3 colorspace
output has 2 # img planes
i_nals = 4
nal[0] payload size = 25
nal[1] payload size = 9
nal[2] payload size = 9
nal[3] payload size = 11894

Можете ли вы просветить меня?


person spartygw    schedule 02.01.2013    source источник
comment
кажется, вы занимаетесь обработкой изображений - не могли бы вы помочь нам открыть эту специальную группу: area51.stackexchange.com/proposals/66531/computer-vision/72084 Просто проголосуйте за вопросы, набравшие менее 10 голосов. Спасибо.   -  person Royi    schedule 01.03.2015


Ответы (1)


Проблема в основном связана с параметром «управление скоростью». Удалите контроль скорости CRF и используйте постоянный квантователь. Постоянный квантователь не является рекомендуемым режимом работы, но в вашем случае он (повторение одного и того же изображения) будет создавать кадры одинакового размера.

Удалять:

param.b_intra_refresh = 1;

//Rate control:
param.rc.i_rc_method = X264_RC_CRF;
param.rc.f_rf_constant = FPS-5;
param.rc.f_rf_constant_max = FPS+5;

Затем добавьте:

 param.rc.i_qp_constant = 18; 
 param.rc.i_qp_min = 18; 
 param.rc.i_qp_max = 18;
person rajneesh    schedule 03.01.2013
comment
Спасибо, это решило проблему рамок одинакового размера. Для кого-то вроде меня, который практически ничего не знает о кодеке, количество ручек и переключателей просто огромно. - person spartygw; 03.01.2013
comment
Кстати, для тех, кто придет к этому позже, фактический синтаксис: param.rc.i_qp_constant=18; param.rc.i_qp_min=18; param.rc.i_qp_max=18; - person spartygw; 03.01.2013
comment
KevinA, ranjessh, кажется, вы занимаетесь обработкой изображений — не могли бы вы помочь нам открыть эту специальную группу: area51.stackexchange.com/proposals/66531/computer-vision/72084 Просто проголосуйте за вопросы, набравшие менее 10 голосов. Спасибо. - person Royi; 01.03.2015