了解视频轨道的组件
此示例将探讨如何查看视频轨道的布局以及如何在其中提取单个图片。
这里使用的样品内容是 Blender Foundation 的 Tears of Steel 。具体来说,我们将使用名为“HD 720p(~365MB,mov,2.0)”的下载。这是一个以扩展名 mov
结尾的单个文件,几乎可以播放任何现代媒体播放器。
我们将使用 Bento4 套件中的 mp4info 和 mp4dump 工具进行轨道布局和结构分析,使用 FFmpeg来提取构成视频轨道的单个图片。
样本电影使用 QuickTime
(MOV)打包格式,该格式基于 ISO 基础媒体文件格式 - 这是 MP4 文件格式系列中所有打包格式的基础的国际标准。这使其与大多数可用工具高度兼容,并且易于分析。
我们首先检查文件的整体结构。基于 ISO 基础媒体文件格式的所有媒体文件都被构造为一个盒子层次结构 - 一个微型文件系统。使用 mp4dump 实用程序通过执行以下命令来提取框结构:
mp4dump tears_of_steel_720p.mov
输出将类似于以下内容:
[ftyp] size=8+12
major_brand = qt
minor_version = 200
compatible_brand = qt
[wide] size=8+0
[mdat] size=8+371579623
[moov] size=8+598972
[mvhd] size=12+96
timescale = 1000
duration = 734167
duration(ms) = 734167
[trak] size=8+244250
[tkhd] size=12+80, flags=f
enabled = 1
id = 1
duration = 734167
width = 1280.000000
height = 534.000000
...
这表示文件的内部结构。例如,你在这里看到一个 moov 框,它有一个 8 字节的标题和 598972 字节的内容。此框是用于描述文件内容的各种元数据框的容器。有关各种盒子及其属性含义的更多信息,请参阅 ISO / IEC 14496-12 。
实际的媒体样本本身 - 压缩的图片和音频波形 - 存储在 mdat 框中,其内容对 mp4dump 实用程序是不透明的。
要排除不相关的数据并简化分析工作流程 - 此示例主要关注视频轨道 - 我们现在从示例影片中删除音轨。执行以下命令:
ffmpeg -i tears_of_steel_720p.mov -an -vcodec copy video_track.mov
请注意,上述步骤还将从输入视频中删除各种自定义扩展元素,将可视内容的本质打包到新的容器文件中并丢弃其他任何内容。如果你在生产场景中执行此操作,请确保你真正可以放弃输入文件中的所有其他元素!
编码视频轨道是一系列图片。使用此处使用的 H.264 编解码器 - 以及所有其他常用的现代编解码器 - 图片可以是各种不同的类型:
- I 图像 - 这些是独立图像,仅使用图像中包含的数据可解码。
- P 图像 - 这些图像将另一张图片作为基线并对该图像应用变换(例如“将这些特定像素向右移动 5 个像素”)。
- B 图像 - 类似于 P 帧,但是是双向的 - 它们还可以参考未来的图像并定义变换,例如“这些在 5 帧中完全可见的特定像素现在是 10%可见”。
图片类型的精确组合可以由编码工作流程自由选择,产生许多优化机会,尽管某些用例可能通过例如要求 I 帧以恰好 2 秒的间隔存在来约束可用的灵活性。
执行以下命令查看视频轨道的图片结构:
mp4info --show-layout video_track.mov
除了呈现整个文件元数据的人类可读形式之外,你还将看到视频轨道图片布局的详细打印输出。
...
00000959 [V] (1) size= 7615, offset=15483377, dts=491008 (39958 ms)
00000960 [V] (1)* size=104133, offset=15490992, dts=491520 (40000 ms)
00000961 [V] (1) size= 16168, offset=15595125, dts=492032 (40042 ms)
00000962 [V] (1) size= 4029, offset=15611293, dts=492544 (40083 ms)
00000963 [V] (1) size= 24615, offset=15615322, dts=493056 (40125 ms)
00000964 [V] (1) size= 4674, offset=15639937, dts=493568 (40167 ms)
00000965 [V] (1) size= 18451, offset=15644611, dts=494080 (40208 ms)
00000966 [V] (1) size= 95800, offset=15663062, dts=494592 (40250 ms)
00000967 [V] (1) size= 30271, offset=15758862, dts=495104 (40292 ms)
00000968 [V] (1) size= 10997, offset=15789133, dts=495616 (40333 ms)
00000969 [V] (1) size= 28458, offset=15800130, dts=496128 (40375 ms)
00000970 [V] (1) size= 9593, offset=15828588, dts=496640 (40417 ms)
00000971 [V] (1) size= 24548, offset=15838181, dts=497152 (40458 ms)
00000972 [V] (1) size= 6853, offset=15862729, dts=497664 (40500 ms)
00000973 [V] (1) size= 27698, offset=15869582, dts=498176 (40542 ms)
00000974 [V] (1) size= 7565, offset=15897280, dts=498688 (40583 ms)
00000975 [V] (1) size= 24682, offset=15904845, dts=499200 (40625 ms)
00000976 [V] (1) size= 5535, offset=15929527, dts=499712 (40667 ms)
00000977 [V] (1) size= 38360, offset=15935062, dts=500224 (40708 ms)
00000978 [V] (1)* size= 82466, offset=15973422, dts=500736 (40750 ms)
00000979 [V] (1) size= 13388, offset=16055888, dts=501248 (40792 ms)
00000980 [V] (1) size= 2315, offset=16069276, dts=501760 (40833 ms)
00000981 [V] (1) size= 21983, offset=16071591, dts=502272 (40875 ms)
00000982 [V] (1) size= 3384, offset=16093574, dts=502784 (40917 ms)
00000983 [V] (1) size= 22225, offset=16096958, dts=503296 (40958 ms)
...
此打印输出中的每一行都是视频轨道中包含的图片。那些用星号标记为 (1)*
的是 I-pictures。你可以看到它们的大小最大,其他的通过引用现有图片来实现更大的压缩,并且仅描述差异。
该列表还包含视频文件中图像数据的偏移和图像的解码时间戳,从而实现进一步的相关和分析。注意,图片的解码顺序/定时不一定与呈现顺序/定时相同! 如果视频中存在 B 图像,它们只能在它们引用的任何图像之后进行解码,即使它们出现在参考图像之前 !
在深入了解视频轨道的结构后,执行以下命令将从 40 秒标记开始的 30 张图片解压缩为 PNG 文件:
ffmpeg -i video_track.mov -ss 00:00:40 -vframes 30 picture%04d.png
提取的图像将被完全解码,因为它们将出现在视频播放器中 - 不可能(没有极其专业的工具)在 P 帧或 B 帧中获得原始数据的直观表示。
观察视频中第 7 个生成的图片是如何完整的场景变化。你可以轻松地将其与上面的 mp4info 输出相关联 - 从 40 秒标记(编号 00000966)开始的第 7 张图片的尺寸远大于靠近它的图片。场景更改很难编码,因为它们会刷新整个图像并包含大量新数据。如果编码器没有给予足够的宽容来优化场景变化(即不允许生成大图片),则视觉输出将是低质量或块状直到下一个 I 图像。通过检查各种图片的带宽(字节)分配,你可以深入了解可能突然出现在视频中的视觉伪像。