ffmpeg源码精读2,视频编码

17 篇文章 1 订阅

ffmpeg视频编码例子:https://git.ffmpeg.org/gitweb/ffmpeg.git/blob/HEAD:/doc/examples/encode_video.c

从main函数入手,核心接口:avcodec_find_encoder_by_name、avcodec_open2、avcodec_send_frame、avcodec_receive_packet
程序主要流程:

  1. 查找编码器
  2. 初始化编码器(编码参数)
  3. 构建视频数据包
  4. 编码数据包
  5. 清理解码器

这个例子编码的是裸流,所以没有封装等操作。

从输入里获得编码器名称

    codec = avcodec_find_encoder_by_name(codec_name);
    if (!codec) {
        fprintf(stderr, "Codec '%s' not found
", codec_name);
        exit(1);
    }

设置详细编码参数(码率、分辨率、帧率、GOP、像素格式等)

    /* put sample parameters */
    c->bit_rate = 400000;
    /* resolution must be a multiple of two */
    c->width = 352;
    c->height = 288;
    /* frames per second */
    c->time_base = (AVRational){1, 25};
    c->framerate = (AVRational){25, 1};

    /* emit one intra frame every ten frames
     * check frame pict_type before passing frame
     * to encoder, if frame->pict_type is AV_PICTURE_TYPE_I
     * then gop_size is ignored and the output of encoder
     * will always be I frame irrespective to gop_size
     */
    c->gop_size = 10;
    c->max_b_frames = 1;
    c->pix_fmt = AV_PIX_FMT_YUV420P;

构建数据包,数据包构建只是一些颜色(yuv),没有实际的图像,对应YUV格式赋值填满即可

        /* prepare a dummy image */
        /* Y */
        for (y = 0; y < c->height; y++) {
            for (x = 0; x < c->width; x++) {
                frame->data[0][y * frame->linesize[0] + x] = x + y + i * 3;
            }
        }

        /* Cb and Cr */
        for (y = 0; y < c->height/2; y++) {
            for (x = 0; x < c->width/2; x++) {
                frame->data[1][y * frame->linesize[1] + x] = 128 + y + i * 2;
                frame->data[2][y * frame->linesize[2] + x] = 64 + x + i * 5;
            }
        }

编码输出,对应两个接口 avcodec_send_frame 和 avcodec_receive_packet,分辨是将数据包传入编码器和从编码器中得到已编码好的数据包,其中 while 循环的意义在于,由于I帧P帧B帧的存在,帧与帧之间需要做参考,所以一帧数据传入,并不一定会及时得到编码好的帧,同理,一帧数据的传入,如果之前编码器中的数据已经不具备参考意义,这时可能会输出多帧数据。

    ret = avcodec_send_frame(enc_ctx, frame);
    if (ret < 0) {
        fprintf(stderr, "Error sending a frame for encoding
");
        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
");
            exit(1);
        }

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

清理编码器对应编码输出,只是传入的数据包为NULL,在ffmpeg接口中有说明,传入NULL时,会将编码器中剩余的数据全部输出

 ...... 
 * @param[in] frame 
 ......
 *                  It can be NULL, in which case it is considered a flush
 *                  packet.  This signals the end of the stream. If the encoder
 *                  still has packets buffered, it will return them after this
 *                  call. Once flushing mode has been entered, additional flush
 *                  packets are ignored, and sending frames will return
 *                  AVERROR_EOF.
 ......
int avcodec_send_frame(AVCodecContext *avctx, const AVFrame *frame);

其余诸如:打开文件、关闭文件、清理资源等不一一展开。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值