使用 Node.js + FFmpeg 生成缩略图、压缩视频、生成预览片段和 HLS 片段

本文分享如何使用 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 播放列表),列出这些小块及其顺序。
  • 传输:播放视频时,设备会逐个下载这些片段,从而实现流畅播放。

那么,这对我们的视频优化过程有什么用呢?实际上,它有两大优点:

  1. HLS 允许用户在线观看视频,无需先下载。视频不再是一个大文件,而是被分割成几个小片段,然后逐个下载。
  2. 它会根据观看者的网络波动来调整视频质量。如果您的连接速度较慢,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

(0)

相关推荐

发表回复

登录后才能评论