我已经使用 VLC 流录制了视频。录音结束后,我点击了停止按钮,几秒钟内就关闭了播放器。现在视频无法播放我以前使用过此功能并且效果很好。
由于播放器快速关闭,我认为视频现在无法播放。 我检查了编解码器详细信息,发现它丢失了。可用的视频具有 H264 - MPEG-4 VAC。
有什么办法可以解决这个问题吗?我已附上可播放视频和当前视频的详细信息。
操作系统 - Windows 11
我尝试使用 vlc 将视频转换为 avi 格式,但它没有开始转换。 我已尝试更新播放器,但它是最新版本。
首先检查以下工具是否会显示您的第一帧(仅适用于 VLC 录制 @ 720p)
如果是,那么您的 MP4 的结构如下(显示前 64 个字节):
00 00 00 18 66 74 79 70 69 73 6F 6D 00 00 00 00 ....ftypisom....
6D 70 34 31 61 76 63 31 00 00 00 00 6D 64 61 74 mp41avc1....mdat
00 00 00 00 00 00 00 00 00 00 02 B0 06 05 FF FF ...........°..ÿÿ
AC DC 45 E9 BD E6 D9 48 B7 96 2C D8 20 D9 23 EE ¬ÜEé½æÙH·–,Ø Ù#î
地点:
左侧是您的字节(写为十六进制字符)。
右侧是解码后的UTF-8文本(如果可以解码)。
在处理文件字节时始终使用十六进制编辑器进行双重检查
通过研究,您将了解到 MP4 文件分为两个主要部分。有
moov
保存元数据(解码器设置以及每帧的字节位置等所需)。另一部分是 mdat
,该部分保存原始音频/视频字节。
损坏的 VLC 录音(MP4)仅包含
mdat
部分。
要修复,您可以使用现有的 MP4 来了解所需的“原子”并将它们复制到新的(修复的)字节集中。您需要编辑名为 Sample Table 的部分(在文件中查找
stbl
)并更新这些详细信息(哪些帧是关键帧?哪些字节位置?帧的哪些时间戳?等等)。
更多信息:MP4 Atom 解析 - 如何配置时间
最简单的修复方法是尝试从 MP4 中手动提取 H.264 帧,然后使用 FFmpeg(或 VLC)将这些视频帧与之前提取的音频(通过使用修复软件)组合起来。
要提取视频帧,您需要循环遍历 MP4 内的块(称为 NAL 单元)。
您的第一个 NALU(类型为 SEI)位于 44 的位置(也称为偏移量)。从该字节位置,您可以向后退 4 个字节,然后从新位置开始,您现在可以通过读取这 4 个字节来获取 NALU 的长度(作为一个 32 位无符号整数,它是无符号的,因为我们不这样做)不要期望看到任何负号,只会返回一个正数)。
我将添加一些实用函数来帮助您入门:
要从数组中的某个位置读取 4 字节值:
function read_UInt32_BE_in_Array( in_array, startPos )
{
return ( (in_array[ startPos+0 ]) << 24 | (in_array[ startPos+1 ]) << 16 | (in_array[ startPos+2 ]) << 8 | (in_array[ startPos+3 ]) );
}
将 4 字节值写入数组中的某个位置:
function write_UInt32_BE_in_Array( in_val, in_array, startPos )
{
in_array[ startPos+0 ] = ( (in_val >> 24) & 0x000000FF );
in_array[ startPos+1 ] = ( (in_val >> 16) & 0x000000FF );
in_array[ startPos+2 ] = ( (in_val >> 8) & 0x000000FF );
in_array[ startPos+3 ] = ( (in_val >> 0) & 0x000000FF );
}
过程(伪代码):
myCurrentPos = 44; //# start of SEI data
type_NALU = myBytes[ myCurrentPos ]; //# check NALU type, should be a 6 if SEI data
sizePos = (myCurrentPos - 4); //# go back -4 steps to reach "size" bytes
sizeNum = read_32bit_BigEndian_at_Pos( sizePos ); //# read the 4 size bytes (in Big Endian format)
//# copy bytes (Array slots) from offset "myCurrentPos" up to position of +"sizeNum".
//# skip to next frame
myCurrentPos = ( sizeNum + 4 )
type_NALU = myBytes[ myCurrentPos ]; //# check NALU type, should be a 5 if Keyframe data.
//# repeat process of re-reading "sizeNum" and then copy by this length.
在输出数组中(每帧)...
00 00 00 01
。 (为新数据创建 H264 起始代码)最后将输出文件保存为
test.h264
并尝试在媒体播放器中播放。