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

简介: CSDN博客专家、《Android系统多媒体进阶实战》作者

博主新书推荐:《Android系统多媒体进阶实战》🚀

Android Audio工程师专栏地址:Audio工程师进阶系列【原创干货持续更新中...... 】🚀

Android多媒体专栏地址:多媒体系统工程师系列【原创干货持续更新中...... 】🚀

专题一 二:AAOS车载系统+AOSP14系统攻城狮入门视频实战课 🚀

专题三:Android14 Binder之HIDL与AIDL通信实战课 🚀

专题四:Android15快速自定义与集成音效实战课 🚀

专题五:Android15音频策略实战课 🚀

专题六:Android15音频性能实战课(无声/杂音/断音/爆音实战案例) 🚀

人生格言: 人生从来没有捷径,只有行动才是治疗恐惧和懒惰的唯一良药.
更多原创,欢迎关注:Android系统攻城狮

点击获取二维码

🍉🍉🍉文章目录🍉🍉🍉

🌻1.前言

本篇目的:理解avcodec_parameters_from_context()如何把AVCodecContext中的编解码参数复制到AVCodecParameters,明确复制范围、目标对象所有权和它在封装流程中的位置。

编码器Context包含编码配置和运行状态,封装器需要的是描述码流的参数对象。avcodec_parameters_from_context()把Context中的编解码类型、格式、尺寸、采样信息和额外数据复制到AVCodecParameters。它不会打开编码器,也不会写入容器文件。
#mermaid-svg-hngiZ1uUTzz01dzZ{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-hngiZ1uUTzz01dzZ .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-hngiZ1uUTzz01dzZ .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-hngiZ1uUTzz01dzZ .error-icon{fill:#552222;}#mermaid-svg-hngiZ1uUTzz01dzZ .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-hngiZ1uUTzz01dzZ .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-hngiZ1uUTzz01dzZ .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-hngiZ1uUTzz01dzZ .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-hngiZ1uUTzz01dzZ .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-hngiZ1uUTzz01dzZ .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-hngiZ1uUTzz01dzZ .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-hngiZ1uUTzz01dzZ .marker{fill:#333333;stroke:#333333;}#mermaid-svg-hngiZ1uUTzz01dzZ .marker.cross{stroke:#333333;}#mermaid-svg-hngiZ1uUTzz01dzZ svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-hngiZ1uUTzz01dzZ p{margin:0;}#mermaid-svg-hngiZ1uUTzz01dzZ .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-hngiZ1uUTzz01dzZ .cluster-label text{fill:#333;}#mermaid-svg-hngiZ1uUTzz01dzZ .cluster-label span{color:#333;}#mermaid-svg-hngiZ1uUTzz01dzZ .cluster-label span p{background-color:transparent;}#mermaid-svg-hngiZ1uUTzz01dzZ .label text,#mermaid-svg-hngiZ1uUTzz01dzZ span{fill:#333;color:#333;}#mermaid-svg-hngiZ1uUTzz01dzZ .node rect,#mermaid-svg-hngiZ1uUTzz01dzZ .node circle,#mermaid-svg-hngiZ1uUTzz01dzZ .node ellipse,#mermaid-svg-hngiZ1uUTzz01dzZ .node polygon,#mermaid-svg-hngiZ1uUTzz01dzZ .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-hngiZ1uUTzz01dzZ .rough-node .label text,#mermaid-svg-hngiZ1uUTzz01dzZ .node .label text,#mermaid-svg-hngiZ1uUTzz01dzZ .image-shape .label,#mermaid-svg-hngiZ1uUTzz01dzZ .icon-shape .label{text-anchor:middle;}#mermaid-svg-hngiZ1uUTzz01dzZ .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-hngiZ1uUTzz01dzZ .rough-node .label,#mermaid-svg-hngiZ1uUTzz01dzZ .node .label,#mermaid-svg-hngiZ1uUTzz01dzZ .image-shape .label,#mermaid-svg-hngiZ1uUTzz01dzZ .icon-shape .label{text-align:center;}#mermaid-svg-hngiZ1uUTzz01dzZ .node.clickable{cursor:pointer;}#mermaid-svg-hngiZ1uUTzz01dzZ .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-hngiZ1uUTzz01dzZ .arrowheadPath{fill:#333333;}#mermaid-svg-hngiZ1uUTzz01dzZ .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-hngiZ1uUTzz01dzZ .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-hngiZ1uUTzz01dzZ .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-hngiZ1uUTzz01dzZ .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-hngiZ1uUTzz01dzZ .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-hngiZ1uUTzz01dzZ .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-hngiZ1uUTzz01dzZ .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-hngiZ1uUTzz01dzZ .cluster text{fill:#333;}#mermaid-svg-hngiZ1uUTzz01dzZ .cluster span{color:#333;}#mermaid-svg-hngiZ1uUTzz01dzZ 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-hngiZ1uUTzz01dzZ .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-hngiZ1uUTzz01dzZ rect.text{fill:none;stroke-width:0;}#mermaid-svg-hngiZ1uUTzz01dzZ .icon-shape,#mermaid-svg-hngiZ1uUTzz01dzZ .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-hngiZ1uUTzz01dzZ .icon-shape p,#mermaid-svg-hngiZ1uUTzz01dzZ .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-hngiZ1uUTzz01dzZ .icon-shape .label rect,#mermaid-svg-hngiZ1uUTzz01dzZ .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-hngiZ1uUTzz01dzZ .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-hngiZ1uUTzz01dzZ .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-hngiZ1uUTzz01dzZ :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 已配置或打开的AVCodecContext
avcodec_parameters_from_context
目标AVCodecParameters
复制通用编解码字段
复制媒体类型专属字段
复制额外数据和侧数据
供封装器使用的参数对象

🌻2.应用场景和用法

2.1把编码器参数交给封装器

典型封装流程会为输出文件创建AVFormatContext和AVStream,编码器则使用独立的AVCodecContext。编码参数确定后,程序需要把参数复制到AVStream->codecpar,供封装器写文件头和处理码流。

对于编码器,常见做法是在avcodec_open2()成功后调用avcodec_parameters_from_context(),这样编码器初始化得到的参数和额外数据也有机会被复制。解码流程也可以把已打开解码器Context的参数复制到参数对象,但如果最初数据已经在AVStream->codecpar中,通常不需要绕道复制。

使用场景 源对象 目标对象
编码后写入容器 编码器AVCodecContext 输出流的AVCodecParameters
重建或检查码流描述 已配置的AVCodecContext 独立分配的AVCodecParameters
缓存编解码信息 Context中的参数字段 调用者管理的参数对象
拷贝失败 任意有效Context 根据负错误码检查内存分配或侧数据复制问题
2.2函数原型与复制语义

函数原型如下:

c 复制代码
int
avcodec_parameters_from_context (AVCodecParameters *par,
                                 const AVCodecContext *codec);

par是目标对象,codec是只读源Context。函数会先重置目标参数对象,再复制公共字段以及视频、音频或字幕对应的专属字段。若Context含有extradata,函数会为目标分配独立内存并复制数据;侧数据和声道布局也通过各自的复制逻辑处理。

成功返回0,失败返回负错误码。该函数不会修改源Context。目标对象中原有的动态字段会被释放并替换,因此调用者应传入已正确初始化或由avcodec_parameters_alloc()分配的对象。对象最终由avcodec_parameters_free()释放。

🌻3.调用流程剖析

3.1重置目标并复制通用字段

函数首先重置目标AVCodecParameters,清理它先前持有的参数和动态数据,然后复制媒体类型、Codec ID、Codec Tag、码率、Profile和Level等通用字段。

这一步决定目标对象以源Context当前的编解码信息为准。它属于一次覆盖式同步,不是把新字段追加到目标对象,也不是两个对象之间建立共享引用。

3.2按媒体类型复制字段和动态数据

视频分支复制像素格式、宽高、场序、色彩信息、Sample Aspect Ratio和帧率等字段。音频分支复制采样格式、声道布局、采样率、Block Align、Frame Size和Padding信息。字幕分支复制宽高。

完成类型字段后,函数会为extradata分配新内存并复制内容,同时复制编码侧数据和声道布局。由于目标持有自己的副本,复制后释放Context不会直接释放参数对象中的这些动态数据。
#mermaid-svg-wqyp7sa4DnUsTaPW{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-wqyp7sa4DnUsTaPW .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-wqyp7sa4DnUsTaPW .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-wqyp7sa4DnUsTaPW .error-icon{fill:#552222;}#mermaid-svg-wqyp7sa4DnUsTaPW .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-wqyp7sa4DnUsTaPW .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-wqyp7sa4DnUsTaPW .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-wqyp7sa4DnUsTaPW .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-wqyp7sa4DnUsTaPW .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-wqyp7sa4DnUsTaPW .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-wqyp7sa4DnUsTaPW .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-wqyp7sa4DnUsTaPW .marker{fill:#333333;stroke:#333333;}#mermaid-svg-wqyp7sa4DnUsTaPW .marker.cross{stroke:#333333;}#mermaid-svg-wqyp7sa4DnUsTaPW svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-wqyp7sa4DnUsTaPW p{margin:0;}#mermaid-svg-wqyp7sa4DnUsTaPW .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-wqyp7sa4DnUsTaPW .cluster-label text{fill:#333;}#mermaid-svg-wqyp7sa4DnUsTaPW .cluster-label span{color:#333;}#mermaid-svg-wqyp7sa4DnUsTaPW .cluster-label span p{background-color:transparent;}#mermaid-svg-wqyp7sa4DnUsTaPW .label text,#mermaid-svg-wqyp7sa4DnUsTaPW span{fill:#333;color:#333;}#mermaid-svg-wqyp7sa4DnUsTaPW .node rect,#mermaid-svg-wqyp7sa4DnUsTaPW .node circle,#mermaid-svg-wqyp7sa4DnUsTaPW .node ellipse,#mermaid-svg-wqyp7sa4DnUsTaPW .node polygon,#mermaid-svg-wqyp7sa4DnUsTaPW .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-wqyp7sa4DnUsTaPW .rough-node .label text,#mermaid-svg-wqyp7sa4DnUsTaPW .node .label text,#mermaid-svg-wqyp7sa4DnUsTaPW .image-shape .label,#mermaid-svg-wqyp7sa4DnUsTaPW .icon-shape .label{text-anchor:middle;}#mermaid-svg-wqyp7sa4DnUsTaPW .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-wqyp7sa4DnUsTaPW .rough-node .label,#mermaid-svg-wqyp7sa4DnUsTaPW .node .label,#mermaid-svg-wqyp7sa4DnUsTaPW .image-shape .label,#mermaid-svg-wqyp7sa4DnUsTaPW .icon-shape .label{text-align:center;}#mermaid-svg-wqyp7sa4DnUsTaPW .node.clickable{cursor:pointer;}#mermaid-svg-wqyp7sa4DnUsTaPW .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-wqyp7sa4DnUsTaPW .arrowheadPath{fill:#333333;}#mermaid-svg-wqyp7sa4DnUsTaPW .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-wqyp7sa4DnUsTaPW .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-wqyp7sa4DnUsTaPW .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-wqyp7sa4DnUsTaPW .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-wqyp7sa4DnUsTaPW .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-wqyp7sa4DnUsTaPW .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-wqyp7sa4DnUsTaPW .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-wqyp7sa4DnUsTaPW .cluster text{fill:#333;}#mermaid-svg-wqyp7sa4DnUsTaPW .cluster span{color:#333;}#mermaid-svg-wqyp7sa4DnUsTaPW 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-wqyp7sa4DnUsTaPW .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-wqyp7sa4DnUsTaPW rect.text{fill:none;stroke-width:0;}#mermaid-svg-wqyp7sa4DnUsTaPW .icon-shape,#mermaid-svg-wqyp7sa4DnUsTaPW .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-wqyp7sa4DnUsTaPW .icon-shape p,#mermaid-svg-wqyp7sa4DnUsTaPW .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-wqyp7sa4DnUsTaPW .icon-shape .label rect,#mermaid-svg-wqyp7sa4DnUsTaPW .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-wqyp7sa4DnUsTaPW .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-wqyp7sa4DnUsTaPW .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-wqyp7sa4DnUsTaPW :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 视频
音频
字幕
源AVCodecContext
重置目标参数
复制通用字段
媒体类型
复制视频格式和尺寸
复制采样格式和声道布局
复制字幕尺寸
复制额外数据和侧数据
返回结果码

封装器仍需由调用者创建和配置。参数复制完成后,常见后续步骤是调用avformat_write_header()写容器头;avcodec_parameters_from_context()本身既不创建AVStream,也不写文件。

🌻4.实战案例

4.1配置MPEG-4编码器

示例使用MPEG-4视频编码器,配置320×240、YUV420P、25帧每秒和目标码率。编码器打开成功后,再准备一个独立的AVCodecParameters作为封装参数目标。

4.2复制编码参数并检查结果

调用avcodec_parameters_from_context()后,检查返回值以及目标对象中的Codec ID、宽高和像素格式。目标参数对象是副本,可以在释放Context后继续使用,直到调用avcodec_parameters_free()。

4.3完整代码
c 复制代码
#include <libavcodec/avcodec.h>
#include <libavutil/pixfmt.h>

int
main (void)
{
  const AVCodec *encoder;
  AVCodecContext *context = NULL;
  AVCodecParameters *parameters = NULL;
  int ret;

  /* 查找MPEG-4视频编码器 */
  encoder = avcodec_find_encoder (AV_CODEC_ID_MPEG4);
  if (encoder == NULL)
    return 1;

  /* 分配编码器Context并设置编码参数 */
  context = avcodec_alloc_context3 (encoder);
  if (context == NULL)
    return 1;

  context->width = 320;
  context->height = 240;
  context->pix_fmt = AV_PIX_FMT_YUV420P;
  context->time_base = (AVRational) { 1, 25 };
  context->framerate = (AVRational) { 25, 1 };
  context->bit_rate = 400000;
  context->gop_size = 12;
  context->max_b_frames = 2;

  /* 打开编码器,使最终编码参数就绪 */
  ret = avcodec_open2 (context, encoder, NULL);
  if (ret < 0)
    goto done;

  /* 创建独立的封装参数对象 */
  parameters = avcodec_parameters_alloc ();
  if (parameters == NULL) {
    ret = AVERROR (ENOMEM);
    goto done;
  }

  /* 把Context中的编码参数复制到参数对象 */
  ret = avcodec_parameters_from_context (parameters, context);
  if (ret < 0)
    goto done;

  /* 确认复制后的基本视频参数 */
  if (parameters->codec_id != AV_CODEC_ID_MPEG4 ||
      parameters->width != 320 ||
      parameters->height != 240 ||
      parameters->format != AV_PIX_FMT_YUV420P) {
    ret = AVERROR_INVALIDDATA;
    goto done;
  }

  ret = 0;

done:
  /* 两个对象独立释放,参数副本不依赖Context生命周期 */
  avcodec_parameters_free (&parameters);
  avcodec_free_context (&context);

  return ret < 0 ? 1 : 0;
}

🌻5.总结

avcodec_parameters_from_context()把AVCodecContext中的编解码描述复制到独立的AVCodecParameters对象,供封装器或其他组件使用。

相关推荐
思想觉悟1 小时前
SEAndroid实战
android·linux·c++
隔窗听雨眠1 小时前
从存储引擎到执行计划:OceanBase高效运维的调优逻辑与工程实践
运维·oceanbase
运维行者_1 小时前
供应链安全成最大风险源,企业如何构建可控的运维体系?
运维·开发语言·网络·数据库·安全·云计算·流量监控
xiaoyunxuexibiji1 小时前
采购协同管理:从备货计划、进度确认到到货签收
大数据·运维·人工智能
画中有画1 小时前
在自动化脚本中调用其他脚本文件
运维·自动化
前进吧-程序员2 小时前
C++20 协程实战:手写 Task、单线程调度器与 awaiter 的三个钩子
linux
Android系统攻城狮2 小时前
Linux FFmpeg深度解析之avcodec_alloc_context3调用流程与实战(十四)
linux·运维·ffmpeg·车载音视频·音视频进阶·ffmpeg音视频进阶
老李IT笔记2 小时前
抹除之后机器上的受管应用可以留下:这一步省掉的是哪段时间
运维·服务器
自由彩虹2 小时前
靶场通关15--bossplayersctf
linux·服务器·网络·安全·web安全·网络安全