Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

I'm trying to extract certain info from ffmpeg output.

Sample ffmpeg output:

configuration:  --enable-memalign-hack --enable-mp3lame --enable-gpl --disable-vhook --disable-ffplay --disable-ffserver --enable-a52 --enable-xvid --enable-faac --enable-faad --enable-amr_nb --enable-amr_wb --enable-pthreads --enable-x264 
libavutil version: 49.0.0
libavcodec version: 51.9.0
libavformat version: 50.4.0
built on Apr 15 2006 04:58:19, gcc: 4.0.1 (Apple Computer, Inc. build 5250)
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'file.mov':
Duration: 00:01:32.0, start: 0.000000, bitrate: 63489 kb/s
Stream #0.0(eng): Audio: pcm_s16le, 48000 Hz, stereo, 1536 kb/s
Stream #0.1(eng), 29.97 fps(r): Video: Apple ProRes 422, 1280x720
Must supply at least one output file

I want to get back a string with just Duration, frame rate, codec, and size, e.g.:

[00:01:32_29.97_Apple ProRes 422_1280x720]

I tried starting with this (from another hint):

ffmpeg -i file.mov 2>&1 | sed -n 's/Duration: \(.*\), start/\1/gp'

to get the Duration, but that just 'removed' the Duration and , start, i.e.:

00:01:32.0: 0.000000, bitrate: 63489 kb/s

PS: I'd also like to remove the Apple from Apple ProRes 422 :-)

Thanks!

Update: I was able to extract the codec with

sed -n "s/.*\Video: \(.*\),.*/\1/p"

but I don't know how to (a) get the size and framerate, and (b) combine the searches on one line...

share|improve this question

4 Answers 4

up vote 3 down vote accepted

awk: It's like magic, but better.

#!/usr/bin/awk -f
/Duration/ {sub(/,/, "", $2); fields["dur"] = $2}
/fps/ { fields["fps"] = $3 }
/Video/ { 
        sub(/.*Video:/, "", $0);
        sub(/\W*Apple\W*/, "", $0);
        split($0, arr, ", ")
        fields["codec"] = arr[1]; 
        fields["res"] = arr[2]; 
}
END {
        printf "[%s_%s_%s_%s]\n", 
                fields["dur"], 
                fields["fps"], 
                fields["codec"],  
                fields["res"]
}
share|improve this answer
    
Sweet! Wow. But for some reason it's not pulling the fps. Instead of 29.97, it returns 3 ... going to read up on awk. –  Ze'ev Jan 30 '12 at 1:52
    
@Dan Forgot the $ in assigning it, fixed. –  Kevin Jan 30 '12 at 1:54
    
Wow! Wicked! I'm sorta following the logic ... but the "" are throwing me ... what the heck are those for? Thanks! –– oh, maybe you're replacing the junk with null? –  Ze'ev Jan 30 '12 at 2:03
    
Not null per se, but the empty string, yes - there is a difference in most languages. –  Kevin Jan 30 '12 at 2:11

To extract part of a line in sed, match the whole line, and use backreferences to print out the bits you want to keep. (If your sed doesn't have the \+ operator, use foo* instead of fo\+.)

$ … | sed -n -e 's/^.*Duration: *\([^,]*\).*$/\1/p' \
             -e 's/^.* \([0-9.]\+\) fps(r).* Video: \([^,]\+\).*, *\([0-9]\+x[0-9]\+\).*$//'
00:01:32.0
29.97 Apple ProRes 422 1280x720

Note that when there are more than one way to decide what text goes into which group, the earlier groups will be as long as possible. For example, at the beginning of the second expression, ^.* \([0-9.]\+\) fps matches a number after a space; if the expression had been ^.*\([0-9.]\+\) fps then only one digit would have been matched inside the group, the earlier digits would have been absorbed by the .*. Conversely, at the end of the second expression, \([0-9]\+\).*$ puts all the digits inside the group, and the .* only begins when [0-9]\+ cannot match any longer, i.e. after the first non-digit.

While it is possible, sed is not good at combining several lines or postprocessing. When your needs grow beyond simple text replacements, turn to awk.

share|improve this answer

You can add several expressions on the same sed command -- if you add something to extract "Apple" from the video stream line, it will still print the two matches, with the replacement.

The only issue is that it will print in two different lines, but you can always |xargs echo or something more elegant.

share|improve this answer
    
OK, but ... how do I do that?? I.e., how do I use sed to extract rather than remove strings? –  Ze'ev Jan 30 '12 at 0:38

You can use sed with -e option to combine several conditions like this:

sed -e <expression1> -e <expression2> ...
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.