FFmpeg05:编解码实战

基础介绍

结构体和函数

AVCodec 编码器结构体
AVCodecContext 编码器上下文
AVFrame 解码后的帧

av_frame_alloc/av_frame_free()
avcodec_alloc_context3()
avcodec_free_context()

解码步骤

  • 查找解码器(avcodec_find_decoder)
  • 打开解码器(avcodec_open2)
  • 解码(avcodec_decode_video2)

视频编码

指定输出文件为out.h264,编码器为libx264
伪造YUV420P数据进行测试

extern "C" {
   
   
    #include <libavutil/log.h>
    #include <libavcodec/avcodec.h>
    #include <libavutil/opt.h>
}
#include <string>
using namespace std;

static int encode(AVCodecContext *ctx, AVFrame *frame, AVPacket *pkt, FILE *out) {
   
   
    int ret = -1;
    ret = avcodec_send_frame(ctx, frame);
    if (ret < 0) {
   
   
        av_log(nullptr, AV_LOG_ERROR, "send frame to encoder error\n");
        goto _END;
    }

    while (ret >= 0) {
   
   
        ret = avcodec_receive_packet(ctx, pkt);
        if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
   
   
            return 0;
        } else if (ret < 0) {
   
   
            return -1;
        }
        fwrite(pkt->data, pkt->size, 1, out);
        av_packet_unref(pkt);
    }

_END:
    return 0;
}

int main(int argc, char* argv[]) {
   
   
    av_log_set_level(AV_LOG_DEBUG);
    string dst;
    string codec_name;
    int ret = -1;
    const AVCodec *codec = nullptr;
    AVCodecContext *codec_ctx = nullptr;
    FILE *fp = nullptr;
    AVFrame *frame = nullptr;
    AVPacket *pkt = nullptr;
    // 1. 输入参数
    if (argc < 3) {
   
   
        av_log(nullptr, AV_LOG_ERROR, "arguments must be more than 2\n");
        goto _ERROR;
    }

    dst = argv[1];
    codec_name = argv[2];

    // 2. 查找编码器
    codec = avcodec_find_encoder_by_name(codec_name.c_str());
    if (!codec) {
   
   
        av_log(nullptr, AV_LOG_ERROR, "could not find encoder %s\n", codec_name.c_str());
        goto _ERROR;
    }
    
    // 3. 创建编码器上下文
    codec_ctx = avcodec_alloc_context3(codec);
    if (!codec_ctx) {
   
   
        av_log(nullptr, AV_LOG_ERROR, "could not allocate codec context\n");
        goto _ERROR;
    }

    // 4. 设置编码器参数
    codec_ctx->width = 640;
    codec_ctx->height = 480;
    codec_ctx->bit_rate = 500000;

    codec_ctx->time_base = (AVRational){
   
   1, 25};
    codec_ctx->framerate = (AVRational){
   
   25, 1};
    codec_ctx->gop_size = 10; // 每10帧一个关键帧
    codec_ctx->max_b_frames = 1; // 一个gop允许1个B
    codec_ctx->pix_fmt = AV_PIX_FMT_YUV420P;

    // 设置264编码器的特殊参数
    if (codec->id == AV_CODEC_ID_H264) {
   
   
        // priv_data是编码器私有数据
        // 通过它可以设置编码器私有参数
        // 这些参数在不同编码器中是不一样的
        av_opt_set(codec_ctx->priv_data, "preset", "slow", 0);
    }

    // 5. 编码器与编码器上下文绑定到一起
    ret = avcodec_open2(codec_ctx, codec, nullptr);
    if (ret < 0) {
   
   
        av_log(nullptr, AV_LOG_ERROR, "could not open codec %s\n", codec_name.c_str());
        goto _ERROR;
    }
    // 6. 创建输出文件
    fp = fopen(dst.c_str(), "wb+");
    if (!fp) {
   
   
        av_log(nullptr, AV_LOG_ERROR, "could not open file %s\n", dst.c_str());
        goto _ERROR;
    }

    // 7. 创建AVFrame
    frame = av_frame_alloc();
    if (!frame) {
   
   
        av_log(nullptr, AV_LOG_ERROR, "could not allocate frame\n");
        goto _ERROR;
    }
    frame->width = codec_ctx->width;
    frame->height = codec_ctx->height;
    frame->format = codec_ctx->pix_fmt;

    // 真正的像素数据分配,并与AVFrame绑定,后面设置为0,会自动根据cpu对齐
    ret = av_frame_get_buffer(frame, 0);
    if (ret < 0) {
   
   
        av_log(nullptr, AV_LOG_ERROR, "could not allocate frame data\n");
        goto _ERROR;
    }

    // 8. 创建AVPacket
    pkt = av_packet_alloc();
    if (!pkt) {
   
   
        av_log(nullptr, AV_LOG_ERROR, "could not allocate packet\n");
        goto _ERROR;
    }
    // 9. 生成视频内容
    for (int i = 0; i < 25; ++i) {
   
   
        // 确保frame是否可写
        ret = av_frame_make_writable(frame);
        if (ret < 0) {
   
   
            break;
        }

        // Y分量
        for (int y 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值