【问题标题】:ffmpeg concat two sources with optional audioffmpeg 连接两个带有可选音频的源
【发布时间】:2023-03-26 12:51:01
【问题描述】:

我想使用 ffmpeg 将两个视频文件连接在一起。我已经找到了这个命令:

ffmpeg -i INPUT1 -i INPUT2 -filter_complex \"[0:v][0:a][1:v][1:a]concat=n=2:v=1:a=1[v][a]\" -map \"[v]\" -map \"[a]\" OUTPUT

问题是,INPUT2 并不总是有音频,所以 ffmpeg 会抛出一个无效的输入流。 我对 ffmpeg 非常缺乏经验,而且我没有从文档中获得智慧。 有没有一种可能的方式可以很好理解,可能在一个命令中?

总结:我想连接两个视频文件,包括音频,但第二个文件可能有也可能没有音频层。

【问题讨论】:

    标签: ffmpeg


    【解决方案1】:

    必须匹配流计数和类型

    要连接的所有段必须具有相同数量和类型的流。因此,如果input1.mp4 有音频,而input2.mp4 没有,那么您需要忽略来自input1.mp4 的音频或为input2.mp4 添加音频。一种方法是使用anullsrc 过滤器添加静音音频,如下所示:

    检测音频

    没有自动添加丢失音频的选项,因此您必须使用ffprobe 检查输入以告诉您输入是否有音频:

    然后,您可以使用首选脚本/编码语言的结果来执行相应的命令。

    【讨论】:

      【解决方案2】:

      对于没有音频的视频,一种简单的方法是添加音频(空音频源):

      ffmpeg -f lavfi \
      -i anullsrc=channel_layout=stereo:sample_rate=44100 \
      -i "videoWithoutAudio.mp4" \
      -shortest -c:v copy -c:a aac "videoWithAudio.mp4"
      

      如果你想更进一步,这里是我的 shell 脚本

      • 连接多个视频
      • 不同的大小、纵横比和格式和
      • 为没有音频的视频添加静音音频

      设置目标尺寸

      targetWidth=1920
      targetHeight=1080
      

      创建缩放表达式,在必要时根据来源放大

      slhck 为 ffmpeg 想出了这个很棒的比例表达式。无论您使用哪种尺寸或纵横比,此表达式都会根据需要进行缩放和填充。

      smartScale="scale=iw*min($targetWidth/iw\,$targetHeight/ih):ih*min($targetWidth/iw\,$targetHeight/ih), pad=$targetWidth:$targetHeight:($targetWidth-iw*min($targetWidth/iw\,$targetHeight/ih))/2:($targetHeight-ih*min($targetWidth/iw\,$targetHeight/ih))/2:color=black, setdar=ratio=16/9, setfield=tff"
      

      制作计数器并设置变量

      c=0
      ffmpegInput=""
      filter_complex_params_1=""
      filter_complex_params_2=""
      

      检查每个视频并做 2 件事:

      1. 检测不到音频

        • 识别没有音频的视频

        • 为这些视频添加空音频

      2. 将 ffmpeg 参数串在一起

        • 将每个视频添加为 ffmpeg 输入

        • 为每个新输入扩展 ffmpegs filter_complex

      您可以将文件放入文件夹中,在文件名前添加数字以确定连接的顺序。不要在文件名中使用空格! "01_SummerVacation_2020.mkv"

      for i in *
      do
      
      # Use file command to recognize the type of data contained in a file
      bashFileCommand=$(file "$i")
      
      # parts of the file command output for many files that are not a video
      regexPattern="image|Image|IMAGE|bitmap|text|Text|TEXT|ocument|DOCUMENT|Microsoft|rchive|empty|directory"
      
      # detect if file is a video or not
      # if the file contains no string of the above regexPattern it is likely a video
      if [[ ! $bashFileCommand =~ $regexPattern ]]; then
      
          # Concatenation works only if all videos contain audio
      
          # detect videos without audio using ffprobe
          # store command arguments for ffprobe query in array: codec_type for audio
          command_audioCodec_type=(ffprobe -v quiet -select_streams a:0 -show_entries stream=codec_type -of default=nw=1:nk=1 "$i")
      
          # execute command in array and store result variables
          result_audioCodec_type=$("${command_audioCodec_type[@]}" | tail -1)
      
      
          if [[ ! $result_audioCodec_type =~ "audio" ]]; then
      
              # Add dummy audio to video
              # Since we cannot overwrite the source file we have to create a temporary file
              # ffmpeg chooses the right format according to the extension. Therefore we add "tmp" in front of the filename. Otherwise we would mess up the extension.
              ffmpeg -f lavfi -i anullsrc=channel_layout=stereo:sample_rate=44100 -i "$i" \
                  -shortest -c:v copy -c:a aac "tmp_${i}"
              # remove original
              rm "${i}"
              # renaming new file to appear as the original
              mv "tmp_${i}" "${i}"
      
          fi
      
      
      
          # iterate over all videos (e.g. 3) and add the parameters to the previous parameters:
      
          # Scale videos to set size
      
          # 1st iteration: [0:v]${smartScale}[scaled_v0];
          # 2nd iteration: [0:v]${smartScale}[scaled_v0];[1:v]${smartScale}[scaled_v1];
          # 3rd iteration: [0:v]${smartScale}[scaled_v0];[1:v]${smartScale}[scaled_v1];[3:v]${smartScale}[scaled_v2];
          filter_complex_params_1="$filter_complex_params_1[${c}:v]${smartScale}[scaled_v${c}]; "
      
          # Scale videos to set size
      
          # 1st iteration: [scaled_v0][0:a]
          # 2nd iteration: [scaled_v0][0:a][scaled_v1][1:a]
          # 3rd iteration: [scaled_v0][0:a][scaled_v1][1:a][scaled_v2][2:a]
          filter_complex_params_2="$filter_complex_params_2[scaled_v${c}][${c}:a]"
      
          # Add inputs
      
          # 1st iteration:  -i video1.mp4
          # 2nd iteration:  -i video1.mp4 -i video2.mp4
          # 3rd iteration:  -i video1.mp4 -i video2.mp4 -i video3.mp4
          ffmpegInput="$ffmpegInput -i ${i}"
      
          # increment counter for filter
          c=$((c+1))
      
      fi
      
      done
      

      创建连接过滤器

      # 3rd (last) iteration: concat=n=3:v=1:a=1[v][a]
      filter_complex_params_3="concat=n=${c}:v=1:a=1[v][a]"
      

      将所有变量组合到最终的 ffmpeg 命令中

      # concatenate videos
      ffmpeg ${ffmpegInput} -filter_complex "${filter_complex_params_1}${filter_complex_params_2}${filter_complex_params_3}" -map "[v]" -map "[a]" -c:v libx264 -crf 23 -c:a aac concatenated.mkv
      

      【讨论】:

        猜你喜欢
        • 2019-03-24
        • 2012-03-09
        • 1970-01-01
        • 1970-01-01
        • 2017-02-11
        • 2018-12-27
        • 2016-05-25
        • 2016-09-06
        • 2020-07-28
        相关资源
        最近更新 更多