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:
Here’s a collection of tutorials that are helpful if you’re new to using Control and Container nodes to create UIs in Godot 4. The Game Dev Artisan video covers creating a simple UI with a reload indicator for a simple 2D tank game: Clear Code’s 11+ hour Ultimate Introduction to Godot 4 has a chapter …
Version 1.0 of the Inventory System is now available. It includes a few new additions since the closed beta: Lots of fixes found their way into this release as well:
It’s not Far Cry, nor Crysis, but it could be. The Realistic Jungle Demo demonstrates that Godot is capable of impressive visuals. If you want to run it yourself, download it from https://wrobot.itch.io/jungledemo. It was announced in this Reddit post. Update: The source code was released (with the commercial assets removed).
Creating network connections with Godot is simple — as long as you have the other party’s IP address, and there’s no NAT gateway involved. Unfortunately, that’s exactly the problem in most cases. You don’t know the other party’s IP, and these days, just about everyone is behind a combination wifi router/gateway/firewall with NAT. Conceptually, NAT …
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
Building UIs in Godot 4
Here’s a collection of tutorials that are helpful if you’re new to using Control and Container nodes to create UIs in Godot 4. The Game Dev Artisan video covers creating a simple UI with a reload indicator for a simple 2D tank game: Clear Code’s 11+ hour Ultimate Introduction to Godot 4 has a chapter …
Inventory System v1.0 available
Version 1.0 of the Inventory System is now available. It includes a few new additions since the closed beta: Lots of fixes found their way into this release as well:
The Godot Jungle Demo
It’s not Far Cry, nor Crysis, but it could be. The Realistic Jungle Demo demonstrates that Godot is capable of impressive visuals. If you want to run it yourself, download it from https://wrobot.itch.io/jungledemo. It was announced in this Reddit post. Update: The source code was released (with the commercial assets removed).
Creating a UDP peer-to-peer connection
Creating network connections with Godot is simple — as long as you have the other party’s IP address, and there’s no NAT gateway involved. Unfortunately, that’s exactly the problem in most cases. You don’t know the other party’s IP, and these days, just about everyone is behind a combination wifi router/gateway/firewall with NAT. Conceptually, NAT …