feat(video): switch vp8 in ffmpeg to realtime (#5260)

This switches vp8 to "realtime" mode that works fast, adapting to
the speed of incoming frames, and produces the best quality in can
given realtime constraints.

In practice, this gives 2x larger video files but no noticible quality
difference. It also eliminates huge delays for encoding the video.

Drive-by: document our ffmpeg option choices and add some links
to documentation for future use.
This commit is contained in:
Dmitry Gozman 2021-02-02 17:14:39 -08:00 committed by GitHub
parent 1ffd654d63
commit 1a464c732c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -52,9 +52,38 @@ export class VideoRecorder {
}
private async _launch(options: types.PageScreencastOptions) {
// How to tune the codec:
// 1. Read vp8 documentation to figure out the options.
// https://www.webmproject.org/docs/encoder-parameters/
// 2. Use the following command to map the options to ffmpeg arguments.
// $ ./third_party/ffmpeg/ffmpeg-mac -h encoder=vp8
// 3. A bit more about passing vp8 options to ffmpeg.
// https://trac.ffmpeg.org/wiki/Encode/VP8
//
// We use the following vp8 options:
// "-qmin 0 -qmax 50" - quality variation from 0 to 50.
// Suggested here: https://trac.ffmpeg.org/wiki/Encode/VP8
// "-crf 8" - constant quality mode, 4-63, lower means better quality.
// "-deadline realtime" - do not use too much cpu to keep up with incoming frames.
// "-b:v 1M" - video bitrate. Default value is too low for vp8
// Suggested here: https://trac.ffmpeg.org/wiki/Encode/VP8
//
// We use "pad" and "crop" video filters (-vf option) to resize incoming frames
// that might be of the different size to the desired video size.
// https://ffmpeg.org/ffmpeg-filters.html#pad-1
// https://ffmpeg.org/ffmpeg-filters.html#crop
//
// We use "image2pipe" mode to pipe frames and get a single video.
// "-f image2pipe -c:v mjpeg -i -" forces input to be read from standard input, and forces
// mjpeg input image format.
// https://trac.ffmpeg.org/wiki/Slideshow
//
// "-y" means overwrite output.
// "-an" means no audio.
const w = options.width;
const h = options.height;
const args = `-loglevel error -f image2pipe -c:v mjpeg -i - -y -an -r ${fps} -c:v vp8 -qmin 0 -qmax 50 -crf 8 -b:v 1M -vf pad=${w}:${h}:0:0:gray,crop=${w}:${h}:0:0`.split(' ');
const args = `-loglevel error -f image2pipe -c:v mjpeg -i - -y -an -r ${fps} -c:v vp8 -qmin 0 -qmax 50 -crf 8 -deadline realtime -b:v 1M -vf pad=${w}:${h}:0:0:gray,crop=${w}:${h}:0:0`.split(' ');
args.push(options.outputFile);
const progress = this._progress;