Monday, May 18, 2009

ffmpeg pipe to mpeg2enc

Occasionally, I'll need to send a video stream into mpeg2enc. Mpeg2enc doesn't take an input file; it only accepts a yuv4mpeg stream. In order to send a yuv4mpeg stream to mpeg2enc, I do this using ffmpeg and the -f yuv4mpegpipe command line switch. Also, for best quality, I will send the stream using the FFMPEG variant of the Huffyuv lossless compression algorithm. ffyhuff is an enhanced version of Huffyuv that compresses better than Huffyuv.

Update 2009/05/19As per Dan Dennedy's comment below, ffmpeg's yuv4mpegpipe command will ignore the -vcodec option and pipe the video stream to mpeg2enc using an uncompressed C420jpeg stream, which is an uncompressed YUV format. Certainly good enough for the likes of me!
*** end update ***

Here is a sample command to reencode a 720P video stream as a yuv4mpeg pipe to mpeg2enc:
ffmpeg -threads 4 -i INPUT.M2V -f yuv4mpegpipe - ¦ mpeg2enc --verbose 0 --multi-thread 4 --aspect 3 --format 3 --frame-rate 4 --video-bitrate 18300 --nonvideo-bitrate 384 --interlace-mode 0 --force-b-b-p --video-buffer 448 --video-norm n --keep-hf --no-constraints --sequence-header-every-gop --min-gop-size 6 --max-gop-size 6 -o OUTPUT.M2V

Note that I am taking advantage of the eight processors in my dual quad core using the multithread switches in the commands to both ffmpeg and mpeg2enc. Note that the eight threads have been split evenly, four to each encoder, to avoid CPU context switching. (Thanks again, Dan!)

Here's another trick: to see the header information of a YUV4MPEG stream, pipe the FFmpeg conversion stream to head -1 like so:
ffmpeg -i intermediate.mov -vcodec mpeg2video -f yuv4mpegpipe - | head -1
ffmpeg -i intermediate.mov -pix_fmt yuv420p -f yuv4mpegpipe - | head -1

The FFmpeg output should show you some very important information, bolded below:
the output format: YUV4MPEG2 stream
height and width: 1280x720
framerate: 30001:1001 (or 29.97fps)
colorspace: C420JPEG
not sure what IP: 1 or XYSCSS is

Duration: 01:19:46.74, start: 0.000000, bitrate: 110301 kb/s
Stream #0.0(eng): Video: mjpeg, yuvj420p, 1280x720 [PAR 1:1 DAR 16:9], 108762 kb/s, 29.97 fps, 29.97 tbr, 30k tbn, 30k tbc
Stream #0.1(eng): Audio: pcm_s16be, 48000 Hz, 2 channels, s16, 1536 kb/s
Output #0, yuv4mpegpipe, to 'pipe:':
Metadata:
encoder : Lavf52.64.2
Stream #0.0(eng): Video: mpeg2video, yuv420p, 1280x720 [PAR 1:1 DAR 16:9], q=2-31, 200 kb/s, 90k tbn, 29.97 tbc
Stream mapping:
Stream #0.0 -> #0.0
Press [q] to stop encoding
YUV4MPEG2 W1280 H720 F30000:1001 Ip A1:1 C420jpeg XYSCSS=420JPEG

Sweet, eh?

As a final note, I am a bit confused on the differences between FFMPEG compression algorithms: ffyhuff and ffv1. If someone has pointers to the documentation on these, I'd be interested in finding out more. A google search just added to my confusion.

the mule

References
mpeg2enc man page
mpeg2enc manual
ffmpeg vs mpeg2enc
Huffyuv
FFV1
FFMPEG How To

related posts
http://crazedmuleproductions.blogspot.com/2010/01/batch-render-redux.html
/2010/01/compile-times-performance-improved.html
FFMPEG HowTo

8 comments:

ddennedy said...

Hi, your example is missing a "- |" between "yuv4mpegpipe" and "mpeg2enc". Also, the ffmpeg option to use vcodec ffvhuf or huffyuv is ignored when using yuv4mpegpipe. It will not actually use any compressed yuv over the pipe. One can verify this using " ffmpeg -i dog.ogv -vcodec ffvhuff -f yuv4mpegpipe - | head -n 1" and compare the output to " ffmpeg -i dog.ogv -f yuv4mpegpipe - | head -n 1". They are the same: C420jpeg, which is one of the uncompressed YUV formats. Finally, you might want to give ffmpeg and mpeg2enc 4 threads each to help prevent context switching.

ddennedy said...

Oh, one more thing about the -threads option. If you have it after the -i, then it only applies to the encoding side of the transcode, and there is no multi-threading in yuv4mpegpipe. However, if you move that before -i, then you can take advantage of multi-threaded decoding, and it will also put the yuv4mpegpipe muxing and writing into a separate thread (you would get 5 load-worthy threads with -threads 4). Hint: in top, press 'H' to see each thread as a separate process.

Cacasodo said...

Dan,
This is fabulous information..thank you very much!

I've reviewed the ffmpeg documentation a number of times, but I've found that it is tough to find out information like this. Do you have a specific or "best" reference that you can point me to?

thanks again,
'sodo

Cacasodo said...

I've fixed the code to your specs.

Very interesting about the order of the threads parameter. This is the type of stuff end users like me need to know.

I will experiment with the performance impact of the threads. Every month or so, I edit and output an hour long video podcast, so these settings will really save me some time.

myTaike 我的台客 said...

Hi guys, I recently discovered the Cinelerra application while searching for a small app to create video from still images with effects like 'pan and zoom.' After reading up on the Cinelerra, I think it would be an overkill for mu purpose. An ideal app would be like the reverse of using VLC to extract still images from video. I will be using scripts via command line for batch processing. I am throwing this question out here to see if you guys know of an open source app that would do this? Thank you very much!

ddennedy said...

myTaike, dvdslideshow does what you want. You should be able to modify it for a different encoding if you do not want DVD compliant MPEG-2.

Cacasodo said...

Nice one, Dan. For one offs, you can use the good ol' Prnt Screen button to capture your entire desktop or Alt-Prnt Screen for the application that is replaying the video. You'd then paste the file into Gimp. Or for direct to Gimp, load Gimp and then do File -> Acquire -> Screen Shot.

Some other ideas here:
http://forums.fedoraforum.org/archive/index.php/t-21587.html

wrzwicky said...

eugenia.gnomefiles.org has a good codec comparison. ffv1 appears to have both low speed and low quality.