AVI、MP4 和“原始”h264 流中的 h264。 NAL 单元格式不同(或 ffmpeg bug)

2023-11-24

TL;DR:我想从 AVI/MP4 文件读取原始 h264 流,甚至是损坏/不完整的。

几乎所有有关 h264 的文档都告诉我它由 NAL 数据包组成。好的。几乎所有地方都告诉我,数据包应该以这样的签名开头00 00 01 or 00 00 00 01。例如,https://stackoverflow.com/a/18638298/8167678, https://stackoverflow.com/a/17625537/8167678

H.264的格式是由NAL单元组成,每个单元开始 具有三个字节的起始前缀,值为 0x00、0x00、0x01 每个单位都有不同的类型,具体取决于第四个的值 这 3 个起始字节之后的字节。一个 NAL 单元不是一帧 视频中,每一帧由多个NAL单元组成。

Okay.

我下载了 random_youtube_video.mp4 并从中删除一帧:

ffmpeg -ss 10 -i random_youtube_video.mp4 -frames 1 -c copy pic.avi

And got: hexdump of AVI Red part - this is part of AVI container, other - actual data. As you can see, here I have 00 00 24 A9 instead of 00 00 00 01

这个AVI文件可以完美播放

I do same for mp4 container: hexdump of mp4

正如您所看到的,这里的字节完全相同。这个MP4文件可以完美播放

I try to strip out raw data: ffmpeg -i pic.avi -c copy pic.h264 Raw data

This file can't play in VLC or even ffmpeg, which produced this file, can't parse it: ffmpeg error

I downloaded mp4 stream analyzer and got: Analysis

MP4Box告诉我:

 Cannot find H264 start code
 Error importing pic.h264: BitStream Not Compliant

当什么都不起作用时,学习 h264 的内部结构是非常困难的。

所以,我有疑问:

  1. mp4里面的实际数据是什么?
  2. 我必须阅读什么来解码该数据(我的意思是不同的附件)
  3. 如何从这个“损坏的”原始流中读取流并获取解码图像(即使使用 ffmpeg)?

UPDATE:

ffmpeg 中似乎有错误:

当我进行双重转换时:

         ffmpeg -ss 10 -i random_youtube_video.mp4 -frames 1 -c copy pic.mp4
         ffmpeg pic.mp4 -c copy pic.h264

enter image description here

但是当我直接转换文件时:

ffmpeg -ss 10 -i random_youtube_video.mp4 -frames 1 -c copy pic.h264 with NALs

我有 NAL 签名和一个额外的 NAL 单元。其他字节相同(选定)。

这是错误?

UPDATE

不,这不是错误,您必须使用选项 -bsf h264_mp4toannexb 将流保存为“Annex B”格式(带前缀)


“我想从 AVI 文件中读取原始 h264 流,甚至是损坏/不完整的文件。”

“几乎所有地方都告诉我,数据包应该以如下签名开头:
00 00 01 or 00 00 00 01"

“......如你所见,我在这里00 00 24 A9代替00 00 00 01"

您的 H264 是 AVCC 格式,这意味着它使用数据sizes(而不是数据起始码)。只有附件 B 才会有您提到的签名作为起始代码。

您寻找帧,不是通过寻找起始代码,而是只是跳过帧大小以达到(请求的)帧的最终正确偏移量......

AVI 处理:

  • 读取大小(四)字节(32 位整数,小尾数法).

  • 提取接下来的字节,直至达到 size amount。

  • 这是您的 H.264 帧(AVCC 格式),解码字节以查看图像。

  • 要转换为附件 B,请尝试替换 H.264 的前 4 个字节帧字节 with 00 00 00 01.

考虑您显示的 AVI 字节(请参阅first图片) :

00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00     ................
00 00 00 00 4C 49 53 54 BA 24 00 00 6D 6F 76 69     ....LISTº$..movi
30 30 64 63 AD 24 00 00 00 00 24 A9 65 88 84 27     00dc.$....$©eˆ„'
C7 11 FE B3 C7 83 08 00 08 2A 7B 6E 59 B5 71 E1     Ç.þ³Çƒ...*{nYµqá
E3 9C 0E 73 E7 10 50 00 18 E9 25 F7 AA 7D 9C 30     ãœ.sç.P..é%÷ª}œ0
E6 2F 0F 20 00 3A 64 AA CA 5E 4F CA FF AE 20 04     æ/. .:dªÊ^OÊÿ® .
07 81 40 00 48 00 0A 28 71 21 84 48 06 18 90 0C     [email protected]..(q!„H....
31 14 57 9E 7A CD 63 A0 E0 9B 96 69 C5 18 AE F2     1.WžzÍc à›–iÅ.®ò
E6 07 02 29 01 20 10 70 A1 0F 8C BC 73 F0 78 FA     æ..). .p¡.Œ¼sðxú
9E 1D E1 C2 BF 8C 62 CE CE AC 14 5A A4 E1 45 44     ž.á¿ŒbÎά.Z¤áED
38 38 85 DB 12 57 3E F6 E0 FB AE 03 04 21 62 8D     88…Û.W>öàû®..!b.
F6 F1 1E 37 1C A2 FF 75 1C F1 02 66 0C 92 07 06     öñ.7.¢ÿu.ñ.f.’..
15 7C 90 15 6F 7D FC BD 13 1E 2B 0C 14 3C 0C 00     .|..o}ü½..+..<..
B0 EA 6F 53 B4 98 D7 80 7A 68 3E 34 69 20 D2 FA     °êoS´˜×€zh>4i Òú
F0 91 FC 75 C6 00 01 18 C0 00 3B 9A C5 E2 7D BF     ð‘üuÆ...À.;šÅâ}¿

一些解释:

  • 忽略前导多个00 bytes.

  • 4C 49 53 54 D6 3C 00 00 6D 6F 76 69包括30 30 64 63= AVI“列表”标题。

  • AD 24 00 00== 小数9389是AVI自己的H264项目大小(必须读入小尾数法).

请注意,AVI 字节包括...
-的一个注释item总计size (AD 24 00 00...或反转为 Little Endian :00 00 24 AD)
-其次是item data (00 00 24 A9 65 88 84 27 ... etc ... C5 E2 7D BF).

This size包括 AVI 的 4 个字节”size" 条目 + 预期字节长度item自己的字节。可以简单地写为:

AVI_Item_Size = ( 4 + item_H264_Frame.length );

AVI 中的 H.264 视频帧字节 :

接下来是item数据,即 H.264视频帧。由于格式/字节布局的纯粹巧合,它也包含一个 4 字节条目data's size(由于您的 H264 是 AVCC 格式,如果它是附件 B,那么您将在此处看到起始代码字节而不是大小字节)。

与 AVI 字节不同,这些 H264size字节被写入大尾数法 format.

  • 00 00 24 A9= 该视频帧的字节大小(而不是起始代码:00 00 00 01).

  • 65 88 84 27 C7 11 FE B3 C7= H.264keyframe(始终以 X5 开头,其中X值基于其他设置)。

  • 请记住,在四个大小字节(甚至起始代码)之后,如果后面跟着...

    • byte X5= 关键帧 (IDR),示例字节65.
    • byte X1= P 或 B 帧,示例字节41.
    • byte X6= SEI(补充增强信息)。
    • byte X7= SPS(序列参数集)。
    • byte X8= PPS(图片参数集)。
    • bytes 00 00 00 X9= 访问单元分隔符。

如果您在 AVI 文件中搜索完全相同的字节,则可以找到 H.264。看third图片,这些是您的 H.264 字节(它们被剪切并粘贴到 AVI 容器中)。

有时,一个帧会被分割成不同的 NAL 单元。因此,如果您提取关键帧并且它仅显示 1/2 或 1/3 而不是完整图像,只需抓取下一个或两个 NAL 并重新尝试解码。

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

AVI、MP4 和“原始”h264 流中的 h264。 NAL 单元格式不同(或 ffmpeg bug) 的相关文章

  • 无法在 QGLWidget 中设置所需的 OpenGL 版本

    我正在尝试在 Qt 4 8 2 中使用 QGLWidget 我注意到 QGLWidget 创建的默认上下文不显示 OpenGL 3 1 以上的任何输出 Qt wiki 有一个教程 http qt project org wiki How t
  • 如何使用C从http下载文件?

    最近几天我试图弄清楚如何从 URL 下载文件 这是我对套接字的第一个挑战 我用它来了解协议 所以我想在没有 cURL 库的情况下只用 C 语言来完成它 我搜索了很多 现在我可以打印页面的源代码 但我认为这与文件不同 我不必只将接收到的数据从
  • 带有 ASP.NET 按钮回发的 jQuery UI 对话框

    我的 ASP NET 页面上有一个运行良好的 jQuery UI 对话框 jQuery function jQuery dialog dialog draggable true resizable true show Transfer hi
  • 在 LINQ 查询中进行转换

    是否可以在 LINQ 查询中进行强制转换 为了编译器的缘故 下面的代码并不糟糕 但最好将其放入一个查询中 Content content dataStore RootControl as Controls Content List
  • 使用 POST 的 HttpWebRequest 的性能

    我有一个用于测试网络服务的小工具 它可以使用 POST 或 GET 调用 Web 服务 使用POST的代码是 public void PerformRequest WebRequest webRequest WebRequest Creat
  • 从结构调用 C++ 成员函数指针

    我找到了有关调用 C 成员函数指针和调用结构中的指针的信息 但我需要调用结构内部存在的成员函数指针 但我无法获得正确的语法 我在类 MyClass 的方法中有以下代码片段 void MyClass run struct int MyClas
  • 在 C# 中解析 JS Date.toIsoString

    我需要将 JS 日期存储为 ISO 8601 日期 我目前正在从格式为 2019 06 22T00 00 00 000Z 的表单中获取日期 正如 JS 的 toIsoString 方法所期望的那样 当这个日期传递到我的 API 控制器时 我
  • 维护 VS Test Project 中单元测试方法之间的上下文

    我想按顺序运行以下单元测试 使用随机数字的名称 密码等创建新客户 检索刚刚创建的客户并断言其属性包含相同的随机数 对同一用户调用 ForgotPassword 函数 并使用相同的随机数作为用户名 清楚地看到 我需要生成一次随机数 并在 3
  • 用于 C++ 中图像分析的 OpenCV 二进制图像掩模

    我正在尝试分析一些图像 这些图像的外部周围有很多噪声 但内部有一个清晰的圆形中心 中心是我感兴趣的部分 但外部噪声正在影响我对图像的二进制阈值处理 为了忽略噪音 我尝试设置一个已知中心位置和半径的圆形蒙版 从而使该圆之外的所有像素都更改为黑
  • 重载算术运算符

    赋值运算符可以声明为 T 运算符 const t 在类中 但不能以这种方式定义算术运算符 它必须是友元函数 我不明白为什么 你能解释一下吗 算术运算符不必须是友元 那么你可以这样定义 MyClass MyClass operator con
  • 从图像创建半透明光标

    是否可以从图像创建光标并使其半透明 我目前正在拍摄自定义图像并覆盖鼠标光标图像 如果我可以将其设为半透明 那就太好了 但不是必需的 销售人员喜欢闪亮的 目前正在做这样的事情 Image cursorImage customImage Get
  • 注入包含接口的所有已注册实现的 Enumerable

    给出以下接口 public interface IMyProcessor void Process 我希望能够注册多个实现 并让我的 DI 容器将它们的可枚举注入到这样的类中 public class MyProcessorLibrary
  • 更改私有模块片段是否会导致模块重新编译?

    On 此页面有关 C 20 模块功能 https www modernescpp com index php c 20 modules private module fragment and header units 我发现了这样的说法 借
  • 在 clang 中向量化函数

    我正在尝试根据此用 clang 对以下函数进行矢量化铿锵参考 http llvm org docs Vectorizers html 它采用字节数组向量并根据以下条件应用掩码this RFC https www rfc editor org
  • 为什么我可以在另一个函数中定义一个函数?

    请参阅下面的代码 我在另一个函数中定义了一个函数 void test1 void void test2 void printf test2 n printf test1 n int main void test1 return 0 这个用法
  • C# 多维数组解析

    我有一个多维数组 内容在调试器中看起来像这样 数组设置为 String s new String 6 4 A B Yes C A B Yes C A B No C A B Yes C A B Yes C A B Yes C A B No C
  • 为什么存在系统调用

    我一直在阅读有关系统调用及其在 Linux 中如何工作的内容 我还有更多的阅读要做 但我读过的一件事都没有回答 那就是 为什么我们需要系统调用 我知道系统调用是用户空间程序要求内核执行某些操作的请求 但我的问题基本上是 为什么用户空间程序本
  • 尝试后终于没有被调用

    由于某种原因 在我的控制台应用程序中 我无法运行我的finally 块 我编写这段代码是为了测试finally块是如何工作的 所以它非常简单 static void Main int i 0 try int j 1 i Generate a
  • 使用通用存储库模式和流畅的 nHibernate

    我目前正在开发一个中型应用程序 它将访问不同站点上的 2 个或更多 SQL 数据库等 我正在考虑使用类似的东西 http mikehadlow blogspot com 2008 03 using irepository pattern w
  • java有类似C#的属性吗? [复制]

    这个问题在这里已经有答案了 C 属性 我的意思是 get 和 set 方法 是一个非常有用的功能 java 也有类似 C 的属性吗 我的意思是我们如何在 java 中实现类似以下 C 代码的内容 public string Name get

随机推荐