ffmpegは、forループ内の2つのビデオで構成される複数のグループをマージします。

ffmpegは、forループ内の2つのビデオで構成される複数のグループをマージします。

私はLinuxに初めてアクセスし、この問題で苦労しています。この問題を解決するのに役立ちます。

バッチプロセスのように、2つのビデオを複数回(フォルダごとに1つ)マージしようとしています。次のビデオの後に自動的に1つのビデオをマージします。

私はandを使用してフォルダ1のリストの上部にあるファイルを取得ffmpegfor 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 directoryglobが機能しないと思われます。たぶんあなたのものタスクリスト実際にはフォルダ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/band/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
}

関連情報