在实际项目中,比如DVR设备,视频一般是MP4格式,MP4并非是流媒体格式,如果视频没有正常写完,会导致无法打开和播放这个MP4文件,有没有办法恢复已经保存的MP4文件,就这个文章我们讨论一下可行的方法。

首先我们需要了解MP4文件的组织架构,MP4文件都是以box的形式存储的,box非常的简单,具有如下的格式

长度 4 byte 也就是说一个box长度不超过uint32长度
名称 4 byte 比如 ftyp free mdat moov等
数据 n byte box内的真正数据

具体的MP4格式,我不会过多的介绍,可以参考其他人的博客,这里只要知道MP4结构比较简单就行了,不要产生畏难心理,以下列出一些博客,可供参考
wqyuwss的专栏
超详细MP4格式分析
以上我们就算对MP4格式有一些基础了解了,如果这些博客已经看不到了,或者不想看这些博客,也没什么大问题,针对我们的实际应用,也就是怎么修复未正常写完的MP4文件,我们往下也会分析。

首先我们需要知道为什么MP4文件打不开,没写完MP4肯定是缺少了文件的一些重要部分,一个正常的MP4文件,其结构如下:

在一级的box结构里面包含四种box类型:ftyp free mdat 和 moov。打不开的原因就是文件缺少了moov box,这个在文件结束时才能确定里面的数据,才能补充到文件的末尾。也有一些MP4文件为了在网络上快速打开,将moov放到mdat的前面,这是在文件写完时,刻意的将mdat整体向后移动moov长度字节,再将moov写到原来mdat起始位置。
是不是我们将moov补齐就可以播放了?
of course not.

我们之前介绍过,box有个描述自身长度的字段,占四个字节,我们写入视频帧到MP4文件,实际上,我们是将这些帧写入mdat box里面,这时候我们也不会去修改mdat box的长度,只有最后会更新这个长度,所以还要相应的修改mdat box的长度字段。

有了这两个地方的修改和添加,我们的MP4文件就完整了。

理论我们已经有了,实际怎么处理我们介绍两种方法。

实际当中,我们也不会自己写muxer的代码,一般我们使用一些开源的库,比如MP4V2和FFMPEG,我们这里以FFMPEG为例。

FFMPEG中基本的MP4文件写入遵循以下调用:

// 写MP4头
avformat_write_header(avfc, &dict);
// 写MP4视频帧
while(n--) {av_interleaved_write_frame(avfc, &video_packet);
}
// 写MP4视频尾,异常情况导致无法调用下面语句,使MP4无法打开
av_write_trailer(avfc);

第一种解决方法要求我们能够修改FFMPEG库,在运行时,将我们需要的数据保存下来,在修复时将moov补充到文件未尾。这需要对FFMPEG库有一定的了解,理论上是非常可行的,我们每隔比如10s,更新一次mdat box的长度字段,并且将此时的moov数据写入一个备用文件,一旦断电,我们检测到这个文件moov没有写入,那就在mdat box向后便宜mdat box 长度字节的位置上,写入我们预存的moov数据。

以上的方法要求我们一直有一个moov备用文件,而且每个10s更新一次。

第二种方法,我们可以只每10s更新一次mdat box的长度字段,甚至不更新这个字段,我们知道moov中有些数据是相对不变的(比如编码器参数,视频的宽高等),有些数据是经常变化的(比如视频时长,帧数等),相对不变的参数我们只需要从一个相似的视频文件中获取(比如DVR前一分钟我们存的视频,与后一分钟视频),经常变化的参数可以从mdat box中获取。

我们需要区分哪些是时变的参数,哪些是相对不变的参数。

对此我们需要分析 moov 中 mvhd edts 和 mdia 这些 box。充分的理解它们的数据组成。

mvhd box

字段 长度(字节单位) 描述 是否时变
size 4 mvhd box 的长度
类型 4 mvhd
版本 1 一般是0
flag 3 一般是0
生成时间 4 基准是1904-1-1 0:00 AM
修订时间 4 基准是1904-1-1 0:00 AM
Time scale 4 计算时间单位
Duration 4 视频长度
播放速度 4 1.0正常速度,16.16浮点表示
播放音量 2 1.0最大音量,8.8浮点表示
保留 10
矩阵结构 36
预览时间 4 开始预览此文件的时间
预览 duration 4
以下查阅其它博客

以上可以看到只有一个字段需要我们修改,需要知道视频的具体时长。

edts box
edts 是一个容器,里面装着 elst box,他的主要作用是对track分成一段一段的,每一段做特殊的播放处理

字段 长度 描述 是否时变
size 4 edts box 的长度
类型 4 edts
elst box n elst box

以下是elst box 的定义

字段 长度 描述 是否时变
size 4 elst box 的长度
类型 4 elst
版本 1 一般是0
flag 3 一般是0
list数量 4
list 12*n list在下面定义

list 如下

字段 长度 描述 是否时变
track duration 4 这一段在视频中的时长
开始时间 4 这一段的开始时间
播放速度 4 这一段的播放速度

这里举一个edts的例子

00 00 00 24    // edts 的长度 总共36字节
65 64 74 73    // edts 的ASCII字符
00 00 00 1C    // elst 的长度 28 字节
65 6C 73 74    // elst 的ASCII字符
00             // 版本
00 00 00       // flag
00 00 00 01    // list 数量 1个
00 00 26 6A    // 这一段的时长 也就是整个视频时长
00 00 00 00    // 从 0 时刻开始
00 01 00 00    // 播放速度 1.0 正常速度

这里我们可以看到,每个视频需要修改 track duration 为视频的整个时长即可。

mdia box
mida box 也是个容器,他的内容很多,包含 mdhd hdlr minf 三种box,同样我们一个个分析

mdhd box

字段 长度 描述 是否时变
size 4 mdhd box 的长度
类型 4 mdhd
版本 1 一般是0
flag 3 一般是0
生成时间 4
修改时间 4
time scale 4
duration 4
语言 2
质量 2

这里可以看到很多和 mvhd 一样的定义,只不过这是针对track的

hdlr box

字段 长度 描述 是否时变
size 4 mdhd box 的长度
类型 4 hdlr
版本 1 一般是0
flag 3 一般是0
Component type 4 handler 类型:mhlr(media handler)dhlr(data handler)
Component subtype 4
Component manufacturer 4
Component flags 4
Component flags mask 4
Component name n

hdlr的内容可以看成是不变的

minf box
minf box 包含 vmhd dinf stbl 三种box
vmhd box

00 00 00 14 76 6D 68 64 00 00 00 01 00 00 00 00 ; ....vmhd........
00 00 00 00                                     ; ....==================  解析  ===================
00 00 00 14: size 20
76 6D 68 64: vmhd
00: version = 0
00 00 01: flag 默认1
00 00: Graphics mode 0,直接拷贝原始图片
00 00 00 00 00 00:Opcolor 三个16位值,用于指定图形模式字段中指示的传输模式操作的红色,绿色和蓝色。

vmhd 的内容也不需要修改

dinf box
dinf 包含一个 dref box

00 00 00 24 64 69 6E 66 00 00 00 1C 64 72 65 66 ; ...$dinf....dref
00 00 00 00 00 00 00 01 00 00 00 0C 75 72 6C 20 ; ............url
00 00 00 01                                     ; ....==================  解析  ===================
00 00 00 24: size 36
64 69 6E 66: dinf
00 00 00 1C: size 28
64 72 65 66: dref
00 : version 0
00 00 00: flag 均为0
00 00 00 01:Entry count 1
00 00 00 0C 75 72 6C 20 00 00 00 01: entry data

dinf 的内容也不需要修改

stbl box
stbl 包含 stsd stts stss stsc stsz stco 6 种 box
stsd box
存放解码必须的描述信息。对于H264视频流,包含一个avc1 box,avc1包含avcC和pasp。avc1包含视频的width和height,avcC包含编码器相关信息,sps,pps等。也不需要改动。
stts box
定义每个sample的时长。

00 00 00 20 73 74 74 73    00 00 00 00 00 00 00 02    ....stts........
00 00 01 2B 00 00 0B 9A    00 00 01 00 00 00 00 00    ................==================  解析  ===================
00 00 00 20: size 32
73 74 74 73: stts
00:version
00 00 00: flag
00 00 00 02: time-to-sample 数量
00 00 01 2B: 具有相同 duration 的连续sample 数量 299
00 00 00 00: sample 的 duration 0
00 00 01 00: 具有相同 duration 的连续sample 数量 256
00 00 00 00: sample 的 duration 0

这里可以让所有sample duration 相同,只修改 sample 数量

stss box
同步sample表,存放关键帧列表,关键帧是为了支持随机访问。

00 00 00 38 73 74 73 73    00 00 00 00 00 00 00 0A    ....stss........
00 00 00 01 00 00 00 1F    00 00 00 3D 00 00 00 5B    ................
00 00 00 79 00 00 00 97    00 00 00 B5 00 00 00 D3    ...y............
00 00 F1 00 00 01 0F 00                               .......==================  解析  ===================
00 00 00 30: size 56
73 74 74 73: stss
00:version
00 00 00: flag
00 00 00 0A: 同步 sample 数量
00 00 00 01: 第1个同步 sample 序号
00 00 00 1F: 第2个同步 sample 序号
00 00 00 3D: 第3个同步 sample 序号
00 00 00 5B: 第4个同步 sample 序号
...

需要根据 mdat box 数据恢复这个表

stsc box
sample-chunk 印射表

00 00 00 40 73 74 73 63    00 00 00 00 00 00 00 04    ....stsc........
00 00 00 01 00 00 00 63    00 00 00 01 00 00 00 02    .......c........
00 00 00 68 00 00 00 01    00 00 00 03 00 00 00 60    ...h............
00 00 00 01 00 00 00 04    00 00 00 01 00 00 00 01    ................==================  解析  ===================
00 00 00 40: size 64
73 74 74 63: stsc
00:version
00 00 00: flag
00 00 00 04: sample to chunk 数量
00 00 00 01: trunk 序号 1
00 00 00 63: trunk 内 sample 数量
00 00 00 01: sample description 的序号
00 00 00 02: trunk 序号 2
00 00 00 68: trunk 内 sample 数量
00 00 00 01: sample description 的序号
00 00 00 03: trunk 序号 3
...

需要根据 mdat box 数据恢复这个表
stsz box
指定每个sample的size。

00 00 04 C4 73 74 73 7A    00 00 00 00 00 00 00 00    ....stsz........
00 00 01 2C 00 00 61 B0    00 00 15 E9 00 00 30 B0    ......a.........
00 00 24 C8 00 00 29 FA    00 00 37 49 00 00 33 5C    ................
00 00 22 A3 00 00 1E 57    00 00 25 A7 00 00 1C DB    ................==================  解析  ===================
00 00 04 C4: size 1220
73 74 74 7A: stsz
00:version
00 00 00: flag
00 00 00 00: 仅当所有sample size相同时使用
00 00 01 2C: sample 数量
00 00 61 B0: 第1个 sample 的 size
00 00 15 E9: 第2个 sample 的 size
00 00 30 B0: 第3个 sample 的 size
00 00 24 C8: 第4个 sample 的 size
...

需要根据 mdat box 数据恢复这个表
stco box
指定每个chunk在文件中的位置

00 00 00 20 73 74 63 6F    00 00 00 00 00 00 00 04    ....stco........
00 00 00 30 00 0F FC 4C    00 1F FA 2E 00 2F DA A4    ==================  解析  ===================
00 00 00 20: size 32
73 74 63 6F: stco
00:version
00 00 00: flag
00 00 00 00: 仅当所有sample size相同时使用
00 00 00 04: chunk 数量
00 00 00 30: 文件第 48 字节
00 0F FC 4C: 文件第 1047628 字节
00 1F FA 2E: 文件第 2095662 字节
00 2F DA A4: 文件第 3136164 字节
...

需要根据 mdat box 数据恢复这个表。

以上就是恢复一个仅有一个视频track的MP4文件需要恢复的数据。

mdat的数据与编码器有关,可能还需要进一步了解编码器的数据格式,比如H264编码。

=====================================================================
以上实现太过麻烦,实际上MP4有一种moof Box,能够将MP4文件分段,分段后的存储格式类似下图

只要分段足够小,视频基本上和流式媒体没什么区别,FFMPEG支持按照文件大小和时长分段,这样在保存时断电,也不会导致整个文件不可用。

设备断电等异常导致MP4文件无法打开的解决方案相关推荐

  1. 如何解决EasyGBS设备录像下载后的MP4文件无法在EasyPlayer.js播放的问题?

    TSINGSEE青犀视频的Easy系列视频监控平台均集成了EasyPlayer播放器作为网页播放能力层.关于EasyPlayer,我们也提供了非常简单易用的SDK及API接口,用户通过API调用就可以 ...

  2. html文件默认应用设置出现问题,处理win10“某个应用导致.mp4文件的默认应用设置出现问题”的方法...

    自从小编将系统升级为win10之后就一直没有出现国大的故障,直到最近使用播放器的时候.系统弹出很长的一个提示信息界面"已重置应用默认设置,某个应用导致.mp4文件的默认应用设置出现问题,因此 ...

  3. (JSP)关于手机端(尤其是苹果手机)pdf文件无法打开的解决方案

    (JSP)关于手机端(尤其是苹果手机)pdf文件无法打开的解决方案 参考文章: (1)(JSP)关于手机端(尤其是苹果手机)pdf文件无法打开的解决方案 (2)https://www.cnblogs. ...

  4. 佳能R5相机断电0KB字节DAT视频文件无法打开播放怎么数据恢复MP4

    佳能相机录制视频过程如遇到异常状况,比如说录着录着突然电池没电,人为误操作没关机前电池或者卡被意外拨出,死机,相机摔落等等意外中断录制的情况,有可能导致录制中的MP4视频变为扩展名为DAT的文件,有时 ...

  5. linux打开.mp4文件,mp4文件扩展名,mp4文件怎么打开?

    .mp4 文件类型:MPEG-4 Video File 扩展名为.mp4的文件是一个视频文件. 文件说明:Movie or video clip that uses MPEG-4 compressio ...

  6. 案例详解:Linux文件系统异常导致数据库文件无法访问

    墨墨导读:某客户单位数据库出现异常,大致现象是:数据库状态是open的,但是其中一个数据文件无法访问,本文分享排查原因与解决问题的整个过程. 通过ls 查看文件都报错,如下所示: [oracle@or ...

  7. Xmind激活版双击文件无法打开的解决方案

    声明:请大家支持正版!此文仅作个人交流学习! 很多小伙伴安装完Xmind后会发现双击无法打开文件,只能在应用界面打开,我在网上也看了很多解决方案,但是很多都是没用的,比如这个: 还有说把最大支持的文件 ...

  8. 方正排版只支持rtf格式的文件在线打开的解决方案

    利用wps后台打开的方式 将doc.docx.wps格式的文件隐藏转换为rtf格式 就可以在线打开了 //原始文件路径 var href = platformWpsUploadUrl() + &quo ...

  9. 计算机异常情况处理ppt,【计算机技能小课堂:Word/Excel/PPT电脑异常导致文件丢失,如何恢复?】- 环球网校...

    [摘要]大家周三好呀!各位环球网校的小伙伴们,新年快乐呀,2020大家要加油哦.今天这一期计算机技能小课堂:word技巧干货!Word Excel PPT电脑异常导致文件丢失,如何恢复.这个主题听起来 ...

最新文章

  1. Linux查看网络信息
  2. kali装电脑_Kali Linux可以安装到平板电脑吗?
  3. python模块实例化_python中zipfile模块实例化解析
  4. ios开发之--调整UISearchBar的输入框的背景颜色
  5. 【caffe】Layer解读之:Date
  6. 前端工程师的价值体现在哪里?
  7. Codeforces Round #469 (Div. 1 A-E)
  8. 计算机网络网络适配器的作用是什么原因,Win10网络适配器在哪里对网络有什么影响 网络适配器出现各种故障的解决方法...
  9. Mac电脑批量修改图片名称
  10. python爬虫— 利用js2xml 获取 script 数据
  11. JS实现刷新_重新加载页面
  12. 【项目】出库流程记录
  13. Python 数据挖掘之中医证型关联规则挖掘
  14. 阿里云推出高效病毒基因序列检索功能,它的底层逻辑原来是这样的
  15. OpenCV(4.0.0) Error: Assertion failed (dst.data == (uchar*)dst_ptr) in cvShowImage
  16. 【论文阅读】Multimodal Fusion with Co-Attention Networks for Fake News Detection --- 虚假新闻检测,多模态融合
  17. android 组件可见,android界面控件可见性方法setVisibility()3个可选参数(visible,invisible,gone)的区别...
  18. 获得天气相关接口六-获得城市最新天气预警
  19. 深度学习基本知识(一)评价方法precision\recall\mAP
  20. 2021年下半年信息系统项目管理师《综合知识》《案例分析》《论文》真题与答案

热门文章

  1. 剑指offer T58-||
  2. extends和implements的区别
  3. python支持double_将int转换为double Python
  4. 资深架构师教你一篇文看懂Hadoop
  5. EasyBCD的使用心得
  6. 内师大计算机学院有博士点吗,山西师范大学博士点哪些
  7. 七夕节-520程序猿(媛)
  8. 《炬丰科技-半导体工艺》湿法清洗过程中硅片表面颗粒的去除
  9. nRF52笔记(19)sd_ble_gap_scan_start主机扫描的使用
  10. 重阳节教育课件PPT模板