2015-09-06 916 views
1

在我的网站上,用户可以上传视频,这些视频在运行中加密并存储在另一台服务器上。我想存储视频比特率,帧速率等,但我要他们不要直接访问,我不能只使用下面的命令:ffprobe - 从文件块中获取视频信息

ffprobe -show_streams -i file.mp4 

我想救了我的服务器上的最后一个块,其中包含MOOV原子但ffprobe正在输出:

Format mov,mp4,m4a,3gp,3g2,mj2 detected only with low score of 1, misdetection possible! 
moov atom not found 
C:\file.mp4: Invalid data found when processing input 

我检查和截断的至少一个字节的原因此,虽然moov atom的是完整的。

从包含moov原子的文件片段获取视频元数据的正确方法是什么?从mdata原子获取信息怎么样?

回答

6

我不认为ffmpeg解析器知道如何找到分块文件的moov原子。它按大块解析(读取或跳过)大块的mp4文件,直到找到moov原子,并且如果您要截断开始的一部分,块结构就会被破坏,因此它不会找到moov原子。

对于您来说,一种可能的解决方案是检测最后具有moov原子的文件,并通过使用-movflags + faststart(或c/C++代码中的类似AVOptions)与ffmpeg重新混合来将moov原子移动到开头。 。然后你可以在moov原子和解析头文件后仍然可以截断文件。

[编辑]

所以,写截片段感知修改的MOV分路器(见注释)的情况下,这里是你将如何去。首先,尽量不要修改mov_read_default(),它是中央递归引擎,此处的任何更改都可能会破坏大多数常规功能。相反,请更改mov_read_header()(因为您只关心标题解析,而不是帧的多路解析)。你会发现这个代码:

if (mov->moov_retry) 
    avio_seek(pb, 0, SEEK_SET); 
if ((err = mov_read_default(mov, pb, atom)) < 0) { 
    av_log(s, AV_LOG_ERROR, "error reading header\n"); 
    mov_read_close(s); 
    return err; 
} 
} while (pb->seekable && !mov->found_moov && !mov->moov_retry++); 
if (!mov->found_moov) { 

这是试图解码标题树结构,其中moov是上层原子。在文件中,它看起来像这样的序列:

$ hexdump -n 32 -s 41934133 -C somefile.mov 
027fdd35 00 00 3e b4 6d 6f 6f 76 00 00 00 6c 6d 76 68 64 |..>.moov...lmvhd| 
027fdd45 00 00 00 00 c9 6b 7b f5 c9 6b 7c 02 00 00 02 58 |.....k{..k|....X| 

0x00003eb4是在“moov”逻辑原子的字节大小,并在其为所谓的大小0x0000006c字节(树结构“mvhd”亚原子在此之后继续进行一段时间)。如果你设置文件指针到该多路分解文件时确切的偏移量,它会被正确地解码:

$ tail -c +41934134 somefile.mov > /tmp/hdr.mov 
$ ffprobe /tmp/hdr.mov 
[..] 
[mov,mp4,m4a,3gp,3g2,mj2 @ 0x7f871b002a00] stream 0, offset 0x3f3e: partial file 
[mov,mp4,m4a,3gp,3g2,mj2 @ 0x7f871b002a00] Could not find codec parameters for stream 0 (Video: h264 (avc1/0x31637661), none(bt709), 1280x720, 10695 kb/s): unspecified pixel format 
[..] 
    Stream #0:0(und): Video: h264 (avc1/0x31637661), none(bt709), 1280x720, 10695 kb/s, 29.97 fps, 29.97 tbr, 600 tbn, 1200 tbc (default) 
[..] 
    Stream #0:1(und): Audio: aac (LC) (mp4a/0x6134706D), 44100 Hz, mono, fltp, 63 kb/s (default) 

你怎么得到的文件偏移到这一点是由你:

  • 您可以添加一些代码到mov_read_header()扫描文件的'moov'(0x6d6f6f76)并设置文件指针4个字节,然后在那个
  • 你可以在你的代码中创建这个片段,扫描moov并截断前导垃圾将该片段保存到文件之前的moov原子

如果您要更改ffmpeg并将其放入ffmpeg版本中,您也可以将其用于其他功能,那么我建议您将其置于某种选项下,以使其不能用于默认文件读取。否则,你可能会冒常规mov/mp4文件解析无法正常工作的风险。

+0

如果我可以在整个文件上使用ffmpeg,我不会问问题。 –

+0

如果你从来没有在磁盘上的整个文件,我不认为ffmpeg可以帮助你。你可以在你的最后一个片段上尝试mplayer,但我怀疑它会做得更好。或者,您可以使用ffmpeg demuxer中的相关代码编写自己的头文件解析器。 (我的印象是,服务器可以访问未加密的文件,因为你可以访问最后一个片段。) –

+0

实际上,考虑到它,你甚至可以添加一个额外的“moov片段分解器”,忽略块和只是扫描对于moov原子,并使用从moov片段分割器调用的ffmpeg中现有的moov解析代码。然后注册为ffmpeg分路器。这样你就可以编写最少的代码。如果你对这种方法感兴趣,我可以给出更多的提示。 –