Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

First part of my question:

I read on the ffmpeg documentation (section 3.2 How do I encode single pictures into movies?) the following:

To encode single pictures into movies, run the command:

  ffmpeg -f image2 -i img%d.jpg movie.mpg    

Notice that `%d' is replaced by the image number: img%03d.jpg means the sequence img001.jpg, img002.jpg, etc...

My question is: Who is doing the translation between img%03d.jpg and img001.jpg, img002.jpg, etc? Is it the shell or ffmpeg?

Second part:

I would like to ask ffmpeg to encode a sequence of images into a video. However, my sequences often start with an index different from 1, (e.g. we can call it start_index) and end on an index that we can call end_index. Moreover, the sequence uses increments of value increment, e.g.:

img_0025.png, img_0030.png, img_0035.png, ... img_0100.png

where start_index was 25, end_index was 100, and increment was 5.

I would like feed an image sequence like the above to ffmpeg without having to rename the sequence first. The documentation explains how to do this with symbolic links, but I was wondering if there is a way to avoid them altogether, maybe using advanced globbing on zsh.

share|improve this question
up vote 8 down vote accepted

Part 1: % is not a special character, so the img%d.jpg argument is passed as is to ffmpeg which “does the job” itself.

Part 2: Looking at ffmpeg documentation, I don't think there is another way to provide input files, so you may have to use symlinks or wait for the “fix”:

If the pattern contains "%d" or "%0Nd", the first filename of the file list specified by the pattern must contain a number inclusively contained between 0 and 4, all the following numbers must be sequential. This limitation may be hopefully fixed.

share|improve this answer

It can be done using pipes only, ie. without renaming and without symlinks.

Here is a script I put together, comments and all.
I've set it up to play at 1 frame per second.
The image processing uses package netpbm

eg: images-to-vid '$HOME/images" '\./img_[0-9]{4}[^/0-9]*' 1024 768

# Make a video from images whose sizes and aspect-ratios may vary.
# Each image is resized to fit maximized within the video frame.  
# The images are positioned centrally and padded (when required) 
# Images are sourced using 'find'.  
# They are selected according to a regular expression.   
# Symbolic links are ignored.  
# Output from 'find' is sorted by path, ie. not by name alone,
#  but with a -maxlevel 1, this is typically the same...
#  You will need to customize the sort if this is not suitable.       
# Note about 'find':  
#    This script uses 'find -regex' instead of 'find -name'. 
#    The pattern must match the whole returned path, 
#       from ^ to $ inclusive  
#    The -regextype option is: posix-extended 
srceD="${1}"        # Source Directory
srceR="${2}"        # Source imaage extended Regex pattern
targW="${3:-800}"   # Target pixel Width
targH="${4:-600}"   # Target pixel Height
targB="${5:-black}" # Target Background colour (X11 colours)
targM="${6:-4}"     # Target screen geometry Modulo (as required by Target codec)
TARGw=$((targW-(targW%targM))); ((TARGw==targW)) || { echo "Target Width  must be divisible by $targM. Rounding down to $TARGw" 1>&2 ; targW=$TARGw; }
TARGh=$((targH-(targH%targM))); ((TARGh==targH)) || { echo "Target Height must be divisible by $targM. Rounding down to $TARGh" 1>&2 ; targH=$TARGh; }
# TODO: test for W/H == 0

cd "$srceD" || exit 2
find . -maxdepth 1 \
    \( -type f \) -and -not \
    \( -type l \) \
       -regextype posix-extended \
       -regex "$srceR" \
       -print0 | 
  sort -z | 
  while IFS= read -d $'\0' -r file ;do
      # make Composite image on coloured Background
      pnmcomp -align=center -valign=middle \
              <(anytopnm "$file" 2>/dev/null |
                pnmscale -xysize $targW $targH) \
              <(ppmmake "$targB" $targW $targH) 
  done |
  ffmpeg -r 1 \
         -f image2pipe \
         -vcodec ppm \
         -i - \
         -y -s ${targW}x${targH} \
         -vcodec mjpeg \
share|improve this answer
Thanks @fered, this is very helpful. Your script does even more than what I wanted, which is great. I am now trying to adapt the script to my needs. If I replace the while loop by a simple loop, that does not prescale nor adds background color: while IFS= read -d $'\0' -r file ;do pnmcomp -align=center -valign=middle <(anytopnm "$file" 2>/devnull) done, the script stops working (i.e. I get pipe: could not find codec parameters). Do you know why? Do I necessarily need pnmscale or ppmmake to feed ffmpeg with pnm images? – Amelio Vazquez-Reina Oct 9 '11 at 21:43
@intrpc. The framing of different size pics was just my personal bent on the issue. I've been wanting to do that ever since I lost the ability to use avisynth (a powerful video scripting environment - avisynth is Windows only :( The main reason I used a netpbm format is that I kept seeing postings about problems feeding jpegs to the pipe, so I just chose the path of least resistance. The video encoding will be the step that causes loss of quality, but ramping up the frame size helps... I suppose you have your specific reasons for using a video, but a simple slide show may work for you. – Peter.O Oct 10 '11 at 9:06

For the first part only: It's ffmpeg doing the job. The shell does not understand the %d string as a special pattern in file names.

share|improve this answer

Your Answer


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.