mathr / blog / #

Video encoding tips

A long while ago I documented how I went about encoding videos. I have since found a much better way to do this, adapt as you see fit for fps and bitrates, and it's possible to do it without intermediate image files - handy when you're experimenting with high definition video.

ppmtoy4m -S 444 -F 50:1 < "video.ppm" |
ffmpeg2theora -f y4m -V 1000 -o "video.ogg" -
oggenc -b 192 -o "audio.ogg" "audio.wav"
oggz-merge -o "final.ogg" "video.ogg" "audio.ogg"

If you do have image files already, ffmpeg can convert them to a yuv4mpeg stream.

ffmpeg -f image2 -i "img%05d.tif" -pix_fmt yuv444p -f yuv4mpegpipe - |
y4mscaler -I sar=1/1 -O preset=dvd |
mpeg2enc -f 8 -q 2 -o "video.m2v"

y4mscaler-9.0 doesn't compile out of the box with the latest mjpegtools libraries, here's the fix (at least for libmjpegtools-dev version 1:1.9.0-0.5ubuntu1):

--- y4mscaler.C.orig    2009-10-28 00:32:21.000000000 +0000
+++ y4mscaler.C 2009-10-28 00:33:51.000000000 +0000
@@ -194,7 +194,7 @@
   if (source.read_stream_header(fd_in) != Y4M_OK)
     mjpeg_error_exit1("Failed to read YUV4MPEG2 header!");
   mjpeg_info("Input Stream Header:");
-  source.stream().log_info(LOG_INFO, "<<< ");
+  source.stream().log_info(mjpeg_loglev_t("info"), "<<< ");
 
   /* set target stream defaults from source stream */
   target.init_stream(source);
@@ -216,7 +216,7 @@
   /* set up target stream */
   target.stream().write_stream_header(fd_out);
   mjpeg_info("Output Stream Header:");
-  target.stream().log_info(LOG_INFO, ">>> ");
+  target.stream().log_info(mjpeg_loglev_t("info"), ">>> ");
 
   /* do some scaling */
   scaling.create_scalers(source, target);

And just another little tip: Dirac encoding is still awesomely slow, so I'm sticking with Theora (or MPEG2 for DVD) for now.