Linux FFmpeg深度解析之avcodec_parameters_copy调用流程与实战(二十五)

简介: 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()重置目标并复制源参数,为动态字段建立独立存储,不处理音视频帧或容器写入。

相关推荐
cakeism8254 小时前
2026 中国企业 DevOps 平台选型:从工具链到一体化平台的决策框架
运维·servlet·devops
Z21-X4 小时前
云原生运维实战笔记:华为云存储类服务全景解析——EVS、OBS、SFS与CBR深度实践
运维·笔记·学习·云原生·华为云
Decay__4 小时前
17_MySQL 监控体系构建 —— mysqld_exporter + Prometheus + Grafana 全栈实战
运维·数据库·sql·mysql·架构
ITKEY_4 小时前
emacs 文件管理Dired, the Directory Editor
linux·编辑器·emacs
天远数科4 小时前
零信任架构实战:基于天远全能家政风险报告构建自动化即时到家保洁与短工抢单安全核验网关
运维·人工智能·架构·自动化
源图客4 小时前
解决CentOS操作系统网络异常问题
linux·运维·centos
听我哔哔4 小时前
口播视频唇形总对不上?Seedance 2.5 在 zeekeAI 里的同步实操
人工智能·音视频
分布式存储与RustFS4 小时前
K8s 集群备份落到自建对象存储:Velero 接 RustFS 配置指南
运维·云原生·开源·对象存储·分布式存储·s3·性能基准
Liuqy-055 小时前
IO模型与并发服务器
服务器·网络·select·多线程·epoll·并发服务器·io多路复用