ffmpeg는 for 루프에서 2개의 비디오로 구성된 여러 그룹을 병합합니다.

ffmpeg는 for 루프에서 2개의 비디오로 구성된 여러 그룹을 병합합니다.

저는 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 directoryglob이 작동하지 않는 것으로 의심됩니다. 어쩌면 당신 것작업 목록실제로 폴더 1이 아닙니다. 이 경우 ffmpeg의 전체 "파일을 찾을 수 없음" 오류 메시지는 *.mp4: No such file or directory- glob이 어떤 파일과도 일치하지 않으므로 매개변수가 filename로 설정됩니다 <literal asterisk><dot>mp4.

두 번째 예에서 매개변수 대체는 ${filename%.*}ffmpeg에 제공한 이름 끝에서 .mp4를 제거합니다. 이것이 아마도 이 No such file or directory.

또한 두 가지 예에서 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##*/} 대체는 절대 경로에서 경로 구성 요소를 제거하고 파일 이름 구성 요소만 남깁니다. 절대 경로를 사용한다는 것은 현재 작업 디렉터리가 *전역 일치를 방해하지 않는다는 것을 의미합니다.

파일 이름이 일치하지 않는 파일을 결합하려면 다른 단계를 수행해야 합니다. 예를 들어. 각 폴더의 첫 번째 파일을 일치시킨 다음 두 번째 파일을 일치시킵니다(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 파일 목록을 작성하고 더 이상 쌍이 존재하지 않을 때까지 쌍(각 목록에 하나씩)을 연결합니다.

<()절차적 대체 대신 입력 파일 쌍을 일치시키고 이를 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
}

관련 정보