Buffering Detection¶
ffmpeg
filter graph implementation doesn’t provide any flow control and
there are situations where out-of-memory error can occur.
Reading multiple files¶
This situation describes a video processing pipeline where:
preroll and source are decoded only once
each video (result) starts with a common preroll
each uncompressed source is transcoded in a “lossless” way to a relatively small file (backup source)
To produce first frame for second output (backup source), ffmpeg
requests
first frame from source decoder. Decoded frame is pushed through filter graph
to both outputs, but preroll needs to be transcoded first. So, while “backup
source” receives frames one-by-one, decoded preroll is buffered in memory.
Instead, you may tell ffmpeg
to read both input files for both outputs and
use trim
filter to cut preroll from “backup source”.
Non-linear editing¶
In this example ffmpeg
cuts out Scene2 from source file and swaps
Scene1 and Scene3, but Result2 follows Result1. Result2
is decoded before Result1, so it is buffered in memory. The only way to
fix this is to decode source twice:
Buffering Prevention¶
Both described situations are detected via
FFMPEG.check_buffering
call.
All inputs must have streams defined with proper metadata
Filters that are used in filter graph must transform scenes in metadata properly (this is already done for
Concat
,SetPTS
andTrim
filters).
from pymediainfo import MediaInfo
from fffw.encoding import *
from fffw.graph import *
# detect information about input file
mi = MediaInfo.parse('source.mp4')
streams = [Stream(m.kind, m) for m in from_media_info(mi)]
# initialize input file with stream and metadata
source = input_file('source.mp4', *streams)
mi = MediaInfo.parse('preroll.mp4')
# initialize input file with stream and metadata
streams = [Stream(m.kind, m) for m in from_media_info(mi)]
preroll = input_file('preroll.mp4', *streams)
ff = FFMPEG()
ff < preroll
ff < source
result = output_file('result.mp4', VideoCodec('libx264'), AudioCodec('aac'))
backup = output_file('backup.mp4', VideoCodec('libx264'), AudioCodec('aac'))
split = source | Split(VIDEO)
split > backup
concat = preroll | Concat(VIDEO)
split | concat
concat > result
ff > result
ff > backup
ff.check_buffering()