从Android Media Recorder流式传输后修复3GP文件

我试图通过本地unix socket从android摄像头流式传输video,并将文件从流写入sdcard。 一切正常,除了文件不能播放任何播放器。 这是因为Android没有填补文件中的一些空白,因为socket不可寻找。 据我了解,我需要在video流结束后进行一些修改。 我在这里 , 这里和这里阅读了几篇文章,但没有一篇文章对我有所帮助。 我正在使用hex编辑器来学习如何手动完成它,所以之后在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 

然后我用以下命令findmdat和moov atoms的起始位置:

 grep -aobE "ftyp|mdat|moov" sample_not_playable.3gp 

它给了我以下输出:

 4:ftyp 28:mdat 1414676:moov 

然后制作1414676 - 28 = 1,414,648 = 0x1595F8

然后我写0x1595F8为25-28字节,就在mdatprimefaces之前。 所以我的标题现在看起来像这样:

 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播放时,我会得到一些损坏的video和音频输出。 这是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 AV: 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 AV: 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创建一个内存表,其中包含帧大小和其他参数,然后在记录结束时在文件的开头写入,因此需要文件句柄的可搜索性。 [哪个sockets不是]

如果您正在将加密内容写入磁盘,并且您希望这样做以便没有人可以播放该文件,则您不必加密整个文件。 您只需加密标头,整个文件无法播放。

如果您迫切需要完整的文件编码,因为您不相信我以前的para,那么使用类似ffmpeg的东西来进行编码。 修改它会自动为您提供加密输出并再次将其保存到硬盘 – 再次删除套接字部分。

你无法在android中实时播放mp4文件。 我见过很多人徒劳无功,如果你理解video/格式,你就无法做到。 mp4不适用于直播。 除非你事先知道你的帧大小[你没有]和编码的确切长度[你最有可能不知道; t]你不能预先创建标题。

PS。 mp4和3gp都是表兄弟,所以同样适用。

许多人将实时流与http pd和伪流混淆。 实时流式传输意味着我没有整个文件,它正在创建并且即时流式传输。 http pd和伪流式传输使用完全可用的文件。

编辑:

如果您的目标是在存储到SD卡之前加密录制的文件,则需要编码器支持。 这意味着在那里获得自己的编码器。 拿ffmpeg,交叉编译成android。 为您的应用程序编写一个小型JNI接口。 首先不加密地获取它。 完成后,ffmpeg会写入流,然后添加加密模块。 解码时也一样。 Y3ng创作。 这是最干净的方法。

编辑2:请参阅spydroid以获得一些function。 那里有类似的。

编辑3:为了提高答案的质量,我正在解释其他答案给出的不完美的解决方法:

人们仍然可以通过在生成mp4时解析mp4并通过套接字单独发送基本流来流式传输AV。 您将面临的唯一问题是您将无法获得完美的AV同步,因为您不知道确切的AV样本时间戳。 只有android知道这一点,并在最后写入mp4标题。 所以对你没有好处。 您必须对video帧的完美采样率做出假设,并且您的音频必须假定为20ms数据包。 在其他音频情况下,您将开始看到长跑的漂移[特别是在您开始有高动作场景的地方]。 这是因为生成的每个音频数据包都不对应于固定的持续时间[除了amr和其他语音编解码器]

首先,你要做的事情并不是很清楚。

您是否只想以编程方式将video保存到可播放的文件中? 如果是这样,您只需要使用文件描述符而不是unix socket。 MediaRecord的这个API设计用于处理文件(不是unix套接字),正是出于随机访问的原因。 所以,我的第一个建议是使用文件描述符,你会在录制结束时得到正确的文件。

您可以在此处获取示例: 如何在Android上捕获video录制?

在这种情况下,如果您正在尝试编写从设备流式传输video的应用程序,则需要在实时中解析流,按帧划分并分别发送帧。 最复杂的部分是解析流(一些video编解码器,例如H263可以解析,其他不可以,特别是如果数据与音频交错)。

我相信这两个项目中的一个实现了这样的function: http : //sipdroid.org/ http://code.google.com/p/imsdroid/