AV1代码学习:函数encode_frame和aom_codec_encode

1.encode_frame函数

在编码端aomenc.c的main函数中,在进入编码过程循环后,循环读取视频的每一帧数据,然后通过encode_frame函数对每一帧进行编码。

encode_frame函数主要是进行一些当前帧进行放缩的工作,并启动计时器,然后调用aom_codec_encode函数进行编码。

static void encode_frame(struct stream_state *stream,
                         struct AvxEncoderConfig *global, struct aom_image *img,
                         unsigned int frames_in) {
  aom_codec_pts_t frame_start, next_frame_start; //起始时间戳
  struct aom_codec_enc_cfg *cfg = &stream->config.cfg;
  struct aom_usec_timer timer;

  frame_start =
      (cfg->g_timebase.den * (int64_t)(frames_in - 1) * global->framerate.den) /
      cfg->g_timebase.num / global->framerate.num;
  next_frame_start =
      (cfg->g_timebase.den * (int64_t)(frames_in)*global->framerate.den) /
      cfg->g_timebase.num / global->framerate.num;

  /* Scale if necessary */
  if (img) {
    if ((img->fmt & AOM_IMG_FMT_HIGHBITDEPTH) &&
        (img->d_w != cfg->g_w || img->d_h != cfg->g_h)) {
      if (img->fmt != AOM_IMG_FMT_I42016) {
        fprintf(stderr, "%s can only scale 4:2:0 inputs\n", exec_name);
        exit(EXIT_FAILURE);
      }
#if CONFIG_LIBYUV
      if (!stream->img) {
        stream->img =
            aom_img_alloc(NULL, AOM_IMG_FMT_I42016, cfg->g_w, cfg->g_h, 16);
      }
      I420Scale_16(
          (uint16_t *)img->planes[AOM_PLANE_Y], img->stride[AOM_PLANE_Y] / 2,
          (uint16_t *)img->planes[AOM_PLANE_U], img->stride[AOM_PLANE_U] / 2,
          (uint16_t *)img->planes[AOM_PLANE_V], img->stride[AOM_PLANE_V] / 2,
          img->d_w, img->d_h, (uint16_t *)stream->img->planes[AOM_PLANE_Y],
          stream->img->stride[AOM_PLANE_Y] / 2,
          (uint16_t *)stream->img->planes[AOM_PLANE_U],
          stream->img->stride[AOM_PLANE_U] / 2,
          (uint16_t *)stream->img->planes[AOM_PLANE_V],
          stream->img->stride[AOM_PLANE_V] / 2, stream->img->d_w,
          stream->img->d_h, kFilterBox);
      img = stream->img;
#else
      stream->encoder.err = 1;
      ctx_exit_on_error(&stream->encoder,
                        "Stream %d: Failed to encode frame.\n"
                        "libyuv is required for scaling but is currently "
                        "disabled.\n"
                        "Be sure to specify -DCONFIG_LIBYUV=1 when running "
                        "cmake.\n",
                        stream->index);
#endif
    }
  }
  if (img && (img->d_w != cfg->g_w || img->d_h != cfg->g_h)) {
    if (img->fmt != AOM_IMG_FMT_I420 && img->fmt != AOM_IMG_FMT_YV12) {
      fprintf(stderr, "%s can only scale 4:2:0 8bpp inputs\n", exec_name);
      exit(EXIT_FAILURE);
    }
#if CONFIG_LIBYUV
    if (!stream->img)
      stream->img =
          aom_img_alloc(NULL, AOM_IMG_FMT_I420, cfg->g_w, cfg->g_h, 16);
    I420Scale(
        img->planes[AOM_PLANE_Y], img->stride[AOM_PLANE_Y],
        img->planes[AOM_PLANE_U], img->stride[AOM_PLANE_U],
        img->planes[AOM_PLANE_V], img->stride[AOM_PLANE_V], img->d_w, img->d_h,
        stream->img->planes[AOM_PLANE_Y], stream->img->stride[AOM_PLANE_Y],
        stream->img->planes[AOM_PLANE_U], stream->img->stride[AOM_PLANE_U],
        stream->img->planes[AOM_PLANE_V], stream->img->stride[AOM_PLANE_V],
        stream->img->d_w, stream->img->d_h, kFilterBox);
    img = stream->img;
#else
    stream->encoder.err = 1;
    ctx_exit_on_error(&stream->encoder,
                      "Stream %d: Failed to encode frame.\n"
                      "Scaling disabled in this configuration. \n"
                      "To enable, configure with --enable-libyuv\n",
                      stream->index);
#endif
  }

  aom_usec_timer_start(&timer);
  aom_codec_encode(&stream->encoder, img, frame_start,
                   (uint32_t)(next_frame_start - frame_start), 0);
  aom_usec_timer_mark(&timer);
  stream->cx_time += aom_usec_timer_elapsed(&timer);
  ctx_exit_on_error(&stream->encoder, "Stream %d: Failed to encode frame",
                    stream->index);
}

2.aom_codec_encode函数

该函数主要作用是编码一帧。在给定的“presentation time.”对视频帧进行编码。演示时间戳(PTS)必须严格增加。

aom_codec_err_t aom_codec_encode(aom_codec_ctx_t *ctx, const aom_image_t *img,
                                 aom_codec_pts_t pts, unsigned long duration,
                                 aom_enc_frame_flags_t flags);

aom_codec_ctx_t 编解码器上下文结构,用户代码和编解码器之间的实际接口
所有编解码器必须完全支持此上下文结构。一般来说,这些数据应该被认为是编解码器算法的私有数据,而不是由调用应用程序操作或检查的。应用程序可以引用“name”成员来获得算法的可打印描述。

它存储编解码器的名称、指向初始化它的aom编解码器的指针、初始化标志、编码器或解码器的配置以及指向内部数据的指针。

typedef struct aom_codec_ctx {
  const char *name;             /**< Printable interface name 可打印接口名称 */
  aom_codec_iface_t *iface;     /**< Interface pointers 接口指针*/
  aom_codec_err_t err;          /**< Last returned error 上次返回的错误*/
  const char *err_detail;       /**< Detailed info, if available 详细信息(如果有) */
  aom_codec_flags_t init_flags; /**< Flags passed at init time 初始化时传递的标志*/
  union {
    /**< Decoder Configuration Pointer 解码器配置指针 */
    const struct aom_codec_dec_cfg *dec;
    /**< Encoder Configuration Pointer */
    const struct aom_codec_enc_cfg *enc;
    const void *raw;
  } config;               /**< Configuration pointer aliasing union */
  aom_codec_priv_t *priv; /**< Algorithm private storage 算法专用存储 */
} aom_codec_ctx_t;

参数:

  • ctx指向此实例上下文的ctx指针
  • img要编码的img图像数据,为NULL表示刷新缓冲区。
  • pts演示时间戳,以时基单位表示。
  • duration显示帧的持续时间,以时基单位为单位。
  • flags用于编码此帧的标志。

返回值:

  • AOM_CODEC_OK:操作已完成,没有错误。
  • AOM_CODEC_INCAPABLE:算法没有所需的功能。
  • AOM_CODEC_INVALID_PARAM:应用程序提供的参数无效,图像格式不受支持,等等

当最后一帧已传递给编码器时,应继续调用此函数,并将img参数设置为NULL。这将向编码器发送流结束条件的信号,并允许它对任何保留的缓冲区进行编码。当调用aom_codec_encode()aom_codec_get_cx_data()未返回任何数据时,编码完成。

该函数主要是调用encoder_encode进行编码。

aom_codec_err_t aom_codec_encode(aom_codec_ctx_t *ctx, const aom_image_t *img,
                                 aom_codec_pts_t pts, unsigned long duration,
                                 aom_enc_frame_flags_t flags) {
  aom_codec_err_t res = AOM_CODEC_OK;

  if (!ctx || (img && !duration))
    res = AOM_CODEC_INVALID_PARAM;
  else if (!ctx->iface || !ctx->priv)
    res = AOM_CODEC_ERROR;
  else if (!(ctx->iface->caps & AOM_CODEC_CAP_ENCODER))
    res = AOM_CODEC_INCAPABLE;
  else {
    /* Execute in a normalized floating point environment, if the platform
     * requires it.
     */
    FLOATING_POINT_INIT
    res = ctx->iface->enc.encode(get_alg_priv(ctx), img, pts, duration, flags);
    FLOATING_POINT_RESTORE
  }

该函数通过get_alg_priv()函数获取aom_codec_ctx_t结构体中的aom_codec_priv_t指针

static aom_codec_alg_priv_t *get_alg_priv(aom_codec_ctx_t *ctx) {
  return (aom_codec_alg_priv_t *)ctx->priv;
}

aom_codec_priv_t

编解码器私有数据结构。
包含编解码器实现专用的数据。此结构对应用程序不透明。

猜你喜欢

转载自blog.csdn.net/BigDream123/article/details/109466387