微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

在 x264 中正确使用 `nalu_process` 回调

如何解决在 x264 中正确使用 `nalu_process` 回调

我希望利用 libx264 的低延迟编码机制,一旦单个 NAL 单元可用,就会调用用户提供的回调,而不必在开始处理之前等待整个帧被编码。

x264 文档说明了有关该设施的以下内容

/* Optional low-level callback for low-latency encoding.  Called for each output NAL unit
 * immediately after the NAL unit is finished encoding.  This allows the calling application
 * to begin processing video data (e.g. by sending packets over a network) before the frame
 * is done encoding.
 *
 * This callback MUST do the following in order to work correctly:
 * 1) Have available an output buffer of at least size nal->i_payload*3/2 + 5 + 64.
 * 2) Call x264_nal_encode( h,dst,nal ),where dst is the output buffer.
 * After these steps,the content of nal is valid and can be used in the same way as if
 * the NAL unit were output by x264_encoder_encode.
 *
 * This does not need to be synchronous with the encoding process: the data pointed to
 * by nal (both before and after x264_nal_encode) will remain valid until the next
 * x264_encoder_encode call.  The callback must be re-entrant.
 *
 * This callback does not work with frame-based threads; threads must be disabled
 * or sliced-threads enabled.  This callback also does not work as one would expect
 * with HRD -- since the buffering period SEI cannot be calculated until the frame
 * is finished encoding,it will not be sent via this callback.
 *
 * Note also that the NALs are not necessarily returned in order when sliced threads is
 * enabled.  Accordingly,the variable i_first_mb and i_last_mb are available in
 * x264_nal_t to help the calling application reorder the slices if necessary.
 *
 * When this callback is enabled,x264_encoder_encode does not return valid NALs;
 * the calling application is expected to acquire all output NALs through the callback.
 *
 * It is generally sensible to combine this callback with a use of slice-max-mbs or
 * slice-max-size.
 *
 * The opaque pointer is the opaque pointer from the input frame associated with this
 * NAL unit. This helps distinguish between nalu_process calls from different sources,* e.g. if doing multiple encodes in one process.
 */
void (*nalu_process)( x264_t *h,x264_nal_t *nal,void *opaque );

这似乎很直接。但是,当我运行以下虚拟代码时,在标记的行上出现段错误。我试图向 x264_nal_encode 本身添加一些调试以了解它出错的地方,但似乎是函数调用本身导致了段错误。我在这里错过了什么吗? (让我们忽略使用 assert 可能使 cb 不可重入的事实——它只是向读者表明我的工作区缓冲区足够大。)

#include <assert.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <x264.h>

#define WS_SIZE 10000000
uint8_t * workspace;

void cb(x264_t * h,x264_nal_t * nal,void * opaque)
{
  assert((nal->i_payload*3)/2 + 5 + 64 < WS_SIZE);
  x264_nal_encode(h,workspace,nal); // Segfault here.
  // Removed: Process nal.
}

int main(int argc,char ** argv)
{
  uint8_t * fake_frame = malloc(1280*720*3);
  memset(fake_frame,1280*720*3);

  workspace = malloc(WS_SIZE);

  x264_param_t param;
  int status = x264_param_default_preset(&param,"ultrafast","zerolatency");
  assert(status == 0);

  param.i_csp = X264_CSP_RGB;
  param.i_width = 1280;
  param.i_height = 720;
  param.i_threads = 1;
  param.i_lookahead_threads = 1;
  param.i_frame_total = 0;
  param.i_fps_num = 30;
  param.i_fps_den = 1;
  param.i_slice_max_size = 1024;
  param.b_annexb = 1;
  param.nalu_process = cb;

  status = x264_param_apply_profile(&param,"high444");
  assert(status == 0);

  x264_t * h = x264_encoder_open(&param);
  assert(h);

  x264_picture_t pic;
  status = x264_picture_alloc(&pic,param.i_csp,param.i_width,param.i_height);
  assert(pic.img.i_plane == 1);

  x264_picture_t pic_out;
  x264_nal_t * nal; // Not used. We process NALs in cb.
  int i_nal;

  for (int i = 0; i < 100; ++i)
  {
    pic.i_pts = i;
    pic.img.plane[0] = fake_frame;
    status = x264_encoder_encode(h,&nal,&i_nal,&pic,&pic_out);
  }

  x264_encoder_close(h);
  x264_picture_clean(&pic);
  free(workspace);
  free(fake_frame);
  return 0;
}

编辑:段错误发生在第一次 cb 调用 x264_nal_encode 时。如果我切换到不同的预设,在第一个回调发生之前编码更多帧,然后在第一个回调之前成功调用 x264_encoder_encode,因此会发生段错误

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。