FFmpeg Demo分析之encode_video.c

前言

本系列文章

FFMPEG Demo分析之muxing.c

FFmpeg Demo分析之demuxing_decoding.c

FFmpeg Demo分析之decode_video.c

本篇文章来介绍一下单独使用libavcodec库进行编码视频文件。编码音频和编码视频的步骤其实都差不多。先来简单介绍下编码的步骤。步骤如下:

找到编码器->分配编码器上下文->给编码器上下文赋值一些必要的编码参数->打开编码器->分配AVPacket和AVFrame->给AVFrame赋值一些必要参数分配data空间->给AVFrame填充编码数据->进行编码生成输出AVPacket->释放资源。

详细的流程图

C++音视频开发学习资料:点击领取→音视频开发(资料文档+视频教程+面试题)(FFmpeg+WebRTC+RTMP+RTSP+HLS+RTP)

C++程序员必看,抓住音视频开发的大浪潮!冲击年薪60万

代码详细分析

#include #include #include #include #include #include //编码 和音频编码一样。这都是老套路了。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"
", frame->pts);    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);    }}int main(int argc, char **argv){    const char *filename, *codec_name;    const AVCodec *codec;    AVCodecContext *c= NULL;    int i, ret, x, y;    FILE *f;    AVFrame *frame;    AVPacket *pkt;    uint8_t endcode[] = { 0, 0, 1, 0xb7 };    if (argc <= 2) {        fprintf(stderr, "Usage: %s  
", argv[0]);        exit(0);    }    filename = argv[1];    codec_name = argv[2];    /* find the mpeg1video encoder */    //找到解码器    codec = avcodec_find_encoder_by_name(codec_name);    if (!codec) {        fprintf(stderr, "Codec '%s' not found
", codec_name);        exit(1);    }    //分配解码器上下文    c = avcodec_alloc_context3(codec);    if (!c) {        fprintf(stderr, "Could not allocate video codec context
");        exit(1);    } //设置一些编码必要参数 比特率、宽度、高度、 时间基、帧率、gop 最大的b帧 、图像格式。这些参数在remuxing.c 讲解过了。    /* 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;  //如果是h264 设置编码的预设参数 慢编码    if (codec->id == AV_CODEC_ID_H264)        av_opt_set(c->priv_data, "preset", "slow", 0);    /* open it */    //打开编码器    ret = avcodec_open2(c, codec, NULL);    if (ret < 0) {        fprintf(stderr, "Could not open codec: %s
", av_err2str(ret));        exit(1);    }   //打开文件    f = fopen(filename, "wb");    if (!f) {        fprintf(stderr, "Could not open %s
", filename);        exit(1);    }      //分配AVPacket    pkt = av_packet_alloc();    if (!pkt)        exit(1);    //初始化AVFrame    frame = av_frame_alloc();    if (!frame) {        fprintf(stderr, "Could not allocate video frame
");        exit(1);    }    frame->format = c->pix_fmt;    frame->width  = c->width;    frame->height = c->height;    //为frame data分配缓存空间,在调用这个函数前必须为AVFrame设置格式、如果视频要设置宽高、音频要设置每帧的采样个数nb_samples、通道数channel_layout    //第二个参数设置缓存数据大小对齐 最好设置为0,ffmpeg会根据cpu自动设置对齐    ret = av_frame_get_buffer(frame, 0);    if (ret < 0) {        fprintf(stderr, "Could not allocate the video frame data
");        exit(1);    }//就编码1秒 25帧数据    /* encode 1 second of video */    for (i = 0; i < 25; i++) {        fflush(stdout);          //使可写        /* make sure the frame data is writable */        ret = av_frame_make_writable(frame);        if (ret < 0)            exit(1);        //写入数据 yuv420p 格式planner yyyy uu vv        /* 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;            }        }        //设置pts          frame->pts = i;        /* encode the image */        encode(c, frame, pkt, f);    }    /* flush the encoder */    encode(c, NULL, pkt, f);    /* add sequence end code to have a real MPEG file */    //对于mpege1 mpeg2 添加一个结束序列码    if (codec->id == AV_CODEC_ID_MPEG1VIDEO || codec->id == AV_CODEC_ID_MPEG2VIDEO)        fwrite(endcode, 1, sizeof(endcode), f);    //释放资源    fclose(f);    avcodec_free_context(&c);    av_frame_free(&frame);    av_packet_free(&pkt);    return 0;} 
发表评论
留言与评论(共有 0 条评论) “”
   
验证码:

相关文章

推荐文章