ffmpeg解码流程 最简 注释最全

第一步 定义一些接下来会用到的变量

代码中有详细解释 就不一一叙述了

#define INBUF_SIZE 4096
//输入文件路径和输出文件路径
    const char* filename, * outfilename;
    //编解码器结构体
    const AVCodec* codec;
    // 解析器上下文 这个东西是为了把你文件中的数据打包到我下面的AVPacket中去 必须要通过这个分成一包一包的 然后才能解压缩
    AVCodecParserContext* parser;
    //编解码器上下文 保存编解码器的一些相关信息
    AVCodecContext* c = NULL;
    //文件指针
    FILE* f;
    //解码后的数据放这里
    AVFrame* frame;
    //缓冲区 AV_INPUT_BUFFER_PADDING_SIZE为内存对齐需要多加的东西
    uint8_t inbuf[INBUF_SIZE + AV_INPUT_BUFFER_PADDING_SIZE];
    //临时的变量 主要是为了等会文件操作更加方便
    uint8_t* data;
    size_t   data_size;
    //验错处理
    int ret;
    //未解码的数据放这里
    AVPacket* pkt;

第二步 给各个变量分配内存空间 然后找到编解码器 分析器 打开编解码器和分析器

    //输入文件路径和输出文件路径
    const char* filename, * outfilename;
    //编解码器结构体
    const AVCodec* codec;
    // 解析器上下文 这个东西是为了把你文件中的数据打包到我下面的AVPacket中去 必须要通过这个分成一包一包的 然后才能解压缩
    AVCodecParserContext* parser;
    //编解码器上下文 保存编解码器的一些相关信息
    AVCodecContext* c = NULL;
    //文件指针
    FILE* f;
    //解码后的数据放这里
    AVFrame* frame;
    //缓冲区 AV_INPUT_BUFFER_PADDING_SIZE为内存对齐需要多加的东西
    uint8_t inbuf[INBUF_SIZE + AV_INPUT_BUFFER_PADDING_SIZE];
    //临时的变量 主要是为了等会文件操作更加方便
    uint8_t* data;
    size_t   data_size;
    //验错处理
    int ret;
    //未解码的数据放这里
    AVPacket* pkt;
    filename = argv[1];
    outfilename = argv[2];
    //给pkt申请内存空间 用来存放未解码的数据
    pkt = av_packet_alloc();
    //把缓冲区后内存对齐的部分设置为0 以防以后出问题
    memset(inbuf + INBUF_SIZE, 0, AV_INPUT_BUFFER_PADDING_SIZE);
    //通过ID拿到对应的编解码器 这里是拿到h.264的编解码器
    codec = avcodec_find_decoder(AV_CODEC_ID_H264);
    //通过编解码器的ID来拿到对应的分析器 分析器是为了从文件流中读取packet
    parser = av_parser_init(codec->id);
    //给编解码器上下文分配内存空间
    c = avcodec_alloc_context3(codec);
    //打开编解码器 打开后一直存在 后续不需要指定
    avcodec_open2(c, codec, NULL);
    //打开文件
    f = fopen(filename, "rb");
    //给解码后的帧分配内存空间
    frame = av_frame_alloc();
    //读取文件
    while (!feof(f)) {
        data_size = fread(inbuf, 1, INBUF_SIZE, f);
        if (!data_size)
            break;
        //临时指针data指向inbuf
        data = inbuf;
        while (data_size > 0) {
            //把这个缓冲区内的数据打包成Packet放入pkt中
            ret = av_parser_parse2(parser, c, &pkt->data, &pkt->size,
                data, data_size, AV_NOPTS_VALUE, AV_NOPTS_VALUE, 0);
            data += ret;
            data_size -= ret;
            //读到一个包 解析一个包
            if (pkt->size)
                decode(c, frame, pkt, outfilename);
        }
    }
    //最后再解码一次 因为最后一帧还没有解析
    decode(c, frame, NULL, outfilename);
    //释放内存空间
    fclose(f);
    av_parser_close(parser);
    avcodec_free_context(&c);
    av_frame_free(&frame);
    av_packet_free(&pkt);

第三步 decode函数 真正的调用解码器去解码

static void decode(AVCodecContext* dec_ctx, AVFrame* frame, AVPacket* pkt,
    const char* filename)
{
    //缓冲区
    char buf[1024];
    //验错
    int ret;
    //把packet发到编解码器解析 之前已经打开了 所以现在直接发就是了
    ret = avcodec_send_packet(dec_ctx, pkt);
    while (ret >= 0) {
        //从解码器哪里拿到解码后的数据 并放入frame中
        ret = avcodec_receive_frame(dec_ctx, frame);
        //如果读到结尾了 那就停止
        if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
            return;
        //下面两步就是把对应的数据写入文件 跟编解码没关系
        snprintf(buf, sizeof(buf), "%s-%d", filename, dec_ctx->frame_number);
        pgm_save(frame->data[0], frame->linesize[0],
            frame->width, frame->height, buf);
    }
}

关于pgm_save函数

static void pgm_save(unsigned char* buf, int wrap, int xsize, int ysize,
    char* filename)
{
    FILE* f;
    int i;

    f = fopen(filename, "w");
    fprintf(f, "P5\n%d %d\n%d\n", xsize, ysize, 255);
    for (i = 0; i < ysize; i++)
        fwrite(buf + i * wrap, 1, xsize, f);
    fclose(f);
}

  • 5
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

杀神李

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值