Recording and streaming with FFmpeg
Once I wanted to try recording and streaming my painting, hoping that it would make me more efficient. Open broadcaster didn’t work on my old hardware, luckily there is ffmpeg https://ffmpeg.org/.
I was experimenting with the options to make it as cpu unintensive as possible (while maintaining some quality) so I would still be able to paint. Here is what I settled on:
Recording
ffmpeg \
-video_size 1680x1050 -framerate 10 -hwaccel auto -f x11grab -i $DISPLAY.0 -vcodec libx264 \
-qp 0 -crf 28 -threads 1 -preset superfast -vprofile baseline -pix_fmt yuv420p \
-f h264 $1_`date +%Y%m%d%H%M`.mkv;
Recording and streaming (with pulseaudio)
FPS="10" # target FPS
GOP="20" # i-frame interval, should be double of FPS,
GOPMIN="10" # min i-frame interval, should be equal to fps,
THREADS="1"
CBR="3000k" # constant bitrate (should be between 1000k - 3000k)
AUDIO_RATE="44100"
ffmpeg -f x11grab -r "$FPS" -i $DISPLAY.0 \
-keyint_min $GOPMIN -minrate $CBR -maxrate $CBR -strict normal -g $GOP -b:v $CBR -bufsize $CBR\
-vcodec libx264 -f flv -qp 0 -crf 28 -threads 1 -preset superfast -vprofile baseline -pix_fmt yuv420p - \
| tee $1_`date +%Y%m%d%H%M`.mkv | ffmpeg -i - -f alsa -i pulse -ar $AUDIO_RATE -vcodec copy\
-acodec aac -f flv rtmp://live.us.picarto.tv/golive/$STREAM_KEY
Making final video
The recorded videos were, of course, huge and often one picture was in several files, since I didn’t finish it in one session. Both the preceding commands take one argument - an identifier of the picture. I could use it to make a list of recorded videos of this pictures:
ffmpeg_make_filelist () { printf "file '%s'\n" ./*$1* > ffmpeg_concat.txt; }
Then ffmpeg can take this file and concat the listed videos:
ffmpeg_concat () { ffmpeg -safe 0 -f concat -i ffmpeg_concat.txt -c copy $1 }
The result is still huge, so I removed duplicate frames (where I was just staring on the screen or went away and was not drawing)
ffmpeg_rmduplicates () { ffmpeg -i $1 -vf mpdecimate,setpts=N/FRAME_RATE/TB -threads 2 ${1}_done.mp4; }
And encoded the video:
ffmpeg_encode () { ffmpeg -i $1 -s 1280x800 -filter:v "fps=15, setpts=0.1*PTS" -vcodec libx264 -crf 22 -threads 2 ${1}_enc.mp4; }