我正在尝试通过本地Unix套接字从Android相机流式传输视频,并将文件从流写入SD卡。一切正常,除了文件不能在任何播放器上播放。这是因为Android没有填补文件中的一些空白,因为套接字是不可搜索的。 据我了解,我需要在视频流结束后进行一些修改。我在这里,这里和这里读了几篇文章,但没有一篇帮助我。我正在使用十六进制编辑器来学习如何手动执行此操作,因此之后在 Android 代码中执行相同的操作将变得微不足道。
这是从流保存的示例文件:https://dl.dropbox.com/u/17510473/sample_not_playable.3gp
任何人都可以修复以使其可玩并告诉他是如何做到的吗?
编辑:我擦除了3gp文件的标题并编写了新文件,如下所示:
00 00 00 18 66 74 79 70 33 67 70 34 00 00 03 00 33 67 70 34 33 67 70 36 00 00 00 00
然后我用以下命令找到 mdat 和 moov 原子的起始位置:
grep -aobE "ftyp|mdat|moov" sample_not_playable.3gp
它给了我以下输出:
4:ftyp
28:mdat
1414676:moov
然后做1414676 - 28 = 1,414,648 = 0x1595F8
然后我0x1595F8写成 25-28 字节,就在之前的 mdat atom 之前。所以我的标题现在看起来像这样:
00 00 00 18 66 74 79 70 33 67 70 34 00 00 03 00 33 67 70 34 33 67 70 36 00 15 95 F8
当我尝试使用mplayer播放它时,我得到了一些损坏的视频和音频输出。以下是mplayer输出中的一些部分:
[amrwb @ 0x7f72ad652380]Frame too small (33 bytes). Truncated file?
[amrwb @ 0x7f72ad652380]Encountered a bad or corrupted frame
[amrwb @ 0x7f72ad652380]Encountered a bad or corrupted frame
[amrwb @ 0x7f72ad652380]Frame too small (33 bytes). Truncated file?
[amrwb @ 0x7f72ad652380]Encountered a bad or corrupted frame
[amrwb @ 0x7f72ad652380]Encountered a bad or corrupted frame
[amrwb @ 0x7f72ad652380]Encountered a bad or corrupted frame
A: 11.0 V: 1.4 A-V: 9.650 ct: 0.023 0/ 0 10% 1% 1.6% 0 0
[mov,mp4,m4a,3gp,3g2,mj2 @ 0x7f72adeafc40]stream 1, offset 0x15e62b: partial file
[h263 @ 0x7f72ad652380]Bad picture start code
[h263 @ 0x7f72ad652380]header damaged
Error while decoding frame!
[h263 @ 0x7f72ad652380]Bad picture start code
[h263 @ 0x7f72ad652380]header damaged
Error while decoding frame!
[h263 @ 0x7f72ad652380]Bad picture start code
[h263 @ 0x7f72ad652380]header damaged
Error while decoding frame!
A: 11.1 V: 1.5 A-V: 9.558 ct: 0.027 0/ 0 9% 1% 1.4% 0 0
[h263 @ 0x7f72ad652380]Bad picture start code
[h263 @ 0x7f72ad652380]header damaged
Error while decoding frame!
我做错了什么?
您需要了解的是,mp4 不是一种可直播的格式。 因此,无论如何您都无法对其进行黑客攻击以使其可实时流式传输。标题 [moov atom] 写在末尾。Android 会在内存中创建一个帧大小和其他参数表,然后在录制结束时将其写入文件开头,因此它需要文件句柄的可搜索性。[插座不是]
如果要将加密内容写入磁盘,并且希望这样做,以便没有人可以播放该文件,则不必加密整个文件。您只需要加密标头,整个文件就无法播放。
如果您因为不相信我以前的段落而迫切需要完整的文件编码,请使用 ffmpeg 之类的东西进行编码。修改它给你加密的输出本身,并再次将其保存到硬盘 - 再次删除套接字部分。
您无法在安卓中实时流式传输 mp4 文件。我见过很多人徒劳地尝试它,如果你了解视频/格式,你就没有办法做到。MP4 不是为直播而设计的。除非您提前知道帧大小[您不知道]和编码的确切长度[您很可能不知道],否则您无法预先创建标头。
PS.mp4和3GP是表兄弟,所以同样的事情适用。
许多人将直播与http pd和伪流媒体混淆。实时流式传输意味着我没有整个文件,它正在创建并且正在动态流式传输。HTTP PD 和伪流式处理与完全可用的文件一起发生。
编辑:
如果您的目标是在存储到SD卡之前加密录制的文件,则需要编码器支持。这意味着在那里安装您自己的编码器。以ffmpeg为例,将其交叉编译为Android。为您的应用程序编写一个小的 JNI 接口。 先获取此内容,而无需加密。 完成后,ffmpeg 会写入流,添加加密模块。解码时也是如此。Y3ng 创建。这是最干净的方法。
编辑2:查看 spydroid 以获取一些功能。那里也有类似的。
编辑3:为了提高答案的质量,我正在解释其他答案也给出的不完美的解决方法:
人们仍然可以通过解析生成的 mp4 并通过套接字单独发送基本流来流式传输 AV。您将面临的唯一问题是您将无法获得完美的 AV 同步,因为您不知道确切的 AV 样本时间戳。只有安卓知道这一点,它会在最后的 mp4 标头中写下这一点。所以对你没有好处。您必须对视频帧的完美采样率做出假设,并且您的音频必须是 amr 才能假设 20ms 数据包。 在其他音频情况下,您将开始在长跑中看到漂移[尤其是在您开始出现高运动场景的情况下]。 这是因为生成的每个音频数据包不对应于固定的持续时间 [amr 和其他语音编解码器除外]
首先,目前还不清楚你想做什么。
您是否只想以编程方式将视频保存到可播放文件?如果是这样,你只需要使用文件描述符而不是 unix 套接字。MediaRecord的这个API被设计为处理文件(不是unix套接字),正是出于随机访问的原因。因此,我的第一个建议是使用文件描述符,您将在录制结束时获得正确的文件。
您可以在此处获取示例:如何在 Android 上捕获视频记录?
在这种情况下,如果您尝试编写一个从设备流式传输视频的应用程序,则需要在现实中解析流,将其除以帧并分别发送帧。最复杂的部分是解析流(一些视频编解码器,例如H263可以解析,而其他不能,特别是如果数据与音频交错)。
我相信这两个项目之一实现了这样的功能:http://sipdroid.org/http://code.google.com/p/imsdroid/