Monday, October 11, 2010

Simple MPEG Trickery

In a previous life I occasionally created MPEG files from still images. I recently found some notes I'd taken and printed out. Since cloud services are all the rage these days, and because this may actually be useful to someone else (who knows?) I thought I'd save the notes here.

Disclaimer: I assume no responsibility for the horrendous formatting of blogger.com.



How to Convert Images to MPEG



Method 1

cat <file>               \
 | anytopnm              \
 | ppmtoy4m -n <n> -r    \
 | mpeg2enc -F 4 -q 1 -Q 5 -H -a 1 -2 1 -4 1 -o <file>.mpg


Explanation:
  1. Convert the file to a pnm (portable anymap)
  2. Convert the pnm to a y4m (YUV4MPEG2) stream.
    • -n: Output a total of <n> frames.
    • -r: Repeat last frame until <n>.
  3. Convert the stream to MPEG
    • -F 4: Format 4: Standard SVCD
    • -q 1: Quantization (1..31; 1 is best quality)
    • -Q 5: Quantization Reduction (0.0..5.0; 5 for sharp images)
    • -H: Keep as much High Frequency information as possible.
    • -a 1: Aspect ratio (1=1:1; 2=4:3; 3=16:9; 4=2.21:1)
    • -4 1: Initial 4x4 subsample search quality (1..4; 1 for best quality)
    • -2 1: Secondary 2x2 subsample quality (1..4; 1 for best quality)

Sadly, that's not as clean as it could be. It would seem that the quality settings do not affect the initial image. The longer the clip, the clearer the MPEG gets, until the new GOP, at which point it resets. I think it's a bug. The following produces larger images and is more complicated, but they are crystal clear. There must be an easier way to do this as well, preferably with a pipe. Transcode is just a wrapper ... I should be able to turn on debugging and find out what it is really doing under the hood.


Method 2


Step 1:
  • Create the input source
cat <file>| anytopnm | ppmtoy4m -n <n>-r > <file>.y4m

Step 2:
  • Transcode the Y4M to MPEG
transcode -C 3 -y ffmpeg,null -F mpeg1 -Q 5 -V -k -i <file>.y4m -o <file>

This creates <file>.m1v. MPEG1 produces slightly smaller files with no appreciable difference in quality.

Explanation
  1. Convert the file to a pnm (portable anymap)
  2. Convert the pnm to a y4m (YUV4MPEG2) stream.
    • -n: Output a total of <n> frames.
    • -r: Repeat last frame until <n>.
  3. Convert the stream to MPEG
    • -C 3: Anti-alias mode 3: Process Full Frame
    • -y ffmpeg,null: Use ffmpeg video codec, no audio codec
    • -F mpeg1: Option to tell ffmpeg to use mpeg1 encoder
    • -Q 5: Encoding quality (0=fastest, 5=best)
    • -V: Use YV12/I420 as internal video codec (fastest processing)
    • -k: Swap red/blue (Cr/Cb) in video. Without this, people get blue faces
    • -i: Input file name
    • -o: Output file form (.m1v or other extension automatically appended).


Method 3


This looks like a very promising method (needs to be fleshed out)

cat <file>.y4m | ffmpeg -f yuv4mpegpipe -i - -target vcd -f mpeg1video -y <output>

or something like


ffmpeg [-f (yuv4mpegpipe)] -i <file> -target vcd [-f mpeg1video]? -y <output>

Explanation
  1. Start with y4m (see above to create)
  2. -target vcd seems to be the magic
  3. -y is force overwrite


Method 4

This is a pretty good way to extend (loop) an MPEG. First, convert it to a YUV stream:


transcode -i <file> -o output -y yuv4mpeg -k

  • The -k is the chroma conversion we need with YUV video

Next, there are two ways to proceed. mpeg2enc is slower, a little less quality, but better compression. ffmpeg is faster, better quality, and the commandline arguments make sense, but it produces bigger files.

Both of these work with yuv4mpeg streams as created in the steps above. The yuv4mpeg stream is text-based, and contains one line at the beginning of the file that need to be removed for looping. Repeat the sed command in the examples below to extend the MPEG duration.

  1. mpeg2enc
    • (cat <file>; sed 1d <file>) | mpeg2enc -v 1 -I 0 -f 8 -F 4 -n <n> -a 2 -o <ouput>
  2. ffmpeg
    • (cat <file>; sed 1d <file>) | ffmpeg -f yuv4mpegpipe -i - -target dvd -b 2000 -y <ouput>

Note: the '-b 2000' overrides the default bitrate to 2mbit. Raising the bitrate gives better quality video at the expense of larger file sizes.


Method 5

This is an all-in-one shot that I've been using with success:


cat <input>               \
 | anytopnm               \
 | pnmtoy4m -r -n 100     \
 | ffmpeg -f yuv4mpegpipe -i - -target vcd -f mpeg1video -y <output>.mpg



Converting Short MPEGs into Long MPEGs


Method 1

This is really just extracting a still frame and then extending it into an MPEG using Method 5 above:

  1. Extract the first frame:

    transcode -i <short_mpeg> -o <framename> -y ppm -c 0-1

  2. Convert it into an MPEG:

    cat <framename>000000.ppm            \
     | ppmtoy4m -r -n ((<seconds> * 30)) \
     | ffmpeg -f yuv4mpegpipe -i - -target vcd -f mpeg1video -y <output>.mpg