是否可以从单个流字节范围块创建新的 mp4 文件?

Posted

技术标签:

【中文标题】是否可以从单个流字节范围块创建新的 mp4 文件?【英文标题】:Is it possible to create new mp4 file from a single streaming byte range chunk? 【发布时间】:2014-06-03 10:04:23 【问题描述】:

如果我在支持字节范围的服务器上有一个远程 mp4 文件,是否可以检索单个字节范围并从该范围数据创建一个新的/自包含的 mp4?

如果我尝试使用 fs.createWriteStream(remoteFilename) 将返回的字节范围数据直接写入 mp4 文件,它不会获得需要播放的视频元数据(持续时间、尺寸等)。

当我得到一个以 0 开头并以 XX 结尾的字节范围时,输出 mp4 是可播放的,但将具有整个视频长度的持续时间元数据,并且当剩余的字节范围完成时将冻结屏幕持续时间。

我还能如何获取一个字节范围并从该流对象创建一个独立的 .mp4 文件?

这样做的重点是避免在我可以使用 ffmpeg 制作 5 秒剪辑之前下载整个 10 分钟的文件。如果我可以计算和下载字节范围,应该有办法将其写入独立的 mp4 文件。

提前感谢您提供的任何帮助。

【问题讨论】:

【参考方案1】:

MP4 文件由方框构成。其中两个主要是 moov 和 mdat(非分段 MP4 的一般情况):

moov 框:包含其他框 :) - 它们中的每一个都包含有关 mdat 框中存在的编码数据的信息(moov = 有关 MP4 文件的元数据)。典型的元数据是持续时间、帧速率、编解码器信息、对视频/音频帧的引用... mdat 框:包含文件的实际编码数据。它可以来自各种编解码器,包括音频和视频数据(或者如果恰好是其中一个)。对于 H264 NAL 单元包含在 mdat 框中。

moov 框(应该)位于文件的开头,用于 MP4 文件网络传输,因此如果您编写从 0 到 XX 的字节范围请求,您可能会得到整个 moov 框 + 一定数量的 mdat 数据。因此,文件可以播放到某个点。如果您的字节范围从 YY 到 XX,那么您可能不会得到一个像样的 moov 框,但是很多 mdat 不能使用,除非它们被重新打包在一个 MP4 文件中,并带有适当的 moov 框引用有关“剪切”mdat 的信息.

可以从字节范围块重新创建有效的 MP4 文件,但它需要 MP4 文件格式结构的高级知识(您还需要检索 moov 框以使其可以承受)。 MP4 文件格式基于ISO base media file format - 指定为 ISO/IEC 14496-12(MPEG-4 第 12 部分)。

我知道 2 个库可以帮助你做你想做的事:一个在 php 中,一个在 Java 中。我不知道 node.js 是否存在这样的库(我想它可以被移植)。即使您不使用它们,上面的 2 个库也包含有关该主题的有价值信息。

要回答您的问题,您可以从不同的角度解决问题。以毫秒为单位知道您想要文件的哪一部分,您可以执行 ffmpeg 命令将完整长度的 MP4 文件服务器端拼接成一个较小的文件,然后使用这个新的较小的 MP4 文件执行您需要的操作(这样您就不需要在客户端下载不必要的数据)。

ffmpeg 命令是(在这种情况下,从文件开头开始 1 分钟处剪切):

ffmpeg -i input.mp4 -ss 00:00:00.000 -t 00:01:00.000 -c:a copy -c:v copy output.mp4

有关above command line的更多信息,请参阅此帖子

这完成得非常快,因为 MP4 文件结构只是重新组织而无需重新转码。

编辑: 或者我可以在远程文件上使用 ffmpeg 并在本地创建新剪辑吗?

ffmpeg -ss 00:01:00.000 -i "http://myfile.mp4" -t 00:02:00.000 -c:a copy -c:v copy output.mp4

假设您的客户端(应用程序/网络)上有 ffmpeg,如果您运行上述命令,ffmpeg 会将 mp4 提取到输入 URL,然后寻找 1 分钟并从那里剪切 2 分钟,然后将生成的内容写入输出。 mp4 本地(当然不下载完整文件)。

ffmpeg 需要在支持http protocol input 的情况下构建(您可以在大多数二进制文件中找到它)。您可以阅读here 以获取有关放置 -ss 参数(优点/缺点)的位置的更多信息。

【讨论】:

感谢您的回复。我看到你的 ffmpeg 命令的唯一问题是我必须在我的服务器上已经有完整的视频文件来创建剪辑服务器端,然后有一个单独的 mp4 来提供给客户端。或者我可以在远程文件上使用 ffmpeg 并在本地创建新剪辑吗? 您好,我在阅读您的评论后更新了我的答案。我希望这能满足您的需求。 我能够让它适用于远程文件。非常感谢您的帮助。 太棒了!救生员!【参考方案2】:

取决于您的远程 MP4 文件是分段 mp4 文件还是平面 mp4 文件。如果它是一个分段的 mp4 文件(我认为它是基于您的字节范围注释),您可以下载 init 字节范围和您感兴趣的片段并将它们连接在一起。

如果您有一个平面 mp4 文件,那么接受的答案是正确的方法。

【讨论】:

以上是关于是否可以从单个流字节范围块创建新的 mp4 文件?的主要内容,如果未能解决你的问题,请参考以下文章

Lambda nodejs - 不支持带有 libcurl 字节范围的 mediainfo

如何从 mp4 视频创建 .mpd mpeg dash 文件

从音频字节创建 wav 文件

按块加载视频/音频 html

文件操作流的存储与读取

Java NIO 详解