Eli Greenberg
Eli Greenberg

Reputation: 321

How can I parse ffprobe output and run ffmpeg depending on the result?

I have had incredible trouble building a binary of ffmpeg for Mac that works correctly for all of my needs. I have an older build that works great remuxing h264 video without problems but lacks a library I need, namely libspeex. I built a newer build based on ffmpeg's git that includes libspeex but crashes when trying to remux h264 from .flv files with bad timecodes (live dumps from rtmpdump). So I have two ffmpeg binaries that each do half of what I need. This is what I have as my current .command file:

for f in ~/Desktop/Uploads/*.flv
do
/usr/local/bin/ffmpeg -i "$f" -vcodec copy -acodec libfaac -ab 128k -ar 48000 -async 1 "${f%.*}".mp4 && rmtrash "$f" || rmtrash "${f%.*}".mp4
done

This ffmpeg binary has libspeex included so it can decode speex audio in the .flv input files. What I'm looking to do is something like this pseudocode:

for f in ~/Desktop/Uploads/*.flv
do
ffprobe input.flv
    if Stream #0:1 contains speex
        ffmpeg-speex -i input.flv -acodec copy -async 1 output.m4a
    fi
ffmpeg-h264 -i input.flv -vcodec copy output.mp4
MP4Box -add output.mp4 -add output.m4a finaloutput.mp4
done

Is something like this possible? Are there any alternatives?

Upvotes: 4

Views: 10183

Answers (2)

Sam
Sam

Reputation: 11

The version of ffprobe that is out now has a -print_format flag that may be useful in your situation. I had a similar issue where I wanted to get the length of a video. I used the -print_format xml flag and then used xmllint on the result to get the value. You will just need to look at the xml output from ffprobe and replace string(.//format/@duration) with the xpath to the elements you want.

XML=`ffprobe -v error -hide_banner -show_format -show_streams -print_format xml "$FILEPATH"`
DATA=`echo "$XML" | xmllint --xpath "string(.//format/@duration)" -`

Upvotes: 1

You could run grep on its output and test whether it found your desired string:

for f in ~/Desktop/Uploads/*.flv; do
    if ffprobe ${f} 2>&1 | egrep 'Stream #0:1.+speex'; then
        ffmpeg-speex -i ${f} -acodec copy -async 1 ${f/%.flv/.m4a}
        SPEEX_ADD="-add ${f/%.flv/.m4a}"
    fi
    ffmpeg-h264 -i ${f} -vcodec copy ${f/%.flv/.mp4}
    MP4Box -add ${f/%.flv/.mp4} ${SPEEX_ADD} ${f/%.flv/-final.mp4}
done

Assuming an input file abc.flv, ffmpeg-speex would output abc.m4a, ffmpeg-h264 would output abc.mp4, and MP4Box would output abc-final.mp4.

Edit: Fixed to grep on stderr also; fixed problem where non-existent .m4a file might be given to MP4Box as an input.

Upvotes: 4

Related Questions