简介: CSDN博客专家、《Android系统多媒体进阶实战》作者
博主新书推荐:《Android系统多媒体进阶实战》🚀
Android Audio工程师专栏地址:Audio工程师进阶系列【原创干货持续更新中...... 】🚀
Android多媒体专栏地址:多媒体系统工程师系列【原创干货持续更新中...... 】🚀
专题一 二:AAOS车载系统+AOSP14系统攻城狮入门视频实战课 🚀
专题三:Android14 Binder之HIDL与AIDL通信实战课 🚀
专题四:Android15快速自定义与集成音效实战课 🚀
专题五:Android15音频策略实战课 🚀
专题六:Android15音频性能实战课(无声/杂音/断音/爆音实战案例) 🚀
人生格言: 人生从来没有捷径,只有行动才是治疗恐惧和懒惰的唯一良药.
更多原创,欢迎关注:Android系统攻城狮

🍉🍉🍉文章目录🍉🍉🍉
🌻1.前言
本篇目的:理解
avcodec_alloc_context3()如何创建并初始化AVCodecContext,明确传入AVCodec与传入NULL时的差别,并通过最小程序检查新Context的初始状态。
AVCodecContext是编解码器的配置和运行状态对象。调用avcodec_alloc_context3()会分配这个对象并设置通用默认值;如果传入具体AVCodec,还会初始化对应的编解码器私有数据和默认选项。该函数不会打开编解码器,也不会开始收发Packet或Frame。
#mermaid-svg-d1Swq7KYT6ROO33w{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-d1Swq7KYT6ROO33w .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-d1Swq7KYT6ROO33w .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-d1Swq7KYT6ROO33w .error-icon{fill:#552222;}#mermaid-svg-d1Swq7KYT6ROO33w .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-d1Swq7KYT6ROO33w .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-d1Swq7KYT6ROO33w .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-d1Swq7KYT6ROO33w .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-d1Swq7KYT6ROO33w .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-d1Swq7KYT6ROO33w .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-d1Swq7KYT6ROO33w .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-d1Swq7KYT6ROO33w .marker{fill:#333333;stroke:#333333;}#mermaid-svg-d1Swq7KYT6ROO33w .marker.cross{stroke:#333333;}#mermaid-svg-d1Swq7KYT6ROO33w svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-d1Swq7KYT6ROO33w p{margin:0;}#mermaid-svg-d1Swq7KYT6ROO33w .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-d1Swq7KYT6ROO33w .cluster-label text{fill:#333;}#mermaid-svg-d1Swq7KYT6ROO33w .cluster-label span{color:#333;}#mermaid-svg-d1Swq7KYT6ROO33w .cluster-label span p{background-color:transparent;}#mermaid-svg-d1Swq7KYT6ROO33w .label text,#mermaid-svg-d1Swq7KYT6ROO33w span{fill:#333;color:#333;}#mermaid-svg-d1Swq7KYT6ROO33w .node rect,#mermaid-svg-d1Swq7KYT6ROO33w .node circle,#mermaid-svg-d1Swq7KYT6ROO33w .node ellipse,#mermaid-svg-d1Swq7KYT6ROO33w .node polygon,#mermaid-svg-d1Swq7KYT6ROO33w .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-d1Swq7KYT6ROO33w .rough-node .label text,#mermaid-svg-d1Swq7KYT6ROO33w .node .label text,#mermaid-svg-d1Swq7KYT6ROO33w .image-shape .label,#mermaid-svg-d1Swq7KYT6ROO33w .icon-shape .label{text-anchor:middle;}#mermaid-svg-d1Swq7KYT6ROO33w .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-d1Swq7KYT6ROO33w .rough-node .label,#mermaid-svg-d1Swq7KYT6ROO33w .node .label,#mermaid-svg-d1Swq7KYT6ROO33w .image-shape .label,#mermaid-svg-d1Swq7KYT6ROO33w .icon-shape .label{text-align:center;}#mermaid-svg-d1Swq7KYT6ROO33w .node.clickable{cursor:pointer;}#mermaid-svg-d1Swq7KYT6ROO33w .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-d1Swq7KYT6ROO33w .arrowheadPath{fill:#333333;}#mermaid-svg-d1Swq7KYT6ROO33w .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-d1Swq7KYT6ROO33w .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-d1Swq7KYT6ROO33w .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-d1Swq7KYT6ROO33w .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-d1Swq7KYT6ROO33w .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-d1Swq7KYT6ROO33w .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-d1Swq7KYT6ROO33w .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-d1Swq7KYT6ROO33w .cluster text{fill:#333;}#mermaid-svg-d1Swq7KYT6ROO33w .cluster span{color:#333;}#mermaid-svg-d1Swq7KYT6ROO33w div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-d1Swq7KYT6ROO33w .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-d1Swq7KYT6ROO33w rect.text{fill:none;stroke-width:0;}#mermaid-svg-d1Swq7KYT6ROO33w .icon-shape,#mermaid-svg-d1Swq7KYT6ROO33w .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-d1Swq7KYT6ROO33w .icon-shape p,#mermaid-svg-d1Swq7KYT6ROO33w .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-d1Swq7KYT6ROO33w .icon-shape .label rect,#mermaid-svg-d1Swq7KYT6ROO33w .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-d1Swq7KYT6ROO33w .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-d1Swq7KYT6ROO33w .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-d1Swq7KYT6ROO33w :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} AVCodec或NULL
avcodec_alloc_context3
分配AVCodecContext
初始化通用默认值
按需初始化编解码器私有数据
返回可配置的Context
🌻2.应用场景和用法
2.1创建编解码器配置对象
编解码流程需要一个AVCodecContext保存参数,例如编码宽高、像素格式、码率、音频采样率和声道布局。avcodec_alloc_context3()负责创建这个对象,让调用者能够继续配置并交给avcodec_open2()初始化。
传入已找到的编解码器时,Context会按该编解码器设置类型、ID和私有默认值。传入NULL时,只初始化通用默认值;调用者之后仍可以通过avcodec_open2()指定Codec,但编码器可能缺少与特定实现相关的默认设置。
| 用法 | 传入参数 | 得到的对象状态 |
|---|---|---|
| 创建解码Context | avcodec_find_decoder()返回的AVCodec |
设置解码器类型与ID,并准备相关私有默认值 |
| 创建编码Context | avcodec_find_encoder()返回的AVCodec |
设置编码器类型与ID,并准备相关私有默认值 |
| 延后选择Codec | NULL |
只创建通用Context,后续再指定Codec |
| 分配失败 | 合法的Codec或NULL |
返回NULL,没有可用Context |
2.2函数原型与返回语义
函数原型如下:
c
AVCodecContext *
avcodec_alloc_context3 (const AVCodec *codec);
参数codec可以是解码器、编码器对象,也可以是NULL。成功时返回新分配的AVCodecContext,失败时返回NULL。返回对象的释放责任属于调用者,应使用avcodec_free_context(),不能只对Context调用av_free()。
同一个Context一旦按某个非空Codec创建,后续调用avcodec_open2()时必须使用相同Codec或传入NULL让FFmpeg沿用已关联的Codec。这个函数只创建并初始化配置对象,不会选择文件流、不解析压缩数据,也不创建AVPacket或AVFrame。
🌻3.调用流程剖析
3.1分配内存并设置通用默认值
avcodec_alloc_context3()先分配AVCodecContext结构体内存。分配成功后调用内部初始化函数,把对象清零,设置AVClass,再根据传入Codec设置codec_type和codec_id。
初始化还会设置一组通用选项和默认回调,例如默认缓冲区申请函数、像素格式和采样格式初值、时间基初值以及声道布局状态。若传入Codec,函数会根据Codec类别配置音频、视频或字幕相关选项。
#mermaid-svg-WItaL8GRwZtBLQbg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-WItaL8GRwZtBLQbg .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-WItaL8GRwZtBLQbg .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-WItaL8GRwZtBLQbg .error-icon{fill:#552222;}#mermaid-svg-WItaL8GRwZtBLQbg .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-WItaL8GRwZtBLQbg .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-WItaL8GRwZtBLQbg .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-WItaL8GRwZtBLQbg .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-WItaL8GRwZtBLQbg .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-WItaL8GRwZtBLQbg .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-WItaL8GRwZtBLQbg .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-WItaL8GRwZtBLQbg .marker{fill:#333333;stroke:#333333;}#mermaid-svg-WItaL8GRwZtBLQbg .marker.cross{stroke:#333333;}#mermaid-svg-WItaL8GRwZtBLQbg svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-WItaL8GRwZtBLQbg p{margin:0;}#mermaid-svg-WItaL8GRwZtBLQbg .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-WItaL8GRwZtBLQbg .cluster-label text{fill:#333;}#mermaid-svg-WItaL8GRwZtBLQbg .cluster-label span{color:#333;}#mermaid-svg-WItaL8GRwZtBLQbg .cluster-label span p{background-color:transparent;}#mermaid-svg-WItaL8GRwZtBLQbg .label text,#mermaid-svg-WItaL8GRwZtBLQbg span{fill:#333;color:#333;}#mermaid-svg-WItaL8GRwZtBLQbg .node rect,#mermaid-svg-WItaL8GRwZtBLQbg .node circle,#mermaid-svg-WItaL8GRwZtBLQbg .node ellipse,#mermaid-svg-WItaL8GRwZtBLQbg .node polygon,#mermaid-svg-WItaL8GRwZtBLQbg .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-WItaL8GRwZtBLQbg .rough-node .label text,#mermaid-svg-WItaL8GRwZtBLQbg .node .label text,#mermaid-svg-WItaL8GRwZtBLQbg .image-shape .label,#mermaid-svg-WItaL8GRwZtBLQbg .icon-shape .label{text-anchor:middle;}#mermaid-svg-WItaL8GRwZtBLQbg .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-WItaL8GRwZtBLQbg .rough-node .label,#mermaid-svg-WItaL8GRwZtBLQbg .node .label,#mermaid-svg-WItaL8GRwZtBLQbg .image-shape .label,#mermaid-svg-WItaL8GRwZtBLQbg .icon-shape .label{text-align:center;}#mermaid-svg-WItaL8GRwZtBLQbg .node.clickable{cursor:pointer;}#mermaid-svg-WItaL8GRwZtBLQbg .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-WItaL8GRwZtBLQbg .arrowheadPath{fill:#333333;}#mermaid-svg-WItaL8GRwZtBLQbg .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-WItaL8GRwZtBLQbg .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-WItaL8GRwZtBLQbg .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-WItaL8GRwZtBLQbg .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-WItaL8GRwZtBLQbg .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-WItaL8GRwZtBLQbg .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-WItaL8GRwZtBLQbg .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-WItaL8GRwZtBLQbg .cluster text{fill:#333;}#mermaid-svg-WItaL8GRwZtBLQbg .cluster span{color:#333;}#mermaid-svg-WItaL8GRwZtBLQbg div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-WItaL8GRwZtBLQbg .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-WItaL8GRwZtBLQbg rect.text{fill:none;stroke-width:0;}#mermaid-svg-WItaL8GRwZtBLQbg .icon-shape,#mermaid-svg-WItaL8GRwZtBLQbg .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-WItaL8GRwZtBLQbg .icon-shape p,#mermaid-svg-WItaL8GRwZtBLQbg .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-WItaL8GRwZtBLQbg .icon-shape .label rect,#mermaid-svg-WItaL8GRwZtBLQbg .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-WItaL8GRwZtBLQbg .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-WItaL8GRwZtBLQbg .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-WItaL8GRwZtBLQbg :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 传入Codec指针
分配Context内存
清零结构体并设置AVClass
设置Codec类别和ID
初始化通用选项和默认回调
返回Context指针
3.2按Codec初始化私有数据
传入具体Codec后,初始化逻辑会检查该Codec是否有私有数据空间;如果有,就为priv_data分配内存,并应用Codec私有选项的默认值。Codec还可以定义一组默认参数,初始化函数会将其写入Context。
因此,传入Codec与传入NULL的区别不只是Context里是否有一个Codec指针。前者能提前获得针对该实现的默认配置,后者只具备公共的基础状态。编码器尤其可能依赖实现级默认值。
分配或私有数据初始化失败时,函数会释放已分配的Context并返回NULL。返回非空对象表示创建成功,但不代表Codec已经完成初始化。真正的打开动作由avcodec_open2()负责。
🌻4.实战案例
4.1选择解码器并准备Context
示例选择H.264解码器,并把其AVCodec对象传给avcodec_alloc_context3()。此时Context已关联解码器类型和ID,但尚未打开,也没有开始解码。
4.2检查初始状态和释放对象
程序检查Codec查找和Context分配是否成功,再确认Context中的Codec ID与选择的解码器一致。最后使用avcodec_free_context()释放对象,该接口会将指针置为NULL。
4.3完整代码
c
#include <libavcodec/avcodec.h>
int
main (void)
{
const AVCodec *decoder;
AVCodecContext *context;
/* 查找H.264解码器实现 */
decoder = avcodec_find_decoder (AV_CODEC_ID_H264);
if (decoder == NULL)
return 1;
/* 分配并初始化与该解码器关联的Context */
context = avcodec_alloc_context3 (decoder);
if (context == NULL)
return 1;
/* 检查分配结果,Context此时还没有打开 */
if (context->codec_id != AV_CODEC_ID_H264 ||
context->codec_type != AVMEDIA_TYPE_VIDEO) {
avcodec_free_context (&context);
return 1;
}
/* 使用配套接口释放Context及其关联资源 */
avcodec_free_context (&context);
return context == NULL ? 0 : 1;
}
🌻5.总结
avcodec_alloc_context3()负责分配并初始化AVCodecContext,传入具体Codec时还会准备相应的私有默认值,但它不会打开编解码器。