私はLinuxに初めてアクセスし、この問題で苦労しています。この問題を解決するのに役立ちます。
バッチプロセスのように、2つのビデオを複数回(フォルダごとに1つ)マージしようとしています。次のビデオの後に自動的に1つのビデオをマージします。
私はandを使用してフォルダ1のリストの上部にあるファイルを取得ffmpeg
しfor loop
、フォルダ2のリストの一番上にあるファイルとマージしてから、リスト全体でプロセスを繰り返そうとします。すべてのビデオがすべて互いにペアリングされるまでのフォルダ数。
各フォルダーに2つのフォルダーを並べて配置し、左側のフォルダーのファイルを右側のフォルダーに並べ替えることを想像してください。 2つの動画を1つの動画に何度もマージしたいです。ダイアグラムを描こうとしましたが、理解できると思います。
これは私のコードです。何度も変更しましたが、最新のコードは次のとおりです。 (ファイルを読んでフォルダ2から1:1に結合することを望みながら、フォルダ-1のディレクトリで実行してみましたが悲しいことに不運。
for filename in *.mp4; do
folder2="/path/to/folder2"
xout="/output/file/as/$(date +'%Y-%m-%d_%H:%M:%S').mp4"
ffmpeg -f concat -i "${filename%}" -i "$vid2/${filename%}" -acodec copy -vcodec copy "$xout"
done
同じエラーが発生する別の試みがあります。
No such file or directory
for filename in *.mp4; do
vid1="/path/folder-1/${filename%.*}"
vid2="path/folder-2/${filename%.*}"
out1="/path/output/$(date +'%Y-%m-%d_%H:%M:%S').mp4"
ffmpeg -f concat -i "$vid1" -i "$vid2" -acodec copy -vcodec copy "$out1"
done
誰もが私が間違っていることを教えてもらえますか?これを行うことはできません。約4時間が経過し、多くのことを試み、forループとループ、ffmpegコマンドなどに関する多くの記事を読みました。 。貴重な時間をありがとうございました、本当にありがとうございました!
答え1
最初の例では、${filename%}
$ filenameをまったく変更せず、concat demuxerを使用して.mp4ファイルを開くようにffmpegに指示すると、-f concat
エラーメッセージが表示されるはず<actual name of $filename>: Invalid data found when processing input
ですが、それが得られるため、No such file or directory
globが機能しないと思われます。たぶんあなたのものタスクリスト実際にはフォルダ1ではありません。この場合、ffmpegの完全な「ファイルが見つかりません」というエラーメッセージは、*.mp4: No such file or directory
-globがどのファイルとも一致しないため、パラメータがfilename
に設定されます<literal asterisk><dot>mp4
。
2番目の例では、パラメータ置換は${filename%.*}
ffmpegに指定した名前の末尾から.mp4を削除します。これがおそらくこのNo such file or directory
。
また、2つの例ではffmpegを使用しています。接続デマルチプレクサ不正確です。 concat demuxerには入力としてテキストファイルが必要です(または以下の例に示すように適切なシェル置換を使用<()
)。例では、すべてのストリームを単一のコンテナに混在させる場合は、入力ファイルを直接指定します。ストリームは「並列」状態になります(字幕ストリームや補助オーディオトラックを追加するなど)。 )。接続はファイルを順次接続します。
必要なのは、フォルダ1の.mp4ファイルをファイル名が一致するフォルダ2の他の.mp4ファイルに関連付けることです...次は、絶対パスを使用してテストした例です。 andの/tmp/a
代わりに/tmp/b
and/path/folder-1
を使用してください/path/folder-2
。/tmp
/path/output
seconddirectory="/tmp/b"
for i in /tmp/a/*.mp4
do
if ! [[ -e "$seconddirectory/${i##*/}" ]]
then
>&2 echo "no matching file in $seconddirectory for $i"
continue
fi
out="${i##*/}"
out="/tmp/${out%.*}-$(date +'%Y-%m-%d_%H:%M:%S')"
ffmpeg -f concat -safe 0 -i <(printf '%s\n' "file '$i'" "inpoint 0" "file '$seconddirectory/${i##*/}'" "inpoint 0") -c copy "$out.mp4"
done
これにより、/tmp/bに一致するファイル名を持つ/tmp/aのすべての.mp4ファイルが/tmp/*として出力されます。日付.mp4、一致するファイルをリンクします。 (注:ファイル名の競合が発生する可能性があるため、出力日のみを使用しないでください。一意の名前(この場合は入力ファイルのデフォルト名)を使用してこれを避けてください。)${i##*/}置換は絶対パスにありますパスコンポーネントを削除し、ファイル名コンポーネントのみを残します。絶対パスを使用することは、現在の作業ディレクトリがグローバル*
マッチングを妨げないことを意味します。
ファイル名が一致しないファイルを結合するには、別の手順を実行する必要があります。例えば。各フォルダの最初のファイルを一致させ、次に2番目のファイルを一致させます(bash globがソートされる順番で)。
a=(/tmp/a/*.mp4)
b=(/tmp/b/*.mp4)
a=("${a[@]:0:${#b[@]}}")
b=("${b[@]:0:${#a[@]}}")
for (( i=0; i<${#a[@]}; i++ ))
do
out="${a[i]##*/}"
out="${out%.*}-${b[i]##*/}"
out="/tmp/${out%.*}-$(date +'%Y-%m-%d_%H:%M:%S')"
ffmpeg -f concat -safe 0 -i <(printf '%s\n' "file '${a[i]}'" "inpoint 0" "file '${b[i]}'" "inpoint 0") -c copy "$out.mp4"
done
これは、globbingと組み合わせた配列変数を使用して各ディレクトリに.mp4ファイルのリストを作成し、ペアが存在しなくなるまでペア(各リストに1つずつ)を関連付けます。
<()
手続き型の代わりに、入力ファイルのペアを一致させ、それをffmpegが必要とする形式でテキストファイルに書き込んでからファイルを処理できます。例えば。最初の例は次のとおりです。
seconddirectory="/tmp/b"
for i in /tmp/a/*.mp4
do
if ! [[ -e "$seconddirectory/${i##*/}" ]]
then
>&2 echo "no matching file in $seconddirectory for $i"
continue
fi
out="${i##*/}"
out="/tmp/${out%.*}-$(date +'%Y-%m-%d_%H:%M:%S')"
printf '%s\n' "file '$i'" "inpoint 0" "file '$seconddirectory/${i##*/}'" "inpoint 0" > "$out.ffcat"
done
for i in /tmp/*.ffcat
do
ffmpeg -f concat -safe 0 -i "$i" -c copy "${i/%.ffcat/.mp4}"
done
タスクを実行するffmpegの代替はmkvmerge
(mkvtoolnixで)です。テキストファイルを入力として要求せずにファイルをリンクする方法を提供します。上記の最初の例では、行ffmpeg
全体を次のように置き換えることができます。
mkvmerge -o "$out.mkv" "$i" + "$seconddirectory/${i##*/}"
生成された出力ファイルは、上記のffmpegの例で使用されているファイルの.mkv
代わりにmatroskaコンテナにあります。.mp4
これらすべてを再利用可能な関数に入れてください。
function concatenation_example() { local a b c i out mf if type mkvmerge >/dev/null then mf=m elif type ffmpeg >/dev/null then mf=f else >&2 echo "This function won't work without either mkvmerge or ffmpeg installed." return 1 fi if [[ ! -d "$1" || ! -d "$2" || ! -d "$3" ]] then >&2 printf '%s\n' "concatenation_example FIRSTDIR SECONDDIR OUTDIR" "all arguments must be directories" return 1 fi for i in "$1"/*.mp4 do if ! [[ -e "$2/${i##*/}" ]] then >&2 echo "no matching file in $2 for $i" continue fi out="${i##*/}" out="$3/${out%.*}-$(date +'%Y-%m-%d_%H:%M:%S')" case "$mf" in (m) mkvmerge -o "$out.mkv" "$i" + "$2/${i##*/}" ;; (f) ffmpeg -f concat -safe 0 -i <(printf '%s\n' "file '$i'" "inpoint 0" "file '$2/${i##*/}'" "inpoint 0") -c copy "$out.mp4" ;; esac done }