Created on January 18, 2023
This is not so much of a guide as it is a template for you to go off of to help speed up the encoding of videos in the Cinepak format. It's intended to supplement the actual guide on encoding in formats supported by old machines which I first wrote a couple years back. If you've already tried encoding a video to Cinepak, you'll probably know that FFmpeg's implementation of it is incredibly slow. I've developed a workaround against the slowness that uses all the CPU cores available in a system.
This is a Bash script, so you'll need some form of Linux or Unix at the very least in order to use it. It assumes you have FFmpeg and GNU Parallel installed already. If you don't, you should install the ffmpeg and parallel packages or get these programs installed in some other way.
You can copy and paste the following text into a new shell script file. One thing to be mindful of is the tmpdir variable. It's set to . by default to represent the current working directory, but if you have a tmpfs directory or other sort of RAM disk handy, you should change the variable to point there to reduce strain on your disk. Do not append a trailing slash to the path.
What this script basically does is take the source video and encode it to many split fragments, with each immediately following the previous. The number of fragments it creates is determined by how many cores GNU Parallel reports are available. The temporary output files are sequentially numbered, and when all of them are finished, an additional execution of FFmpeg is run to concatenate all of the fragments back into one clip at the working directory.
The required arguments for start/cutoff times and the output filenames are written to a named pipe, which works a little bit differently from a plain old file on the surface. Named pipes have other applications, but here it's just being used as a temporary buffer for text. The concatenation list is written to the same pipe as well using a single printf command in combination with seq.
As soon as it is done with everything (or the user presses <CTRL> + C to abort the script), it cleans up all of the temporary files it created, including the named pipe and the clip fragments.
Note the use of bc for performing certain calculations, particularly for division. The scale=1 argument is passed to it so that the each fragment's duration has one-tenth precision. This should be enough to avoid repeating fragments on systems with high core counts working with very short clips, as well as potential loss of audio synchronization when trying to use higher precision.
The actual ffmpeg command being run uses ideal settings for a Cinepak AVI - proportionally downscaling a video to a height of 240 pixels if it is larger, setting it to 15 FPS, and using the pcm_u8 audio codec at 8000Hz in mono. You can change these if you want, but setting them higher could result in more space being used up, as well them possibly being harder to play back on slower systems.
The --bar argument is used with Parallel to display a progress bar to show how many fragments have been fully encoded so far. Initially, this bar will not move very much, but when it does, it should be an indicator that the clip is almost ready.
To run this script, first enable the execute bit for the owner:
Then run it with a source file as the argument:
The resulting output should be a new video labeled mcdonals.avi.
In case you want to use the Microsoft Video 1 codec for reduced size at the cost of quality, you can pass msvideo1 as a second argument:
You can also prepend this with time if you want to compare how long this script takes against running a standalone ffmpeg command writing to one file, being constrained by the single-threaded Cinepak encoder. I ran a test on one of my 30 second videos, and with the script using a 16 core CPU, it took only 10 seconds, while using one thread took a full minute and 33 seconds!
No comments for this page.
Leave a Comment