使用 FFmpeg 无损导出剪映轨道视频片段

背景

在通过视频剪辑软件编辑完视频之后,我们通常会思考如何归档素材 。这其实是一件挺头疼的事情,对于普通的视频创作者来说,创作之前并不确切地知道哪些片段会被用利用上。

这种情况下,剪辑的过程,本身就是一个挑选的过程。无论是出于精选高光片段便于日后复用,还是节省存储空间的目的,这个需求都是切实存在的。

基础思路

我们只要获取到时间线上每个片段对应的原素材文件路径、起始位置、终止位置(或持续时间),便可以使用工具(FFmpeg)进行剪切导出。

草稿文件解析

On MacOS

草稿文件名称为 draft_info.json,位于

bash 复制代码
/Users/user/Movies/JianyingPro/User Data/Projects/com.lveditor.draft

On Windows

草稿文件名称为 draft_content.json,位于

sql 复制代码
C:\Users\user\AppData\Local\JianyingPro\User Data\Projects\com.lveditor.draft\

文件结构

读取文件信息,观察结构可以发现以下关键信息

JSON 复制代码
{
  "materials": {
    "videos": [
      {
        "id": "ED9E7016-7A4D-4251-804F-2EBCAE19BC25",
        "path": "##_draftpath_placeholder_[草稿ID]_##/materials/video/C0631.MP4"
      },
      {
        "id": "2F408BAD-5031-4CC8-942D-DDAFD71B2A92",
        "path": "/Users/xxx/Desktop/videos/C0631.MP4"
      }
    ]
  },
  "tracks": [
    {
      "type": "video",
      "segments": [
        {
          "material_id": "ED9E7016-7A4D-4251-804F-2EBCAE19BC25",
          "source_timerange": {
            "duration": 833333,
            "start": 1350000
          }
        }
      ]
    }
  ]
}

其中 materials 字段记录了所有素材的基本信息,比较关键的主要是文件存放位置;而 tracks 字段记录了轨道信息,我们可以从中找到对应的视频片段(segment),从而获取到片段的时间范围信息。

通过 ID 的映射,我们可以获取到:文件地址、开始时间,持续时间,然后就可以开始编写导出逻辑了。

需要注意的是 ##_draftpath_placeholder_xxx_## 字样代表的是草稿文件夹自身的位置,因此在处理时需要做替换。

借助 FFmpeg 导出

FFmpeg 是一个非常强大的跨平台流媒体处理程序,并且是开源的。同时作为命令行工具,它可以轻易地集成到脚本和程序中,作为底层工具支撑上层应用。

我们的项目正是一个基于 FFmpeg 的简单包装,由于运行时需要调用它,因此你需要提前安装 ffmpeg并将命令加入到环境(PATH)中。

Tips: 在 MacOS 中你可以通过 brew install ffmpeg 便捷地完成安装,其他方式详见官网

完整项目的地址见 Github - emosheeep/capcut-export,运行起来大概是下面这样:

lua 复制代码
Usage: ccexp [options] <file> [output]

Export video clips from CapCut editor tracks, helps archive materials.

Arguments:
  file                      CapCut/Jianying draft info json file.
  output                    The output directory, default is cwd.

Options:
  -V, --version             output the version number
  -p,--concurrent <number>  The number of tasks processed in parallel, the default is number of CPU.
  --offset <number>         Expand the video clips' time range to both sides for about specific seconds, default is 2s.
  --verbose                 To be verbose. (default: false)
  -h, --help                display help for command

接下来我们介绍 ffmpeg 命令的基础用法:

Shell 复制代码
ffmpeg -ss 2 -t 3 -c copy -y -i /path/to/input.mp4 /path/to/output.mp4

在上面的命令中:

  • -ss 代表设置起始位置为 2s 处

  • -t 代表导出片段的持续时间为 3s

  • -c copy 指定使用流式复制的方式拷贝原视频。流式复制不会对原视频重新解码和编码,因此它是无损的,也正因没有这个过程,它的速度也快很多。

  • -y 自动同意命令运行过程中需要确认的流程。主要是同意在存在同名文件时执行覆盖操作。

所以这行命令翻译过来就是:导出原视频从 2s 处开始,持续 3s 的片段到指定位置

为什么觉得导出视频的时间范围不那么精确?

在使用 FFmpeg 进行视频剪辑或者截取的时候,可能会出现时间范围不精准的情况,有两个主要原因:

视频关键帧(Keyframes)

关键帧是能够完全独立于其他帧进行解码的帧,通常每几秒视频就会有一个关键帧 。FFmpeg 使用 -ss 选项跳跃到特定的时间位置,默认情况下,它会跳跃到最近的关键帧。如果你选定的开始时间点并没有关键帧,FFmpeg 就会选择最近的前一个关键帧作为开始点,这样就可能造成精度问题。

如果你想精确地指定开始时间,则需要将 -ss 参数放到 -i 参数之后。但这种做法同样会面临一些问题:

  • 流式复制截取:虽是无损画质,但在视频开始位置可能有会短暂的黑屏问题。原因正是上面提到的关键帧选取问题,你选定的时间点没有关键帧,或对应的帧无法单独解码。

  • 不使用流式复制:将会存在解码和重编码问题,耗时较长不说,还可能造成画质的损失。

相比之下,画质的保留更为重要,对于时间点不准确的问题,在上面的工具中,可以通过控制 offset 参数扩大两边的范围来尽可能保留更多的视频内容。

关于归档素材这件事...

最初意识到归档素材 这件事还是在「影视飓风」一期关于素材管理的视频

其中提到软件「DAVINCI · 达芬奇」具备将轨道上未经编辑的视频片段原样导出 的功能。看完视频的我回想起自己曾经拍摄的一堆长视频素材,是删了觉得可惜,想整理又心有余而力不足

自那一刻起,我便思索「剪映专业版」何时才能具备这项功能?为此我还特地保留了一些草稿不舍得删除,想等这项功能落地之后,导出存档,然后再清理电脑。直到期待许久没有回应,才无奈亲力亲为。好在倒也是凭借作为程序员的经验和直觉,完成了这件事。想来做的过程还是挺有趣的😅,甚至会联想到突"技术宅拯救世界"。

也许对于单纯记录生活,拍拍 vlog 的普通创作者来说,压根不会想到归档这件事。毕竟不是商业创作,没有必要做的如此认真。但我为什么突然执着于此呢?其实还是源自于发自内心想记录生活这件事。万一年底想剪个年度混剪,总不至于连素材都找不到嘛,对不对?

相关推荐
hzw051016 分钟前
nrm的安装及使用
node.js
昨天今天明天好多天3 小时前
【Node.js]
前端·node.js
熊的猫4 小时前
DOM 规范 — MutationObserver 接口
前端·javascript·chrome·webpack·前端框架·node.js·ecmascript
爱编程的鱼7 小时前
Node.js事件循环:解锁异步编程的奥秘
node.js
南暮思鸢7 小时前
Node.js is Web Scale
经验分享·web安全·网络安全·node.js·ctf题目·hackergame 2024
程序员小杰@7 小时前
Playwright 快速入门:Playwright 是一个用于浏览器自动化测试的 Node.js 库
node.js
Martin -Tang8 小时前
vite和webpack的区别
前端·webpack·node.js·vite
王解8 小时前
webpack loader全解析,从入门到精通(10)
前端·webpack·node.js
ldq_sd18 小时前
node.js安装和配置教程
node.js
我真的很困19 小时前
坤坤带你学浏览器缓存
前端·http·node.js