本文分享如何使用 Node.js 和 FFmpeg 优化上传的视频。处理一些有趣的用例,例如生成缩略图、视频压缩、生成预览片段和生成 HLS 片段。
主要依赖项:
- ffmpeg-static:此软件包为各种操作系统(包括 macOS、Linux 和 Windows)提供 FFmpeg 的静态二进制文件。通过它可以轻松地将 FFmpeg 集成到您的应用程序中,而无需在系统上单独安装它。
- fluent-ffmpeg:这是 FFmpeg 的封装程序,可简化其在 Node.js 应用程序中的使用。它提供了更用户友好的 API 来构建和执行 FFmpeg 命令,使操作音频和视频文件变得更加容易。
在介绍完依赖关系后,开始进入用例。
生成缩略图
在本例中,尝试为一段视频生成一个缩略图,请看下面的代码。
ffmpeg('/path/to/video.mp4')
.outputOptions([
'-ss 00:00:01', // 定位到视频 1 秒处获取缩略图
'-vframes 1', // 捕捉一帧
'-q:v 5', // 设置输出质量(越低越好)
'-vf scale=300:-1' // 缩放同时保持宽高比
])
.save('/path/to/thumbnail.jpg')
.on('end', () => {
console.log('Thumbnail has been generated successfully!');
})
.on('error', (err) => {
console.log(`Error: ${err.message}`);
});
-ss 00:00:01
:此选项告诉 FFmpeg 在捕捉帧之前寻找视频的1-second
标记。这对于选择视频中的特定时刻作为缩略图很有用。-vframes 1
:此选项指定只从视频中捕获一帧。本质上,它告诉 FFmpeg 在提取完这一帧后停止处理。-q:v 5
:设置图像的输出质量。值的范围从1
(最高质量)到31
(最低质量)。值5
表示质量和文件大小之间的良好平衡,适合制作缩略图。-vf scale=300:-1
:这将应用视频滤镜 (vf
) 来缩放输出图像。宽度设置为300 pixels
,-1
表示将自动计算高度以保持视频的原始宽高比。
当然,还有另一个与此相关的用例,您可以通过循环间隔以指定的间隔生成多个缩略图。例如,您可以每 10 秒生成一个。
视频压缩
在这个用例中尝试通过压缩视频来尽可能地缩小视频大小,同时考虑大小、时间和质量等因素。代码如下:
ffmpeg('/path/to/video.mp4')
.outputOptions([
'-c:v libx264', // 视频编解码器
'-preset veryfast', // 以合理的质量和文件大小进行快速编码
'-movflags +faststart', // 针对网络流媒体进行优化
'-crf 27', // 质量恒定速率因子
'-tag:v avc1' // 用于 QuickTime 兼容性的标签
])
.save('/path/to/compressed/video.mp4')
.on('end', () => {
console.log('Video has been compressed successfully!');
})
.on('error', (err) => {
console.log(`Error: ${err.message}`);
});
代码解释:
-c:v libx264
:将视频编解码器设置为libx264
,这是广泛使用的视频编码编解码器H.264
。它在质量和压缩效率之间提供了良好的平衡。-preset veryfast
:预设选项控制编码速度。veryfast
预设允许更快的编码时间,同时仍保持合理的质量和文件大小。预设范围从ultrafast
(压缩率最低,最快)到veryslow
(压缩率最高,最慢)。-crf 27
:恒定速率因子 (CRF) 控制输出视频的质量。值越低,质量越好,典型值范围从18
(高质量) 到28
(低质量)。CRF27
表示以牺牲一些质量为代价来追求较小的文件大小。-movflags +faststart
:此选项对于优化视频以在网络上流式传输非常有用。它将元数据移动到文件的开头,允许在下载整个文件之前开始播放。-tag:v avc1
:为视频流设置特定标签,可提高与某些播放器(尤其是 QuickTime)的兼容性。标签avc1
表示视频流使用的H.264
编码。
当谈到压缩时,您可以考虑其他选项,但必须权衡每个选项的利弊:
- 两遍压缩:编码过程分为两个单独的过程来处理视频文件,这可以提高质量。另一方面,它增加了编码时间,并且需要更多的 CPU 和内存资源。
- 使用 H.265 编解码器代替 H.264:这可以提高压缩效率并支持更高分辨率(如 8K)。另一方面,您可能会遇到兼容性问题,增加压缩时间,并需要更多计算资源。
生成预览片段
当您将鼠标悬停在视频缩略图上时,您想播放该视频的预览片段。实现代码如下:
ffmpeg('/path/to/video.mp4')
.setStartTime('00:00:00')
.duration('00:00:03')
.outputOptions([
'-c:v libx264', // 视频编解码器
'-preset veryfast', // 以合理的质量和文件大小进行快速编码
'-movflags +faststart', // 针对网络流媒体进行优化
'-crf 27', // 质量恒定速率因子
'-tag:v avc1' // 用于 QuickTime 兼容性的标签
])
.save('/path/to/preview-clip.mp4')
.on('end', () => {
console.log('The preview clip has been successfully!');
})
.on('error', (err) => {
console.log(`Error: ${err.message}`);
});
.setStartTime('00:00:00')
:此方法指定剪辑的起点。在本例中,它从视频的最开始(0 seconds)
处开始,您可以调整此值以从视频中的任意点开始。.duration('00:00:03')
:此方法设置输出剪辑的持续时间。此处,它指定剪辑应持续3
秒钟。生成的预览将仅包含原始视频的此片段。
至于传递的选项,它们与压缩情况相同,因为如果能同时压缩生成的预览片段,效果会更好。
生成 HLS 片段
HLS (HTTP Live Streaming)是苹果公司开发的一种协议,用于在互联网上传输视频和音频内容。但它是如何工作的呢?
- 分段:视频文件被分割成小块(通常长约 10 秒)。
- 播放列表:创建一个索引文件(称为 M3U8 播放列表),列出这些小块及其顺序。
- 传输:播放视频时,设备会逐个下载这些片段,从而实现流畅播放。
那么,这对我们的视频优化过程有什么用呢?实际上,它有两大优点:
- HLS 允许用户在线观看视频,无需先下载。视频不再是一个大文件,而是被分割成几个小片段,然后逐个下载。
- 它会根据观看者的网络波动来调整视频质量。如果您的连接速度较慢,HLS 会降低视频质量以防止缓冲。如果您的连接速度有所改善,它会切换回更高质量的视频。
很有趣,对吧?现在让我们尝试为两种分辨率(360 和 720)生成 HLS 片段:
const createMasterPlaylist = () => {
const masterPlaylistContent = `
#EXTM3U
#EXT-X-VERSION:6
#EXT-X-STREAM-INF:BANDWIDTH=1500000,RESOLUTION=1280x720
720p.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=300000,RESOLUTION=640x360
360p.m3u8
`.trim();
fs.writeFileSync(`/path/to/master.m3u8/file`, masterPlaylistContent);
};
for (const width of [360, 720]) {
ffmpeg('/path/to/video.mp4')
.outputOptions([
'-c:v libx264',
'-preset veryfast',
'-movflags +faststart',
'-crf 27',
'-tag:v avc1',
'-f hls',
'-hls_time 10',
'-hls_list_size 0',
'-hls_flags independent_segments'
])
.output(`/path/to/${width}p.m3u8/file`)
.videoFilter(`scale=${width}:-2`)
.on('progress', () => {
console.log(`An HLS ${width}p segment has been generated successfully!`);
})
.on('end', () => {
if (width === 720) {
createMasterPlaylist();
}
console.log(`All HLS segments for ${width}p has been generated successfully!`);
})
.on('error', (err) => {
console.log(`Error: ${err.message}`);
})
.run();
}
代码解释:
-f hls
:指定输出格式为HLS。-hls_time 10
:将每个 HLS 片段的持续时间设置为10
秒。每个片段的长度大约为该值,这有助于流畅播放。-hls_list_size 0
:表示播放列表M3U8
(文件)中的条目数不受限制。所有片段都将包含在播放列表中。-hls_flags independent_segments
:设置此标志后,可确保每个片段都以关键帧(I 帧)开始,并且可以播放而无需参考前面的片段。这对于查找和提高播放性能非常有用,尤其是在用户可能会在视频中跳转的自适应流媒体场景中。.videoFilter(scale=${width}:-2)
:FFmpeg 将调整视频的大小,使其宽度为${width}
像素,并根据原始纵横比计算相应的高度。使用值-2
将确保高度为偶数(某些编解码器通常需要这样做)。这可确保您的视频不会扭曲或拉伸,如果您手动设置两个尺寸而不考虑其比例,则可能会发生这种情况。.run()
方法开始使用所有指定的选项和设置执行 FFmpeg 命令。
视频处理是一项资源密集型操作,因此最好在专门用于此任务的单独的 CPU 优化服务器中处理它。最后,我认为使用另一种多线程编程语言(如 C++ 或 Rust)而不是 Node.js 进行视频处理会更好。
本文来自作者投稿,版权归原作者所有。如需转载,请注明出处:https://www.nxrte.com/jishu/53688.html