Making videos for the web with Godot 4’s Movie Writer
Normally I use OBS for screen recording, but there are cases where it makes sense to use Godot’s built-in movie writer that was recently announced.
For example, if you have a slow PC or really demanding game, OBS will skip frames. It makes sense since OBS is just recording what’s on the screen in real time, while Godot has to do most of the work running the game. Recording with Godot directly will slow down the action at recording time, and you cannot hear any audio while that happens. But the video playback will end up being buttery smooth at 60 fps and include audio. It will also result in huge files. 321MB for 8 seconds, at 1280x800px (also Steam Deck’s native 16:10 resolution). Still, that’s not a video file I want to embed into any webpage or wherever as-is.
The best tool for converting video from the command line or programmatically is still ffmpeg. I’m running this on Windows in WSL2, on Ubuntu 22.04.
The best option for .webm seems to be the VP9 codec. Their docs provide some examples. I’ve tested a few parameters. For two-pass targeting an average bitrate, the target bitrate is specified with the -b:v switch:
# will take longer but smaller fileffmpeg-itilemap.avi-c:vlibvpx-vp9-b:v2M-pass1-an-fnull/dev/null&&\ffmpeg-itilemap.avi-c:vlibvpx-vp9-b:v2M-pass2-c:alibopustilemap-average.webm
This is what the output looks like:
gray@Battlestation:/mnt/c/Users/gray/godot/arpg$ffmpeg-itilemap.avi-c:vlibvpx-vp9-b:v2M-pass1-an-fnull/dev/null&&\ffmpeg-itilemap.avi-c:vlibvpx-vp9-b:v2M-pass2-c:alibopustilemap-average.webmffmpegversion4.4.2-0ubuntu0.22.04.1Copyright (c) 2000-2021 the FFmpeg developersbuiltwithgcc11 (Ubuntu 11.2.0-19ubuntu1)configuration:--prefix=/usr--extra-version=0ubuntu0.22.04.1--toolchain=hardened--libdir=/usr/lib/x86_64-linux-gnu--incdir=/usr/include/x86_64-linux-gnu--arch=amd64--enable-gpl--disable-stripping--enable-gnutls--enable-ladspa--enable-libaom--enable-libass--enable-libbluray--enable-libbs2b--enable-libcaca--enable-libcdio--enable-libcodec2--enable-libdav1d--enable-libflite--enable-libfontconfig--enable-libfreetype--enable-libfribidi--enable-libgme--enable-libgsm--enable-libjack--enable-libmp3lame--enable-libmysofa--enable-libopenjpeg--enable-libopenmpt--enable-libopus--enable-libpulse--enable-librabbitmq--enable-librubberband--enable-libshine--enable-libsnappy--enable-libsoxr--enable-libspeex--enable-libsrt--enable-libssh--enable-libtheora--enable-libtwolame--enable-libvidstab--enable-libvorbis--enable-libvpx--enable-libwebp--enable-libx265--enable-libxml2--enable-libxvid--enable-libzimg--enable-libzmq--enable-libzvbi--enable-lv2--enable-omx--enable-openal--enable-opencl--enable-opengl--enable-sdl2--enable-pocketsphinx--enable-librsvg--enable-libmfx--enable-libdc1394--enable-libdrm--enable-libiec61883--enable-chromaprint--enable-frei0r--enable-libx264--enable-sharedWARNING:libraryconfigurationmismatchavcodecconfiguration:--prefix=/usr--extra-version=0ubuntu0.22.04.1--toolchain=hardened--libdir=/usr/lib/x86_64-linux-gnu--incdir=/usr/include/x86_64-linux-gnu--arch=amd64--enable-gpl--disable-stripping--enable-gnutls--enable-ladspa--enable-libaom--enable-libass--enable-libbluray--enable-libbs2b--enable-libcaca--enable-libcdio--enable-libcodec2--enable-libdav1d--enable-libflite--enable-libfontconfig--enable-libfreetype--enable-libfribidi--enable-libgme--enable-libgsm--enable-libjack--enable-libmp3lame--enable-libmysofa--enable-libopenjpeg--enable-libopenmpt--enable-libopus--enable-libpulse--enable-librabbitmq--enable-librubberband--enable-libshine--enable-libsnappy--enable-libsoxr--enable-libspeex--enable-libsrt--enable-libssh--enable-libtheora--enable-libtwolame--enable-libvidstab--enable-libvorbis--enable-libvpx--enable-libwebp--enable-libx265--enable-libxml2--enable-libxvid--enable-libzimg--enable-libzmq--enable-libzvbi--enable-lv2--enable-omx--enable-openal--enable-opencl--enable-opengl--enable-sdl2--enable-pocketsphinx--enable-librsvg--enable-libmfx--enable-libdc1394--enable-libdrm--enable-libiec61883--enable-chromaprint--enable-frei0r--enable-libx264--enable-shared--enable-version3--disable-doc--disable-programs--enable-libaribb24--enable-libopencore_amrnb--enable-libopencore_amrwb--enable-libtesseract--enable-libvo_amrwbenc--enable-libsmbclientlibavutil56.70.100/56.70.100libavcodec58.134.100/58.134.100libavformat58.76.100/58.76.100libavdevice58.13.100/58.13.100libavfilter7.110.100/7.110.100libswscale5.9.100/5.9.100libswresample3.9.100/3.9.100libpostproc55.9.100/55.9.100GuessedChannelLayoutforInputStream#0.1 : stereoInput#0, avi, from 'tilemap.avi':Duration:N/A,start:0.000000,bitrate:N/AStream#0:0: Video: mjpeg (Baseline) (MJPG / 0x47504A4D), yuvj420p(pc, bt470bg/unknown/unknown), 1280x800 [SAR 1:1 DAR 8:5], 60 fps, 60 tbr, 60 tbn, 60 tbcStream#0:1: Audio: pcm_s32le ([1][0][0][0] / 0x0001), 48000 Hz, stereo, s32, 3072 kb/sStreammapping:Stream#0:0 -> #0:0 (mjpeg (native) -> vp9 (libvpx-vp9))Press [q] to stop, [?]for help[swscaler @ 0x55932cefff40] deprecated pixel format used, make sure you did set range correctly[libvpx-vp9 @ 0x55932cee54c0] v1.11.0Output#0, null, to '/dev/null':Metadata:encoder:Lavf58.76.100Stream#0:0: Video: vp9, yuv420p(tv, bt470bg/unknown/unknown, progressive), 1280x800 [SAR 1:1 DAR 8:5], q=2-31, 2000 kb/s, 60 fps, 60 tbnMetadata:encoder:Lavc58.134.100libvpx-vp9Sidedata:cpb:bitratemax/min/avg:0/0/2000000buffersize:0vbv_delay:N/Aframe=533fps=35q=0.0Lsize=N/Atime=00:00:00.00bitrate=N/Aspeed=0xvideo:0kBaudio:0kBsubtitle:0kBotherstreams:0kBglobalheaders:0kBmuxingoverhead:unknownOutputfileisempty,nothingwasencodedffmpegversion4.4.2-0ubuntu0.22.04.1Copyright (c) 2000-2021 the FFmpeg developersbuiltwithgcc11 (Ubuntu 11.2.0-19ubuntu1)configuration:--prefix=/usr--extra-version=0ubuntu0.22.04.1--toolchain=hardened--libdir=/usr/lib/x86_64-linux-gnu--incdir=/usr/include/x86_64-linux-gnu--arch=amd64--enable-gpl--disable-stripping--enable-gnutls--enable-ladspa--enable-libaom--enable-libass--enable-libbluray--enable-libbs2b--enable-libcaca--enable-libcdio--enable-libcodec2--enable-libdav1d--enable-libflite--enable-libfontconfig--enable-libfreetype--enable-libfribidi--enable-libgme--enable-libgsm--enable-libjack--enable-libmp3lame--enable-libmysofa--enable-libopenjpeg--enable-libopenmpt--enable-libopus--enable-libpulse--enable-librabbitmq--enable-librubberband--enable-libshine--enable-libsnappy--enable-libsoxr--enable-libspeex--enable-libsrt--enable-libssh--enable-libtheora--enable-libtwolame--enable-libvidstab--enable-libvorbis--enable-libvpx--enable-libwebp--enable-libx265--enable-libxml2--enable-libxvid--enable-libzimg--enable-libzmq--enable-libzvbi--enable-lv2--enable-omx--enable-openal--enable-opencl--enable-opengl--enable-sdl2--enable-pocketsphinx--enable-librsvg--enable-libmfx--enable-libdc1394--enable-libdrm--enable-libiec61883--enable-chromaprint--enable-frei0r--enable-libx264--enable-sharedWARNING:libraryconfigurationmismatchavcodecconfiguration:--prefix=/usr--extra-version=0ubuntu0.22.04.1--toolchain=hardened--libdir=/usr/lib/x86_64-linux-gnu--incdir=/usr/include/x86_64-linux-gnu--arch=amd64--enable-gpl--disable-stripping--enable-gnutls--enable-ladspa--enable-libaom--enable-libass--enable-libbluray--enable-libbs2b--enable-libcaca--enable-libcdio--enable-libcodec2--enable-libdav1d--enable-libflite--enable-libfontconfig--enable-libfreetype--enable-libfribidi--enable-libgme--enable-libgsm--enable-libjack--enable-libmp3lame--enable-libmysofa--enable-libopenjpeg--enable-libopenmpt--enable-libopus--enable-libpulse--enable-librabbitmq--enable-librubberband--enable-libshine--enable-libsnappy--enable-libsoxr--enable-libspeex--enable-libsrt--enable-libssh--enable-libtheora--enable-libtwolame--enable-libvidstab--enable-libvorbis--enable-libvpx--enable-libwebp--enable-libx265--enable-libxml2--enable-libxvid--enable-libzimg--enable-libzmq--enable-libzvbi--enable-lv2--enable-omx--enable-openal--enable-opencl--enable-opengl--enable-sdl2--enable-pocketsphinx--enable-librsvg--enable-libmfx--enable-libdc1394--enable-libdrm--enable-libiec61883--enable-chromaprint--enable-frei0r--enable-libx264--enable-shared--enable-version3--disable-doc--disable-programs--enable-libaribb24--enable-libopencore_amrnb--enable-libopencore_amrwb--enable-libtesseract--enable-libvo_amrwbenc--enable-libsmbclientlibavutil56.70.100/56.70.100libavcodec58.134.100/58.134.100libavformat58.76.100/58.76.100libavdevice58.13.100/58.13.100libavfilter7.110.100/7.110.100libswscale5.9.100/5.9.100libswresample3.9.100/3.9.100libpostproc55.9.100/55.9.100GuessedChannelLayoutforInputStream#0.1 : stereoInput#0, avi, from 'tilemap.avi':Duration:N/A,start:0.000000,bitrate:N/AStream#0:0: Video: mjpeg (Baseline) (MJPG / 0x47504A4D), yuvj420p(pc, bt470bg/unknown/unknown), 1280x800 [SAR 1:1 DAR 8:5], 60 fps, 60 tbr, 60 tbn, 60 tbcStream#0:1: Audio: pcm_s32le ([1][0][0][0] / 0x0001), 48000 Hz, stereo, s32, 3072 kb/sStreammapping:Stream#0:0 -> #0:0 (mjpeg (native) -> vp9 (libvpx-vp9))Stream#0:1 -> #0:1 (pcm_s32le (native) -> opus (libopus))Press [q] to stop, [?]for help[swscaler @ 0x562739e33040] deprecated pixel format used, make sure you did set range correctly[libvpx-vp9 @ 0x562739e14040] v1.11.0[libopus @ 0x562739e165c0] No bit rate set. Defaulting to 96000 bps.Output#0, webm, to 'tilemap-average.webm':Metadata:encoder:Lavf58.76.100Stream#0:0: Video: vp9, yuv420p(tv, bt470bg/unknown/unknown, progressive), 1280x800 [SAR 1:1 DAR 8:5], q=2-31, 2000 kb/s, 60 fps, 1k tbnMetadata:encoder:Lavc58.134.100libvpx-vp9Sidedata:cpb:bitratemax/min/avg:0/0/2000000buffersize:0vbv_delay:N/AStream#0:1: Audio: opus, 48000 Hz, stereo, flt, 96 kb/sMetadata:encoder:Lavc58.134.100libopusframe=533fps=3.2q=0.0Lsize=2600kBtime=00:00:08.86bitrate=2401.8kbits/sspeed=0.054xvideo:2479kBaudio:114kBsubtitle:0kBotherstreams:0kBglobalheaders:0kBmuxingoverhead:0.289294%
And on this ancient i7-4790K, it runs dog slow. It processed the 8.86-second-long video at 5% speed, dragging it out to almost three minutes. But the payoff is worth it. Instead of 321MB, the video file is down to 2.6MB:
This release improves weight management. Inventories can now configure an option weight limit, and item stacking and item transfer strategies are weight-aware. The crafting demo and crafting mechanic in the inventory tour have been improved. Auto-crafting is limited to the crafting slide, so that items don’t automatically and unexpectedly get crafted while stepping through the …
Right after I got my Steam Deck, I wanted to know how hard it is to get a Godot game running on it. What’s the developer experience for someone who’s stepping through this for the first time? It was really easy to do, so I’m sharing this here, whether you’re following along or like to …
I had a setup with nested CanvasLayer nodes. Toggling the visibility of the root CanvasLayer doesn’t hide any nested CanvasLayer nodes. My solution was to listen to the visibility_changed signal, find any CanvasLayer child nodes, and apply the same visibility to them.
Just a couple of days ago, Godot 4.0 alpha 17 was announced. Today, Godot Engine 4.0 beta 1 was released. Be sure to check out the announcement. There are lots of improvements across the board; rendering, lighting, physics and navigation, animation, and scripting.
Making videos for the web with Godot 4’s Movie Writer
Normally I use OBS for screen recording, but there are cases where it makes sense to use Godot’s built-in movie writer that was recently announced.
For example, if you have a slow PC or really demanding game, OBS will skip frames. It makes sense since OBS is just recording what’s on the screen in real time, while Godot has to do most of the work running the game. Recording with Godot directly will slow down the action at recording time, and you cannot hear any audio while that happens. But the video playback will end up being buttery smooth at 60 fps and include audio. It will also result in huge files. 321MB for 8 seconds, at 1280x800px (also Steam Deck’s native 16:10 resolution). Still, that’s not a video file I want to embed into any webpage or wherever as-is.
The best tool for converting video from the command line or programmatically is still ffmpeg. I’m running this on Windows in WSL2, on Ubuntu 22.04.
The best option for .webm seems to be the VP9 codec. Their docs provide some examples. I’ve tested a few parameters. For two-pass targeting an average bitrate, the target bitrate is specified with the -b:v switch:
This is what the output looks like:
And on this ancient i7-4790K, it runs dog slow. It processed the 8.86-second-long video at 5% speed, dragging it out to almost three minutes. But the payoff is worth it. Instead of 321MB, the video file is down to 2.6MB:
Related Posts
Inventory System 2 Alpha 3 available
This release improves weight management. Inventories can now configure an option weight limit, and item stacking and item transfer strategies are weight-aware. The crafting demo and crafting mechanic in the inventory tour have been improved. Auto-crafting is limited to the crafting slide, so that items don’t automatically and unexpectedly get crafted while stepping through the …
Running Godot Games on Steam Deck
Right after I got my Steam Deck, I wanted to know how hard it is to get a Godot game running on it. What’s the developer experience for someone who’s stepping through this for the first time? It was really easy to do, so I’m sharing this here, whether you’re following along or like to …
Toggling Visibility of Nested CanvasLayers
I had a setup with nested CanvasLayer nodes. Toggling the visibility of the root CanvasLayer doesn’t hide any nested CanvasLayer nodes. My solution was to listen to the visibility_changed signal, find any CanvasLayer child nodes, and apply the same visibility to them.
Godot Engine 4 reaches beta
Just a couple of days ago, Godot 4.0 alpha 17 was announced. Today, Godot Engine 4.0 beta 1 was released. Be sure to check out the announcement. There are lots of improvements across the board; rendering, lighting, physics and navigation, animation, and scripting.