关于ngx_rtmp_hls_append_sps_pps造成的hls: error appenging SPS/PPS NALs错误

2023-11-16

关于ngx_rtmp_hls_append_sps_pps造成的hls: error appenging SPS/PPS NALs错误

一giao我哩giao。

今天在调试同rtmp配合nginx推流的时候,发现推live可以推成功,结果在推hls时出现以上错误,经过一顿猛虎操作,发现nginx错误日志报出了一下图片错误:
在这里插入图片描述

然后根据这个狗东西回到源码看看是什么原因造成的,看下面图片,看到是先因为在ngx_rtmp_hls_copy拷贝时缺少了5个字节的原因造成的那个狗东西。*in是类似一种节点,里面包含当前缓冲区和指向下一个缓冲区的next指针。
上面即(*in)->next时已经没有数据了,所以读取失败,最终导致hls: error appenging SPS/PPS NALs错误。
在这里插入图片描述
在这里插入图片描述

然后就开始分析分析…,为什么live都可以播放,而hls说我缺少sps/pps部分字节呢?而且我的h264裸流是包含sps/pps数据的,因为我保存下来验证多次了。所以在这里也非常的头疼。。。。

然后接着就去ffmpeg的源码中尝试寻找答案,首先肯定在写头中寻找,因为它里面有保存着关于sps/pps内容的extredata和其大小。然后跟踪该写头源码函数,发现当我们在初始化输出流的上下文AVCodecContext设置是AV_CODEC_ID_H264而不是AV_CODEC_ID_AAC格式时,ffmpeg会自动调用ff_isom_write_avcc帮我们转成AV_CODEC_ID_AAC(应该是为了在nginx在传输)。
在这里插入图片描述

结果重点来了:
跳到ff_isom_write_avcc函数中将AV_CODEC_ID_H264转化时,发现len如果小于等于6就不帮你转以至于无法转成AV_CODEC_ID_AAC在nginx传输,所以就报出上面的狗东西。
继续往下看。
在这里插入图片描述

看回上上张图片,这个len就是我们par->extradata_size,也就是用于保存sps/pps的数据,他在写头发送首包的时候被发送,看到这里已经明白了把,终于顺藤摸瓜找到源头了。

然后我立马回到初始化的函数当中看,虽然也是赋值了,但是却被后面的语句给覆盖了。。。。。。真是我日xxx。
部分代码如下(因为保密所以拷贝网上其它代码作示例):

//初始化部分
//codec_ctx->time_base = AVRational{1, 25};
//codec_ctx->bit_rate = 1400 * 1000;
stream->codecpar->time_base = AVRational{1, 25};//codecpar是新版本的解码上下文,因为旧版的后续将被分离不再使用。所以现在要慢慢习惯要新版本的。
stream->codecpar->bit_rate = 1400 * 1000;
//记住初始化一定要添加extradata数据和extradata_size大小。具体怎么做百度有的。

//结果一拷贝的时候由于我是直接给codecpar赋值而没有给codec_ctx赋值,结果就被覆盖掉了。
avcodec_parameters_from_context(stream->codecpar, codec_ctx);

所以改过来后,应该是先给旧版的AVCodecContext赋值,在赋值给新版的codecpar。

//初始化部分
codec_ctx->time_base = AVRational{1, 25};
codec_ctx->bit_rate = 1400 * 1000;
//stream->codecpar->time_base = AVRational{1, 25};//codecpar是新版本的解码上下文,因为旧版的后续将被分离不再使用。所以现在要慢慢习惯要新版本的。
//stream->codecpar->bit_rate = 1400 * 1000;
//记住初始化一定要添加extradata数据和extradata_size大小。具体怎么做百度有的。

//结果一拷贝的时候由于我是直接给codecpar赋值而没有给codec_ctx赋值,结果就被覆盖掉了。
avcodec_parameters_from_context(stream->codecpar, codec_ctx);

但是还没完,还有一点也非常重要,就是ffmpeg打开网络流和拷贝值到新版的顺序。必须要在打开网络流后才能拷贝值到新版中。即完整的写法不是上面两个,而是这个第三个写法:

//1 各种初始化,这里只写两个。
codec_ctx->time_base = AVRational{1, 25};//应该根据帧率设置
codec_ctx->bit_rate = 1400 * 1000;
//记住初始化一定要添加extradata数据和extradata_size大小。具体怎么做百度有的。

//2
avcodec_open2(codec_ctx, codec, nullptr);

//3 将AVCodecContext的成员复制到AVCodecParameters结构体。前后两行不能调换顺序
avcodec_parameters_from_context(stream->codecpar, codec_ctx);

总结:
实际上上面的错误改法步骤就是:
1)添加sps/pps数据和大小。extradata,extradata_size。
2)打开网络流和拷贝值到新版codecpar(编码时)的顺序。

这就是本篇文章的核心内容。

注意!!!:以上是编码时候写法,因为编码是由我们自定义初始化的,旧版的AVCodecContext可以认为是没有内容的,所以我们在编码时需要给旧版赋值在拷贝到新版中。两个结构最好都要有值,因为好像只有一个有我试过好像也不行。
而解码时:由于我们编码的时候已经对新版的codecpar赋过值了,所以应该以新版的值为基准,将新版的值拷贝给旧版。和上面的函数不一样,该函数为:

avcodec_parameters_to_context(codec_ctx, stream->codecpar);

具体对新版AVCodecParameters的使用可以看一下的文章:
用AVCodecParameters代替AVCodecContext

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

关于ngx_rtmp_hls_append_sps_pps造成的hls: error appenging SPS/PPS NALs错误 的相关文章

  • C 中的变量定义是什么意思[重复]

    这个问题在这里已经有答案了 你们能告诉我 这在 C 中意味着什么吗 define Privileged Data Privileged Data static int dVariable 编译器对变量进行寻址有特殊意义吗 这只是一个宏Pri
  • 切换图片框可见性 C#

    为什么图片框控件的可见性属性在这里不起作用 我最初将它们设置为 false 以便在屏幕加载时它们不可见 但后来我想切换这个 我已完成以下操作 但似乎不起作用 这是一个 Windows 窗体应用程序 private void Action w
  • C# 中的协变和逆变

    首先我要说的是 我是一名正在学习 C 编程的 Java 开发人员 因此 我会将我所知道的与我正在学习的进行比较 我已经使用 C 泛型几个小时了 我已经能够在 C 中重现我在 Java 中知道的相同内容 除了几个使用协变和逆变的示例 我正在读
  • 为什么派生类不使用基类的operator=(赋值运算符)?

    以下是实际问题的简化版本 而不是打电话Base operator int 代码似乎生成了一个临时的Derived对象并复制它 既然函数签名似乎完美匹配 为什么不使用基本赋值运算符 这个简化的示例没有显示任何不良影响 但原始代码在析构函数中有
  • 在运行时设置 DataGridView 上的 DataFormatString?

    是否可以在运行时设置 ASP NET DataGridView 中的列或单元格的 DataFormatString 属性 这应该有效 BoundField priceField grid Columns 0 as BoundField pr
  • 在 GCC 和 Clang 下,使用 lambda 的简单 RAII 包装器的复制初始化意外失败

    我在创建一个简单的 RAII 包装器时遇到了一个意想不到的问题 更不用说下面代码的逻辑不完整性了 复制构造函数和赋值运算符未删除等 这意味着是一个SSCCE 令我印象深刻的是复制初始化我的包装器与临时 lambda 的结果会导致编译错误 而
  • 为什么假设 send 可能返回的数据少于在阻塞套接字上传输的请求数据?

    在流套接字上发送数据的标准方法始终是调用 send 并写入一大块数据 检查返回值以查看是否发送了所有数据 然后再次调用 send 直到整个消息被接受 例如 这是一个常见方案的简单示例 int send all int sock unsign
  • 将 C# 反射代码移植到 Metro-Ui

    我正在尝试移植使用反射的现有 C 类 通用工厂 但我无法编译这段代码 Type types Assembly GetAssembly typeof TProduct GetTypes foreach Type type in types i
  • 在通过网络发送之前压缩位图

    我正在尝试通过网络发送位图屏幕截图 因此我需要在发送之前对其进行压缩 有一个库或方法可以做到这一点吗 当您将图像保存到流时 您have选择一种格式 几乎所有位图格式 bmp gif jpg png 都使用一种或多种压缩形式 因此 只需选择适
  • C 中的模仿函数重写

    具体来说 函数重写能够调用基本重写方法 这有两部分 一个是预编译的库代码 1 另一个是库的用户代码 2 我在这里实现了一个尽可能最小的经典 Person 和 Employee 示例 非常感谢了解 OOP 概念的铁杆 C 开发人员的回应 我正
  • 特定设备的不同字体大小

    我目前正在开发通用应用程序 我需要分别处理移动设备和桌面的文本框字体大小 我找到了一些方法 但都不能解决问题 使用 VisualStateManager 和 StateTrigger 为例
  • 如何使用泛型类型的 DataContractSerializer 编写自定义序列化器?

    我想编写一个自定义序列化器 用于将会话状态存储到Azure 缓存 预览版 这意味着这个自定义序列化器必须实现IDataCacheObjectSerializer 如果我错了 请告诉我 我需要编写这个自定义序列化程序的原因是我需要序列化一些包
  • 指示泛型返回动态类型的对象

    这个问题是我原来问题的后续问题here https stackoverflow com questions 2541184 using a type object to create a generic 假设我有以下泛型类 简化 class
  • 使用scanf()时如何区分整数和字符

    我只是使用该功能scanf 代码如下 scanf d a printf d a 当我输入1时 它会像我想要的那样打印1 但即使我输入 1a 它也会像以前一样打印 1 当用户输入非整数时 例如 2 3 12ab 1 a 我想向用户显示 输入整
  • 数据损坏 C++ 和 Python 之间的管道

    我正在编写一些代码 从 Python 获取二进制数据 将其通过管道传输到 C 对数据进行一些处理 在本例中计算互信息度量 然后将结果通过管道传输回 Python 在测试时 我发现如果我发送的数据是一组尺寸小于 1500 X 1500 的 2
  • 无法通过 LINQ to Entities 使用某些功能?

    我正在尝试使用 LINQ 查询在项目上实现搜索功能 由于数据有时包含带有重音符号和其他符号的字符 因此我创建了一种方法来删除这些字符以进行搜索 这是我的代码 var addresses from a in db Addresses join
  • 为什么C语言中可以使用多个分号?

    在 C 中我可以执行以下操作 int main printf HELLO WORLD 它有效 这是为什么 我个人的想法 分号是一个 NO OPERATION 来自维基百科 指示符 拥有一大串分号与拥有一个分号并告诉 C 语句已结束具有相同的
  • 如何强制执行特定的 UserControl 设计

    我正在编写一个基本用户控件 它将由一堆其他用户控件继承 我需要对所有这些后代控件强制执行某种设计 例如 顶部必须有几个按钮以及一个或两个标签 后代用户控件区域的其余部分可以自由放置任何内容 最初 我认为我可以将一个面板放到 Base Use
  • 通过 cmake 链接作为外部项目包含的 opencv 库[重复]

    这个问题在这里已经有答案了 我对 cmake 比较陌生 经过几天的努力无法弄清楚以下事情 我有一个依赖于 opencv 的项目 它本身就是一个 cmake 项目 我想静态链接 opencv 库 我正在做的是我的项目中有一份 opencv 源
  • 如何从函数返回矩阵(二维数组)? (C)

    我创建了一个生成宾果板的函数 我想返回宾果板 正如我没想到的那样 它不起作用 这是函数 int generateBoard int board N M i j fillNum Boolean exists True initilize se

随机推荐

  • VSCode问题记录

    20230304 0 引言 这几年的编程方式还真是各种变化 从一开始直接VIM 到后面使用jupyter进行机器学习相关 然后再过渡到vim的形式并加以tmux批量化 最后去年使用了vscode作为IDE 随着工具的变化 那么很多习惯也都随
  • UnityVR--EventManager--事件中心2

    目录 前言 事件中心的结构 EventManager事件管理器 EventType事件类型 EventListener监听及回调 EventDataBase回调时需要传递的参数 总结 前言 上一篇 事件中心1 中 简单解释了委托 事件 监听
  • 【Java SE】类和对象(全网最细详解)

    点进来你就是我的人了博主主页 戳一戳 欢迎大佬指点 欢迎志同道合的朋友一起加油喔 目录 前言 一 面向对象的初步认知 1 什么是面向对象 2 面向对象和面向过程的区别 二 类和对象的基本概念 三 类和对象的定义和使用 1 类的创建 2 对象
  • 数据库的url配置8.0

    spring datasource username root spring datasource password lhh12345 spring datasource url jdbc mysql localhost 3306 myba
  • numpy.diag()结构及用法

    numpy diag v k 0 官方文档 以一维数组的形式返回方阵的对角线 或非对角线 元素 或将一维数组转换成方阵 非对角线元素为0 两种功能角色转变取决于输入的v 1 更深层的见numpy diagnal 参数详解 v array l
  • windows获取系统DPI

    dc GetDeviceCaps LOGPIXELSX 每英寸水平逻辑像素数 dc GetDeviceCaps LOGPIXELSY 每英寸垂直逻辑像素数 dc GetDeviceCaps HORZRES 水平像素总数 dc GetDevi
  • [Java]获取java方法注释实例

    Method methods company class getMethod getId null PK pk methods getAnnotation PK class System out println pk
  • vue指令中v-show和v-if以及keep-alive的区别

    v if 属于条件显示 满足条件就显示元素 不满足就删除元素 通过操作DOM元素完成 v if的首次渲染显示的开销较小 因为它只渲染满足条件的那一个元素 切换组件时 其开销较大 因为它每切换以此就要重新触发生命周期渲染显示新元素 v if值
  • JS实现轮播图(自动+手动)

    网页轮播图效果 核心原理 tips 代码在文章末尾 这个ul就是我们这四张图片的父盒子 我们通过对这个父盒子添加动画函数来实现移动 然后给父盒子来一个溢出隐藏就达到了轮播的效果 动画函数如下 function animate obj tar
  • 【python爬虫】8.温故而知新

    文章目录 前言 回顾前路 代码实现 体验代码 功能拆解 获取数据 解析提取数据 存储数据 程序实现与总结 前言 Hello又见面了 上一关我们学习了爬虫数据的存储 并成功将QQ音乐周杰伦歌曲信息的数据存储进了csv文件和excel文件 学到
  • 8.typescript-函数的类型

    今儿个甚是乏累呢 但是 lt 下面可能是正题儿 gt 1 函数声明 1 function student x string y number string 2 return 我是 x 今年 y 岁 3 4 5 console log stu
  • 商品期货怎么玩? 1手交易需要多少钱?

    期货市场中有许多大宗商品 把他们统称为商品期货 近几年我国商品期货品种不时在增加 固然期货风险比较高 但收益也十分可观 而且商品期货开户几乎没有门槛 国内商品期货免费开户 无资金限制 凭身份证和银行卡即可办理 开设期货帐户 能在网上开期货帐
  • Unity XCode iOS 实现拍照和相册选择上传头像

    显示弹窗 通过UIAlertController来创建一个弹窗 if defined cplusplus extern C endif 导出接口供unity使用 void IOS Open IOSCameraController app I
  • 剑指 Offer 25. 合并两个排序的链表(java+python)

    输入两个递增排序的链表 合并这两个链表并使新链表中的节点仍然是递增排序的 示例1 输入 1 gt 2 gt 4 1 gt 3 gt 4 输出 1 gt 1 gt 2 gt 3 gt 4 gt 4 限制 0 lt 链表长度 lt 1000 思
  • sql语句学习(b站韩顺平的demo)

    表的CRUD varchar varchar2 char的区别 时间 时间戳使用 创建表 创建一张表 表结构与已经存在的表一致 查看表的信息 表中增加一列 修改表中的列 删除表中的列 修改表名 修改表的字符集 修改表中的列名 表中数据的插入
  • 关于算法,我们都应知道的

    定义 算法是指对特定问题求解步骤的一种描述 特性 1 有穷性 算法是由若干条指令组成的有穷序列 总是在执行若干次后结束 不可能永不停止 2 确定性 每条语句有确定的含义 无歧义 3 可行性 算法在当前环境条件下可以通过有限次运算实现 4 输
  • JavaEE学习记录day09集合03 Map集合、Stream流

    JavaEE学习记录day09集合03 Map集合 Stream流 1 Map集合 1 1Map集合概述和特点 理解 Map集合概述 interface Map
  • 看书标记【R语言数据分析与挖掘实战】5

    第五章 挖掘模型 5 1 分类预测 回归分析 回归分析是确定预测属性 数值型 与其他变量间相互依赖的定量 关系的最常用的统计学方法 包括线性回归 非线性回归 Logistic回归 因变量有0 1两种取值 岭回归 自变量间有多重共线性 主成分
  • JavaScript引擎,V8引擎的原理

    为什么需要JavaScript引擎 高级的编程语言都是需要转成最终的机器指令来执行 我们所编写的js无论h是交给浏览器或者node执行 最后都是需要被CPU执行的 CPU只认识自己的指令集 机器语言 才能被CPU所执行 所以我们需要js引擎
  • 关于ngx_rtmp_hls_append_sps_pps造成的hls: error appenging SPS/PPS NALs错误

    关于ngx rtmp hls append sps pps造成的hls error appenging SPS PPS NALs错误 一giao我哩giao 今天在调试同rtmp配合nginx推流的时候 发现推live可以推成功 结果在推h