Comment by dekhn
4 days ago
I've gotten pretty good at various bits of ffmpeg over time. Its CLI has a certain logic to it... it's order dependent (not all unix CLIs are).
Lately, I've been playing around with more esoteric functionality. For example, storing raw video straight off a video camera on a fairly slow machine. I built a microscope and it reads frames off the camera at 120FPS in raw video format (YUYV 1280x720) which is voluminous if you save it directly to disk (gigs per minute). Disks are cheap but that seemed wasteful, so I was curious about various close-to-lossless techniques to store the exact images, but compressed quickly. I've noticed that RGB24 conversion in ffmpeg is extremely slow, so instead after playing around with the command line I ended up with:
ffmpeg -f rawvideo -pix_fmt yuyv422 -s 1280x720 -i test.raw -vcodec libx264 -pix_fmt yuv420p movie.mp4 -crf 13 -y
This reads in raw video- because raw video doesn't have a container, it lacks metadata like "pixel format" and "image size", so I have to provide those. It's order dependent- everything before "-i test.raw" is for decoding the input, and everythign after is for writing the output. I do one tiny pixel format conversion (that ffmpeg can do really fast) and then write the data out in a very, very close to lossless format with a container (I've found .mkv to be the best container in most cases).
Because I hate command lines, I ended up using ffmpeg-python which composes the command line from this:
self.process = (
ffmpeg.
input(
"pipe:",
format="rawvideo",
pix_fmt="yuyv422",
s="{}x{}".format(1280, 720),
threads=8
)
.output(
fname, pix_fmt="yuv422p", vcodec="libx264", crf=13
)
.overwrite_output()
.global_args("-threads", "8")
.run_async(pipe_stdin=True)
)
and then I literally write() my frames into the stdin of that process. I had to limit the number of threads because the machine has 12 cores and uses at least 2 at all times to run the microscope.
I'm still looking for better/faster lossless YUV encoding.
>Its CLI has a certain logic to it... it's order dependent (not all unix CLIs are).
Which is appropriate. A Unix pipeline is dependent on the order of the components, and complex FFMpeg invocations entail doing something analogous.
>I ended up using ffmpeg-python which composes the command line from this
A lot of people like this aesthetic, but doing "fluent" interfaces like this is often considered un-Pythonic. (My understanding is that ffmpeg-python is designed to mirror the command-line order closely.) The preference (reinforced by the design of the standard library and built-in types) is to have strong https://en.wikipedia.org/wiki/Command%E2%80%93query_separati... . By this principle, it would look something more like
where using a separate construction process for the input produces a different runtime type, which also cues the processing code that it needs to read from stdin.
To be honest what I really wanted is more like a programming API or config file than attempting to express complex pipelines and filters in a single command line.
As for what's unpythonic: don't care. My applications has code horrors that even Senior Fellows cannot unsee.
I get that. My critique is for the library authors, not you.
Similar, arguably simpler, Python library that provides an interface to FFmpeg command line is ffmpy [0], of which I am the author.
[0] https://github.com/Ch00k/ffmpy
> I'm still looking for better/faster lossless YUV encoding.
Look no further: https://trac.ffmpeg.org/wiki/Encode/FFV1
I spent some time with this on my data set, and in my hands I wasn't able to produce results that were convincingly better than libx264, but with slower encodes and larger output files. It's really hard to beat libx264.
>> I'm still looking for better/faster lossless YUV encoding.
> I wasn't able to produce results that were convincingly better than libx264
With "-qp 0"? Otherwise, it's not a valid comparison... "-crf 13" is nowhere near lossless (though it might appear so visually).
FFV1 is much better than H264 at lossless compression in my experience. Here's a random sample of a ten second 4K input I had handy (5.5G uncompressed):
But yeah, if you don't actually require truly lossless data, it's a huge waste.
I am here to sell you on one word: ramdisks.
If you are doing processing with intermediate steps you do not want to keep? Ramdisks. Oh yeah. Oh yeah.
This seems to be very forgotten tech. First time I used that was to load NetHack to ram instead of the slow diskette on my Atari. Now I still use it as webcache for work to not bother the database with so many requests.
When I set up the server, the ramdisk didn't have a way of shrinking when space wasn't needed so had to make sure it doesn't eat up all memory when growing unlimited. I bet it's smarter nowadays.
Not forgotten at all -- in fact, if your system has has a /tmp directory, it is almost certainly a RAMdisk.
1 reply →
Slow ffmpeg pipelines are typically cpu-bound rather than io-bound.
e.g. When doing a simple copy, progress status messages upgrade to scientific notation.