Bash - ffmpeg가 본문에서 실행될 때 줄 읽기가 실패하는 동안

Bash - ffmpeg가 본문에서 실행될 때 줄 읽기가 실패하는 동안

나는 이것에 대해 한동안 고민해 왔습니다. 어쩌면 여러분 중 한 분이 저를 도와주실 수 있을 것입니다.

비디오의 특정 위치에서 비디오 프레임을 추출하려고 합니다. 이를 위해 위치는 "hh:mm:ss" 형식으로 텍스트 파일에 한 줄에 하나씩 저장됩니다. bash 스크립트는 파일의 줄을 읽고 각 줄에 대해 ffmpeg를 실행합니다.

문제는 ffmpeg가 "정상적으로" 실행되는지 여부에 따라 텍스트 파일에서 읽은 입력이 변경된다는 것입니다. ffmpeg를 실행하지 않는 경우 다른 명령(예: ls)을 실행하고 잘못된 설정으로 ffmpeg를 실행하면(즉시 종료되도록) 모든 것이 들여쓰기로 진행됩니다. ffmpeg를 사용하면 타임스탬프 파일에서 읽는 것이 유효하지 않습니다.

내 추측으로는 ffmpeg가 bash 스크립트가 실행되는 환경을 어지럽히는 것 같지만 운영 체제 설계에 따르면 이것이 가능하지 않아야 합니다.

다음은 최소한의 예와 그 출력입니다.

스크립트 extract.sh:

OUTDIR=samples

for f in test.txt; do    # in reality a proper filter such as "f in video-*.txt"
  BASE=${f%%.txt}
  VIDEO=${BASE}.mkv

  cd $OUTDIR

  while read ss; do
    echo "ffmpeg -i ../${VIDEO} -vsync 0 -ss ${ss} -t 00:00:01 '${BASE}-${ss}-%02d.png'"
    (ffmpeg -i ../invalid.mkv -vsync 0 -ss ${ss} -t 00:00:01 "${BASE}-${ss}-%02d.png" 2>&1) >> ${BASE}.log
    #(ffmpeg -i ../${VIDEO} -vsync 0 -ss ${ss} -t 00:00:01 "${BASE}-${ss}-%02d.png" 2>&1) >> ${BASE}.log
  done < ../${f}

  cd ..
done

타임스탬프 파일 test.txt:

00:00:42
00:01:20
00:02:20
00:04:20
00:05:56
00:06:40

스크립트의 첫 번째 ffmpeg 명령은 잘못된 명령입니다(잘못된 비디오 파일). 활성화되면 다음에서 입력을 올바르게 읽습니다 test.txt.

$ ./extract.sh 
ffmpeg -i ../test.mkv -vsync 0 -ss 00:00:30 -t 00:00:01 'test-00:00:30-%02d.png'
ffmpeg -i ../test.mkv -vsync 0 -ss 00:00:42 -t 00:00:01 'test-00:00:42-%02d.png'
ffmpeg -i ../test.mkv -vsync 0 -ss 00:01:20 -t 00:00:01 'test-00:01:20-%02d.png'
ffmpeg -i ../test.mkv -vsync 0 -ss 00:02:20 -t 00:00:01 'test-00:02:20-%02d.png'
ffmpeg -i ../test.mkv -vsync 0 -ss 00:04:20 -t 00:00:01 'test-00:04:20-%02d.png'
ffmpeg -i ../test.mkv -vsync 0 -ss 00:05:56 -t 00:00:01 'test-00:05:56-%02d.png'
ffmpeg -i ../test.mkv -vsync 0 -ss 00:06:40 -t 00:00:01 'test-00:06:40-%02d.png'

첫 번째(잘못된) ffmpeg 명령을 비활성화하고 두 번째(올바른) 명령을 활성화한 후 읽은 타임스탬프가 test.txt올바르지 않습니다.

$ ./extract.sh 
ffmpeg -i ../test.mkv -vsync 0 -ss 00:00:30 -t 00:00:01 'test-00:00:30-%02d.png'
ffmpeg -i ../test.mkv -vsync 0 -ss  -t 00:00:01 'test--%02d.png'
ffmpeg -i ../test.mkv -vsync 0 -ss 00:01:20 -t 00:00:01 'test-00:01:20-%02d.png'
ffmpeg -i ../test.mkv -vsync 0 -ss 05:56 -t 00:00:01 'test-05:56-%02d.png'

어떤 아이디어가 있나요?

답변1

  1. 변수를 사용할 때는 큰따옴표를 사용하세요. 예를 들어,

    cd "$OUTDIR"
    
  2. ffmpeg:출력 파일 이름이 마음에 들지 않습니다 . 따라서 $ss( ) 에서 해당 항목을 제거 하거나 다른 항목( ) ${ss//:/}으로 변경하십시오 .${ss//:/_}

    ffmpeg -i "../$VIDEO" -vsync 0 -ss "$ss" -t 00:00:01 "$BASE-${ss//:/}-%02d.png" >> "$BASE.log" 2>&1 </dev/null
    
  3. ../심볼릭 링크를 통해 처리하는 경우 상위 디렉터리 구성이 중단될 수 있습니다. 따라서 samples디렉터리에서 작업하는 것보다 해당 디렉터리 로 이동하는 것이 좋습니다 .

  4. 일반적으로 변수 이름을 모두 대문자로 사용하지 마십시오. 쉘 관리 변수 이름( 등)과 충돌할 수 $PATH있습니다 $SECONDS.

함께 모아서,

#!/bin/bash
outdir=samples

for vt in video-*.txt
do
    base=${vt%.txt}
    video=$base.mkv

    while read ss
    do
        echo "ffmpeg -i '$video' -vsync 0 -ss '$ss' -t 00:00:01 '$outdir/$base-${ss//:/}-%02d.png'" >&2
        ffmpeg -i "$video" -vsync 0 -ss "$ss" -t 00:00:01 "$outdir/$base-${ss//:/}-%02d.png" >> "$outdir/$base.log" 2>&1
    done <"$vt"
done

내 예제 파일에서는 각 샘플 포인트에 대해 50개의 PNG 파일을 생성합니다.

답변2

조금 늦을 수도 있지만 문제는 ffmpeg표준 입력에서도 읽어서 while-read-loop에서 읽은 데이터를 소비한다는 것입니다.

이상한 타임 스탬프 혼란에 빠졌습니다. 이 문제를 해결하려면 ffmpeg다음 두 가지 방법으로 명령의 표준 입력을 리디렉션할 수 있습니다.

옵션 1: 명령줄에서 ffmpeg 뒤에 -nostdin을 입력합니다.

예:

while read f; do ffmpeg -nostdin  -i "$f" -codec copy "${f%.*}.mp4" ; done

옵션 2: ffmpeg 명령줄 끝에 < /dev/null 배치

예:

while read f; do ffmpeg -i "$f" -codec copy "${f%.*}.mp4" < /dev/null; done 

여기에서 이 솔루션을 찾았습니다.

Bash 루프의 ffmpeg 문제

관련 정보