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

🍉🍉🍉文章目录🍉🍉🍉
🌻1.前言
本篇目的:理解
avcodec_parameters_copy()如何把一个AVCodecParameters对象的参数复制到另一个对象,并通过实战检查动态数据是否独立。
封装格式中的AVStream通过codecpar保存流的编码参数。转封装或创建过滤器链时,常常需要把一条流的参数复制到另一对象。
avcodec_parameters_copy()会先重置目标对象,再复制参数,并为外部数据分配独立存储。它不复制音视频帧,也不负责把参数写入容器。
#mermaid-svg-YqBWtax3QBMLzrzE{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-YqBWtax3QBMLzrzE .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-YqBWtax3QBMLzrzE .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-YqBWtax3QBMLzrzE .error-icon{fill:#552222;}#mermaid-svg-YqBWtax3QBMLzrzE .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-YqBWtax3QBMLzrzE .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-YqBWtax3QBMLzrzE .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-YqBWtax3QBMLzrzE .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-YqBWtax3QBMLzrzE .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-YqBWtax3QBMLzrzE .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-YqBWtax3QBMLzrzE .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-YqBWtax3QBMLzrzE .marker{fill:#333333;stroke:#333333;}#mermaid-svg-YqBWtax3QBMLzrzE .marker.cross{stroke:#333333;}#mermaid-svg-YqBWtax3QBMLzrzE svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-YqBWtax3QBMLzrzE p{margin:0;}#mermaid-svg-YqBWtax3QBMLzrzE .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-YqBWtax3QBMLzrzE .cluster-label text{fill:#333;}#mermaid-svg-YqBWtax3QBMLzrzE .cluster-label span{color:#333;}#mermaid-svg-YqBWtax3QBMLzrzE .cluster-label span p{background-color:transparent;}#mermaid-svg-YqBWtax3QBMLzrzE .label text,#mermaid-svg-YqBWtax3QBMLzrzE span{fill:#333;color:#333;}#mermaid-svg-YqBWtax3QBMLzrzE .node rect,#mermaid-svg-YqBWtax3QBMLzrzE .node circle,#mermaid-svg-YqBWtax3QBMLzrzE .node ellipse,#mermaid-svg-YqBWtax3QBMLzrzE .node polygon,#mermaid-svg-YqBWtax3QBMLzrzE .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-YqBWtax3QBMLzrzE .rough-node .label text,#mermaid-svg-YqBWtax3QBMLzrzE .node .label text,#mermaid-svg-YqBWtax3QBMLzrzE .image-shape .label,#mermaid-svg-YqBWtax3QBMLzrzE .icon-shape .label{text-anchor:middle;}#mermaid-svg-YqBWtax3QBMLzrzE .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-YqBWtax3QBMLzrzE .rough-node .label,#mermaid-svg-YqBWtax3QBMLzrzE .node .label,#mermaid-svg-YqBWtax3QBMLzrzE .image-shape .label,#mermaid-svg-YqBWtax3QBMLzrzE .icon-shape .label{text-align:center;}#mermaid-svg-YqBWtax3QBMLzrzE .node.clickable{cursor:pointer;}#mermaid-svg-YqBWtax3QBMLzrzE .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-YqBWtax3QBMLzrzE .arrowheadPath{fill:#333333;}#mermaid-svg-YqBWtax3QBMLzrzE .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-YqBWtax3QBMLzrzE .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-YqBWtax3QBMLzrzE .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-YqBWtax3QBMLzrzE .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-YqBWtax3QBMLzrzE .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-YqBWtax3QBMLzrzE .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-YqBWtax3QBMLzrzE .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-YqBWtax3QBMLzrzE .cluster text{fill:#333;}#mermaid-svg-YqBWtax3QBMLzrzE .cluster span{color:#333;}#mermaid-svg-YqBWtax3QBMLzrzE 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-YqBWtax3QBMLzrzE .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-YqBWtax3QBMLzrzE rect.text{fill:none;stroke-width:0;}#mermaid-svg-YqBWtax3QBMLzrzE .icon-shape,#mermaid-svg-YqBWtax3QBMLzrzE .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-YqBWtax3QBMLzrzE .icon-shape p,#mermaid-svg-YqBWtax3QBMLzrzE .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-YqBWtax3QBMLzrzE .icon-shape .label rect,#mermaid-svg-YqBWtax3QBMLzrzE .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-YqBWtax3QBMLzrzE .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-YqBWtax3QBMLzrzE .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-YqBWtax3QBMLzrzE :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 源AVCodecParameters
avcodec_parameters_copy
重置目标对象
复制字段和动态数据
独立的目标参数对象
🌻2.应用场景和用法
2.1在参数对象之间复制编码信息
该接口适合复制源流的编解码参数到另一个AVCodecParameters,例如转封装时从输入流复制到输出流,或把参数复制到码流过滤器的输入参数对象。
| 场景 | 复制目标 | 复制后仍需处理的内容 |
|---|---|---|
| 转封装 | 输入流codecpar到输出流codecpar |
根据输出容器要求处理codec_tag等字段 |
| 码流过滤器 | 流参数到过滤器par_in |
初始化过滤器并处理其输出参数 |
| 参数快照 | 当前参数对象到新分配的对象 | 管理新对象的释放 |
| 初始化编码上下文 | 不应直接用此函数 | 使用avcodec_parameters_to_context() |
2.2函数原型与返回语义
c
int avcodec_parameters_copy(AVCodecParameters *dst,
const AVCodecParameters *src);
| 参数或返回值 | 含义 |
|---|---|
dst |
已分配的目标参数对象 |
src |
要复制的源参数对象 |
| 返回值 | 成功返回非负值,失败返回负的AVERROR错误码 |
函数会先释放目标对象已持有的动态数据,再复制结构字段。extradata、编码侧数据和AVChannelLayout等需要管理的内容会建立目标侧自己的存储。函数不接管源对象,也不改变源对象的所有权。
目标对象应由avcodec_parameters_alloc()创建,并在使用后通过avcodec_parameters_free()释放。若目标需要变成AVCodecContext,应使用avcodec_parameters_to_context();反向从上下文生成参数则使用avcodec_parameters_from_context()。
🌻3.调用流程剖析
3.1重置目标并复制字段
源码先调用内部重置逻辑清理目标对象,再把源结构中的字段复制到目标。随后将动态字段指针置空,避免目标对象沿用源对象的地址。
对于extradata,函数按extradata_size分配带输入缓冲区填充空间的新内存并复制字节。它还复制编码侧附加数据,并通过av_channel_layout_copy()建立独立声道布局。
#mermaid-svg-MZxcXRxxfaf6fein{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-MZxcXRxxfaf6fein .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-MZxcXRxxfaf6fein .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-MZxcXRxxfaf6fein .error-icon{fill:#552222;}#mermaid-svg-MZxcXRxxfaf6fein .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-MZxcXRxxfaf6fein .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-MZxcXRxxfaf6fein .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-MZxcXRxxfaf6fein .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-MZxcXRxxfaf6fein .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-MZxcXRxxfaf6fein .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-MZxcXRxxfaf6fein .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-MZxcXRxxfaf6fein .marker{fill:#333333;stroke:#333333;}#mermaid-svg-MZxcXRxxfaf6fein .marker.cross{stroke:#333333;}#mermaid-svg-MZxcXRxxfaf6fein svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-MZxcXRxxfaf6fein p{margin:0;}#mermaid-svg-MZxcXRxxfaf6fein .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-MZxcXRxxfaf6fein .cluster-label text{fill:#333;}#mermaid-svg-MZxcXRxxfaf6fein .cluster-label span{color:#333;}#mermaid-svg-MZxcXRxxfaf6fein .cluster-label span p{background-color:transparent;}#mermaid-svg-MZxcXRxxfaf6fein .label text,#mermaid-svg-MZxcXRxxfaf6fein span{fill:#333;color:#333;}#mermaid-svg-MZxcXRxxfaf6fein .node rect,#mermaid-svg-MZxcXRxxfaf6fein .node circle,#mermaid-svg-MZxcXRxxfaf6fein .node ellipse,#mermaid-svg-MZxcXRxxfaf6fein .node polygon,#mermaid-svg-MZxcXRxxfaf6fein .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-MZxcXRxxfaf6fein .rough-node .label text,#mermaid-svg-MZxcXRxxfaf6fein .node .label text,#mermaid-svg-MZxcXRxxfaf6fein .image-shape .label,#mermaid-svg-MZxcXRxxfaf6fein .icon-shape .label{text-anchor:middle;}#mermaid-svg-MZxcXRxxfaf6fein .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-MZxcXRxxfaf6fein .rough-node .label,#mermaid-svg-MZxcXRxxfaf6fein .node .label,#mermaid-svg-MZxcXRxxfaf6fein .image-shape .label,#mermaid-svg-MZxcXRxxfaf6fein .icon-shape .label{text-align:center;}#mermaid-svg-MZxcXRxxfaf6fein .node.clickable{cursor:pointer;}#mermaid-svg-MZxcXRxxfaf6fein .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-MZxcXRxxfaf6fein .arrowheadPath{fill:#333333;}#mermaid-svg-MZxcXRxxfaf6fein .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-MZxcXRxxfaf6fein .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-MZxcXRxxfaf6fein .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-MZxcXRxxfaf6fein .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-MZxcXRxxfaf6fein .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-MZxcXRxxfaf6fein .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-MZxcXRxxfaf6fein .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-MZxcXRxxfaf6fein .cluster text{fill:#333;}#mermaid-svg-MZxcXRxxfaf6fein .cluster span{color:#333;}#mermaid-svg-MZxcXRxxfaf6fein 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-MZxcXRxxfaf6fein .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-MZxcXRxxfaf6fein rect.text{fill:none;stroke-width:0;}#mermaid-svg-MZxcXRxxfaf6fein .icon-shape,#mermaid-svg-MZxcXRxxfaf6fein .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-MZxcXRxxfaf6fein .icon-shape p,#mermaid-svg-MZxcXRxxfaf6fein .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-MZxcXRxxfaf6fein .icon-shape .label rect,#mermaid-svg-MZxcXRxxfaf6fein .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-MZxcXRxxfaf6fein .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-MZxcXRxxfaf6fein .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-MZxcXRxxfaf6fein :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 源参数对象
清理目标旧数据
复制普通字段
深拷贝附加数据与声道布局
返回成功或AVERROR
复制不是合并:目标原有参数会被重置,之后由源对象的内容替代。实现先重置目标再读取源字段,因此源和目标必须是不同对象,不能把同一个指针同时作为dst和src。
3.2复制结果进入转封装或编码流程
转封装时,常见关系是in_stream->codecpar复制到out_stream->codecpar。复制成功后,应用还可能根据输出容器要求调整codec_tag,并设置输出流时间基,再写入容器头。
参数复制本身不执行码流转换。若编码格式、分辨率或采样格式需要改变,应进入解码、处理和重新编码流程,而不是只复制参数对象。
🌻4.实战案例
4.1准备源参数和目标对象
案例构造AAC音频参数,设置采样率、码率、声道布局和两字节AudioSpecificConfig,再分别分配源对象与目标对象。
4.2执行深拷贝并检查字段
调用avcodec_parameters_copy()后检查返回值、基本字段、声道布局和extradata内容。目标extradata应有自己的分配空间,释放目标对象不会释放源对象的数据。
4.3完整代码
c
#include <libavcodec/codec_par.h>
#include <libavcodec/avcodec.h>
#include <libavutil/mem.h>
#include <string.h>
int
main (void)
{
AVCodecParameters *src = NULL;
AVCodecParameters *dst = NULL;
int ret = 1;
const uint8_t aac_config[2] = { 0x12, 0x10 };
src = avcodec_parameters_alloc ();
dst = avcodec_parameters_alloc ();
if (src == NULL || dst == NULL)
goto done;
/* 设置源对象的基本AAC音频参数 */
src->codec_type = AVMEDIA_TYPE_AUDIO;
src->codec_id = AV_CODEC_ID_AAC;
src->format = AV_SAMPLE_FMT_FLTP;
src->sample_rate = 44100;
src->bit_rate = 128000;
av_channel_layout_default (&src->ch_layout, 2);
/* 准备带FFmpeg要求填充空间的codec extradata */
src->extradata = av_mallocz (
sizeof (aac_config) + AV_INPUT_BUFFER_PADDING_SIZE);
if (src->extradata == NULL)
goto done;
memcpy (src->extradata, aac_config, sizeof (aac_config));
src->extradata_size = sizeof (aac_config);
/* 将源参数复制到独立目标对象 */
if (avcodec_parameters_copy (dst, src) < 0)
goto done;
/* 检查普通字段和动态extradata是否正确复制 */
if (dst->codec_id != src->codec_id
|| dst->sample_rate != src->sample_rate
|| dst->bit_rate != src->bit_rate
|| dst->extradata_size != src->extradata_size
|| dst->extradata == src->extradata
|| memcmp (dst->extradata, src->extradata,
src->extradata_size) != 0)
goto done;
ret = 0;
done:
/* 两个参数对象分别拥有各自的动态数据 */
avcodec_parameters_free (&dst);
avcodec_parameters_free (&src);
return ret;
}
🌻5.总结
avcodec_parameters_copy()重置目标并复制源参数,为动态字段建立独立存储,不处理音视频帧或容器写入。