web-dev-qa-db-ja.com

FFmpegを使って2つのMP4ファイルを連結する方法?

私はffmpegを使って2つのmp4ファイルを連結しようとしています。私はこれを自動プロセスにする必要があるのでffmpegを選びました。 2つのファイルを.tsファイルに変換してから連結し、その連結された.tsファイルをエンコードしようとしています。ファイルはh264とaacでエンコードされているので、品質を同じにするか、できるだけオリジナルに近い品質に保ちます。

ffmpeg -i part1.mp4 -vcodec copy -vbsf h264_mp4toannexb -acodec copy part1.ts
ffmpeg -i part2.mp4 -vcodec copy -vbsf h264_mp4toannexb -acodec copy part2.ts
cat part1.ts part2.ts > parts.ts
ffmpeg -y -i parts.ts -acodec copy -ar 44100 -ab 96k -coder ac -vbsf h264_mp4toannexb parts.mp4

残念ながら、エンコード中にffmpegから次のエラーメッセージが返されます。

[h264 @ 0x1012600]sps_id out of range
[h264 @ 0x1012600]non-existing SPS 0 referenced in buffering period
[h264 @ 0x1012600]sps_id out of range
[h264 @ 0x1012600]non-existing SPS 0 referenced in buffering period
[NULL @ 0x101d600]error, non monotone timestamps 13779431 >= 13779431kbits/s    
av_interleaved_write_frame(): Error while opening file

これはエンコードの途中で起こります。2つの.tsファイルを連結して動作させることはできないと私は考えています。

279
Mark L

中間フォーマットとしてmpgを使用しましたが、うまくいきました(注:これは危険な例です。-qscale 0はビデオを再エンコードします)。

ffmpeg -i 1.mp4 -qscale 0 1.mpg
ffmpeg -i 2.mp4 -qscale 0 2.mpg
cat 1.mpg 2.mpg | ffmpeg -f mpeg -i - -qscale 0 -vcodec mpeg4 output.mp4
30
Mark L

FFmpegには3つの連結方法があります。

1. 連結ビデオフィルタ

ffmpeg -i opening.mkv -i episode.mkv -i ending.mkv \
  -filter_complex "[0:v] [0:a] [1:v] [1:a] [2:v] [2:a] concat=n=3:v=1:a=1 [v] [a]" \
  -map "[v]" -map "[a]" output.mkv

このメソッドは再エンコードを実行します。

2. 連結デマルチプレクサ

$ cat mylist.txt
file '/path/to/file1'
file '/path/to/file2'
file '/path/to/file3'

$ ffmpeg -f concat -i mylist.txt -c copy output

Windowsの場合:

(echo file 'first file.mp4' & echo file 'second file.mp4' )>list.txt
ffmpeg -safe 0 -f concat -i list.txt -c copy output.mp4

3. 連結プロトコル

ffmpeg -i "concat:input1|input2" -codec copy output

このメソッドはMP4を含む多くのフォーマットでは機能しません。これらのフォーマットの性質と、このメソッドによって実行される単純化された連結のためです。

どちらを使うか

  • 連結フィルタ:入力が同じパラメータ(幅、高さなど)を持たない場合、または同じフォーマット/コーデックではない場合、あるいはフィルタリングを実行する場合に使用します。 。 (一致しない入力だけを再エンコードして同じコーデックや他のパラメータを共有することができます。その後、他の入力の再エンコードを避けるためにconcat demuxerを使用します)。

  • concat demuxer:再エンコードを避けたいがフォーマットがファイルレベルの連結をサポートしていない場合(一般ユーザーが使用するほとんどのファイルがファイルレベルの連結をサポートしていない)に使用します。

  • 連結プロトコル:ファイルレベルの連結をサポートする形式(MPEG-1、MPEG-2 PS、DV)で使用します。 MP4と一緒に使用しないでください。

疑問がある場合は、concat demuxerを試してください。

また見なさい

548
rogerdpack

MP4ファイル用

.mp4ファイル(私はDailyMotion.comから入手しました。50分のテレビ番組、3つのパートに分けて3つの.mp4ビデオファイルとしてダウンロード可能)については、以下が効果的な解決策でした。 Windows 7 、そしてではないはファイルの再エンコードを含みます。

ファイルの名前を変更しました(asfile1.mp4file2.mp4file3.mp4)その部分が完全なテレビのエピソードを見るための正しい順序であったように。

それから私は以下の内容で簡単なバッチファイル(concat.bat)を作成しました:

:: Create File List
echo file file1.mp4 >  mylist.txt 
echo file file2.mp4 >> mylist.txt
echo file file3.mp4 >> mylist.txt

:: Concatenate Files
ffmpeg -f concat -i mylist.txt -c copy output.mp4

バッチファイル、およびffmpeg.exeは、両方とも.mp4ファイルと同じフォルダに配置する必要があります。 を結合します。次にバッチファイルを実行します。通常、実行には10秒未満かかります。
.

補遺(2018/10/21) -

あなたが探しているものがたくさんの再入力なしで現在のフォルダーのすべてのmp4ファイルを指定する方法であるならば、代わりにあなたのWindows バッチファイルでこれを試してください(にオプションを含める必要があります - safe 0 ):

:: Create File List
for %%i in (*.mp4) do echo file '%%i'>> mylist.txt

:: Concatenate Files
ffmpeg -f concat -safe 0 -i mylist.txt -c copy output.mp4

これはWindows 7のバッチファイルで動作します。 コマンドラインでは使用しないでください。バッチファイルでしか機能しません。

50
Ed999

これは、中間ファイルを必要とせずにこれを実行する(1分もかからない)高速で損失のない方法です。

ls Movie_Part_1.mp4 Movie_Part_2.mp4 | Perl -ne 'print "file $_"' | ffmpeg -f concat -i - -c copy Movie_Joined.mp4

"ls"は結合するファイルを含んでいます

(注 - 私のファイルにはスペースも奇妙なものもありませんでした。この考えを「ハード」ファイルで行いたい場合は、適切なシェルエスケープが必要になります)。

48
cnd

mP4ファイルの場合:

それらがまったく同じ(100%同じコーデック、同じ解像度、同じタイプ)のMP4ファイルではない場合は、最初にそれらを中間ストリームにトランスコーディングする必要があります。

ffmpeg -i myfile1.mp4 -c copy -bsf:v h264_mp4toannexb -f mpegts temp1.ts
ffmpeg -i myfile2.mp4 -c copy -bsf:v h264_mp4toannexb -f mpegts temp2.ts
// now join
ffmpeg -i "concat:temp1.ts|temp2.ts" -c copy -bsf:a aac_adtstoasc output.mp4

注!:出力は最初のファイルのようになります(2番目のファイルではありません)。

35
T.Todua

私は3つの.mp3オーディオファイルを1つの.m4aファイルに連結しようとしていました、そして、このffmpegコマンドは働きます。

入力コマンド

ffmpeg -i input1.mp3 -i input2.mp3 -i input3.mp3 -filter_complex concat=n=3:v=0:a=1 -f MOV -vn -y input.m4a

の意味: "-filter_complex concat = n = 3:v = 0:a = 1"

concatは、メディア連結(結合)機能を使用することを意味します。
nは、入力ファイルの総数を確認することを意味します。
vは、にビデオがあることを意味します。 0 =ビデオなし、1 =ビデオを含むを使用します。
aに音声があることを意味しますか? 0 =音声なし、1 =音声を含むを使用します。
- fは強制設定ファイル形式を意味します(サポートされているすべての形式を表示するには、ffmpeg -formatsを使用します)。
- vnは、ビデオを無効にすることを意味します(-anは、必要でなければオーディオも無効にします)。
- yは、出力ファイルを上書きすることを意味します(出力ファイルがすでに存在する場合)。

詳細については、ffmpeg -h fullを使用してください。すべてのオプションを印刷します(すべてのフォーマットおよびコーデック固有のオプションを含む、非常に長いものです)。

32
Ellie Tam

Ffmpegでのさまざまな連結方法に関する詳細なドキュメントは、 にあります

簡単な連結には、 「連結フィルタ」 を使用できます。 。

再エンコードを実行します。このオプションは、入力のビデオ/オーディオフォーマットが異なる場合に最適です。

2つのファイルを連結する場合:

ffmpeg -i input1.mp4 -i input2.webm \
-filter_complex "[0:v:0] [0:a:0] [1:v:0] [1:a:0] concat=n=2:v=1:a=1 [v] [a]" \
-map "[v]" -map "[a]" output.mp4

3つのファイルを連結する場合:

ffmpeg -i input1.mp4 -i input2.webm -i input3.mp4 \
-filter_complex "[0:v:0] [0:a:0] [1:v:0] [1:a:0] [2:v:0] [2:a:0] concat=n=3:v=1:a=1 [v] [a]" \
-map "[v]" -map "[a]" output.mp4

これは、同じ入力ファイルタイプと複数の入力ファイルタイプに対して機能します。

11
SJ00

rogerdpackとEd999の回答に基づいて、私は自分の.shバージョンを作成しました。

#!/bin/bash

[ -e list.txt ] && rm list.txt
for f in *.mp4
do
   echo "file $f" >> list.txt
done

ffmpeg -f concat -i list.txt -c copy joined-out.mp4 && rm list.txt

現在のフォルダ内のすべての*.mp4ファイルをjoined-out.mp4に結合します。

macでテストしました。

結果のファイルサイズは私の60のテスト済みファイルの正確な合計です。損失ではありません。必要なものだけ

6

こちらのドキュメントから: https://trac.ffmpeg.org/wiki/Concatenate

MP4ファイルがある場合は、最初にそれらをMPEG-2トランスポートストリームにトランスコードすることで、ロスレスで連結することができます。 H.264ビデオとAACオーディオでは、次のものを使用できます。

ffmpeg -i input1.mp4 -c copy -bsf:v h264_mp4toannexb -f mpegts intermediate1.ts
ffmpeg -i input2.mp4 -c copy -bsf:v h264_mp4toannexb -f mpegts intermediate2.ts
ffmpeg -i "concat:intermediate1.ts|intermediate2.ts" -c copy -bsf:a aac_adtstoasc output.mp4

このアプローチはすべてのプラットフォームで機能します。

これをクロスプラットフォームのスクリプトにカプセル化する機能が必要だったので、fluent-ffmpegを使用して次の解決策を思いついた。

const unlink = path =>
  new Promise((resolve, reject) =>
    fs.unlink(path, err => (err ? reject(err) : resolve()))
  )

const createIntermediate = file =>
  new Promise((resolve, reject) => {
    const out = `${Math.random()
      .toString(13)
      .slice(2)}.ts`

    ffmpeg(file)
      .outputOptions('-c', 'copy', '-bsf:v', 'h264_mp4toannexb', '-f', 'mpegts')
      .output(out)
      .on('end', () => resolve(out))
      .on('error', reject)
      .run()
  })

const concat = async (files, output) => {
  const names = await Promise.all(files.map(createIntermediate))
  const namesString = names.join('|')

  await new Promise((resolve, reject) =>
    ffmpeg(`concat:${namesString}`)
      .outputOptions('-c', 'copy', '-bsf:a', 'aac_adtstoasc')
      .output(output)
      .on('end', resolve)
      .on('error', reject)
      .run()
  )

  names.map(unlink)
}

concat(['file1.mp4', 'file2.mp4', 'file3.mp4'], 'output.mp4').then(() =>
  console.log('done!')
)
4
itslittlejohn

私は認められた答えでMac上でいくつかのMP4を連結するためにオプション3を使っているとき私はパイプ演算子が私のために働かなかったことがわかりました。

次のワンライナーは、中間ファイルの作成を必要とせずに、mp4sを連結するためにMac(High Sierra)上で動作します。

ffmpeg -f concat -safe 0 -i <(for f in ./*.mp4; do echo "file '$PWD/$f'"; done) -c copy output.mp4

3
Ben Siver

これは私がいくつかのGoPro mp4を720pのmp4に連結するために作ったスクリプトです。助けになれば幸いです。

#!/bin/sh
cmd="( "
for i; do
    cmd="${cmd}ffmpeg -i $i -ab 256000 -vb 10000000 -mbd rd -trellis 2 -cmp 2 -subcmp 2 -g 100 -f mpeg -; "
done
cmd="${cmd} ) | ffmpeg -i - -vb 10000000 -ab 256000 -s 1280x720 -y out-`date +%F-%H%M.%S`.mp4"
echo "${cmd}"
eval ${cmd}
3
Reid Ellis

これは私のために働いていました(ウィンドウズ)

ffmpeg -i "concat:input1|input2" -codec copy output

特に

ffmpeg -i "concat:01.mp4|02.mp4" -codec copy output.mp4

Python

いくつかのpythonコードを使って、1つのフォルダ内にある多くのmp4でそれを行う

stringa = ""
for f in glob.glob("*.mp4"):
    stringa += f + "|"

os.system("ffmpeg -i \"concat:" + stringa + "\" -codec copy output.mp4")
2
Giovanni Gianni

現在のディレクトリからすべてのmp4ファイルをマージする

私は個人的には後で削除しなければならない外部ファイルを作成したくないので、私の解決策はファイル番号のリストを含むものです(file_1_name, file_2_name, file_10_name, file_20_name, file_100_name、...のように)

#!/bin/bash
filesList=""
for file in $(ls -1v *.mp4);do #lists even numbered file
    filesList="${filesList}${file}|"
done
filesList=${filesList%?} # removes trailing pipe
ffmpeg -i "concat:$filesList" -c copy $(date +%Y%m%d_%H%M%S)_merged.mp4
1
Pipo

.mp4ファイルの場合、オープンソースのコマンドラインツールmp4boxを使用する方が速くてうまくいくことがわかりました。それからあなたはそれをこのように使うことができます:

mp4box.exe -add video1.mp4 -cat video2.mp4 destvideo.mp4

ほとんどのプラットフォームでは、ここからダウンロードしてください。 https://gpac.wp.imt.fr/mp4box/

1
Mario
ffmpeg \
  -i input_1.mp4 \
  -i input_2.mp4 \
  -filter_complex '[0:v]pad=iw*2:ih[int];[int][1:v]overlay=W/2:0[vid]' \
  -map [vid] \
  -c:v libx264 \
  -crf 23 \
  -preset veryfast \
  output.mp4
1
Deepak Kumar

以下のスクリプトはWindows 10のPowerShellで私のために働いたさまざまな試みの後。

    $files=Get-ChildItem -path e:\ -Filter *.mp4


    $files| ForEach-Object  {"file '$($_.FullName)'"}| Out-File -FilePath e:\temp.txt -Encoding ASCII


    if (-not (test-path "e:\ffmpeg\bin\ffmpeg.exe")) {throw "e:\ffmpeg\bin\ffmpeg.exe needed"}

    E:\ffmpeg\bin\ffmpeg.exe -safe 0 -f concat -i "e:\temp.txt" -c copy -bsf:v hevc_mp4toannexb -an e:\joined.mp4

    # Conversion Cleanup
    Remove-Item e:\temp.txt

ここでは、最初の2行で次の内容のテキストファイルtemp.txtが作成されます。

file 'e:\first.mp4'
file 'e:\second.mp4'

3行目、4行目は、パスでffmpegが使用可能かどうかを確認し、 "joint.mp4"を作成します。

他の答えとの主な違いは以下の通りです

usage  of -bsf:v hevc_mp4toannexb -an

上記の私のmp4ファイルがうまくいったので、あなたはあなたのビデオエンコーディングによっては以下のような他の代替手段を使う必要があるかもしれません。

h264_mp4toannexb

そのようなビットストリームフィルタはすべて https://ffmpeg.org/ffmpeg-bitstream-filters.html にあります。

1
rahul maindargi

ここで説明するconcatプロトコル。 https://trac.ffmpeg.org/wiki/Concatenate#protocol

中間ファイルを回避するために名前付きパイプを使用して実装される場合

非常に高速(読み取り:インスタント)で、フレームがドロップされず、正常に動作します。

名前付きパイプファイルを削除し、ビデオがffmpeg -i filename.mp4だけで実行できるH264およびAACかどうかを忘れずに確認してください(h264およびaacの言及を確認してください)

0

これは、コマンド置換とconcatビデオフィルターを使用してMP4ファイルでいっぱいのディレクトリに参加するための方法です(これは再エンコードされます)-他の誰かが、特に多くのファイルを持っている場合、 1つの急降下で17個のファイルに参加しました):

ffmpeg $(for f in *.mp4 ; do echo -n "-i $f "; done) -filter_complex \
"$(i=0 ; for f in *.mp4 ; do echo -n "[$i:v] [$i:a] " ; i=$((i+1)) ; done \
&& echo "concat=n=$i:v=1:a=1 [v] [a]")" -map "[v]" -map "[a]" output.mp4

N.B.このコマンドは、名前が付けられた順序でファイルを結合します(つまり、ls *.mp4を実行した場合に表示されるのと同じ順序)-私の場合、それぞれにトラック番号が付いていたので、うまく機能しました。

0
Peter