【问题标题】:Fix 3GP file after streaming from Android Media Recorder从 Android Media Recorder 流式传输后修复 3GP 文件
【发布时间】:2012-08-13 05:36:45
【问题描述】:

我正在尝试通过本地 unix 套接字从 android 相机流式传输视频并将文件从流写入 sdcard。一切正常,除了文件不能用任何播放器播放。这是因为 Android 没有填补文件中的一些空白,因为套接字是不可搜索的。据我了解,我需要在视频流结束后进行一些修改。我读了几篇文章hereherehere,但都没有帮助我。我正在使用十六进制编辑器来学习如何手动执行此操作,因此之后在 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!

我做错了什么?

【问题讨论】:

  • 你想知道如何为Android流媒体编码3gp视频吗?
  • 我从 Android 设备接收到有效流,录制该流,然后我想让录制的文件可播放。就是这样。

标签: android video video-streaming 3gp android-mediarecorder


【解决方案1】:

您需要了解的是,mp4 不是 live 可流式传输格式。因此,无论如何您都无法破解以使其实时流式传输。标题 [moov atom] 写在最后。 Android 创建一个帧大小和其他参数的内存表,然后在记录结束时将其写入文件开头,因此它需要文件句柄的可查找性。 [不是套接字]

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

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

您无法在 android 中对 mp4 文件进行 live 流式传输。我见过很多人徒劳地尝试它,如果您了解视频/格式,就没有办法做到这一点。 mp4 不是为直播而设计的。除非您事先知道帧大小 [您不知道] 和编码的确切长度 [您很可能不知道;t],否则您无法预先创建标头。

ps。 mp4 和 3gp 是近亲,所以同样适用。

许多人将实时流媒体与 http pd 和伪流媒体混淆。实时流媒体意味着我没有整个文件,它正在创建并且还在动态流中。 http pd 和伪流使用完全可用的文件进行。

编辑:

如果您的目标是在存储到 sdcard 之前加密录制的文件,则需要编码器支持。这意味着在其中安装您自己的编码器。拿ffmpeg,交叉编译到android。为您的应用程序编写一个小的 JNI 接口。先把它弄好,不用加密。完成后,在 ffmpeg fwrite 流的位置,添加您的加密模块。解码时同样的事情。 Y3ng 创作。这是最干净的方法。

编辑 2: 请参阅 spydroid 以获得一些适合您的功能。那里有类似的。

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

仍然可以通过解析生成的 mp4 并通过套接字分别发送基本流来流式传输 AV。您将面临的唯一问题是您将无法获得完美的 AV 同步,因为您不知道确切的 AV 样本时间戳。只有 android 知道这一点,并将其写入最后的 mp4 标头中。所以对你没有好处。您必须对视频帧的完美采样率做出假设,并且您的音频必须是 amr 才能假设 20ms 数据包。在其他音频案例中,您将开始看到长时间运行的漂移[尤其是在您开始出现高运动场景的情况下]。这是因为每个生成的音频包不对应固定的时长【amr等语音编解码器除外】

【讨论】:

  • 感谢您很好地解释了我的问题。问题是我迫切需要加密整个文件。我仅将套接字用于需要动态加密视频的目的(该要求也很迫切)。那么,你能提出什么建议?我有以下要求: 1. 在 android 设备上录制视频时即时加密视频(不将任何未加密的数据写入磁盘),2. 能够在设备上播放文件,从而动态解密并提供解密的流到视频播放器。 3. 能够解密文件,拥有完全可播放的视频,可以在PC上的任何播放器上播放。
  • 然后就像我建议的那样,您需要放入自己的编码器来进行编码。使用 ffmpeg 并将其安装到设备上。一旦你有了它,只需在输出之前对其进行一些更改以加密输出。还使用 ffmpeg 解码流,因此在解码之前解密输入。对于第 3 点,您可以自己编写一个非常简单的解密模块,该模块只需输入一个文件并输出另一个文件。
  • 谢谢。但我不是在 NDK 中编码。 Java中是否有视频编码的实现?你能建议我可以将视频编码成什么格式吗?你能为此提供一些代码sn-ps吗?
  • 好的。问题是我已经有使用 Java 而不是 JNI 的加密模块。我需要使用它。我阅读了 spydroid 的整个源代码。事实上,我从那里学会了如何通过本地套接字流式传输视频。 Spydroid 使用它的 h263 打包器将流转换为 RTP。你能建议我需要什么格式来编码我的视频以匹配上面列出的 3 个标准吗?你能提供一些你会建议的视频格式的代码 sn-ps 或文档吗?谢谢。
  • 哦,有道理。非常感谢!
【解决方案2】:

首先,您要做什么不是很清楚。

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

您可以在此处获取示例:How can I capture a video recording on Android?

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

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

【讨论】:

  • 问题是我想即时加密视频,然后将其写入磁盘。这就是为什么我需要使用 unix socket 来实时加密视频。问题是这个加密文件在我解密后无法播放。所以我只需要将流式视频写入文件并使其可播放。
  • 我讨厌有人问我这个问题,但我还是要问它“你需要在运行时加密视频的核心原因是什么”?我的意思是你真的需要在运行时加密它吗?你想保护这个文件不被其他应用程序访问吗?我只是认为解决加密问题可能比修复半写流更容易。
  • 顺便说一句。还有一件奇怪的事。看起来您文件中的 mdat 在 moov 之前。我的印象是它写在文件的最后,因为它包含帧信息。
  • 加密视频文件实际上是应用程序的主要目的:)。所以我们需要这样做。当您对 Android 的 MediaRecorder 说不要将流写入文件,而是在套接字中流式传输 mdat atom 时,一旦您按下 Stop,它就会为您提供 moov atom 并且最终文件看起来像是附加的有问题的文件。那么关于如何修复它使其可玩的任何想法?
  • 你是对的。 moov 是最后写的(我忘了这个)。我查看了文件,发现以下内容:
猜你喜欢
  • 1970-01-01
  • 2011-02-27
  • 2013-04-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-09-15
  • 1970-01-01
相关资源
最近更新 更多