困惑于x264和编码视频帧

时间:2013-01-02 19:43:13

标签: image-processing video-streaming h.264 libavcodec libx264

我构建了一个测试驱动程序,用于编码我捕获的一系列图像。我正在使用libx264,并根据这个人的答案基于我的驱动程序:

StackOverflow link

在我的情况下,我开始通过读取JPG图像并转换为YUV并将相同的帧一遍又一遍地传递给x264编码器。

我的期望是,因为帧是相同的,所以编码器的输出将非常小且恒定。

相反,我发现NAL有效负载从几个字节变化到几KB,并且根据我在编码器参数中指定的帧速率而变化很大。

显然我不懂视频编码。为什么输出大小变化太大?

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,在磁盘上大约是9KB。通过编码器运行相同图像的输出如下所示:

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
你可以开导我吗?

1 个答案:

答案 0 :(得分:2)

Rhe问题主要是由于“速率控制”参数。删除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;