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 have a bash script looping through the results of a find and performing an ffmpeg encoding of some FLV files. Whilst the script is running the ffmpeg output seems to be interupted and is outputting some strange looking errors like the one below. I've no idea what is going on here. Can anyone point me in the right direction?

It's as though the loop is still running when it shouldn't be and interupting the ffmpeg process.

The specific error is:

frame=   68 fps= 67 q=28.0 00000000000000000000000000001000size=      22kB time=00:00:00.50 bitrate= 363.2kbits/s dup=1 drop=0    
Enter command: <target> <time> <command>[ <argument>]
Parse error, at least 3 arguments were expected, only 1 given in string 'om/pt_br/nx/R3T4N2_HD3D_demoCheckedOut.flv'

Some more details from the ffmpeg output:

[buffer @ 0xa30e1e0] w:800 h:600 pixfmt:yuv420p tb:1/1000000 sar:0/1 sws_param:flags=2
[libx264 @ 0xa333240] using cpu capabilities: MMX2 SSE2Fast SSSE3 FastShuffle SSE4.1 Cache64
[libx264 @ 0xa333240] profile High, level 3.1
[libx264 @ 0xa333240] 264 - core 122 r2184 5c85e0a - H.264/MPEG-4 AVC codec - Copyleft 2003-2012 - http://www.videolan.org/x264.html - options: cabac=1 ref=5 deblock=1:0:0 analyse=0x3:0x113 me=umh subme=8 psy=1 psy_rd=1.00:0.00 mixed_ref=1 me_range=16 chroma_me=1 trellis=1 8x8dct=1 cqm=0 deadzone=21,11 fast_pskip=1 chroma_qp_offset=-2 threads=1 sliced_threads=0 nr=0 decimate=1 interlaced=0 bluray_compat=0 constrained_intra=0 bframes=3 b_pyramid=2 b_adapt=2 b_bias=0 direct=3 weightb=1 open_gop=0 weightp=2 keyint=250 keyint_min=25 scenecut=40 intra_refresh=0 rc_lookahead=50 rc=cbr mbtree=1 bitrate=500 ratetol=1.0 qcomp=0.60 qpmin=0 qpmax=69 qpstep=4 vbv_maxrate=500 vbv_bufsize=1000 nal_hrd=none ip_ratio=1.40 aq=1:1.00
Output #0, mp4, to './mp4s/pt_br/teamcenter/tc8_interactive/videos/8_SRM_EN.mp4':
  Metadata:
    audiodelay      : 0
    canSeekToEnd    : true
    encoder         : Lavf54.3.100
    Stream #0:0: Video: h264 (![0][0][0] / 0x0021), yuv420p, 800x600, q=-1--1, 500 kb/s, 30k tbn, 29.97 tbc
    Stream #0:1: Audio: aac (@[0][0][0] / 0x0040), 44100 Hz, mono, s16, 128 kb/s
Stream mapping:
  Stream #0:1 -> #0:0 (vp6f -> libx264)
  Stream #0:0 -> #0:1 (mp3 -> libfaac)
Press [q] to stop, [?] for help
error parsing debug value0 00000000000000000000000000000000size=      13kB time=00:00:00.-3 bitrate=-3165.5kbits/s dup=1 drop=0    
debug=0
frame=   68 fps= 67 q=28.0 00000000000000000000000000001000size=      22kB time=00:00:00.50 bitrate= 363.2kbits/s dup=1 drop=0    
Enter command: <target> <time> <command>[ <argument>]
Parse error, at least 3 arguments were expected, only 1 given in string 'om/pt_br/nx/R3T4N2_HD3D_demoCheckedOut.flv'

The script is as follows

#!/bin/bash
LOGFILE=encodemp4ize.log
echo '' > $LOGFILE
STARTTIME=date
echo "Started at `$STARTTIME`" >> $LOGFILE
rsync -avz flvs/ mp4s/ --exclude '*.flv'
#find flvs/ -name "*.flv" > flv-files
# The loop
find flvs/ -name "*.flv" | while read f
do
FILENAME=`echo $f | sed 's#flvs/##'`
MP4FILENAME=`echo $FILENAME | sed 's#.flv#.mp4#'`
ffmpeg -i "$f" -vcodec libx264 -vprofile high -preset slow -b:v 500k -maxrate 500k -bufsize 1000k -threads 0 -acodec libfaac -ab 128k "./mp4s/$MP4FILENAME"
echo "$f MP4 done" >> $LOGFILE
done
share|improve this question
    
I'm not much of a scripter, but an obvious suggestion - have your script print out the lines it is executing. They may not be what you think they are. –  Faheem Mitha Apr 12 '12 at 14:15
    
As a side issue: mp4filename=$(basename "$f" mp4) might be useful (see man basename and man dirname for more info) –  Peter.O Apr 12 '12 at 14:34
    
Say bash -x myscript to get a line-by-line trace of the script's execution, with all the variables expanded. Oh, and incidentally, you've reinvented the basename wheel on the FILENAME= line. :) –  Warren Young Apr 12 '12 at 16:35
    
I've found the solution. The bash script seems to product input (Namely the 'c' key) which interferes with the ffmpeg process. Piping "< /dev/null" into ffmpeg like so: ffmpeg -i "./$f" -vcodec libx264 -vprofile high -preset slow -b:v 500k -maxrate 500k -bufsize 1000k -threads 0 -acodec libfaac -ab 128k "./mp4s/$MP4FILENAME" < /dev/null Fixes the issue. via [linuxquestions.org/questions/programming-9/… [1]: linuxquestions.org/questions/programming-9/… –  Willburt Apr 12 '12 at 18:37

2 Answers 2

up vote 11 down vote accepted

Your question is actually Bash FAQ #89: just add </dev/null to prevent ffmpeg from reading its standard input.


I've taken the liberty of fixing up your script for you because it contains a lot of potential errors. A few of the important points:

  • Filenames are tricky to handle, because most filesystems allow them to contain all sorts of unprintable characters normal people would see as garbage. Making simplifying assumptions like "file names contain only 'normal' characters" tends to result fragile shell scripts that appear to work on "normal" file names and then break the day they run into a particularly nasty file name that doesn't follow the script's assumptions. On the other hand, correctly handling file names can be such a bother that you may find it not worth the effort if the chance of encountering a weird file name is expected to be near zero (i.e. you only use the script on your own files and you give your own files "simple" names). Sometimes it is possible to avoid this decision altogether by not parsing file names at all. Fortunately, that is possible with find(1)'s -exec option. Just put {} in the argument to -exec and you don't have to worry about parsing find output.

  • Using sed or other external processes to do simple string operations like stripping extensions and prefixes is inefficient. Instead, use parameter expansions which are part of the shell (no external process means it will be faster). Some helpful articles on the subject are listed below:

  • Use $( ), and don't use `` anymore: Bash FAQ 82.

  • Avoid using UPPERCASE variable names. That namespace is generally reserved by the shell for special purposes (like PATH), so using it for your own variables is a bad idea.

And now, without further ado, here's a cleaned up script for you:

#!/bin/sh

logfile=encodemp4ize.log
echo "Started at $(date)." > "$logfile"
rsync -avz --exclude '*.flv' flvs/ mp4s/

find flvs/ -type f -name '*.flv' -exec sh -c '
for flvsfile; do
    file=${flvsfile#flvs/}
    < /dev/null ffmpeg -i "$flvsfile" -vcodec libx264 -vprofile high \
        -preset slow -b:v 500k -maxrate 500k -bufsize 1000k \
        -threads 0 -acodec libfaac -ab 128k \
        "mp4s/${file%flv}"mp4
    printf %s\\n "$flvsfile MP4 done." >> "$logfile"
done
' _ {} +

Note: I used POSIX sh because you didn't use or need any bash-specific features in your original.

share|improve this answer
1  
It's a brilliant answer! Thank you for the effort writing up corrected script. Just wondering is there a similar to Greg's Wiki guide to zsh? Thanks! –  Art Oct 24 '12 at 5:05
    
@Art Sorry, I don't know very much about zsh. Maybe some of the zsh people on the site would know. –  jw013 Oct 24 '12 at 13:09

I've found the solution. The bash script seems to produce input (Namely the 'c' key) which interferes with the ffmpeg process.

Adding < /dev/null to the ffmpeg command line, like so:

ffmpeg -i "./$f" -vcodec libx264 -vprofile high -preset slow -b:v 500k -maxrate 500k -bufsize 1000k -threads 0 -acodec libfaac -ab 128k "./mp4s/$MP4FILENAME" < /dev/null

fixes the issue.

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.