使用ffmpeg进行video转换,以定位Android和iOS移动设备

我正在为Android和IOS构build一个反应本机应用程序,后端API使用NodeJS编写。

用户可以从他们的手机上传video,一旦上传了用户,他们的朋友就可以观看video – 因此video需要以可在Android和IOS上播放的格式进行存储。

我的问题涉及用户上传的video转换。 几年前,我开发了一个类似的应用程序。 我使用了repo node-fluent-ffmpeg ,它提供了一个很好的API来与FFmpeg进行交互。

在之前的项目(这是一个networking应用程序),我把上传的video转换成两个文件,一个.mp4和一个.webm – 如果用户上传了一个MP4,那么我会跳过MP4步骤,如果他们上传一个。 WEBM。

这有点慢。 现在我几年后也遇到了同样的要求,经过一番调查,我认为把video转换成最后一个项目是错误的。

我读过,我可以简单地使用FFmpeg来更改video的容器格式,这比从头开始转换它们要快得多。

我上次使用的video转换代码沿着以下方向行进:

var convertVideo = function (source, format, output, success, failure, progress) { var converter = ffmpeg(source); var audioCodec = "libvorbis"; if (format.indexOf("mp4") != -1) { audioCodec = "aac"; } converter.format(format) .withVideoBitrate(1024) .withAudioCodec(audioCodec) .on('end', success) .on('progress', progress) .on('error', failure); converter.save(output); }; 

用法:

转换成mp4:

 convertVideo("PATH_TO_VIDEO", "mp4", "foo.mp4", () => {console.log("success");}); 

转换为webm:

 convertVideo("PATH_TO_VIDEO", "webm", "foo.webm", () => {console.log("success");}); 

任何人都可以在这里指出一个代码的气味关于这个操作的性能? 这个代码是否比IOS和Android之间的跨平台兼容性做得更多?

值得一提的是,在这个项目中,支持较旧的操作系统版本并不是什么大不了的事情。

编解码器和容器/格式有什么区别?

您应该了解编解码器(如H.264,VP9)和容器格式(如MP4,WebM)之间的区别 。 容器只存储编码的video和audio信息。 通常情况下,您可以通过streamffmpeg -i input -c copy outputffmpeg -i input -c copy output )来在容器之间切换,但是由于历史原因,您会发现有些容器不接受某些编解码器,或者某些播放器可能无法处理某个编解码器容器(例如,只有最近的软件才能够读取MP4中的VP9video)。 看看这个容器格式的概述,看看哪个编解码器是受支持的。

什么是不同的移动操作系统的限制?

为了定位iOS和Android平台,您需要检查给定的video文件是否与支持的编解码器/格式兼容:

  • Android支持的媒体格式
  • iOS支持的媒体格式以及iPhone规格页面底部的说明

当然,随着时间的推移,你可能会改变,但一般来说,共同点是:

  • H.264video
  • MP4容器
  • 主要configuration文件
  • 最大分辨率为1920×1080 – 虽然如果设备支持,分辨率可能会更高,但很less有需要超过全高清的移动设备,因为人们无法察觉到与4K / UHD之间的差异,除非它是一个大的片剂。
  • 帧速率不应超过某个最大值(例如60 Hz)
  • 色度子采样应该是4:2:0。
  • AAC-LCaudio

具体约束取决于设备,显然是安装的操作系统版本。 并非所有这些细节都在iOS / Android文档中提到。 您一定要做一些尝试,如果不确定,请重新编码video。

那么,我应该用什么编解码器/格式编码?

苹果公司在MPEG生态系统方面投入了大量资金,传统上支持H.264和H.265(HEVC)。 他们不支持WebM中的VP8和VP9。 因此,如果您有VP8 / VP9video,并且希望跨video可视化,请将其重新编码为H.264。

我应该如何做实际的编码?

请确保您使用足够高的比特率,以避免将更多的文物添加到已经有损video中。 你现在正在做的不应该只是做一个一遍的目标比特率编码。 相反,执行两遍编码来提高编码的质量和效率(尽pipe需要更长的时间)。 如果您不关心特定的文件大小(如用于libx264的CRF ),也可以使用恒定的质量模式。 阅读FFmpeg H.264编码指南了解更多信息。

未来呢?

请注意,除了苹果之外,几乎所有科技行业的大玩家都join了开放媒体联盟 。 他们正在开发名为“ AV1 ”的VP9的后续产品,该产品将得到所有主stream浏览器厂商(Chrome,Firefox,Edge)和Android的支持。

H.265 / HEVC似乎也是一个不错的select,但是与x265编码相比, x264目前仍然非常慢,而x264是最stream行的开源H.264编码器。

WebM和MP4只是容器,而不是实际使用的编码器。 通常情况下,webm将是vp8或vp9,mp4大多数时间将是h264。 您可以使用stream副本更改容器(ffmpeg命令:-vcodec copy),但不能在不编码整个stream的情况下更改编码器types。 当您运行复制命令时,您也无法调整video的大小或更改比特率。 复制完全是这样听起来的,你正在复制底层框架,并把它们包装在不同的容器中。

我会质疑你为什么要编码到webm。 无论是iOS和Android将播放(大部分)MP4video没有问题。 如果您想要强制执行某种格式的types,那么您可以检查传入的video并尝试执行某些标准(例如h264基准video和不超过1080p的aacaudio)。 如果inputstream不符合此标准,则对video进行编码,指定编码器,比特率和大小。 如果它符合你的标准,只需运行-vcodec copy -acodec copy。 它看起来像你的特定的图书馆将是.audioCodec('复制').videoCodec('复制')。

这很容易,你只是像YouTube一样的大厂商去做,这是目前的MP4 / H.264 / AAC

当你的目标是Android或更好的“任何”操作系统或设备,以获得最大的。 您还需要注意编解码器的详细设置。 内置于设备中的硬件解码器往往对他们想要解码的内容非常挑剔。

Youtube以这种方式定义video编解码器设置

对于h264:

  • 逐行扫描(无隔行扫描)
  • 高调
  • 连续2个B帧
  • closures的GOP。 一半帧率的GOP。
  • CABAC
  • 可变比特率。 不需要比特率限制,虽然我们提供以下推荐比特率供参考
  • 色度子采样:4:2:0

我唯一可以补充的是:实际上你应该关心比特率,如果你太高(例如全高清video超过15MBit / s),硬件解码器可能会造成麻烦。

对于AAC:

  • 频道:立体声或立体声+ 5.1
  • 采样率96khz或48khz

容器:MP4

  • 没有编辑列表(或video可能无法正确处理)
  • 文件前面的moovprimefaces(快速启动)

而且,h264绝对是最受欢迎的编解码器,所以它的编码速度比VP8 / 9和VP8 / 9还要快得多。 所以在我看来,没有什么好的理由(除了“道德”之外)只用于h264 – 更不用说“x264”比h264更快,并且应该保证相同的兼容性

Conclusio:

任何人都可以在这里指出一个代码的气味关于这个操作的性能? 这个代码是否比IOS和Android之间的跨平台兼容性要做得更多?

不幸的是,这一切都取决于你input什么样的video。 你的代码绝对不会太多,但在“尽量节省计算时间”方面远远不够。 您可以检查input的video是否与所有列出的参数匹配,然后再将其发送到编码,但说实话,从经验中得到的最相容的结果是当您将所有input重新编码为上述设置时。