我正在尝试通过本地unix套接字从Android摄像头流式传输视频,并将文件从流写入sdcard。一切正常,除了文件不能播放任何播放器。这是因为Android没有填补文件中的一些空白,因为socket不可寻找。据我所知,我需要在视频流结束后进行一些修改。我阅读了几篇文章here,here和here,但没有一篇文章对我有所帮助。我正在使用十六进制编辑器来学习如何手动完成它,所以之后在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原子之前。所以我的标题现在看起来像这样:
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!
我做错了什么?
答案 0 :(得分:13)
您需要了解的是mp4不是实时可流式处理格式。因此,无论如何你都无法破解它以使其可以流动。标题[moov atom]写在最后。 Android创建一个内存表,其中包含帧大小和其他参数,然后在记录结束时在文件的开头写入,因此需要文件句柄的可搜索性。 [哪个插座不是]
如果您正在将加密内容写入磁盘,并且您希望这样做以便没有人可以播放该文件,则您不必加密整个文件。您只需加密标头,整个文件无法播放。
如果您迫切需要完整的文件编码,因为您不相信我以前的para,那么请使用像ffmpeg这样的编码。修改它会为您提供加密输出并再次将其保存到硬盘 - 再次删除套接字部分。
您无法在Android中执行直播 mp4文件流式传输。我见过很多人徒劳无功,如果你理解视频/格式,你就无法做到。 mp4不适用于直播。除非你事先知道你的帧大小[你没有]和编码的确切长度[你很可能不知道; t]你不能预先创建标题。
PS。 mp4和3gp都是表兄弟,所以同样适用。
许多人将实时流式传输与http pd和伪流式传输混淆。实时流式传输意味着我没有整个文件,它正在被创建并且还在运行中进行流式传输。 http pd和伪流式传输使用完全可用的文件进行。
编辑:
如果您的目标是在存储到SD卡之前加密录制的文件,则需要编码器支持。这意味着在那里获得自己的编码器。拿ffmpeg,交叉编译成android。为您的应用程序编写一个小型JNI接口。首先进行此操作而不加密。完成后,ffmpeg会写入流,然后添加加密模块。解码时也一样。 Y3ng创作。这是最干净的方法。
编辑2: 请参阅spydroid以获取一些功能。那里有类似的东西。
编辑3:为了提高答案的质量,我正在解释其他答案也给出了一个不完美的解决方法:
仍然可以通过在生成mp4时解析mp4并通过套接字单独发送基本流来传输AV。您将面临的唯一问题是您将无法获得完美的AV同步,因为您不知道确切的AV样本时间戳。只有android知道它,并在最后写入mp4标题。所以对你没有好处。您必须对视频帧的完美采样率做出假设,并且您的音频必须假定为20ms数据包。在其他音频情况下,您将开始看到长跑的漂移[特别是在您开始有高动作场景的地方]。这是因为生成的每个音频数据包都不对应固定的持续时间[除了amr和其他语音编解码器]
答案 1 :(得分:4)
首先,你要做的事情并不是很清楚。
您是否只想以编程方式将视频保存到可播放的文件中?如果是这样,您只需要使用文件描述符而不是unix socket。 MediaRecord的这个API设计用于处理文件(不是unix套接字),正是出于随机访问的原因。所以,我的第一个建议是使用文件描述符,你会在录制结束时得到正确的文件。
您可以在此处获取示例:How can I capture a video recording on Android?
在这种情况下,如果您尝试编写从设备流式传输视频的应用程序,则需要在实时中解析流,按帧划分并分别发送帧。最复杂的部分是解析流(一些视频编解码器,例如H263可以被解析而其他不可以,特别是如果数据与音频交错)。
我相信这两个项目中的一个实现了这样的功能: http://sipdroid.org/ http://code.google.com/p/imsdroid/