Linux FFmpeg深度解析之avcodec_send_packet调用流程与实战(十七)

发布时间:2026/11/2 11:12:38
Linux FFmpeg深度解析之avcodec_send_packet调用流程与实战(十七) 简介CSDN博客专家、《Android系统多媒体进阶实战》作者博主新书推荐《Android系统多媒体进阶实战》Android Audio工程师专栏地址Audio工程师进阶系列【原创干货持续更新中……】Android多媒体专栏地址多媒体系统工程师系列【原创干货持续更新中……】专题一 二AAOS车载系统AOSP14系统攻城狮入门视频实战课专题三Android14 Binder之HIDL与AIDL通信实战课专题四Android15快速自定义与集成音效实战课专题五Android15音频策略实战课专题六Android15音频性能实战课(无声/杂音/断音/爆音实战案例)人生格言人生从来没有捷径只有行动才是治疗恐惧和懒惰的唯一良药.更多原创,欢迎关注Android系统攻城狮点击获取二维码文章目录1.前言2.应用场景和用法2.1向解码器提交压缩数据包2.2函数原型与返回语义3.调用流程剖析3.1检查上下文并保存输入包3.2按发送接收状态机推进解码4.实战案例4.1准备解码对象4.2提交包并处理EAGAIN4.3发送与接收代码5.总结1.前言本篇目的理解avcodec_send_packet()如何把压缩数据包提交给解码器分析输入何时被接受、何时需要重试并通过发送循环验证EAGAIN的处理方式。Demuxer从媒体文件中取出压缩数据后应用需要把AVPacket交给解码器。avcodec_send_packet()负责提交输入并不保证一次调用就能立即产出AVFrame。如果解码器内部暂时无法接收新包调用者需要先取出已有输出再重试同一个包。可以暂时不能Demuxer得到AVPacket提交压缩数据解码器能否接收输入进入解码器状态先读取已有AVFrame后续调用读取解码结果2.应用场景和用法2.1向解码器提交压缩数据包解码流程中demuxer读取容器并将压缩数据封装为AVPacket解码器通过avcodec_send_packet()接收它。一个包可能产生零帧、一帧或多帧因此发送和接收不能假设严格的一包一帧。常见使用场景场景调用方式需要关注的结果常规解码发送demuxer取出的目标流AVPacket成功表示包被接受后续继续取帧解码器暂时忙收到AVERROR(EAGAIN)先调用接收接口取出输出再重试原包输入文件结束发送NULL包通知解码器进入draining状态排出延迟帧seek或切换码流后恢复先清空旧解码状态使用avcodec_flush_buffers()后再提交新包2.2函数原型与返回语义intavcodec_send_packet(AVCodecContext*avctx,constAVPacket*avpkt);参数或返回值含义avctx已打开的解码器上下文avpkt待解码的压缩包传入NULL表示输入结束并启动draining0输入包已被接受或draining请求已接受AVERROR(EAGAIN)当前无法接收新输入必须先读取输出之后重试当前包AVERROR_EOF已进入draining状态不能再发送普通包AVERROR(EINVAL)上下文未打开、上下文对应编码器或状态不允许提交提交接口会为内部输入包建立引用调用者仍需按自己的生命周期释放AVPacket。如果包不是引用计数数据FFmpeg可能需要复制数据。相邻接口的分工是av_read_frame()从容器读取压缩包avcodec_send_packet()提交输入avcodec_receive_frame()取出解码帧avcodec_flush_buffers()在seek等场景重置解码器状态。3.调用流程剖析3.1检查上下文并保存输入包源码先确认AVCodecContext已经打开且对应解码器。如果上下文已经开始draining普通输入会返回AVERROR_EOF。对于带数据或side data的包函数先检查内部输入包槽位是否为空。如果槽位仍有未处理数据返回AVERROR(EAGAIN)否则调用av_packet_ref()保存输入包引用。调用成功仅表示包已进入解码器输入状态不等于已经得到输出帧。否是AVCodecContext与AVPacket检查解码器和draining状态内部输入槽是否可用返回EAGAIN引用输入包并保存返回提交结果3.2按发送接收状态机推进解码avcodec_send_packet()和avcodec_receive_frame()构成一组相互配合的接口。当发送返回EAGAIN应用要读取输出输出读取到EAGAIN后再重试尚未被接受的输入包。FFmpeg保证发送端和接收端不会同时处于EAGAIN因此调用者可以通过另一端继续推进。成功EAGAIN得到帧EAGAIN发送当前AVPacket发送结果循环读取AVFrame接收结果重试当前AVPacket对EAGAIN收到的包不能直接丢弃也不能读取完输出后改发下一个包这个包尚未被接受必须重试它。输入文件结束时发送NULL包是另一种状态转换之后应持续接收直到AVERROR_EOF。4.实战案例4.1准备解码对象先通过avcodec_find_decoder()查找解码器创建并打开AVCodecContext再从demuxer取得匹配流的AVPacket。发送前应确认包属于目标音视频流并为接收过程准备可复用的AVFrame。4.2提交包并处理EAGAIN发送循环需要保留当前包直到提交成功。若发送返回EAGAIN先排空当前可用帧再重试相同的AVPacket。4.3发送与接收代码下面的函数接收一个已经准备好的解码器上下文、压缩包和帧对象。process_frame()代表应用自己的帧处理逻辑。#includelibavcodec/avcodec.h#includelibavutil/error.h/* 读取当前可用帧直到解码器需要更多输入 */staticintreceive_available_frames(AVCodecContext*decoder,AVFrame*frame){intret;while(1){retavcodec_receive_frame(decoder,frame);if(retAVERROR(EAGAIN)||retAVERROR_EOF)return0;if(ret0)returnret;/* 在这里处理当前解码帧 */process_frame(frame);/* 及时释放当前帧持有的引用 */av_frame_unref(frame);}}/* 提交一个包若输入槽暂不可用先接收帧再重试 */staticintsubmit_packet(AVCodecContext*decoder,constAVPacket*packet,AVFrame*frame){intret;while(1){retavcodec_send_packet(decoder,packet);if(ret!AVERROR(EAGAIN))break;/* EAGAIN表示当前包未被接受先取出已有输出 */retreceive_available_frames(decoder,frame);if(ret0)returnret;}if(ret0)returnret;/* 包已接受继续取出当前已经产生的帧 */returnreceive_available_frames(decoder,frame);}实战中submit_packet()成功后demuxer才继续读取下一包。遇到文件末尾时应单独发送NULL包并继续接收不能把普通包的EAGAIN处理误用为输入结束流程。5.总结avcodec_send_packet()把压缩包提交给解码器遇到EAGAIN时要求调用者先接收输出并重试尚未被接受的原包。

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询