FFmpeg 新旧版本编码 API 的区别

前言

FFmpeg 3.x 之前,视频编码函数为 avcodec_encode_video2,3.x 及之后的版本,avcodec_encode_video2 被弃用,取而代之的是 avcodec_send_frame() 和 avcodec_receive_packet(),下面将从 API 的使用和源码实现两个角度来分析它们的区别。

API 的使用

旧版 API

下面摘抄了 ffmpeg 转码示例程序的部分代码:

static int encode_write_frame(AVFrame *frame, unsigned int stream_index, int *got_frame) {
    int ret;
    int got_frame_local;
    AVPacket enc_pkt;
    int (*enc_func)(AVCodecContext *, AVPacket *, const AVFrame *, int *) =
        (ifmt_ctx->streams[stream_index]->codecpar->codec_type ==
         AVMEDIA_TYPE_VIDEO) ? avcodec_encode_video2 : avcodec_encode_audio2;

    if (!got_frame)
        got_frame = &got_frame_local;

    av_log(NULL, AV_LOG_INFO, "Encoding frame\n");
    /* encode frame */
    enc_pkt.data = NULL;
    enc_pkt.size = 0;
    av_init_packet(&enc_pkt);
    ret = enc_func(stream_ctx[stream_index].enc_ctx, &enc_pkt,
            frame, got_frame);
    av_frame_free(&frame);
    if (ret < 0)
        return ret;
    if (!(*got_frame))
        return 0;

    /* prepare packet for muxing */
    enc_pkt.stream_index = stream_index;
    av_packet_rescale_ts(&enc_pkt,
                         stream_ctx[stream_index].enc_ctx->time_base,
                         ofmt_ctx->streams[stream_index]->time_base);

    av_log(NULL, AV_LOG_DEBUG, "Muxing frame\n");
    /* mux encoded frame */
    ret = av_interleaved_write_frame(ofmt_ctx, &enc_pkt);
    return ret;
}

新版 API

下面摘抄的是 ffmpeg 视频编码示例程序的部分代码:

static void encode(AVCodecContext *enc_ctx, AVFrame *frame, AVPacket *pkt,
                   FILE *outfile)
{
    int ret;

    /* send the frame to the encoder */
    if (frame)
        printf("Send frame %3"PRId64"\n", frame->pts);

    ret = avcodec_send_frame(enc_ctx, frame);
    if (ret < 0) {
        fprintf(stderr, "Error sending a frame for encoding\n");
        exit(1);
    }

    while (ret >= 0) {
        ret = avcodec_receive_packet(enc_ctx, pkt);
        if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
            return;
        else if (ret < 0) {
            fprintf(stderr, "Error during encoding\n");
            exit(1);
        }

        printf("Write packet %3"PRId64" (size=%5d)\n", pkt->pts, pkt->size);
        fwrite(pkt->data, 1, pkt->size, outfile);
        av_packet_unref(pkt);
    }
}

可以看到,在使用上,新旧版本的编码 API 的主要区别有:

  1. 旧版 API 一个函数即可完成编码操作,编码成功后可直接使用压缩后的数据。新版 API 需要两个函数一起使用,一个 send,一个 receive,分别用于发送原始视频数据、获取编码后的数据;具体在哪里完成了编码动作,暂时未知。
  2. 旧版 API 一次编码动作对应 0 个或 1 个 AVFrame 和 0 个或 1 个 AVPacket。新本 API 一次编码动作对应 0 个或 1 个 AVFrame 和 0 个或多个 AVPacket。

源码实现

函数声明

avcodec_encode_video2

/**
* Encode a frame of video.
*
* Takes input raw video data from frame and writes the next output packet, if
* available, to avpkt. The output packet does not necessarily contain data for
* the most recent frame, as encoders can delay and reorder input frames
* internally 
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
使用 FFmpeg 进行图片转视频时,我们可以使用以下步骤: 1. 初始化 FFmpeg,包括注册所有的组件和分配 AVFormatContext 内存 ``` av_register_all(); avformat_alloc_output_context2(&oc, NULL, NULL, filename); if (!oc) { printf("Could not deduce output format from file extension: using MPEG.\n"); avformat_alloc_output_context2(&oc, NULL, "mpeg", filename); } ``` 2. 创建 AVStream,并设置相关参数如编码器、帧率、分辨率等 ``` AVCodec *codec = avcodec_find_encoder(AV_CODEC_ID_H264); if (!codec) { printf("Codec not found\n"); exit(1); } video_st = avformat_new_stream(oc, codec); if (!video_st) { printf("Could not allocate stream\n"); exit(1); } video_st->id = oc->nb_streams - 1; c = video_st->codecpar; c->codec_id = codec->id; c->codec_type = AVMEDIA_TYPE_VIDEO; c->width = width; c->height = height; c->format = AV_PIX_FMT_YUV420P; c->bit_rate = 400000; c->codec_tag = 0; ``` 3. 打开编码器并写入头文件 ``` avcodec_open2(c, codec, NULL) < 0) { printf("Could not open codec\n"); exit(1); } avformat_write_header(oc, NULL); ``` 4. 为每一帧图像创建 AVFrame,并将其转换为 YUV 格式 ``` AVFrame *frame = av_frame_alloc(); frame->format = c->format; frame->width = c->width; frame->height = c->height; av_image_alloc(frame->data, frame->linesize, c->width, c->height, c->format, 32); ``` 5. 将 YUV 格式的帧写入文件 ``` avcodec_send_frame(c, frame); while (avcodec_receive_packet(c, &pkt) == 0) { pkt.stream_index = video_st->index; av_interleaved_write_frame(oc, &pkt); av_packet_unref(&pkt); } ``` 6. 写入文件尾并释放内存 ``` av_write_trailer(oc); avcodec_free_context(&c); av_frame_free(&frame); avformat_free_context(oc); ``` 以上是使用 FFmpeg 进行图片转视频的大致流程。具体实现时,需要根据具体的需求进行参数设置、错误处理等。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值