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
编解码器私有数据结构。
包含编解码器实现专用的数据。此结构对应用程序不透明。