【问题标题】:Cut multiple parts from a video and merge them together从视频中剪切多个部分并将它们合并在一起
【发布时间】:2018-06-30 22:55:53
【问题描述】:

我正在尝试从视频中剪切特定部分,然后使用 nodejs 和 ffmpeg 将所有这些部分合并到一个视频文件中。

这是我的代码,目前我只能将视频中的一部分从.setStartTime 剪切到.setDuration,并且正在保存该部分。

var ffmpeg = require('fluent-ffmpeg');

var command = ffmpeg()
  .input('./videos/placeholder-video.mp4')
  .setStartTime('00:00:03')
  .setDuration('02')
  .output('./videos/test.mp4')

  .on('start', function(commandLine) {
    console.log('Started: ' + commandLine);
  })

  .on('end', function(err) {   
    if(!err)
    {
      console.log('conversion Done');
    }                 
  })

  .on('error', function(err){
    console.log('error: ', +err);
  }).run();

如何从视频中剪切出多个部分并将它们合并到一个视频文件中。我知道.mergeToFile 方法,但是从我的视频中剪切不同部分后如何使用它。

我尝试使用.setStartTime.setDuration 两次,如下所示,但第一个被忽略了。

.input('./videos/placeholder-video.mp4')
.setStartTime('00:00:03')
.setDuration('02')
.setStartTime('00:00:15')
.setDuration('05')
.output('./videos/test.mp4')

【问题讨论】:

    标签: node.js video ffmpeg


    【解决方案1】:

    请阅读更新

    目前无法测试,但请尝试以下操作: 设置两次输入视频,如下所示:

    .input('./videos/placeholder-video.mp4')
    .setStartTime('00:00:03')
    .setDuration('02')
    .input('./videos/placeholder-video.mp4')
    .setStartTime('00:00:15')
    .setDuration('05')
    

    然后您可以将多个输入与.mergeToFile 合并。


    更新

    由于.setDuration 的限制,我的答案无法正常工作。它是一个输出选项,因此它定义了转码到输出文件的时间:https://github.com/fluent-ffmpeg/node-fluent-ffmpeg 它不用于定义输入的长度/持续时间。

    另一个选项是.loop,但显然不支持此用途:https://video.stackexchange.com/questions/12905/repeat-loop-input-video-with-ffmpeg/12906#12906

    如果你真的要使用nodejs,你需要多个命令

    • 将输入视频剪切成临时文件,每个剪切一个
    • 将临时文件合并到一个输出文件中

    类似这样的:

    var command1 = ffmpeg()
      .input('./small.mp4')
      .seekInput('00:00:02')
      .withDuration(1)
      .output('./temp1.mp4')
      .run();
    
    var command2 = ffmpeg()
      .input('./small.mp4')
      .seekInput('00:00:01')
      .withDuration(3)
      .output('./temp2.mp4')
      .run();
    
    var command2 = ffmpeg()
      .input('./temp1.mp4')
      .input('./temp2.mp4')
      .mergeToFile('./merge.mp4', './temp');
    

    大问题:如果临时文件不存在,您的 nodejs 脚本将无法启动。 所以使用 bash 或批处理脚本会容易得多。

    【讨论】:

    • 谢谢。在给.output.input 两次之后,我现在得到了两个文件,但它们没有按预期进行编辑。 test1.mp4 应该是 3sec,但它应该是 6sec,应该是 test2.mp4test2.mp4 比原始视频少 2sec
    • 你说得对,即使正确使用,我的答案也不起作用;)我的想法是使用 .input 两次,但使用输出。而是只使用.mergeToFile,即使没有.run。但正如我所说,它不起作用是因为.setDuration,这是一个输出选项,而不是输入(github.com/fluent-ffmpeg/node-fluent-ffmpeg)。 ffmpeg 不知道您需要的选项.loop 或难以使用或需要重新编码 (video.stackexchange.com/a/12906)。 我的建议:编写一个 bash 脚本并调用 ffmpeg 3 次:将视频 2 次剪切到所需长度并合并到临时文件中。
    • 你是对的,我的节点应用程序崩溃了,因为它在脚本运行时找不到这两个临时文件,但是当我将第三个命令放入 setTimeout 并等待这些临时文件生成然后它工作并合并它们。而且我不知道如何编写 bash 脚本,我的要求实际上是从视频中剪切部分并通过浏览器中的 Web 应用程序将它们合并。那么我的 bash 脚本将如何工作。无论如何,非常感谢你的回答。
    • 很高兴您现在有了一个可行的解决方案 ? 如果您有一个 Web 应用程序,那么 shell 脚本将很难使用,而且是个坏主意。 Nodejs 也将是我的首选方式!很高兴现在有一个工作示例。
    【解决方案2】:

    这就是我的解决方法:

    (async function() {
      const ffmpeg = require('fluent-ffmpeg')
      
      function ffmpegPromise(fn) {
        return new Promise((res, rej) => {
          fn.on('error', (e) => rej(e))
            .on('end', () => res('finished!'))
            .run()
        })
      }
    
      const file1 = ffmpeg().input('./videos/placeholder-video.mp4')
      .setStartTime('00:00:03')
      .setDuration(2)
      .output('./videos/test1.mp4')
      
      const file2 = ffmpeg().input('./videos/placeholder-video.mp4')
      .setStartTime('00:00:10')
      .setDuration(2)
      .output('./videos/test2.mp4')
      
      const files = await Promise.all([ffmpegPromise(file1), ffmpegPromise(file2)])
      console.log(files) // ['finished!', 'finished!']
    
      ffmpeg()
        .mergeAdd('./videos/test1.mp4')
        .mergeAdd('./videos/test2.mp4')
        .mergeToFile('./videos/mergedFile.mp4')
        .on('end', () => {
           fs.unlink('./videos/test1.mp4', err => {
             if (err) console.error(err)
           })
           fs.unlink('./videos/test2.mp4', err => {
             if (err) console.error(err)
           })
         })     
    })()
    

    File1 实例化 ffmpeg。在使用 '.run()' 命令调用 ffmpegPromise 之前,代码不会运行。它从 3 秒开始,需要 2 秒的视频。然后将 2 秒的视频剪辑保存到文件 './videos/test1.mp4'。

    File2 做同样的事情,只是它从 10 秒开始并需要 2 秒的视频。然后将 2 秒的视频剪辑保存到文件 './videos/test2.mp4'。

    ffmpegPromise 将 ffmpeg 实例化函数传递给 promise,因此可以等待。

    Promise.all 同时调用 'file1' 和 'file2' 并返回 'finished!'当文件被保存时。

    ffpeg().mergeAdd()...mergeToFile(...) 将两个 2 秒的视频剪辑合并到一个文件中,即“./videos/mergedFile.mp4”。完成后,会触发 'end' 事件,并且 fs.unlink 将删除 test1 和 test2 视频。

    【讨论】:

    • 您的答案可以通过添加有关代码的作用以及它如何帮助 OP 的更多信息来改进。
    猜你喜欢
    • 2017-07-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-04-15
    • 1970-01-01
    • 2015-02-14
    • 1970-01-01
    • 2022-01-04
    相关资源
    最近更新 更多