FFmpeg 基本API avcodec_send_packet函数内部调用流程分析

1、avcodec_send_packet函数定义

avcodec_send_packet 是 FFmpeg 多媒体处理框架中的核心函数,属于其解码 API 的关键组成部分。

其主要功能是解码器输入函数:负责向解码器提交压缩数据包(AVPacket),现代解码 API 核心:取代旧版 avcodec_decode_video2/avcodec_decode_audio4 所属模块:libavcodec 库(编解码器核心库)。

cpp 复制代码
int avcodec_send_packet(AVCodecContext *avctx, 
                        const AVPacket *avpkt)
  • attribute_align_arg:编译器属性,确保栈对齐(x86架构重要优化)
  • 返回值:int 类型错误码(0=成功,负值=错误)
  • 参数:
    • avctx:编解码器上下文,包含解码器状态和配置
    • avpkt:输入数据包(可为NULL表示刷新解码器)

2、avcodec_send_packet函数流程分析

2.1 参数验证阶段

  • 检查编解码器是否已打开:!avcodec_is_open(avctx)
  • 检查是否为解码器:!av_codec_is_decoder(avctx->codec)
  • 无效数据包检查:avpkt && !avpkt->size && avpkt->data

2.2 状态检查

  • 如果正在draining(刷新状态):dc->draining_started,直接返回AVERROR_EOF

2.3 数据包处理

  • 当收到有效数据包时(有数据或边数据):
    • 检查内部缓冲区是否为空:!AVPACKET_IS_EMPTY(avci->buffer_pkt)
    • 如果缓冲区非空,返回EAGAIN(要求先处理缓冲帧)
    • 缓冲区为空则复制数据包:av_packet_ref(avci->buffer_pkt, avpkt)
  • 当收到空包(draining信号):
    • 设置dc->draining_started = 1 开始刷新解码器

2.4 解码触发

  • 检查缓冲区帧是否为空:!avci->buffer_frame->buf0
  • 检查是否非draining状态:!dc->draining_started
  • 满足条件时调用decode_receive_frame_internal()

2.5 返回结果

  • 成功返回0
  • 错误返回相应错误码
    具体源码分析如下:
cpp 复制代码
int avcodec_send_packet(AVCodecContext *avctx, const AVPacket *avpkt)
{
    // 获取内部结构体指针
    AVCodecInternal *avci = avctx->internal;
    DecodeContext     *dc = decode_ctx(avci);
    int ret;

    // 1. 基本参数校验
    if (!avcodec_is_open(avctx) || !av_codec_is_decoder(avctx->codec))
        return AVERROR(EINVAL);

    // 2. 检查draining状态
    if (dc->draining_started)
        return AVERROR_EOF;

    // 3. 数据包有效性检查
    if (avpkt && !avpkt->size && avpkt->data)
        return AVERROR(EINVAL);

    // 4. 有效数据包处理
    if (avpkt && (avpkt->data || avpkt->side_data_elems)) {
        // 4.1 检查缓冲区是否已满
        if (!AVPACKET_IS_EMPTY(avci->buffer_pkt))
            return AVERROR(EAGAIN);
        
        // 4.2 复制数据包到内部缓冲区
        ret = av_packet_ref(avci->buffer_pkt, avpkt);
        if (ret < 0)
            return ret;
    } 
    // 5. 处理draining信号(空包)
    else {
        dc->draining_started = 1;
    }

    // 6. 触发解码(非draining状态且缓冲区有空位)
    if (!avci->buffer_frame->buf[0] && !dc->draining_started) {
        ret = decode_receive_frame_internal(avctx, avci->buffer_frame);
        // 只处理严重错误(忽略EAGAIN和EOF)
        if (ret < 0 && ret != AVERROR(EAGAIN) && ret != AVERROR_EOF)
            return ret;
    }

    return 0;
}

3、avcodec_send_packet函数内部调用流程

相关推荐
lingran__27 分钟前
C++_stack和queue和priority_queue(容器适配器)
开发语言·c++
小保CPP32 分钟前
OpenCV C++基于极值区域滤波算法的场景文本检测(OCR)
c++·人工智能·opencv·算法·计算机视觉·ocr
星恒随风38 分钟前
C++ 多态底层原理:静态绑定、动态绑定、虚函数表与工程实践
开发语言·c++·笔记·学习
白色冰激凌1 小时前
[SECS/GEM研究] (四)HSMS 用TCP取代串口
网络·c++·网络协议·secs/gem
ShineWinsu2 小时前
对于Linux:http的解析
linux·网络·c++·网络协议·http·请求·响应
choumin11 小时前
创建型模式——工厂方法模式
c++·设计模式·工厂方法模式·创建型模式
云小逸11 小时前
【SVN 详细使用指南:从入门到团队协作】
c++·svn
ziguo112216 小时前
深入浅出 C/C++ 数据类型:从入门到踩坑
linux·c语言·c++·windows·visual studio
白色冰激凌17 小时前
[SECS/GEM研究] (三)SECS-I 串口上消息怎么分块和重传
c++·secs/gem
光头闪亮亮17 小时前
Fyne ( go跨平台GUI )项目实战-项目开发必备基础知识(中)
android·c++·go