JulianJ
JulianJ

Reputation: 1315

Why is my bash script halting with ffmpeg?

I have a text file that contains frame numbers line by line and I am using a bash script and ffmpeg to cycle through each line and attempt to print out a thumbnail of each frame.

Each time I run the bash script in my terminal it halts with an error having created the first thumbnail. It seems it is not given the thumbnail a unique name. What am I doing wrong?

My bash script:

#!/bin/bash
source text.txt
while read name
do
ffmpeg -i result.mp4 -vf "setpts=N+1,select='eq(n,$name)'" -vframes 1 frames-$i.jpg
done <text.txt

The error:

File 'frames-.jpg' already exists. Overwrite ? [y/N] Not overwriting - exiting

Upvotes: 2

Views: 675

Answers (2)

John Mark Mitchell
John Mark Mitchell

Reputation: 4822

First, I am guessing you are not needing to source the file text.txt in your script. When a file is sourced by source filename or . filename the lines of code in the file are executed as if they were printed at the command line. As such, I have removed this section of your script.

Second, as noted by others you did not define or update a $i variable. A modification as such might work for you:

#!/bin/bash

i="0"
while read -r name || [[ -n "${name}" ]]; do  # allows for last line with no newline
    ffmpeg -i result.mp4 -vf "setpts=N+1,select='eq(n,${name})'" -vframes 1 frames-${i}.jpg
    if [ "$?" -eq "0" ]; then
        printf -- 'ffmpeg succeeded - creating frames-%s.jpg for %s\n' "${i}" "${name}"
    else
        printf -- 'ffmpeg failed - was unable to create frames-%s.jpg for %s\n' "${i}" "${name}"
    fi
    let i+="1"
done <text.txt

Some additional notes on the script above:

  1. It is recommended to use -r with read to disable interpretation of backslash escapes and line-continuation in the data read. This can keep you from a plague of issues if your input ever has bash escapable characters.

  2. I added || [[ -n "${name}" ]] to the while condition to allow for the last line in your input file to not have a newline as the last character. Otherwise the last line will be ignored by the standard read process as it requires a newline character at the end of each line.

  3. I added a check of the bash builtin variable $?. The return value of the previous command is stored in $?. 0 indicates success, others indicates error.


EDIT

If you want to help troubleshoot what ffmpeg is doing, you can try the following modified script:

#!/bin/bash

set -x  # activate bash debugging output

while read -r frame_number || [[ -n "${frame_number}" ]]; do  # allows for last line with no newline
    ffmpeg -i result.mp4 -vf "setpts=N+1,select='eq(n,${frame_number})'" -vframes 1 frames-${frame_number}.jpg
    if [ $? -eq 0 ]; then
        printf -- 'ffmpeg succeeded - creating frames-%s.jpg\n' "${frame_number}"
    else
        printf -- 'ffmpeg failed - was unable to create frames-%s.jpg\n' "${frame_number}"
    fi
done <text.txt

The edits include:

  1. Streamlining the script to use the frame numbers from the text.txt for the jpeg file name.
  2. Enabled bash debugging by adding set -x.

Using the modified script above you should be able to see all the output from ffmpeg each time it runs. My mock tests show that all should be functioning correctly per your desired outcomes. Can you test again and report back your findings?

Upvotes: 2

Jahid
Jahid

Reputation: 22428

Try defining $i:

i=0
while read name
do
((i++))
ffmpeg -i result.mp4 -vf "setpts=N+1,select='eq(n,$name)'" -vframes 1 frames-$i.jpg
done <text.txt

Upvotes: 1

Related Questions