使用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 output
( ffmpeg -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重新编码为上述设置时。