Page Not Found
We could not find what you were looking for.
Please contact the owner of the site that linked you to the original URL and let them know their link is broken.
diff --git a/404.html b/404.html index ade25c01..5ef5c4d6 100644 --- a/404.html +++ b/404.html @@ -2,7 +2,7 @@
- +We could not find what you were looking for.
Please contact the owner of the site that linked you to the original URL and let them know their link is broken.
Just your friendly neighborhood video embed site
\\n \\n\\n```\\n\\n< br />\\nThese interactive sites usually deploy a live script, like a Javascript framework. Examples are NodeJS, ExpressJS, Svelte, etc. These are used to parse video and thumbnails realtime so they can be embedded on Discord (or potentially other platforms).\\n\\n### Discord's End\\n\\nTraditionally, Discord's media embedder will impose it's own video embed size limit (50 MiB) when a user sends a direct video link as usual. But in this case Discord will embed the thumbnail first, not the video. You could say the link \\\"tricks\\\" Discord by showing a \\\"false face\\\" first.\\n\\n\\n\\n## Strengths & Limitations\\n\\nAfter a combination of countless hours of observation, rigorous testing throughout the period of a year, and conversations with the sites' creators, the current strengths & limitations of this exploit are enumerated below.\\n\\n#### Strengths\\n\\n- You can embed non-web compatible codecs such as [HEVC](https://wiki.x266.mov/docs/video/HEVC) in [MP4/MOV](https://wiki.x266.mov/docs/introduction/terminology#mp4--m4v), but the user must be using a compatible browser. [Thorium](https://thorium.rocks) or Safari version 13 or greater will work for HEVC playback.\\n- There is no maximum size. You could embed a video the size of a raw Bluray, although I do not condone this unless you have the necessary legal permissions to do so or you're uploading a Creative Commons licensed movie like Big Buck Bunny while adhering to the restrictions of the applicable Creative Commons license. This also means you can send high bitrate gaming clips to your friends without any restrictions, assuming you already have a place to upload them.\\n\\n#### Limitations\\n\\n- You can only use [hotlinks](https://simple.wikipedia.org/wiki/Hotlinking), which means direct linking to the video itself ending in the appropriate file extension such as `.mp4`. Cloud services like Google Drive or OneDrive will not work for storage.\\n- You cannot use Discord's CDN (cdn.discordapp.com) as the video source. I assume this is because of Discord's proxy blocking embeds over 50 MiB, but **only discord.nfp.is can do this**, as it **proxies cdn.discordapp.com** itself.\\n- You cannot embed videos in any resolutions higher than 3840 x 2160, Discord imposes a hard limit for this on all video after it was discovered that some videos could play normally but then be maliciously scaled to ridiculous resolutions during playback to crash Discord.\\n\\n\\n\\n## Differences between Sites\\n\\nAs mentioned before, there are five known sites at the time of writing. They all serve the same function, but one may interest you more than another due to slight differences in features & functionality.\\n\\nHere are the sites, each with one noteworthy special benefit:\\n\\n- https://stolen.shoes - Recognition, as it is the OG.\\n- https://discord.nfp.is - You can use Discord CDN as video source.\\n- https://embeds.video - Immediately input video source into the URL (`https://embeds.video/https://example.com/v/video.mp4`)\\n- https://x266.mov/discord-embed - Attractive domain, simple layout.\\n- https://autocompressor.net/av1 - Lots of info dump, pretty advanced features.\\n\\nThat concludes the technical overview! Next, let's cover the history of this exploit.\\n\\n## The Lore\\n\\n### Dwayne\\n\\nIn around April of 2022, a Reddit user going by the name of u/CreativeGamer03 [posted a video on r/discordapp](https://www.reddit.com/r/discordapp/comments/u96kky/someone_sent_this_in_the_memes_channel_and_bruh) of a link where a GIF of Dwayne \\\"The Rock\\\" Johnson plays caption with \\\"Is this a GIF or is it a video?\\\" When played, a low-quality music video of Rick Astley's \\\"Never Gonna Give You Up\\\" plays.\\n\\nThe link used is now unfortunately [removed](https://archuser.de/the-rock).\\n\\n### Discovery\\nOn 23rd June 2022, a Discord user *Clybius* on the AV1 Community server asked people for [VP9](https://wiki.x266.mov/docs/video/VP9) or [H.264](https://wiki.x266.mov/docs/video/AVC) videos that were over 100 MB in size. At the time the current 500 MB nitro tier did not exist. They then decided to use a 59 minute 1080p sample video of nature scenery from around the world with a thumbnail featuring a GIF of a waterfall to test the exploit. It worked.\\n\\nHe tried shortly afterward with [AV1](https://wiki.x266.mov/docs/video/AV1). Eureka, it also worked:\\n\\n![AV1](/img/clybius-av1.webp)\\n\\nClybius confirmed that this could be patched if discovered. He cites having had the idea from the Dwayne Johnson example above, but forgetting about it for a couple of months. So, it seems this entire concept stemmed from a silly rickroll.\\n\\n![Dwayne](/img/clybius-dwayne.webp)\\n\\n### The Experiments & Interactive Site\\n\\nAfter the discovery of AV1 embedding, experimentation brought about the discovery that *any* video codec will work as long as the user can decode/play the codec and the container/extension is an MP4, MOV, or WebM. These are all traditionally web-compatible containers. If you're interested in learning about containers, please see the [Containers](https://wiki.x266.mov/docs/introduction/terminology#container) section on the [Terminology](https://wiki.x266.mov/docs/introduction/terminology) page.\\n\\nThis applies to HEVC, ProRes, [xHE-AAC](https://wiki.x266.mov/docs/audio/AAC#xhe-aac), and other bizarre codecs that are rarely seen on the Web.\\n\\nWhile experimentating, Clybius converted one their idle domains `stolen.shoes` into an interactive embedder that provided a textbox for a video URL, a thumbnail URL, a width value, & a height value for the desired video. This would be the first website for Discord embedding.\\n\\n### Virality\\n\\nIt's not long before people outside of the AV1 Community discovered `stolen.shoes`, and its popularity increased rapidly. Its use usually involved the illicit distribution of full-length, unauthorized copies of movies; this sometimes happened very shortly after some movies were released. There were a couple notable instances of this happenening that caused quite the stir online each time.\\n\\n- The first instance featured the DreamWorks sequel of \\\"Puss in Boots (2011)\\\", \\\"Puss in Boots: The Last Wish (2022)\\\". A 1080p video sourced from a streaming site was the first wake up call that attracted attention to the existence of these embed sites. This example used `stolen.shoes`.\\n\\n![puss](/img/stolenshoes-puss.webp)\\n\\n- The second instance was when highly-anticipated animated film \\\"The Super Mario Bros. Movie (2023)\\\" produced by Illumination, Universal Studios, and Nintendo was spread around Discord. It was first spotted as a Cam (A camera recording by someone in theaters), then as it went out on streaming services a different link appeared but spread faster and with upgraded 1080p quality. Both used `stolen.shoes` as the embed site.\\n\\n![mario](/img/stolenshoes-mario.webp)\\n\\n- The third instance is very recent as of the day this was posted. A streaming-service sourced \\\"Five Nights at Freddy's (2023)\\\" was spread around since the movie released both in theaters and streaming service (Peacock) day one, and it gained steam extremely fast as most people had not seen it yet. Currently, this illegal novelty is gaining [hundreds of upvotes within the r/discordapp subreddit](https://www.reddit.com/r/discordapp/comments/17hx45y/is_discordnfp_an_ip_grabber/). The copy seems to be a compressed 720p encode. This example used `discord.nfp.is`.\\n\\n![fnaf](/img/discordnfpis-fnaf.webp)\\n\\nNote the ones listed here are the ones that I saw become extremely popular. There may be lesser known links that have been spread around privately or just did not cause enough noise for me to notice. Some less popular examples I've noticed, featuring more illicit copyrighted content distribution: \\n- Top Gun Maverick (2022)\\n- The SpongeBob trilogy (2005/2015/2020)\\n- Spider-Man: Across the Spider-Verse (2023)\\n\\n\\n## Closing\\n\\nThe ability to embed unusually large videos on Discord has enabled both positive and negative use cases. On the one hand, it allows high-quality content to be shared easily among friends. However, it has also facilitated mass copyright infringement by empowering virtually anyone with a Discord accound to freely spread pirated movies.\\n\\nWhile this is fascinating from a technical perspective, embedding techniques like these tread a fine ethical line. As with anything, it is important to be mindful of how our actions affect others, and I should remind everyone that content creators deserve to be compensated for their work. As users, we should support them by accessing their content via legitimate platforms.\\n\\nIt is hard to say how long this exploit will continue to be usable. Instead of enabling piracy, which may cause Discord to be more likely to patch this exploit if they see it as a serious threat, let's instead use these capabilities responsibly to share our own creations, gaming highlights, and other media which we can share legally. Given some thoughtfulness, perhaps we can find a fair balance between respecting copyright law and appeasing Discord's sensibilities while allowing some creative flexibility on the platform.\\n\\nThank you for reading this blog post, I hope you learned something!\"},{\"id\":\"av1-encoding-for-dummies\",\"metadata\":{\"permalink\":\"/blog/av1-encoding-for-dummies\",\"source\":\"@site/blog/2023-09-03-av1-for-dummies.mdx\",\"title\":\"AV1 Encoding for Dummies\",\"description\":\"This guide will show you how to encode in AV1 the *right* and *optimal* way.\",\"date\":\"2023-09-03T00:00:00.000Z\",\"tags\":[{\"label\":\"video\",\"permalink\":\"/blog/tags/video\"},{\"label\":\"compression\",\"permalink\":\"/blog/tags/compression\"}],\"readingTime\":15.865,\"hasTruncateMarker\":true,\"authors\":[{\"name\":\"Simulping\",\"title\":\"Maintainer / Encoder\",\"url\":\"https://github.com/Simulping\",\"image_url\":\"https://avatars.githubusercontent.com/u/12994794?v=4\",\"imageURL\":\"https://avatars.githubusercontent.com/u/12994794?v=4\"},{\"name\":\"Gianni Rosato\",\"title\":\"Maintainer\",\"url\":\"https://github.com/gianni-rosato\",\"image_url\":\"https://avatars.githubusercontent.com/u/35711760?v=4\",\"imageURL\":\"https://avatars.githubusercontent.com/u/35711760?v=4\"}],\"frontMatter\":{\"title\":\"AV1 Encoding for Dummies\",\"description\":\"This guide will show you how to encode in AV1 the *right* and *optimal* way.\",\"slug\":\"av1-encoding-for-dummies\",\"authors\":[{\"name\":\"Simulping\",\"title\":\"Maintainer / Encoder\",\"url\":\"https://github.com/Simulping\",\"image_url\":\"https://avatars.githubusercontent.com/u/12994794?v=4\",\"imageURL\":\"https://avatars.githubusercontent.com/u/12994794?v=4\"},{\"name\":\"Gianni Rosato\",\"title\":\"Maintainer\",\"url\":\"https://github.com/gianni-rosato\",\"image_url\":\"https://avatars.githubusercontent.com/u/35711760?v=4\",\"imageURL\":\"https://avatars.githubusercontent.com/u/35711760?v=4\"}],\"tags\":[\"video\",\"compression\"],\"image\":\"/img/compare-guide.webp\",\"hide_table_of_contents\":false},\"unlisted\":false,\"prevItem\":{\"title\":\"Embedding the Un-Embeddable\",\"permalink\":\"/blog/embedding-the-un-embeddable\"},\"nextItem\":{\"title\":\"Reducing Image Load Online\",\"permalink\":\"/blog/site-optimization\"}},\"content\":\"This guide will show you how to encode in AV1 the *right* and *optimal* way. Yes, you using standalone ``libaom``, ``libsvtav1``, and ``librav1e`` from FFmpeg or even piping ``yuv4mpeg`` into **mainline** aomenc are all unoptimal.\\n\\n\x3c!--truncate--\x3e\\n\\n\\n![Compare](/img/compare-guide.webp)\\n\\nIn this guide, we'll be installing Av1an for chunked encoding and infinite threading, because the current state of AV1 encoders, except for [SVT-AV1](https://wiki.x266.mov/docs/encoders/SVT-AV1), unfortunately lacks threading and will only use very low amount of cores, which hampers speeds. The only caveat to this approach is **RAM consumption**, encoding 2160p (4K) with [aomenc](https://wiki.x266.mov/docs/encoders/aomenc) with 4 workers could take upwards of **16GB** of RAM! So do keep this in mind.\\n\\n## Installing the Tools\\n\\nGiven all of the different operating systems that people use on a day to day basis and the various different encoding workflows that exist, there are a number of ways to do this.\\n\\n**Jump to**: [Windows](#microsoft-windows) | [macOS](#macos) | [Linux](#linux)\\n\\n## Microsoft Windows\\n\\n### The GUI Way\\n1. Install [NMKODER](https://github.com/n00mkrad/nmkoder) which is a GUI front-end to av1an with all dependencies installed.\\n2. You're done, you can skip to the encoding part\\n\\n:::danger Almost abandonware\\nSince Nmkoder already ships everything by default and its last release was 29th March 2022. You need to manually update all encoders and tools to get better encoding speeds. Missing out on updates will result in your encodes being sub-optimal.\\n:::\\n\\n### The WSL2 Way\\n\\n*(Recommended)*\\n\\nIf you're not already familiar with WSL2, the The Windows Subsystem for Linux (WSL) is a feature of the Windows operating system that allows you to run a Linux file system, along with Linux command-line tools and GUI apps, directly on Windows. This lets Linux distributions run on bare metal without managing any virtual machines, so encoding performance is very good.\\n\\nThe easiest way to encode with WSL2 is to use [rAV1ator CLI](https://wiki.x266.mov/docs/utilities/rav1ator-cli), an interactive TUI for [Av1an](https://wiki.x266.mov/docs/utilities/av1an). An ArchWSL2 installation tutorial is provided [here](https://wiki.x266.mov/docs/utilities/rav1ator-cli#windows).\\n\\n### The Automated Way\\n\\nThere is now a batch script for automating the install process, which can be found [here](https://github.com/Hishiro64/av1an-win-script). The instructions are in the README file.\\n\\n:::caution\\nThe script will download outdated version encoders and tools such as `aom-av1-psy` and MKVToolNix v76.0, if you are fine with these you can proceed.\\n:::\\n\\n### The Manual Way\\n\\n1. Install **Python 3.10.x, this will change so consult from the** [Vapoursynth website](http://www.vapoursynth.com/doc/installation.html) **if you're reading this from the future** from [here](https://www.python.org/downloads/windows/) and select \\\"Windows Installer 64-bit\\\". Upon installation check the tick for adding Python to PATH like so\\n![Python PATH](/img/python-path.webp))\\n\\n2. Download and install Vapoursynth from [here](https://github.com/vapoursynth/vapoursynth/releases) and select \\\"VapourSynth64-RXX.exe\\\"\\n3. Open the terminal and type ``vsrepo.py install lsmas ffms2`` to install some plugins for Av1an to work.\\n4. Download MKVToolNix from [here](https://mkvtoolnix.download/downloads.html#windows), select \\\"mkvtoolnix-64bit-XX.X.X-setup.exe\\\", and install **(Also available on winget!)**\\n5. Download Av1an from [here](https://github.com/master-of-zen/Av1an/releases) (SELECT LATEST AND CLICK THE \\\"ASSETS\\\" DROPDOWN)\\n6. Download **shared libraries** FFmpeg from [gyan.dev](https://www.gyan.dev/ffmpeg/builds)\\n7. Download a pre-built fork of Aomenc ([aom-av1-lavish](https://github.com/Clybius/aom-av1-lavish/tree/Endless_Merging)) which has neat stuff such as sane defaults, new tunes, optimizations, etc. This can be downloaded for Windows [here](https://autumn.revolt.chat/attachments/download/-2EiZW1edcT9anApFZ1PJBEber-pJ6z02NiQBjbr28) *(Current as of Sept 6, 2023)*\\n:::info\\nIf you opt to compile aomenc yourself, you can view the instructions on how to do that [here](https://wiki.x266.mov/docs/encoders/aomenc/#installation).\\n:::\\n8. Move Av1an, FFmpeg **(Including the FFmpeg DLLs)**, and aomenc to somewhere preferable, eg ``C:\\\\Encoding``.\\n9. Add the folder **AND MKVTOOLNIX INSTALLATION FOLDER** to the [Windows PATH environment](https://www.maketecheasier.com/what-is-the-windows-path/).\\n\\n\\n## macOS\\n\\nmacOS is very similar to Linux, although there aren't any GUI tools for AV1 encoding that I can comfortably recommend.\\n\\n**Homebrew + Macports for Av1an + rav1e:**\\n*Note that some commands may have to be run with `sudo`, which I won't explicitly include for security reasons.*\\n\\nInstalling the Homebrew package manager is a well documented process at this point:\\n```bash\\n/bin/bash -c \\\"$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)\\\"\\n```\\n\\nAs is installing MacPorts. Install the relevent `.pkg` for your macOS version from the MacPorts Project website:\\n[www.macports.org/install.php](https://www.macports.org/install.php)\\n\\nNow, you can run the following commands:\\n```bash\\nbrew update && brew upgrade\\nbrew install rav1e aom mkvtoolnix ffmpeg\\n# Usually you must run MacPorts commands for package installations as root\\nport upgrade outdated\\nport install av1an\\n```\\n\\nThis is the easiest way to get everything set up & working to produce AV1 video with `rav1e` or mainline `aomenc` & Av1an. You can check that things are installed by running the following commands & parsing their output:\\n```bash\\n% av1an --version\\nav1an 0.4.1-unstable (rev e10880d) (Release)\\n\\n* Compiler\\n rustc 1.70.0 (LLVM 16.0)\\n\\n* Target Triple\\n aarch64-apple-darwin\\n\\n* Date Info\\n Commit Date: 2023-06-25\\n\\n* VapourSynth Plugins\\n systems.innocent.lsmas : Not found\\n com.vapoursynth.ffms2 : Not found\\n```\\n```bash\\n% rav1e --version | grep \\\"release\\\" -C 1 \\nrav1e 0.6.6 () (release)\\nrustc 1.69.0 (84c898d65 2023-04-16) (built from a source tarball) aarch64-apple-darwin\\n```\\n```bash\\n% aomenc --help | grep \\\"AOMedia\\\" -C 3\\n\\nIncluded encoders:\\n\\n av1 - AOMedia Project AV1 Encoder 3.6.1 (default)\\n\\n Use --codec to switch to a non-default encoder.\\n```\\n\\nNotice `systems.innocent.lsmas : Not found` in the Av1an output. This means you won't be able to use the lsmash chunking method through vapoursynth & may instead have to rely on hybrid chunking, through `-m hybrid`. This is slower & takes up disk space while encoding, but still works. A sample Av1an command with this basic installation may look like this:\\n\\n```bash\\nav1an -i \\\"input\\\" -y --resume --verbose --split-method av-scenechange -m hybrid -c mkvmerge -e rav1e --force -v \\\" --tiles 8 -s 4 --quantizer 80 --no-scene-detection\\\" --photon-noise 7 --chroma-noise --pix-format yuv420p10le -w 8 -o \\\"output.mkv\\\"\\n```\\n\\n**Building From Source**\\n\\nIf you want lsmash support, aom-av1-lavish instead of mainline, or anything else that isn't covered by the more basic installation, you'll have to compile from source. Things are very similar to Linux, with a few oddities:\\n\\n- macOS sometimes doesn't have a `/usr/local/bin` by default. You can fix this by doing `mkdir /usr/local/bin`.\\n- Homebrew installs *everything* in its own directory structure. If you're building things from source that rely on libraries from vapoursynth, zimg, lsmash, etc, make sure to copy them from `/opt/homebrew/lib` to `/usr/local/lib`. Finding them is a matter of `ls | grep \\\"keyword\\\"` & copying what looks reasonable to be associated with the tool you're using.\\n- Building most things from source will have instructions for \\\\*nix which work for both macOS & Linux. Even if it says Linux, there's a good chance it'll work on macOS as well, & it is always worth trying Linux build instructions on Mac. I won't be going through building every encoding tool & dependency from source, as it is generally much more intuitive than Windows, but building Av1an is worth detailing here just as an example.\\n```bash\\nbrew install git rust nasm\\ngit clone https://github.com/master-of-zen/Av1an\\ncd Av1an\\nRUSTFLAGS=\\\"-C target-cpu=native\\\" cargo build --release\\ncd .. && cd target/release\\ncp av1an /usr/local/bin\\n```\\n\\n**More Difficult: Building aom-av1-lavish from Source**\\n\\nIf you want to make the most out of your hardware & eke out every last drop of quality, it may be worth building aom-av1-lavish from source. The first step is to clone it from the Endless Merging branch:\\n```bash\\ngit clone https://github.com/Clybius/aom-av1-lavish -b Endless_Merging\\ncd aom-av1-lavish\\n```\\nNow, you need to make some manual changes to the source code until Clybius merges [this commit](https://github.com/Clybius/aom-av1-lavish/pull/1/files).\\n- Add the line `#include \\\"aq_variance.h\\\"` at line 19 in `av1/encoder/encodeframe_utils.c`\\n- Comment out line 2546 in `av1/encoder/speed_features.c`. This line is `const int qindex_thresh_cdef_sf_s1_s3_l2[2] = { 92, 48 };` & becomes `// const int qindex_thresh_cdef_sf_s1_s3_l2[2] = { 92, 48 };`.\\n\\nNow you can continue to build according to the Linux instructions below. Obviously you'll need cmake, which you can install with homebrew along with any other tools you may need. While still in the `aom-av1-lavish` directory:\\n```bash\\nmkdir -p aom_build && cd aom_build\\ncmake .. -DBUILD_SHARED_LIBS=0 -DENABLE_DOCS=0 -DCONFIG_TUNE_BUTTERAUGLI=0 -DCONFIG_TUNE_VMAF=0 -DCONFIG_AV1_DECODER=0 -DENABLE_TESTS=0 -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_FLAGS=\\\"-flto -O3 -march=native\\\" -DCMAKE_C_FLAGS=\\\"-flto -O3 -march=native -pipe -fno-plt\\\" -DCMAKE_LD_FLAGS=\\\"-flto -O3 -march=native\\\"\\nmake -j$(nproc)\\n# This may need to be run as root:\\nmake install\\n```\\n\\nNow you can run `aomenc --help | grep \\\"AOMedia\\\" -C 3` to see if lavish installed. If you're getting the same output as above, you may need to copy the `aomenc` executable to `/opt/local/bin`, `/usr/local/bin`, & `/opt/homebrew/bin` if you already installed mainline aomenc. Running the version info command again, the correct output should look something like this:\\n```bash\\n% aomenc --help | grep AOMedia -C 3\\n\\nIncluded encoders:\\n\\n av1 - AOMedia Project AV1 Encoder Psy v3.6.0 (default)\\n\\n Use --codec to switch to a non-default encoder.\\n```\\n\\nNotice how it says `AOMedia Project AV1 Encoder Psy` instead of `AOMedia Project AV1 Encoder`. You should be all set after this to start using aom-av1-lavish & following the current parameter meta as outlined below.\\n\\n## Linux\\n\\n:::info\\nYet again, try using Arch. It's way easier.\\n:::\\n\\n### The GUI Way\\n\\n- Install [Aviator](https://github.com/gianni-rosato/aviator) ([SVT-AV1](https://wiki.x266.mov/docs/encoders/SVT-AV1) + [FFmpeg](https://wiki.x266.mov/docs/utilities/FFmpeg)) or [rAV1ator](https://giannirosato.com/blog/post/aviator-1/) basically same thing but [Av1an](https://wiki.x266.mov/docs/utilities/av1an.mdx) + [rav1e](https://wiki.x266.mov/docs/encoders/rav1e). Both are only available as [Flatpaks](https://beta.flathub.org/apps/net.natesales.Aviator). Keep in mind Aviator ships with **SVT-AV1** and rAV1ator with **rav1e** instead of aomenc/AOM-AV1, which I will not be covering here.\\n\\n### The TUI Way\\n\\n*(Recommended)*\\n\\n- Install [rav1ator-cli](https://wiki.x266.mov/docs/utilities/rav1ator-cli), a TUI for using Av1an meant to be easy to use. Much more flexible than the GUI options & can work with a number of encoders. See [this page](https://wiki.x266.mov/docs/utilities/rav1ator-cli/#installation) for more info. Can be easily used on any distro.\\n\\n### The Compiling Route\\n\\n#### Ubuntu\\n\\nThe guide below is targeted towards 22.04, packages and other things may be different on other versions. First Install Rust via `rustup` first, as apt version of Rust is severely outdated, then you can continue.\\n\\nInstall dependencies:\\n```bash\\nsudo apt install wget python unzip unrar build-essential meson autoconf automake libtool git nasm yasm python3-dev python3-pip cython3 libass-dev libqt5websockets5-dev libfftw3-dev libtesseract-dev ffmpeg libavcodec-dev libavformat-dev libswscale-dev libavutil-dev libswresample-dev libmediainfo-dev mkvtoolnix mediainfo perl nasm yasm git cmake libavutil-dev libavcodec-dev libavformat-dev libavdevice-dev libavfilter-dev libswscale-dev libswresample-dev libpostproc-dev llvm libclang-dev libssl-dev\\n```\\n\\nInstall l-smash:\\n```bash\\ngit clone https://github.com/l-smash/l-smash.git\\ncd l-smash\\n./configure --enable-shared --extra-cflags=\\\"-march=native\\\"\\nmake -j$(nproc)\\nsudo make install\\n```\\n\\nInstall zimg:\\n```bash\\ngit clone --recursive https://github.com/sekrit-twc/zimg.git\\ncd zimg\\n./autogen.sh\\n./configure\\nmake -j$(nproc)\\nsudo make install\\n```\\n\\nInstall ImageMagick:\\n```bash\\ngit clone https://github.com/ImageMagick/ImageMagick\\ncd ImageMagick\\n./configure\\nmake -j$(nproc)\\nsudo make install\\n```\\n\\nInstall Vapoursynth R63:\\n```bash\\nwget https://github.com/vapoursynth/vapoursynth/archive/refs/tags/R63.zip\\nunzip R63.zip\\ncd vapoursynth-R63\\n./autogen.sh\\n./configure CFLAGS=\\\"-march=native\\\" CXXFLAGS=\\\"-march=native\\\" --libdir=/usr/lib\\nmake -j$(nproc)\\nsudo make install\\nsudo mkdir /usr/lib/vapoursynth\\nsudo ldconfig\\n```\\nThe plugin directory will be located in `/usr/lib/vapoursynth`.\\n\\n\\nInstall L-SMASH-Works Vapoursynth Plugin:\\n```bash\\ngit clone https://github.com/AkarinVS/L-SMASH-Works -b ffmpeg-4.5\\ncd L-SMASH-Works/VapourSynth && mkdir build && cd build\\nmeson .. --optimization=3 --default-library=static -Db_lto=true -Dc_args=\\\"-march=native\\\" -Dcpp_args=\\\"-march=native\\\"\\nninja -j$(nproc)\\nsudo cp libvslsmashsource.so /usr/lib/vapoursynth/\\n```\\n\\n:::danger\\nL-SMASH-Works doesn't work on **aarch64**, it is recommended to use other plugins instead.\\n:::\\n\\nInstall FFMS2 Vapoursynth Plugin:\\n```bash\\ngit clone https://github.com/FFMS/ffms2\\ncd ffms2\\n./autogen.sh\\n./configure CFLAGS=\\\"-O3 -march=native\\\" CXXFLAGS=\\\"-O3 -march=native\\\"\\nmake -j$(nproc)\\nsudo cp src/core/.libs/libffms2.so src/core/.libs/libffms2.so.5 src/core/.libs/libffms2.so.5.0.0 /usr/lib/vapoursynth\\n```\\n\\nInstall Av1an:\\n```bash\\ngit clone https://github.com/master-of-zen/Av1an\\ncd Av1an\\nRUSTFLAGS=\\\"-C target-cpu=native\\\" cargo build --release\\nsudo cp target/release/av1an /usr/local/bin\\n```\\n\\nWhen there's no errors, proceed to compiling `aom-av1-lavish`.\\n\\n### Arch\\n\\nInstall dependencies:\\n```bash\\nsudo pacman -S vapoursynth ffmpeg av1an mkvtoolnix-gui git perl cmake ninja meson nasm vapoursynth-plugin-lsmashsource ffms2\\n```\\n\\nyou're done, proceed.\\n\\n#### Compiling aom-av1-lavish\\n``` bash\\ngit clone https://github.com/Clybius/aom-av1-lavish -b Endless_Merging\\ncd aom-av1-lavish && mkdir -p aom_build && cd aom_build\\ncmake .. -DBUILD_SHARED_LIBS=0 -DENABLE_DOCS=0 -DCONFIG_TUNE_BUTTERAUGLI=0 -DCONFIG_TUNE_VMAF=0 -DCONFIG_AV1_DECODER=0 -DENABLE_TESTS=0 -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_FLAGS=\\\"-flto -O3 -march=native\\\" -DCMAKE_C_FLAGS=\\\"-flto -O3 -march=native -pipe -fno-plt\\\"\\nmake -j$(nproc)\\nsudo make install\\n```\\n\\n## Encoding\\n\\nThe moment you've all been waiting for, let's just get into it. Here's an example *recommended* parameter as of now (09/03/23) [MM/DD/YY]:\\n```bash\\nav1an -x 300 -i input.mkv -w 4 -e aom -c mkvmerge --resume -m lsmash --photon-noise=10 --set-thread-affinity=2 --verbose -a \\\" -an \\\" -f \\\" -an \\\" -v \\\" --bit-depth=10 --cpu-used=4 --end-usage=q --cq-level=24 --threads=2 --tile-columns=0 --tile-rows=0 --lag-in-frames=64 --tune-content=psy --tune=ssim --enable-keyframe-filtering=1 --disable-kf --kf-max-dist=9999 --enable-qm=1 --deltaq-mode=0 --aq-mode=0 --quant-b-adapt=1 --enable-fwd-kf=0 --arnr-strength=1 --sb-size=dynamic --enable-dnl-denoising=0 \\\" -o \\\"output.mkv\\\"\\n```\\n\\n:::info Parameter Meta\\nIt is strongly recommended to join the [AV1 Discord server](https://discord.gg/vpREHAvYvh) to get the latest updates on what to use and which to set, as it's the only easily reachable place for everything AV1 & encoding tips in general.\\n:::\\nNow let's dissect it one-by-one\\n\\n**Av1an parameters:**\\n\\n- ``-i`` Input.\\n\\n- ``-x 300`` Sets scene split length to 300 frames, you can increase it for more quality at the tradeoff of video seekability.\\n\\n- ``-w 4`` Specifies the amount of \\\"workers\\\" or amount of encoders working on the video.\\n\\n- ``--verbose`` Sets logging to verbose.\\n\\n- ``--resume`` Resumes the encode even when you haven't encoded yet. I strongly recommend leaving this if you resume a lot since you can accidentally delete your whole progress (There's no delete confirmation feature.. yet) if you \\\"resumed\\\" without the parameter in place.\\n\\n- ``-e aom`` Specifies we're using aomenc encoder which should be the default option.\\n\\n- ``-c mkvmerge`` Specifies we're using mkvmerge (MKVToolNix) to concatenate the parts when done, you can specify with ffmpeg if you want to but this is the best method.\\n\\n- ``-m lsmash`` Specifies we're using l-smash (Vapoursynth plugin) to split the videos, this is also the best method because ffms2 causes video lag (Tested a year ago, might change now) and other methods just suck (Slow and not worth it, learned the hard way). You can attempt to use ffms2 when inputting VC-1 videos as it is not possible with l-smash (Or convert it to lossless with x264 qp 0).\\n\\n- ``-f \\\" -an \\\"`` ``-f`` Stands for ffmpeg parameters, ``-an`` is to remove all audio since its better to encode and merge it separately. To crop use ``-f \\\" -an -vf crop=1920:800 \\\"`` for example to crop the video to 1920x800.\\n\\n- ``-v \\\" \\\"`` Is where you put the encoder's parameters in.\\n\\n- ``-a \\\" -an \\\"`` FFmpeg audio encoding options, we're removing it cause we can always add it later. But if you want to, you can also encode directly. Here's an example for encoding to Opus using libopus assuming stereo: `-a \\\" -c:a libopus -b:a 128k \\\"`.\\n\\n- ``--photon-noise=10`` AV1 grain synthesis, which is a technique where the encoder puts fake grain in so it looks more natural and potentially hiding video artifacts (cause grain is hard to encode and explodes bitrate usage because of their randomness), 5-8 for almost none to little grain, 10-14 for medium, 15+ heavy, 20+ extremely heavy, 30+ for extremely grainy 90s live action films.\\n\\n- ``--set-thread-affinity=2`` Pins the thread to the encoder, aligns with ``--threads=2`` in the encoder parameter so set them accordingly.\\n\\n\\n**aomenc parameters:**\\n- ``--bit-depth=10`` We're using 10bit because it makes the video smaller and reduces [banding](https://developer.mozilla.org/en-US/docs/Web/Media/Formats/Video_codecs#contouring).\\n\\n- ``--cpu-used=4`` This is the preset which ranges from 0-9, you can go to 3 if you want more efficiency, 2 if you have a lot of time, 4 is the sweet spot, and 6 if you want speed. Don't go above 6 (Worst efficiency) or even 0 (It would take WEEKS to finish).\\n\\n- ``--end-usage=q --cq-level=24`` This specifies that we are going to use a knockoff version of CRF level similar to x264/x265 encoders, in this case CRF 24.\\n\\n- `--threads=2` Sets the amount of threads the encoder can use, aligns with `--set-thread-affinity` in Av1an.\\n\\n- ``--tile-columns=0 --tile-rows=0`` This is the tiles options, where the encoder splits the videos into tiles to encode faster, see the image below (Yellow lines):\\n \\n\\n:::note Tile usage\\nDo NOT use tiles for 1080p and below, use 1 ``tile-columns`` at 1440p (2K), 2 ``tile-columns`` and 1 ``tile-rows`` for 2160p (4K)\\n:::\\n\\n- ``--lag-in-frames=64`` Similar to x264/x265 `rc-lookahead`. Sets a number of frames to look ahead for frametype and ratecontrol, allowing for better compression decision making. Setting to a value greater than 64 is generally not considered useful.\\n \\n- ``--aq-mode`` adaptive quantization mode, 0 is better most of the time\\n\\n- ``--tune-content=psy --tune=ssim`` As the name suggests they are tunes that affect the video output, for the better, and for the worst\\n\\n:::info Tunes to use\\nSet ``tune-content`` to ``animation`` if you're encoding above ``cq-level=30`` A.K.A lower quality, despite it's name\\nSet ``tune-content`` to ``psy`` for everything else, **do not use if you encode above ``cq-level=30``**\\nFor ``tune``, this is a bit tricky. For now, the meta seems to be ``ssim``, but back then it was ``lavish`` which is considered THE best tune because it's based on [butteraugli](https://github.com/google/butteraugli). Now it's fallen behind because its more blurry than ``ssim``, and before that it was ``butteraugli``, and then ``ipq_vmaf_psy``, and finally just ``ipq``. \\nIf you use any of the VMAF tunes, **you need to specify ``--vmaf-model-path=`` to where you put it**.\\n:::\\n\\n- ``--enable-keyframe-filtering=1`` We're setting it to 1 because of compatibility reasons, 2 is more efficient but there are seeking issues and FFmpeg for some reason can't input it.\\n\\n- ``--sb-size=dynamic`` Allows the encoder to use 128x128 block partitioning besides 64x64 which gives an efficiency boost, ignore it.\\n\\n- ``--deltaq-mode`` set to 0 because its just better.\\n\\n- ``--arnr-strength=1`` Controls how strong the filtering will be, 1 is good for 3D Pixar CGI-like and 2D animation, use 4 if you're doing live action content. Using maximum at higher bitrates would just result in a blurry mess.\\n\\n- ``--disable-kf --enable-fwd-kf=0`` We're disabling keyframes cause **Av1an already did scene detection, so we wont have to.**. And it speeds things up.\\n\\n- ``--kf-max-dist=9999`` Maximum keyframe interval, we're setting it at the highest possible value since av1an's scene detection keyframe interval is already 240 by default\\n\\n- ``--enable-chroma-deltaq=1 --enable-qm=1 --quant-b-adapt=1`` Parameters that give you free efficiency boost.\\n\\n- ``--enable-dnl-denoising=0`` Disables the encoder's built-in denoising technique when grain synthesis is enabled, you can optionally set it to 1 when you have a pretty noisy video since it works quite well.\\n\\n\\n:::info Concatenation Error on Linux\\nRun ``ulimit -n 200000``, resume, and it should concatenate just fine. If it still errors, head to the encode directory > encode, and run ``mkvmerge @../options.json``\\n:::\\n\\n\\n## Merging Everything\\n\\nOnce you're done just encode your audio using ffmpeg (or just passthrough it), subtitles should be carried along with your video output, and merge them in MKVToolNix! Don't want Matroska files? That's fine, you can use FFmpeg or MP4Box to output into `mp4`, just keep in mind that PGS/SUP/VOBSUB subtitles are not supported and Opus audio support is still experimental.\\n\\n\\n## Tips & Tricks\\n\\n- `--denoise-noise-level=10` Alternative to `photon-noise`, slower than photon-noise and is the OG grain synthesis method, performs okay and just serves as an alternative. Don't attempt to use it at high values (>12) since it creates noticeable grain patterns.\\n\\n- `--arnr-maxframes` to set max reference frames that will be used to filter the encode, higher values would make the video blurrier at high fidelity but look better at lower bitrates.\\n\\n- `--butteraugli-resize-factor=2` if you use any of the butteraugli-based tunes (lavish, butteraugli) to speed it up without much losses and `--butteraugli-intensity-target=250` to match the content light level.\\n\\n\\n## Final Thoughts\\n\\nEncoding has always been about experimentation for the best, there is really no \\\"One size fits all\\\" for encoding content, as they differ from scene complexity, how it's captured (2D/Real life), film grain, dark scenes, etc. So experiment away for your specific type of content!\\n\\n> **Guide originally hosted on https://rentry.co/AV1, rewrite and migration by Simulping.**\"},{\"id\":\"site-optimization\",\"metadata\":{\"permalink\":\"/blog/site-optimization\",\"source\":\"@site/blog/2023-07-21-site-optimization.mdx\",\"title\":\"Reducing Image Load Online\",\"description\":\"A big part of understanding any multimedia codec technology is knowing the application for such technology. For images, a big use case is web delivery.\",\"date\":\"2023-07-21T00:00:00.000Z\",\"tags\":[{\"label\":\"image\",\"permalink\":\"/blog/tags/image\"},{\"label\":\"web\",\"permalink\":\"/blog/tags/web\"},{\"label\":\"compression\",\"permalink\":\"/blog/tags/compression\"}],\"readingTime\":9.25,\"hasTruncateMarker\":true,\"authors\":[{\"name\":\"Gianni Rosato\",\"title\":\"Maintainer\",\"url\":\"https://github.com/gianni-rosato\",\"image_url\":\"https://avatars.githubusercontent.com/u/35711760?v=4\",\"imageURL\":\"https://avatars.githubusercontent.com/u/35711760?v=4\"}],\"frontMatter\":{\"title\":\"Reducing Image Load Online\",\"description\":\"A big part of understanding any multimedia codec technology is knowing the application for such technology. For images, a big use case is web delivery.\",\"slug\":\"site-optimization\",\"authors\":[{\"name\":\"Gianni Rosato\",\"title\":\"Maintainer\",\"url\":\"https://github.com/gianni-rosato\",\"image_url\":\"https://avatars.githubusercontent.com/u/35711760?v=4\",\"imageURL\":\"https://avatars.githubusercontent.com/u/35711760?v=4\"}],\"tags\":[\"image\",\"web\",\"compression\"],\"image\":\"/img/_DSC8466-smaller.jpg\",\"hide_table_of_contents\":false},\"unlisted\":false,\"prevItem\":{\"title\":\"AV1 Encoding for Dummies\",\"permalink\":\"/blog/av1-encoding-for-dummies\"}},\"content\":\"A big part of understanding any multimedia codec technology is knowing the application for such technology. For images, a big use case is web delivery. Compared to other multimedia, images are incredibly popular on the Web & knowing how to serve them properly can be a massive boon to your website's traffic as well as less of a headache for users on slower connections or who are under bandwidth constraints. The most disappointing part is that images are often poorly done on the web; all too frequently will you run into a site serving massive photographic PNGs for no reason, or photography sites serving photographs fresh out of the editing software with no thought put into their final delivery. A little effort, patience, & knowledge will go a long way toward improving the user experience for individuals using your site, & this article will illustrate some of the basics.\\n\\n\x3c!--truncate--\x3e\\n\\n:::caution\\nThese instructions are for *photographic* images; other kinds of images, like non-photographic, artwork, pixel art, etc. should likely be handled differently.\\n:::\\n\\n:::danger\\nMany images won't load properly unless your browser supports JXL, AVIF, & proper ICCv2 color management. This is for demonstration purposes only & shouldn't represent an actual common website experience. If you're curious anyway, the following browsers can display the contents of this page perfectly:\\n- [Thorium](https://thorium.rocks/) | *Linux, [macOS](https://github.com/Alex313031/Thorium-Special/releases), [Windows](https://github.com/Alex313031/thorium/releases/), [Android](https://github.com/Alex313031/Thorium-Special/releases)*\\n- [Waterfox](https://www.waterfox.net/) | *[Linux](https://flathub.org/apps/net.waterfox.waterfox), [macOS](https://www.waterfox.net/download/), [Windows](https://www.waterfox.net/download/)*\\n- [Mercury](https://thorium.rocks/mercury) | *[Linux](https://github.com/Alex313031/Mercury/releases), [Windows](https://github.com/Alex313031/Mercury/releases)*\\n:::\\n\\n## Fire & Forget\\n\\nFirst, we'll illustrate what *not* to do, which is fortunately not incredibly difficult to avoid. Taking an image straight out of your editing software at a massive size will often bloat the size & resolution to something that isn't generally usable for a website regardless of the codec you're using & its quality per bit. It can be argued there are specific use cases that demand incredible resolution & fidelity coexist on the Web, but we won't be covering those here. Here's an example of a bloated image:\\n\\n*exported straight from Darktable at JPEG q90, with no scaling*\\n\\n![bloated_jpeg](/img/_DSC8466.jpg)\\n\\n**2.2 MB**\\n\\n## Massive Improvement\\n\\nThe easiest way to have a large improvement without doing much work is to simply resize the image before serving it. Even if you exported a lossy JPEG, resizing should remove a lot of artifacts. The way to perceive a worst-case for an image's size on a site is to inspect the image element's width & height, which should give us an estimate of how large we should make our image. Any larger than this value is unreasonable since we're overfilling the element's size for no reason & the image is being scaled down anyway.\\n\\n![box-size-mac](/img/box-size-mac.avif)\\n*Inspect Element in Firefox. The Mac used to take this screenshot has a relatively high display resolution of 2560x1664. Because Macs scale things differently, we're probably going to want to double the horizontal resolution here.*\\n\\nThe width is the most important value here, so our new image is going to be exported with a width of 1699 pixels. This new image, encoded at JPEG q90 with `cjpegli`, looks like this:\\n\\n![smaller_jpeg](/img/_DSC8466-smaller.jpg)\\n\\nObviously, there's lost fidelity compared to the original, but considering this is *so much smaller*, it is worth the trade-off for many. It is also worth noting we are using an improved jpeg encoder in the form of `cjpegli`, although that is secondary to the resize. If it doesn't look as good as you want it to, you can always scale the resolution up a bit, though currently, it looks plenty passable for its size.\\n\\n2.2 MB -> **233 kB**\\n\\n### Lazy Loading\\n\\nA bonus tip is to add the `loading=\\\"lazy\\\"` attribute to your picture tag to allow the image to load only when scrolled to by a user. This doesn't save bandwidth, but it improves the user experience by loading images further down the page only when necessary. An example may look like this:\\n\\n```html\\n \\n```\\n\\n## New Codecs\\n\\nIf you desire further improvement, it may be time to consider using a newer codec like [AVIF](https://wiki.x266.mov/docs/images/AVIF) or [JPEG-XL](https://wiki.x266.mov/docs/images/JXL). These options will compress far more effectively than JPEG, with the only trade-off being browser support. We're not going to consider [WebP](/docs/images/WebP) or [HEIC](/docs/images/HEIC), since WebP is not competitive enough with JPEG for photographic imagery (often being worse) & HEIC has been superseded by AVIF - which sees greater support anyhow - & is not royalty free, effectively preventing widespread Web adoption forever. Again, we're just considering *lossy* compression for *photographic* images; it is a different story with WebP elsewhere, as it performs well on non-photographic content & is almost always better than PNG for 8-bit lossless compression. So, we are left with JXL & AVIF for now.\\n\\n### Fallbacks\\n\\nAVIF sees widespread support, but JPEG-XL isn't quite there yet with Web support as Google continues to push AVIF (it is debatable if it ever will be outside the Apple ecosystem). Even with AVIF, adoption isn't remotely close to JPEG, so it is worth providing a fallback. This can look like the following example:\\n\\n```html\\n \\n```\\n\\nHere is a JXL falling back to an AVIF falling back to a WebP falling back to a JPEG. Pretty intense to have this many fallbacks unless you're really after the ultimate compression ratio, but it is certainly an option. AVIF & JPEG alone will probably be enough for most.\\n\\n### Compression Efficacy\\n\\nLet's look at how our image examples compare to the original with our new codec selection. We'll be aiming for high visual fidelity, so around the same quality as our initial JPEG encoded with `cjpegli` (which scores ~`83.01` with the [SSIMULACRA2](/docs/metrics/SSIMULACRA2) visual fidelity metric).\\n\\n![smaller_jxl](/img/_DSC8466-smaller.jxl)\\n\\n**137.0 kB** *JPEG-XL image, encoded with `cjxl lossless.png out.jxl -d 1.49 -e 9`. Score: ~`83.04`* *3.06s user time*\\n\\n![smaller_avif](/img/_DSC8466-smaller.avif)\\n\\n**124.8 kB** *AVIF image, encoded with `avifenc -c aom -s 4 -j 8 -d 10 -y 444 --min 1 --max 63 -a end-usage=q -a cq-level=16 -a tune=ssim lossless.png out.avif`. Score: ~`83.03`* *7.54s user time*\\n\\nJXL also supports lossless transcoding of JPEG images. This means every pixel is identical, the image just has a smaller filesize than the original JPEG; if you can use JXL, you can transcode existing JPEGs losslessly on your site & save some bandwidth that way. The JPEG transcode below gives a higher SSIMULACRA2 score than the original for some reason, but I'll chalk that up to a decoding inconsistency between how the `ssimulacra2` program decodes JPEG & JXL. Either way, the scores are fairly close.\\n\\n![smaller_jxl_jpeg-recomp](/img/_DSC8466-smaller-recomp.jxl)\\n\\n**189.4 kB** *JPEG-XL image from JPEG, encoded with `cjxl input.jpg input-recomp.jxl -d 0.0 -e 9 --brotli_effort=11`. Score: ~`84.92` (???)* *0.67s user time*\\n\\nThe final trick we can use, while not a new codec at all, still increases quality per bit. Encoding an XYB JPEG with `cjpegli` encodes with the perceptual XYB colorspace using an ICC profile to modify the original JPEG colors, avoiding JPEG's normal YCbCr which isn't perceptually optimized for the human visual system. Using XYB, we can afford identical quality with less bitrate than normal JPEG. This has universal compatibility, but not every application understands how to handle the XYB color profile (although color-managed modern browsers should be fine).\\n\\n![smaller_jpeg_xyb](/img/_DSC8466-smaller-xyb.jpg)\\n\\n**208.3 kB** *XYB JPEG, encoded with `cjpegli lossless.png out.jpg --xyb -d 1.155`. Score: ~`83.04`* *0.10s user time*\\n\\nIn this particular instance, AVIF seems to be the overall winner. This isn't always the case due to JXL's superiority at higher fidelity & with more detailed images, but according to SSIMULACRA2, AVIF has the best quality per bit with this image. You can use your own eyes to further clarify your choice, though. It is worth mentioning that as these were encoded from a 16-bit source PNG, the JXL image is the only one that maintains the full original bit depth, & AVIF isn't fast to encode.\\n\\n## Responsive Images\\n\\nDisplaying an image that is too large for a viewport is a waste of bandwidth, & displaying an image that's too small for the viewport leaves fidelity to be desired. Luckily, we have the [Responsive Image Linter](https://ausi.github.io/respimagelint/) that can help us figure out which image sizes we should be using.\\n\\n![responsive_image_linter](/img/responsive_image_linter.avif)\\n\\nIn our fire & forget example, we see that we are serving an image that is far too large. We already know that, but now we can see that given various viewport sizes we could be serving images that have respective widths of 270px, 958px, 1350px, 1660px, & 1916px to optimize for delivery to a variety of different devices. Here's how we'd write that in HTML:\\n\\n```html\\n\\n```\\n\\nIt is worth noting that this example above & the example below aren't perfect implementations of a responsive image given the conditions of this site, but the general concept still applies. Some things to note:\\n\\n- `srcset` = the images available to your browser to serve, & their respective widths\\n- `sizes` = the conditions given to the browser explaining under what conditions should it serve which image\\n- `(min-width: XXXpx) YYYpx` = Given the viewport is at least XXX wide, serve an image of YYY horizontal resolution. The browser will pick an image from srcset that is CSS pixels \\\\* display scaling.\\n- `calc(100vw - 24px)` = Usually preceded by a (min-width) condition. Specifies a value the browser should calculate on its own to pick the closest option from the srcset. Let's say we have `(min-width: 997px) calc(75vw - 257px)`. This means given the viewport is at least 997px wide, calculate 0.75 \\\\* the current viewport resolution - 257 to find the closest image in the srcset to fit the number of pixel specified.\\n\\n\\n\\nThat's all! Massive thanks to Auto-Rez Media Technologies for the inspiration behind this article & explicit permission to use their [Reduce Your Page's Image Load](https://autocompressor.net/blog/reduce-image-load) blog post when writing this entry. I have [confirmed](https://autumn.revolt.chat/attachments/GtFGuwNfeRdcwUN0MWzhDCAiiadWOk88XXC3pQv6RI) with their leadership that this wiki entry can be safely licensed under CC BY-SA 4.0.\"}]}}")}}]); \ No newline at end of file diff --git a/assets/js/318608aa.e518b717.js b/assets/js/318608aa.a32bb04d.js similarity index 99% rename from assets/js/318608aa.e518b717.js rename to assets/js/318608aa.a32bb04d.js index 8b016808..b654ab8f 100644 --- a/assets/js/318608aa.e518b717.js +++ b/assets/js/318608aa.a32bb04d.js @@ -1 +1 @@ -"use strict";(self.webpackChunkcodec_wiki=self.webpackChunkcodec_wiki||[]).push([[6003],{1306:(e,n,i)=>{i.r(n),i.d(n,{assets:()=>o,contentTitle:()=>l,default:()=>h,frontMatter:()=>r,metadata:()=>c,toc:()=>a});var t=i(4848),s=i(8453);i(1470),i(9365);const r={title:"vpxenc",sidebar_position:8},l="vpxenc",c={id:"encoders/vpxenc",title:"vpxenc",description:"The content in this entry is incomplete & is in the process of being completed.",source:"@site/docs/encoders/vpxenc.mdx",sourceDirName:"encoders",slug:"/encoders/vpxenc",permalink:"/docs/encoders/vpxenc",draft:!1,unlisted:!1,editUrl:"https://github.com/av1-community-contributors/codec-wiki/tree/main/docs/encoders/vpxenc.mdx",tags:[],version:"current",sidebarPosition:8,frontMatter:{title:"vpxenc",sidebar_position:8},sidebar:"tutorialSidebar",previous:{title:"Aurora1 AV1",permalink:"/docs/encoders/Aurora1"},next:{title:"SVT-VP9",permalink:"/docs/encoders/SVT-VP9"}},o={},a=[{value:"FFmpeg",id:"ffmpeg",level:2},{value:"Supported Color Space",id:"supported-color-space",level:2},{value:"Installing (Binary)",id:"installing-binary",level:2},{value:"Compiling (Windows/MacOS/Linux)",id:"compiling-windowsmacoslinux",level:2},{value:"Cloning",id:"cloning",level:3},{value:"./configure file",id:"configure-file",level:3},{value:"Other ./configure options",id:"other-configure-options",level:3},{value:"Running GNU make",id:"running-gnu-make",level:3},{value:"VP8",id:"vp8",level:2},{value:"VP9",id:"vp9",level:2},{value:"Encoding",id:"encoding",level:3}];function d(e){const n={a:"a",admonition:"admonition",code:"code",em:"em",h1:"h1",h2:"h2",h3:"h3",li:"li",ol:"ol",p:"p",pre:"pre",strong:"strong",table:"table",tbody:"tbody",td:"td",th:"th",thead:"thead",tr:"tr",ul:"ul",...(0,s.R)(),...e.components};return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(n.h1,{id:"vpxenc",children:"vpxenc"}),"\n",(0,t.jsx)(n.admonition,{title:"Under Maintenance",type:"info",children:(0,t.jsx)(n.p,{children:"The content in this entry is incomplete & is in the process of being completed."})}),"\n",(0,t.jsxs)(n.p,{children:["vpxenc is part of the libvpx library for working with the ",(0,t.jsx)(n.a,{href:"/docs/video/VP9",children:"VP9"})," & ",(0,t.jsx)(n.a,{href:"/docs/video/VP8",children:"VP8"})," video codecs. It is capable of encoding & decoding both formats, where vpxenc is the multipurpose encoder. VP9 competes with ",(0,t.jsx)(n.a,{href:"/docs/video/HEVC",children:"HEVC"})," (h265) & ",(0,t.jsx)(n.a,{href:"/docs/video/AVC",children:"AVC"})," (h264) in coding efficiency, and has been superseded by ",(0,t.jsx)(n.a,{href:"/docs/video/AV1",children:"AV1"}),". VP8 competes with AVC."]}),"\n",(0,t.jsxs)(n.p,{children:["By default, vpxenc isn't as competitive as it could be, but even when used properly, most tests show that h265 offers slightly better quality per bit with efficient encoders like ",(0,t.jsx)(n.a,{href:"/docs/encoders/x265",children:"x265"}),"."]}),"\n",(0,t.jsx)(n.h2,{id:"ffmpeg",children:"FFmpeg"}),"\n",(0,t.jsxs)(n.p,{children:["vpxenc is available in FFmpeg via ",(0,t.jsx)(n.code,{children:"libvpx"})," for ",(0,t.jsx)(n.strong,{children:"VP8"})," and ",(0,t.jsx)(n.code,{children:"libvpx-vp9"})," for ",(0,t.jsx)(n.strong,{children:"VP9"}),", to check if you have it, run ",(0,t.jsx)(n.code,{children:"ffmpeg -h encoder=libvpx"})," or ",(0,t.jsx)(n.code,{children:"ffmpeg -h encoder=libvpx-vp9"}),".\nNon-FFmpeg standard VP8/VP9 parameters are ",(0,t.jsx)(n.strong,{children:"not"})," supported."]}),"\n",(0,t.jsx)(n.h2,{id:"supported-color-space",children:"Supported Color Space"}),"\n",(0,t.jsx)(n.p,{children:"vpxenc supports the following color spaces:"}),"\n",(0,t.jsxs)(n.table,{children:[(0,t.jsx)(n.thead,{children:(0,t.jsxs)(n.tr,{children:[(0,t.jsx)(n.th,{children:"Format"}),(0,t.jsx)(n.th,{style:{textAlign:"center"},children:"Chroma Subsampling"}),(0,t.jsx)(n.th,{children:"Supported Bit Depth(s)"})]})}),(0,t.jsxs)(n.tbody,{children:[(0,t.jsxs)(n.tr,{children:[(0,t.jsx)(n.td,{children:"YUV420P"}),(0,t.jsx)(n.td,{style:{textAlign:"center"},children:"4:2:0"}),(0,t.jsx)(n.td,{children:"8-bit"})]}),(0,t.jsxs)(n.tr,{children:[(0,t.jsx)(n.td,{children:"YUVA420P"}),(0,t.jsx)(n.td,{style:{textAlign:"center"},children:"4:2:0"}),(0,t.jsx)(n.td,{children:"8-bit (Alpha Channel)"})]}),(0,t.jsxs)(n.tr,{children:[(0,t.jsx)(n.td,{children:"YUV422P"}),(0,t.jsx)(n.td,{style:{textAlign:"center"},children:"4:2:2"}),(0,t.jsx)(n.td,{children:"8-bit"})]}),(0,t.jsxs)(n.tr,{children:[(0,t.jsx)(n.td,{children:"YUV440P"}),(0,t.jsx)(n.td,{style:{textAlign:"center"},children:"4:4:0"}),(0,t.jsx)(n.td,{children:"8-bit"})]}),(0,t.jsxs)(n.tr,{children:[(0,t.jsx)(n.td,{children:"YUV444P"}),(0,t.jsx)(n.td,{style:{textAlign:"center"},children:"4:4:4"}),(0,t.jsx)(n.td,{children:"8-bit"})]}),(0,t.jsxs)(n.tr,{children:[(0,t.jsx)(n.td,{children:"GBRP"}),(0,t.jsx)(n.td,{style:{textAlign:"center"},children:"-"}),(0,t.jsx)(n.td,{children:"8-bit"})]}),(0,t.jsxs)(n.tr,{children:[(0,t.jsx)(n.td,{children:"YUV420P10LE"}),(0,t.jsx)(n.td,{style:{textAlign:"center"},children:"4:2:0"}),(0,t.jsx)(n.td,{children:"10-bit"})]}),(0,t.jsxs)(n.tr,{children:[(0,t.jsx)(n.td,{children:"YUV422P10LE"}),(0,t.jsx)(n.td,{style:{textAlign:"center"},children:"4:2:2"}),(0,t.jsx)(n.td,{children:"10-bit"})]}),(0,t.jsxs)(n.tr,{children:[(0,t.jsx)(n.td,{children:"YUV440P10LE"}),(0,t.jsx)(n.td,{style:{textAlign:"center"},children:"4:4:0"}),(0,t.jsx)(n.td,{children:"10-bit"})]}),(0,t.jsxs)(n.tr,{children:[(0,t.jsx)(n.td,{children:"YUV444P10LE"}),(0,t.jsx)(n.td,{style:{textAlign:"center"},children:"4:4:4"}),(0,t.jsx)(n.td,{children:"10-bit"})]}),(0,t.jsxs)(n.tr,{children:[(0,t.jsx)(n.td,{children:"GBRP10LE"}),(0,t.jsx)(n.td,{style:{textAlign:"center"},children:"-"}),(0,t.jsx)(n.td,{children:"10-bit"})]}),(0,t.jsxs)(n.tr,{children:[(0,t.jsx)(n.td,{children:"YUV420P12LE"}),(0,t.jsx)(n.td,{style:{textAlign:"center"},children:"4:2:0"}),(0,t.jsx)(n.td,{children:"12-bit"})]}),(0,t.jsxs)(n.tr,{children:[(0,t.jsx)(n.td,{children:"YUV422P12LE"}),(0,t.jsx)(n.td,{style:{textAlign:"center"},children:"4:2:2"}),(0,t.jsx)(n.td,{children:"12-bit"})]}),(0,t.jsxs)(n.tr,{children:[(0,t.jsx)(n.td,{children:"YUV440P12LE"}),(0,t.jsx)(n.td,{style:{textAlign:"center"},children:"4:4:0"}),(0,t.jsx)(n.td,{children:"12-bit"})]}),(0,t.jsxs)(n.tr,{children:[(0,t.jsx)(n.td,{children:"YUV444P12LE"}),(0,t.jsx)(n.td,{style:{textAlign:"center"},children:"4:4:4"}),(0,t.jsx)(n.td,{children:"12-bit"})]}),(0,t.jsxs)(n.tr,{children:[(0,t.jsx)(n.td,{children:"GBRP12LE"}),(0,t.jsx)(n.td,{style:{textAlign:"center"},children:"-"}),(0,t.jsx)(n.td,{children:"12-bit"})]})]})]}),"\n",(0,t.jsx)(n.h2,{id:"installing-binary",children:"Installing (Binary)"}),"\n",(0,t.jsxs)(n.p,{children:["Windows builds are available on Lastrosade's ",(0,t.jsx)(n.a,{href:"https://jeremylee.sh/bins/",children:"website"})," and can be downloaded ",(0,t.jsx)(n.a,{href:"https://jeremylee.sh/bins/vpx.7z",children:"here"}),"."]}),"\n",(0,t.jsx)(n.p,{children:'For Linux and MacOS, it may be be available when searching "vpxenc" or "libvpx" in their respective package managers.'}),"\n",(0,t.jsx)(n.h2,{id:"compiling-windowsmacoslinux",children:"Compiling (Windows/MacOS/Linux)"}),"\n",(0,t.jsxs)(n.p,{children:["Windows users are recommended to compile via MinGW-W64 which comes with ",(0,t.jsx)(n.a,{href:"https://msys2.org/",children:"MSYS2"}),"."]}),"\n",(0,t.jsx)(n.p,{children:"nasm/yasm, and the GNU build tools (make, configure) are required for this operation."}),"\n",(0,t.jsx)(n.h3,{id:"cloning",children:"Cloning"}),"\n",(0,t.jsx)(n.p,{children:"First, cloning"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:"git clone https://chromium.googlesource.com/webm/libvpx\ncd libvpx\nmkdir build && cd build\n"})}),"\n",(0,t.jsx)(n.h3,{id:"configure-file",children:"./configure file"}),"\n",(0,t.jsx)(n.p,{children:"Now here comes the annoying part, the configure file have really bad defaults. So you will need to adjust them, here are some recommended options you should use:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:'./configure --cpu=native --extra-cxxflags="-O3 -flto -march=native" --extra-cflags="-O3 -flto -march=native" --as=auto --enable-vp9-highbitdepth --enable-libyuv --enable-webm-io --enable-vp9 --enable-runtime-cpu-detect --enable-internal-stats --enable-postproc --enable-vp9-postproc --enable-static --disable-shared --enable-vp9-temporal-denoising --disable-unit-tests --disable-docs --enable-multithread\n'})}),"\n",(0,t.jsx)(n.p,{children:"Now let's break down what each of them do."}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsxs)(n.p,{children:[(0,t.jsx)(n.code,{children:"--cpu=native"}),"\nNative CPU optimizations."]}),"\n"]}),"\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsxs)(n.p,{children:[(0,t.jsx)(n.code,{children:'--extra-cxxflags="-O3 -flto -march=native" --extra-cflags="-O3 -flto -march=native"'}),"\nMore native CPU optimizations for faster encoding."]}),"\n"]}),"\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsxs)(n.p,{children:[(0,t.jsx)(n.code,{children:"--as=auto"}),"\nSet the assembler to auto, so it can choose between ",(0,t.jsx)(n.code,{children:"yasm"})," and ",(0,t.jsx)(n.code,{children:"nasm"}),"."]}),"\n"]}),"\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsxs)(n.p,{children:[(0,t.jsx)(n.code,{children:"--enable-vp9-highbitdepth"}),"\nEnables high bit depth (>=10 bits) when encoding VP9."]}),"\n"]}),"\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsxs)(n.p,{children:[(0,t.jsx)(n.code,{children:"--enable-libyuv"}),"\nEnables YUV4MPEG input support (IMPORTANT), otherwise it will only accept RAW."]}),"\n"]}),"\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsxs)(n.p,{children:[(0,t.jsx)(n.code,{children:"--enable-webm-io"}),"\nEnables input and output support for WebM container."]}),"\n"]}),"\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsxs)(n.p,{children:[(0,t.jsx)(n.code,{children:"--enable-vp9"}),"\nEnables VP9 encoding support."]}),"\n"]}),"\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsxs)(n.p,{children:[(0,t.jsx)(n.code,{children:"--enable-runtime-cpu-detect"}),"\nEnables runtime CPU detection."]}),"\n"]}),"\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsxs)(n.p,{children:[(0,t.jsx)(n.code,{children:"--enable-internal-stats"}),"\nEnables internal statistics for the encoder for debug purposes."]}),"\n"]}),"\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsxs)(n.p,{children:[(0,t.jsx)(n.code,{children:"--enable-postproc"}),"\nEnables postprocessing stuff for better video quality."]}),"\n"]}),"\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsxs)(n.p,{children:[(0,t.jsx)(n.code,{children:"--enable-vp9-postproc"}),"\nEnables VP9-specific postprocessing stuff for better video quality."]}),"\n"]}),"\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsxs)(n.p,{children:[(0,t.jsx)(n.code,{children:"--enable-static"}),"\nEnables static builds."]}),"\n"]}),"\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsxs)(n.p,{children:[(0,t.jsx)(n.code,{children:"--disable-shared"}),"\nDisables shared builds."]}),"\n"]}),"\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsxs)(n.p,{children:[(0,t.jsx)(n.code,{children:"--enable-vp9-temporal-denoising"}),"\nDisables spatial denoising for VP9 and enables temporal instead."]}),"\n"]}),"\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsxs)(n.p,{children:[(0,t.jsx)(n.code,{children:"--disable-unit-tests"}),"\nDisables unit tests, unless you want to test the encoder as a developer. This should be disabled."]}),"\n"]}),"\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsxs)(n.p,{children:[(0,t.jsx)(n.code,{children:"--disable-docs"}),"\nDisables documentation, as enabling this also requires doxygen."]}),"\n"]}),"\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsxs)(n.p,{children:[(0,t.jsx)(n.code,{children:"--enable-multithread"}),"\nEnables the usage of multiple CPU threads for encoding and decoding."]}),"\n"]}),"\n"]}),"\n",(0,t.jsx)(n.h3,{id:"other-configure-options",children:"Other ./configure options"}),"\n",(0,t.jsx)(n.p,{children:"There are other options you may want use to either speed up compiliation or drop unwanted features."}),"\n",(0,t.jsxs)(n.ol,{children:["\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsxs)(n.p,{children:[(0,t.jsx)(n.code,{children:"--disable-vp8 --disable-vp9-decoder --disable-vp8-decoder"}),"\nDisables VP8 encoding and ",(0,t.jsx)(n.code,{children:"vpxdec"})," (decoder) to be compiled."]}),"\n"]}),"\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsxs)(n.p,{children:[(0,t.jsx)(n.code,{children:"--enable-small"}),"\nPrioritizes smaller encoder binary size over encoding speed."]}),"\n"]}),"\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsxs)(n.p,{children:[(0,t.jsx)(n.code,{children:"--target="}),"\nEnables target compilation for a specific operating system or CPU architecture. There's a lot of them. Here's an exhaustive list of all of them based on the configure file:"]}),"\n"]}),"\n"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:"arm64-android-gcc\narm64-darwin-gcc\narm64-darwin20-gcc\narm64-darwin21-gcc\narm64-darwin22-gcc\narm64-darwin23-gcc\narm64-linux-gcc\narm64-win64-gcc\narm64-win64-vs15\narm64-win64-vs16\narm64-win64-vs16-clangcl\narm64-win64-vs17\narm64-win64-vs17-clangcl\narmv7-android-gcc\narmv7-darwin-gcc\narmv7-linux-rvct\narmv7-linux-gcc\narmv7-none-rvct\narmv7-win32-gcc\narmv7-win32-vs14\narmv7-win32-vs15\narmv7-win32-vs16\narmv7-win32-vs17\narmv7s-darwin-gcc\narmv8-linux-gcc\nloongarch32-linux-gcc\nloongarch64-linux-gcc\nmips32-linux-gcc\nmips64-linux-gcc\nppc64le-linux-gcc\nsparc-solaris-gcc\nx86-android-gcc\nx86-darwin8-gcc\nx86-darwin8-icc\nx86-darwin9-gcc\nx86-darwin9-icc\nx86-darwin10-gcc\nx86-darwin11-gcc\nx86-darwin12-gcc\nx86-darwin13-gcc\nx86-darwin14-gcc\nx86-darwin15-gcc\nx86-darwin16-gcc\nx86-darwin17-gcc\nx86-iphonesimulator-gcc\nx86-linux-gcc\nx86-linux-icc\nx86-os2-gcc\nx86-solaris-gcc\nx86-win32-gcc\nx86-win32-vs14\nx86-win32-vs15\nx86-win32-vs16\nx86-win32-vs17\nx86_64-android-gcc\nx86_64-darwin9-gcc\nx86_64-darwin10-gcc\nx86_64-darwin11-gcc\nx86_64-darwin12-gcc\nx86_64-darwin13-gcc\nx86_64-darwin14-gcc\nx86_64-darwin15-gcc\nx86_64-darwin16-gcc\nx86_64-darwin17-gcc\nx86_64-darwin18-gcc\nx86_64-darwin19-gcc\nx86_64-darwin20-gcc\nx86_64-darwin21-gcc\nx86_64-darwin22-gcc\nx86_64-darwin23-gcc\nx86_64-iphonesimulator-gcc\nx86_64-linux-gcc\nx86_64-linux-icc\nx86_64-solaris-gcc\nx86_64-win64-gcc\nx86_64-win64-vs14\nx86_64-win64-vs15\nx86_64-win64-vs16\nx86_64-win64-vs17\ngeneric-gnu\n"})}),"\n",(0,t.jsxs)(n.p,{children:["For ",(0,t.jsx)(n.strong,{children:"Windows"})," compilation with MinGW you may need to use ",(0,t.jsx)(n.code,{children:"--target=x86_64-win64-gcc"})," and ",(0,t.jsx)(n.code,{children:"--target=arm64-darwin22-gcc"})," for ",(0,t.jsx)(n.strong,{children:"MacOS"}),"."]}),"\n",(0,t.jsx)(n.h3,{id:"running-gnu-make",children:"Running GNU make"}),"\n",(0,t.jsxs)(n.p,{children:["After successfully running the configure command above, run ",(0,t.jsx)(n.code,{children:"make -j $(nproc)"})," to start compiling with your CPU count. The resulting binary will be called ",(0,t.jsx)(n.code,{children:"vpxenc"})," and you can copy it wherever you like."]}),"\n",(0,t.jsx)(n.h2,{id:"vp8",children:"VP8"}),"\n",(0,t.jsx)(n.p,{children:(0,t.jsx)(n.em,{children:"Incomplete"})}),"\n",(0,t.jsx)(n.h2,{id:"vp9",children:"VP9"}),"\n",(0,t.jsxs)(n.p,{children:["For encoding VP9, vpxenc's default parameters are not considered optimal. There are a lot of options that are either disabled without reason or are simply misconfigured, hurting coding efficiency at little cost otherwise. As of mid-2021, some parameters (the TPL-model, lag-in-frames and auto-alt-ref frames) were changed (since libvpx 1.9.0 and libvpx 1.10.0) which means that there's not much use of setting these three parameters unless you're in ",(0,t.jsx)(n.a,{href:"/docs/utilities/ffmpeg",children:"FFmpeg"}),". This section covers the most important options libvpx-vp9 has to offer, recommended settings, & what they do."]}),"\n",(0,t.jsx)(n.p,{children:"It is important to note that the vpxenc parameters provided below are considered optimal because they are efficient, but VP9 Profile 2 isn't compatible with many hardware-accelerated VP9 decoding implementations."}),"\n",(0,t.jsx)(n.h3,{id:"encoding",children:"Encoding"}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsx)(n.li,{children:(0,t.jsx)(n.code,{children:"--codec=vp9"})}),"\n"]}),"\n",(0,t.jsx)(n.p,{children:"Self-explanatory."}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsx)(n.li,{children:(0,t.jsx)(n.code,{children:"--passes=2"})}),"\n"]}),"\n",(0,t.jsxs)(n.p,{children:["vpxenc's 2-pass mode is quite fast compared to 2-pass in ",(0,t.jsx)(n.a,{href:"/docs/encoders/x264",children:"x264"})," and x265. Only use 1-pass mode for real-time applications, which won't be covered here yet. It is the default in the standalone vpxenc libvpx-vp9 encoder."]}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsx)(n.li,{children:(0,t.jsx)(n.code,{children:"--webm"})}),"\n"]}),"\n",(0,t.jsxs)(n.p,{children:["Enables WebM output for the encoder, and passes the encoder flags set. It is not necessary to enable it, but since it passes the encoder flags, I would use it. Can be changed to ",(0,t.jsx)(n.code,{children:"--ivf"})," for an ivf video stream."]}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsx)(n.li,{children:(0,t.jsx)(n.code,{children:"--good"})}),"\n"]}),"\n",(0,t.jsxs)(n.p,{children:["This is a sort of quality deadline, the minimum speed the encoder is allowed to go to. It isn't recommended to use ",(0,t.jsx)(n.code,{children:"-\u2013best"})," as it is slow for the quality uplift you get. Do not use RT for anything but real-time encoding."]}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsx)(n.li,{children:(0,t.jsx)(n.code,{children:"--threads=8"})}),"\n"]}),"\n",(0,t.jsx)(n.p,{children:"Dictates the number of threads the encoder should spawn. It doesn\u2019t mean it\u2019ll scale all that well over those 8 threads. On a 16 thread CPU with a single encoder instance, I would use 8 threads. With multiple encoder instance encoding(with qencoder/av1an/neav1e), I would set it to 2 threads."}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsx)(n.li,{children:(0,t.jsx)(n.code,{children:"--profile=2"})}),"\n"]}),"\n",(0,t.jsx)(n.p,{children:"VP9 profile 2 is obligatory if you want 10-bit & 12-bit support for HDR, and improved quality from 8-bit."}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsx)(n.li,{children:(0,t.jsx)(n.code,{children:"--lag-in-frames=25"})}),"\n"]}),"\n",(0,t.jsx)(n.p,{children:"Lag-in-frames is the libvpx equivalent of lookahead in x264. The higher the number, the slower the encoder will be, but at the upside of making it more efficient. Going above \u2013lag-in-frames=12 also activates another setting called alternate reference frames. 25 is the maximum you can get in libvpx-vp9. It is the default in the standalone vpxenc libvpx-vp9 encoder."}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsx)(n.li,{children:(0,t.jsx)(n.code,{children:"--end-usage=q"})}),"\n"]}),"\n",(0,t.jsx)(n.p,{children:"Q mode is the closest equivalent to CRF that libvpx-vp9 offers, so use it if maximum quality is desired."}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsx)(n.li,{children:(0,t.jsx)(n.code,{children:"--cq-level=25"})}),"\n"]}),"\n",(0,t.jsx)(n.p,{children:"For 1080p30 8-bit content, it is recommended to go with a Q of 25; you can go lower if you value higher quality over pure efficiency. For 1080p60 8-bit content, I would recommend going with a higher Q value with a delta of around 15. So, a Q of 30 to 40 is usually recommended. Depending on the content, you may have to tune this value, so this advice is only useful in choosing a starting point."}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsx)(n.li,{children:(0,t.jsx)(n.code,{children:"--kf-max-dist=[input FPS * 10]"})}),"\n"]}),"\n",(0,t.jsxs)(n.p,{children:["This tells the encoder to have a maximum number of frames between keyframes. It will usually place a lower number of keyframes in content like movies, TV shows, or animated shows, so you can set it to a very high number or not set it at all if you want maximum efficiency for this kind of content. Otherwise, I would go with the 10-second rule: ",(0,t.jsx)(n.code,{children:"--kf-max-dist=240"})," for 24FPS content, 300 for 30FPS content, 600 for 60FPS content, and so on."]}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsx)(n.li,{children:(0,t.jsx)(n.code,{children:"--cpu-used=3"})}),"\n"]}),"\n",(0,t.jsxs)(n.p,{children:["This is where the biggest balance of quality to speed is with libvpx-vp9. This is similar to presets in x264 and x265, except the lower the number, the slower the encoder takes. Using ",(0,t.jsx)(n.code,{children:"--cpu-used=3"})," & below enables RDO, which increases quality at the expense of speed."]}),"\n",(0,t.jsx)(n.admonition,{type:"info",children:(0,t.jsxs)(n.p,{children:[(0,t.jsx)(n.code,{children:"--cpu-used=5"})," and above are ",(0,t.jsx)(n.em,{children:"slower"})," in the 1st pass, so it isn't recommended to use them anyway."]})}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsx)(n.li,{children:(0,t.jsx)(n.code,{children:"--auto-alt-ref=6"})}),"\n"]}),"\n",(0,t.jsx)(n.p,{children:'Activates alternate reference frames. Alternate reference frames are "invisible" frames which are used as references when creating the final display frames.'}),"\n",(0,t.jsx)(n.p,{children:"More alternate reference frames is typically more efficient. Setting this greater than 1 activates overlay frames and isn't compatible with the 8-bit color profiles."}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsx)(n.li,{children:(0,t.jsx)(n.code,{children:"--arnr-maxframes=7"})}),"\n"]}),"\n",(0,t.jsx)(n.p,{children:"This is the maximum number of alternate reference frames the encoder is allowed to use. For most content, 7 is usually a good bet, and it is the default. With animated content, going with a value of 12 or to the max is a good bet, as animated content benefits from more additional alt-ref frames than other content. Be aware that increasing this value will impact encode speed."}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsx)(n.li,{children:(0,t.jsx)(n.code,{children:"--arnr-strength=4"})}),"\n"]}),"\n",(0,t.jsx)(n.p,{children:"This setting dictates how much denoising will occur in the alt-ref frames. Lowering it to 2 or 3 is usually a good bet for noisier/grainy content to try and retain more detail, but 4 is a sane starting place. The default setting is 5, which is fine for most content, but it can be beneficial going a bit lower. For animation, keeping the default of 5 is likely a better option."}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsx)(n.li,{children:(0,t.jsx)(n.code,{children:"--aq-mode=0"})}),"\n"]}),"\n",(0,t.jsxs)(n.p,{children:["Adaptive quantization is the way for an encoder to spend more bits in certain areas to improve ",(0,t.jsx)(n.a,{href:"/docs/introduction/psychovisual",children:"psychovisual fidelity"}),". ",(0,t.jsx)(n.code,{children:"-\u2013aq-mode=0"})," works well on clean content (animation, video games, screen content). ",(0,t.jsx)(n.code,{children:"--aq-mode=2"})," is recommended when you want to give more detail to more complex parts of a video."]}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsx)(n.li,{children:(0,t.jsx)(n.code,{children:"--frame-boost=1"})}),"\n"]}),"\n",(0,t.jsxs)(n.p,{children:["This flag lets the encoder periodically boost the bitrate of a scene/frame if it needs it. Leaving it at the default ",(0,t.jsx)(n.code,{children:"--frame-boost=0"})," is usually a good bet, & this isn't a particularly salient change."]}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsx)(n.li,{children:(0,t.jsx)(n.code,{children:"--tune-content=default"})}),"\n"]}),"\n",(0,t.jsxs)(n.p,{children:["This determines how the encoder is tuned. In libvpx-vp9, there are three options: ",(0,t.jsx)(n.code,{children:"default"}),", ",(0,t.jsx)(n.code,{children:"screen"}),", and ",(0,t.jsx)(n.code,{children:"film"}),". Default is for most scenarios, screen is for screen content(video games, live-streaming content like web pages & your screen), and film is for heavily dithered/grainy video. Leaving it at the default for about everything but screen content as described above is probably the best option. ",(0,t.jsx)(n.code,{children:"--tune-content=screen"})," with ",(0,t.jsx)(n.code,{children:"--aq-mode=2"})," is not recommended, as it creates some odd artifacts. It is advised to use ",(0,t.jsx)(n.code,{children:"--aq-mode=0"})," if ",(0,t.jsx)(n.code,{children:"--tune-content=screen"})," is activated, or if you want better perceptual quality, ",(0,t.jsx)(n.code,{children:"--aq-mode=1"}),"."]}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsx)(n.li,{children:(0,t.jsx)(n.code,{children:"--row-mt=1"})}),"\n"]}),"\n",(0,t.jsxs)(n.p,{children:["Enables row multi-threading in libvpx-vp9. ",(0,t.jsx)(n.em,{children:"Always"})," enable it no matter what, as it does not hurt efficiency, but boosts speed considerably. This feature is disabled by default."]}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsx)(n.li,{children:(0,t.jsx)(n.code,{children:"--bit-depth=10"})}),"\n"]}),"\n",(0,t.jsxs)(n.p,{children:["Always use 10-bit for maximum efficiency & minimal banding, even with an 8-bit source. Make sure to enable ",(0,t.jsx)(n.code,{children:"-\u2013profile=2"})," as mentioned above."]}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsx)(n.li,{children:(0,t.jsx)(n.code,{children:"--tile-columns=1"})}),"\n"]}),"\n",(0,t.jsxs)(n.p,{children:["This setting divides the video into tile columns for easier parallelization when encoding & decoding. Setting ",(0,t.jsx)(n.code,{children:"-\u2013tile-columns=1"}),", you will get 2\xb9 tile columns. Setting it higher is a trade-off between parallelization & coding efficiency, as more tiles means less information your encoder can work with, and this will result in decreased efficiency. Do note there is an upper threshold in regards to the number of tile columns you can get due to the fixed minimum tile width of 256 pixels. So, this means 4 tile columns (2\xb2) for 720p and 1080p, 8 tile columns (2\u2074) for 1440p/4k, and so on. If you set a tile column number that is too high, it will drop down to the lowest supported number of tile columns at the input resolution."]}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsx)(n.li,{children:(0,t.jsx)(n.code,{children:"--tile-rows=0"})}),"\n"]}),"\n",(0,t.jsxs)(n.p,{children:["This setting divides the video into tile rows. This option is different from columns because although it also makes decoding performance higher, it does not scale as well as tile columns & doesn\u2019t increase encoder threading nearly as much. Always use more tile-columns than rows, or leave the number of tile rows at default (0). Leaving the encoder defaults at ",(0,t.jsx)(n.code,{children:"-\u2013tile-rows=0"})," & ",(0,t.jsx)(n.code,{children:"\u2013-tile-columns=0"})," will result in the highest overall coding efficiency possible with these options."]}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsx)(n.li,{children:(0,t.jsx)(n.code,{children:"--enable-tpl=1"})}),"\n"]}),"\n",(0,t.jsx)(n.p,{children:"This option enables a temporal layer model, which helps with coding efficiency. It is the default in the standalone vpxenc libvpx-vp9 encoder."}),"\n",(0,t.jsx)(n.p,{children:"All of these options are only available for the standalone vpxenc program. Here is a sample FFmpeg command line interpretation of the commands above, with some options missing:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:"ffmpeg -i input.mkv -c:v libvpx-vp9 -pix_fmt yuv420p10le -pass 1 -quality good -threads 4 -profile:v 2 -lag-in-frames 25 -crf 25 -b:v 0 -g 240 -cpu-used 4 -auto-alt-ref 1 -arnr-maxframes 7 -arnr-strength 4 -aq-mode 0 -tile-rows 0 -tile-columns 1 -enable-tpl 1 -row-mt 1 -f null -\nffmpeg -i input.mkv -c:v libvpx-vp9 -pix_fmt yuv420p10le -pass 2 -quality good -threads 4 -profile:v 2 -lag-in-frames 25 -crf 25 -b:v 0 -g 240 -cpu-used 4 -auto-alt-ref 1 -arnr-maxframes 7 -arnr-strength 4 -aq-mode 0 -tile-rows 0 -tile-columns 1 -enable-tpl 1 -row-mt 1 output.mkv\n"})}),"\n",(0,t.jsx)(n.p,{children:"Alternatively, you can pass a raw .y4m stream to standalone vpxenc & encode that way."}),"\n",(0,t.jsx)(n.p,{children:(0,t.jsx)(n.em,{children:"VP9 section written based on work by BlueSwordM, who has granted written permission for this wiki page to exist in its current fashion"})})]})}function h(e={}){const{wrapper:n}={...(0,s.R)(),...e.components};return n?(0,t.jsx)(n,{...e,children:(0,t.jsx)(d,{...e})}):d(e)}},9365:(e,n,i)=>{i.d(n,{A:()=>l});i(6540);var t=i(8215);const s={tabItem:"tabItem_Ymn6"};var r=i(4848);function l(e){let{children:n,hidden:i,className:l}=e;return(0,r.jsx)("div",{role:"tabpanel",className:(0,t.A)(s.tabItem,l),hidden:i,children:n})}},1470:(e,n,i)=>{i.d(n,{A:()=>y});var t=i(6540),s=i(8215),r=i(3104),l=i(6347),c=i(205),o=i(7485),a=i(1682),d=i(9466);function h(e){return t.Children.toArray(e).filter((e=>"\n"!==e)).map((e=>{if(!e||(0,t.isValidElement)(e)&&function(e){const{props:n}=e;return!!n&&"object"==typeof n&&"value"in n}(e))return e;throw new Error(`Docusaurus error: Bad["'])(?.*?)\1/,f=/\{(? [\d,-]+)\}/,x={js:{start:"\\/\\/",end:""},jsBlock:{start:"\\/\\*",end:"\\*\\/"},jsx:{start:"\\{\\s*\\/\\*",end:"\\*\\/\\s*\\}"},bash:{start:"#",end:""},html:{start:"\x3c!--",end:"--\x3e"}},b={...x,lua:{start:"--",end:""},wasm:{start:"\\;\\;",end:""},tex:{start:"%",end:""},vb:{start:"['\u2018\u2019]",end:""},vbnet:{start:"(?:_\\s*)?['\u2018\u2019]",end:""},rem:{start:"[Rr][Ee][Mm]\\b",end:""},f90:{start:"!",end:""},ml:{start:"\\(\\*",end:"\\*\\)"},cobol:{start:"\\*>",end:""}},j=Object.keys(x);function g(e,t){const n=e.map((e=>{const{start:n,end:s}=b[e];return`(?:${n}\\s*(${t.flatMap((e=>[e.line,e.block?.start,e.block?.end].filter(Boolean))).join("|")})\\s*${s})`})).join("|");return new RegExp(`^\\s*(?:${n})\\s*$`)}function v(e,t){let n=e.replace(/\n$/,"");const{language:s,magicComments:o,metastring:a}=t;if(a&&f.test(a)){const e=a.match(f).groups.range;if(0===o.length)throw new Error(`A highlight range has been given in code block's metastring (\`\`\` ${a}), but no magic comment config is available. Docusaurus applies the first magic comment entry's className for metastring ranges.`);const t=o[0].className,s=h()(e).filter((e=>e>0)).map((e=>[e-1,[t]]));return{lineClassNames:Object.fromEntries(s),code:n}}if(void 0===s)return{lineClassNames:{},code:n};const c=function(e,t){switch(e){case"js":case"javascript":case"ts":case"typescript":return g(["js","jsBlock"],t);case"jsx":case"tsx":return g(["js","jsBlock","jsx"],t);case"html":return g(["js","jsBlock","html"],t);case"python":case"py":case"bash":return g(["bash"],t);case"markdown":case"md":return g(["html","jsx","bash"],t);case"tex":case"latex":case"matlab":return g(["tex"],t);case"lua":case"haskell":case"sql":return g(["lua"],t);case"wasm":return g(["wasm"],t);case"vb":case"vba":case"visual-basic":return g(["vb","rem"],t);case"vbnet":return g(["vbnet","rem"],t);case"batch":return g(["rem"],t);case"basic":return g(["rem","f90"],t);case"fsharp":return g(["js","ml"],t);case"ocaml":case"sml":return g(["ml"],t);case"fortran":return g(["f90"],t);case"cobol":return g(["cobol"],t);default:return g(j,t)}}(s,o),r=n.split("\n"),i=Object.fromEntries(o.map((e=>[e.className,{start:0,range:""}]))),l=Object.fromEntries(o.filter((e=>e.line)).map((e=>{let{className:t,line:n}=e;return[n,t]}))),d=Object.fromEntries(o.filter((e=>e.block)).map((e=>{let{className:t,block:n}=e;return[n.start,t]}))),u=Object.fromEntries(o.filter((e=>e.block)).map((e=>{let{className:t,block:n}=e;return[n.end,t]})));for(let h=0;h void 0!==e));l[t]?i[l[t]].range+=`${h},`:d[t]?i[d[t]].start=h:u[t]&&(i[u[t]].range+=`${i[u[t]].start}-${h-1},`),r.splice(h,1)}n=r.join("\n");const m={};return Object.entries(i).forEach((e=>{let[t,{range:n}]=e;h()(n).forEach((e=>{m[e]??=[],m[e].push(t)}))})),{lineClassNames:m,code:n}}const y={codeBlockContainer:"codeBlockContainer_Ckt0"};var N=n(4848);function A(e){let{as:t,...n}=e;const s=function(e){const t={color:"--prism-color",backgroundColor:"--prism-background-color"},n={};return Object.entries(e.plain).forEach((e=>{let[s,o]=e;const a=t[s];a&&"string"==typeof o&&(n[a]=o)})),n}(d());return(0,N.jsx)(t,{...n,style:s,className:(0,r.A)(n.className,y.codeBlockContainer,u.G.common.codeBlock)})}const k={codeBlockContent:"codeBlockContent_biex",codeBlockTitle:"codeBlockTitle_Ktv7",codeBlock:"codeBlock_bY9V",codeBlockStandalone:"codeBlockStandalone_MEMb",codeBlockLines:"codeBlockLines_e6Vv",codeBlockLinesWithNumbering:"codeBlockLinesWithNumbering_o6Pm",buttonGroup:"buttonGroup__atx"};function B(e){let{children:t,className:n}=e;return(0,N.jsx)(A,{as:"pre",tabIndex:0,className:(0,r.A)(k.codeBlockStandalone,"thin-scrollbar",n),children:(0,N.jsx)("code",{className:k.codeBlockLines,children:t})})}var w=n(9532);const C={attributes:!0,characterData:!0,childList:!0,subtree:!0};function E(e,t){const[n,o]=(0,s.useState)(),a=(0,s.useCallback)((()=>{o(e.current?.closest("[role=tabpanel][hidden]"))}),[e,o]);(0,s.useEffect)((()=>{a()}),[a]),function(e,t,n){void 0===n&&(n=C);const o=(0,w._q)(t),a=(0,w.Be)(n);(0,s.useEffect)((()=>{const t=new MutationObserver(o);return e&&t.observe(e,a),()=>t.disconnect()}),[e,o,a])}(n,(e=>{e.forEach((e=>{"attributes"===e.type&&"hidden"===e.attributeName&&(t(),a())}))}),{attributes:!0,characterData:!1,childList:!1,subtree:!1})}var L=n(1765);const T={codeLine:"codeLine_lJS_",codeLineNumber:"codeLineNumber_Tfdd",codeLineContent:"codeLineContent_feaV"};function _(e){let{line:t,classNames:n,showLineNumbers:s,getLineProps:o,getTokenProps:a}=e;1===t.length&&"\n"===t[0].content&&(t[0].content="");const c=o({line:t,className:(0,r.A)(n,s&&T.codeLine)}),i=t.map(((e,t)=>(0,N.jsx)("span",{...a({token:e})},t)));return(0,N.jsxs)("span",{...c,children:[s?(0,N.jsxs)(N.Fragment,{children:[(0,N.jsx)("span",{className:T.codeLineNumber}),(0,N.jsx)("span",{className:T.codeLineContent,children:i})]}):i,(0,N.jsx)("br",{})]})}var S=n(1312);function U(e){return(0,N.jsx)("svg",{viewBox:"0 0 24 24",...e,children:(0,N.jsx)("path",{fill:"currentColor",d:"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"})})}function M(e){return(0,N.jsx)("svg",{viewBox:"0 0 24 24",...e,children:(0,N.jsx)("path",{fill:"currentColor",d:"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"})})}const z={copyButtonCopied:"copyButtonCopied_obH4",copyButtonIcons:"copyButtonIcons_eSgA",copyButtonIcon:"copyButtonIcon_y97N",copyButtonSuccessIcon:"copyButtonSuccessIcon_LjdS"};function I(e){let{code:t,className:n}=e;const[o,a]=(0,s.useState)(!1),c=(0,s.useRef)(void 0),i=(0,s.useCallback)((()=>{!function(e,t){let{target:n=document.body}=void 0===t?{}:t;if("string"!=typeof e)throw new TypeError(`Expected parameter \`text\` to be a \`string\`, got \`${typeof e}\`.`);const s=document.createElement("textarea"),o=document.activeElement;s.value=e,s.setAttribute("readonly",""),s.style.contain="strict",s.style.position="absolute",s.style.left="-9999px",s.style.fontSize="12pt";const a=document.getSelection(),c=a.rangeCount>0&&a.getRangeAt(0);n.append(s),s.select(),s.selectionStart=0,s.selectionEnd=e.length;let r=!1;try{r=document.execCommand("copy")}catch{}s.remove(),c&&(a.removeAllRanges(),a.addRange(c)),o&&o.focus()}(t),a(!0),c.current=window.setTimeout((()=>{a(!1)}),1e3)}),[t]);return(0,s.useEffect)((()=>()=>window.clearTimeout(c.current)),[]),(0,N.jsx)("button",{type:"button","aria-label":o?(0,S.T)({id:"theme.CodeBlock.copied",message:"Copied",description:"The copied button label on code blocks"}):(0,S.T)({id:"theme.CodeBlock.copyButtonAriaLabel",message:"Copy code to clipboard",description:"The ARIA label for copy code blocks button"}),title:(0,S.T)({id:"theme.CodeBlock.copy",message:"Copy",description:"The copy button label on code blocks"}),className:(0,r.A)("clean-btn",n,z.copyButton,o&&z.copyButtonCopied),onClick:i,children:(0,N.jsxs)("span",{className:z.copyButtonIcons,"aria-hidden":"true",children:[(0,N.jsx)(U,{className:z.copyButtonIcon}),(0,N.jsx)(M,{className:z.copyButtonSuccessIcon})]})})}function H(e){return(0,N.jsx)("svg",{viewBox:"0 0 24 24",...e,children:(0,N.jsx)("path",{fill:"currentColor",d:"M4 19h6v-2H4v2zM20 5H4v2h16V5zm-3 6H4v2h13.25c1.1 0 2 .9 2 2s-.9 2-2 2H15v-2l-3 3l3 3v-2h2c2.21 0 4-1.79 4-4s-1.79-4-4-4z"})})}const R={wordWrapButtonIcon:"wordWrapButtonIcon_Bwma",wordWrapButtonEnabled:"wordWrapButtonEnabled_EoeP"};function V(e){let{className:t,onClick:n,isEnabled:s}=e;const o=(0,S.T)({id:"theme.CodeBlock.wordWrapToggle",message:"Toggle word wrap",description:"The title attribute for toggle word wrapping button of code block lines"});return(0,N.jsx)("button",{type:"button",onClick:n,className:(0,r.A)("clean-btn",t,s&&R.wordWrapButtonEnabled),"aria-label":o,title:o,children:(0,N.jsx)(H,{className:R.wordWrapButtonIcon,"aria-hidden":"true"})})}function $(e){let{children:t,className:n="",metastring:o,title:a,showLineNumbers:c,language:i}=e;const{prism:{defaultLanguage:u,magicComments:m}}=(0,l.p)(),h=function(e){return e?.toLowerCase()}(i??function(e){const t=e.split(" ").find((e=>e.startsWith("language-")));return t?.replace(/language-/,"")}(n)??u),f=d(),x=function(){const[e,t]=(0,s.useState)(!1),[n,o]=(0,s.useState)(!1),a=(0,s.useRef)(null),c=(0,s.useCallback)((()=>{const n=a.current.querySelector("code");e?n.removeAttribute("style"):(n.style.whiteSpace="pre-wrap",n.style.overflowWrap="anywhere"),t((e=>!e))}),[a,e]),r=(0,s.useCallback)((()=>{const{scrollWidth:e,clientWidth:t}=a.current,n=e>t||a.current.querySelector("code").hasAttribute("style");o(n)}),[a]);return E(a,r),(0,s.useEffect)((()=>{r()}),[e,r]),(0,s.useEffect)((()=>(window.addEventListener("resize",r,{passive:!0}),()=>{window.removeEventListener("resize",r)})),[r]),{codeBlockRef:a,isEnabled:e,isCodeScrollable:n,toggle:c}}(),b=function(e){return e?.match(p)?.groups.title??""}(o)||a,{lineClassNames:j,code:g}=v(t,{metastring:o,language:h,magicComments:m}),y=c??function(e){return Boolean(e?.includes("showLineNumbers"))}(o);return(0,N.jsxs)(A,{as:"div",className:(0,r.A)(n,h&&!n.includes(`language-${h}`)&&`language-${h}`),children:[b&&(0,N.jsx)("div",{className:k.codeBlockTitle,children:b}),(0,N.jsxs)("div",{className:k.codeBlockContent,children:[(0,N.jsx)(L.f4,{theme:f,code:g,language:h??"text",children:e=>{let{className:t,style:n,tokens:s,getLineProps:o,getTokenProps:a}=e;return(0,N.jsx)("pre",{tabIndex:0,ref:x.codeBlockRef,className:(0,r.A)(t,k.codeBlock,"thin-scrollbar"),style:n,children:(0,N.jsx)("code",{className:(0,r.A)(k.codeBlockLines,y&&k.codeBlockLinesWithNumbering),children:s.map(((e,t)=>(0,N.jsx)(_,{line:e,getLineProps:o,getTokenProps:a,classNames:j[t],showLineNumbers:y},t)))})})}}),(0,N.jsxs)("div",{className:k.buttonGroup,children:[(x.isEnabled||x.isCodeScrollable)&&(0,N.jsx)(V,{className:k.codeButton,onClick:()=>x.toggle(),isEnabled:x.isEnabled}),(0,N.jsx)(I,{className:k.codeButton,code:g})]})]})]})}function W(e){let{children:t,...n}=e;const o=(0,c.A)(),a=function(e){return s.Children.toArray(e).some((e=>(0,s.isValidElement)(e)))?e:Array.isArray(e)?e.join(""):e}(t),r="string"==typeof a?$:B;return(0,N.jsx)(r,{...n,children:a},String(o))}function D(e){return(0,N.jsx)("code",{...e})}var P=n(8774);var q=n(3427),G=n(1422);const O={details:"details_lb9f",isBrowser:"isBrowser_bmU9",collapsibleContent:"collapsibleContent_i85q"};function F(e){return!!e&&("SUMMARY"===e.tagName||F(e.parentElement))}function Z(e,t){return!!e&&(e===t||Z(e.parentElement,t))}function J(e){let{summary:t,children:n,...o}=e;(0,q.A)().collectAnchor(o.id);const a=(0,c.A)(),i=(0,s.useRef)(null),{collapsed:l,setCollapsed:d}=(0,G.u)({initialState:!o.open}),[u,m]=(0,s.useState)(o.open),h=s.isValidElement(t)?t:(0,N.jsx)("summary",{children:t??"Details"});return(0,N.jsxs)("details",{...o,ref:i,open:u,"data-collapsed":l,className:(0,r.A)(O.details,a&&O.isBrowser,o.className),onMouseDown:e=>{F(e.target)&&e.detail>1&&e.preventDefault()},onClick:e=>{e.stopPropagation();const t=e.target;F(t)&&Z(t,i.current)&&(e.preventDefault(),l?(d(!1),m(!0)):d(!0))},children:[h,(0,N.jsx)(G.N,{lazy:!1,collapsed:l,disableSSRStyle:!0,onCollapseTransitionEnd:e=>{d(e),m(!e)},children:(0,N.jsx)("div",{className:O.collapsibleContent,children:n})})]})}const Y={details:"details_b_Ee"},K="alert alert--info";function Q(e){let{...t}=e;return(0,N.jsx)(J,{...t,className:(0,r.A)(K,Y.details,t.className)})}function X(e){const t=s.Children.toArray(e.children),n=t.find((e=>s.isValidElement(e)&&"summary"===e.type)),o=(0,N.jsx)(N.Fragment,{children:t.filter((e=>e!==n))});return(0,N.jsx)(Q,{...e,summary:n,children:o})}var ee=n(1107);function te(e){return(0,N.jsx)(ee.A,{...e})}const ne={containsTaskList:"containsTaskList_mC6p"};function se(e){if(void 0!==e)return(0,r.A)(e,e?.includes("contains-task-list")&&ne.containsTaskList)}const oe={img:"img_ev3q"};var ae=n(7293);const ce={Head:a.A,details:X,Details:X,code:function(e){return function(e){return void 0!==e.children&&s.Children.toArray(e.children).every((e=>"string"==typeof e&&!e.includes("\n")))}(e)?(0,N.jsx)(D,{...e}):(0,N.jsx)(W,{...e})},a:function(e){return(0,N.jsx)(P.A,{...e})},pre:function(e){return(0,N.jsx)(N.Fragment,{children:e.children})},ul:function(e){return(0,N.jsx)("ul",{...e,className:se(e.className)})},li:function(e){return(0,q.A)().collectAnchor(e.id),(0,N.jsx)("li",{...e})},img:function(e){return(0,N.jsx)("img",{decoding:"async",loading:"lazy",...e,className:(t=e.className,(0,r.A)(t,oe.img))});var t},h1:e=>(0,N.jsx)(te,{as:"h1",...e}),h2:e=>(0,N.jsx)(te,{as:"h2",...e}),h3:e=>(0,N.jsx)(te,{as:"h3",...e}),h4:e=>(0,N.jsx)(te,{as:"h4",...e}),h5:e=>(0,N.jsx)(te,{as:"h5",...e}),h6:e=>(0,N.jsx)(te,{as:"h6",...e}),admonition:ae.A,mermaid:()=>null};function re(e){let{children:t}=e;return(0,N.jsx)(o.x,{components:ce,children:t})}},6266:(e,t,n)=>{"use strict";n.d(t,{i:()=>o});var s=n(4586);function o(e){void 0===e&&(e={});const{i18n:{currentLocale:t}}=(0,s.A)(),n=function(){const{i18n:{currentLocale:e,localeConfigs:t}}=(0,s.A)();return t[e].calendar}();return new Intl.DateTimeFormat(t,{calendar:n,...e})}},8426:(e,t)=>{function n(e){let t,n=[];for(let s of e.split(",").map((e=>e.trim())))if(/^-?\d+$/.test(s))n.push(parseInt(s,10));else if(t=s.match(/^(-?\d+)(-|\.\.\.?|\u2025|\u2026|\u22EF)(-?\d+)$/)){let[e,s,o,a]=t;if(s&&a){s=parseInt(s),a=parseInt(a);const e=s{"use strict";n.d(t,{R:()=>c,x:()=>r});var s=n(6540);const o={},a=s.createContext(o);function c(e){const t=s.useContext(a);return s.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function r(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(o):e.components||o:c(e.components),s.createElement(a.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/8509.6103d1a5.js b/assets/js/8509.6103d1a5.js deleted file mode 100644 index 5905b135..00000000 --- a/assets/js/8509.6103d1a5.js +++ /dev/null @@ -1 +0,0 @@ -(self.webpackChunkcodec_wiki=self.webpackChunkcodec_wiki||[]).push([[8509],{7293:(e,t,n)=>{"use strict";n.d(t,{A:()=>L});var s=n(6540),o=n(4848);function c(e){const{mdxAdmonitionTitle:t,rest:n}=function(e){const t=s.Children.toArray(e),n=t.find((e=>s.isValidElement(e)&&"mdxAdmonitionTitle"===e.type)),c=t.filter((e=>e!==n)),a=n?.props.children;return{mdxAdmonitionTitle:a,rest:c.length>0?(0,o.jsx)(o.Fragment,{children:c}):null}}(e.children),c=e.title??t;return{...e,...c&&{title:c},children:n}}var a=n(8215),r=n(1312),i=n(7559);const l={admonition:"admonition_xJq3",admonitionHeading:"admonitionHeading_Gvgb",admonitionIcon:"admonitionIcon_Rf37",admonitionContent:"admonitionContent_BuS1"};function d(e){let{type:t,className:n,children:s}=e;return(0,o.jsx)("div",{className:(0,a.A)(i.G.common.admonition,i.G.common.admonitionType(t),l.admonition,n),children:s})}function u(e){let{icon:t,title:n}=e;return(0,o.jsxs)("div",{className:l.admonitionHeading,children:[(0,o.jsx)("span",{className:l.admonitionIcon,children:t}),n]})}function m(e){let{children:t}=e;return t?(0,o.jsx)("div",{className:l.admonitionContent,children:t}):null}function h(e){const{type:t,icon:n,title:s,children:c,className:a}=e;return(0,o.jsxs)(d,{type:t,className:a,children:[(0,o.jsx)(u,{title:s,icon:n}),(0,o.jsx)(m,{children:c})]})}function p(e){return(0,o.jsx)("svg",{viewBox:"0 0 14 16",...e,children:(0,o.jsx)("path",{fillRule:"evenodd",d:"M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"})})}const f={icon:(0,o.jsx)(p,{}),title:(0,o.jsx)(r.A,{id:"theme.admonition.note",description:"The default label used for the Note admonition (:::note)",children:"note"})};function x(e){return(0,o.jsx)(h,{...f,...e,className:(0,a.A)("alert alert--secondary",e.className),children:e.children})}function b(e){return(0,o.jsx)("svg",{viewBox:"0 0 12 16",...e,children:(0,o.jsx)("path",{fillRule:"evenodd",d:"M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"})})}const g={icon:(0,o.jsx)(b,{}),title:(0,o.jsx)(r.A,{id:"theme.admonition.tip",description:"The default label used for the Tip admonition (:::tip)",children:"tip"})};function j(e){return(0,o.jsx)(h,{...g,...e,className:(0,a.A)("alert alert--success",e.className),children:e.children})}function v(e){return(0,o.jsx)("svg",{viewBox:"0 0 14 16",...e,children:(0,o.jsx)("path",{fillRule:"evenodd",d:"M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"})})}const N={icon:(0,o.jsx)(v,{}),title:(0,o.jsx)(r.A,{id:"theme.admonition.info",description:"The default label used for the Info admonition (:::info)",children:"info"})};function y(e){return(0,o.jsx)(h,{...N,...e,className:(0,a.A)("alert alert--info",e.className),children:e.children})}function k(e){return(0,o.jsx)("svg",{viewBox:"0 0 16 16",...e,children:(0,o.jsx)("path",{fillRule:"evenodd",d:"M8.893 1.5c-.183-.31-.52-.5-.887-.5s-.703.19-.886.5L.138 13.499a.98.98 0 0 0 0 1.001c.193.31.53.501.886.501h13.964c.367 0 .704-.19.877-.5a1.03 1.03 0 0 0 .01-1.002L8.893 1.5zm.133 11.497H6.987v-2.003h2.039v2.003zm0-3.004H6.987V5.987h2.039v4.006z"})})}const B={icon:(0,o.jsx)(k,{}),title:(0,o.jsx)(r.A,{id:"theme.admonition.warning",description:"The default label used for the Warning admonition (:::warning)",children:"warning"})};function C(e){return(0,o.jsx)("svg",{viewBox:"0 0 12 16",...e,children:(0,o.jsx)("path",{fillRule:"evenodd",d:"M5.05.31c.81 2.17.41 3.38-.52 4.31C3.55 5.67 1.98 6.45.9 7.98c-1.45 2.05-1.7 6.53 3.53 7.7-2.2-1.16-2.67-4.52-.3-6.61-.61 2.03.53 3.33 1.94 2.86 1.39-.47 2.3.53 2.27 1.67-.02.78-.31 1.44-1.13 1.81 3.42-.59 4.78-3.42 4.78-5.56 0-2.84-2.53-3.22-1.25-5.61-1.52.13-2.03 1.13-1.89 2.75.09 1.08-1.02 1.8-1.86 1.33-.67-.41-.66-1.19-.06-1.78C8.18 5.31 8.68 2.45 5.05.32L5.03.3l.02.01z"})})}const w={icon:(0,o.jsx)(C,{}),title:(0,o.jsx)(r.A,{id:"theme.admonition.danger",description:"The default label used for the Danger admonition (:::danger)",children:"danger"})};const A={icon:(0,o.jsx)(k,{}),title:(0,o.jsx)(r.A,{id:"theme.admonition.caution",description:"The default label used for the Caution admonition (:::caution)",children:"caution"})};const E={...{note:x,tip:j,info:y,warning:function(e){return(0,o.jsx)(h,{...B,...e,className:(0,a.A)("alert alert--warning",e.className),children:e.children})},danger:function(e){return(0,o.jsx)(h,{...w,...e,className:(0,a.A)("alert alert--danger",e.className),children:e.children})}},...{secondary:e=>(0,o.jsx)(x,{title:"secondary",...e}),important:e=>(0,o.jsx)(y,{title:"important",...e}),success:e=>(0,o.jsx)(j,{title:"success",...e}),caution:function(e){return(0,o.jsx)(h,{...A,...e,className:(0,a.A)("alert alert--warning",e.className),children:e.children})}}};function L(e){const t=c(e),n=(s=t.type,E[s]||(console.warn(`No admonition component found for admonition type "${s}". Using Info as fallback.`),E.info));var s;return(0,o.jsx)(n,{...t})}},8509:(e,t,n)=>{"use strict";n.d(t,{A:()=>ie});var s=n(6540),o=n(8453),c=n(5260),a=n(2303),r=n(8215),i=n(5293),l=n(6342);function d(){const{prism:e}=(0,l.p)(),{colorMode:t}=(0,i.G)(),n=e.theme,s=e.darkTheme||n;return"dark"===t?s:n}var u=n(7559),m=n(8426),h=n.n(m);const p=/title=(? ["'])(?.*?)\1/,f=/\{(? [\d,-]+)\}/,x={js:{start:"\\/\\/",end:""},jsBlock:{start:"\\/\\*",end:"\\*\\/"},jsx:{start:"\\{\\s*\\/\\*",end:"\\*\\/\\s*\\}"},bash:{start:"#",end:""},html:{start:"\x3c!--",end:"--\x3e"}},b={...x,lua:{start:"--",end:""},wasm:{start:"\\;\\;",end:""},tex:{start:"%",end:""},vb:{start:"['\u2018\u2019]",end:""},vbnet:{start:"(?:_\\s*)?['\u2018\u2019]",end:""},rem:{start:"[Rr][Ee][Mm]\\b",end:""},f90:{start:"!",end:""},ml:{start:"\\(\\*",end:"\\*\\)"},cobol:{start:"\\*>",end:""}},g=Object.keys(x);function j(e,t){const n=e.map((e=>{const{start:n,end:s}=b[e];return`(?:${n}\\s*(${t.flatMap((e=>[e.line,e.block?.start,e.block?.end].filter(Boolean))).join("|")})\\s*${s})`})).join("|");return new RegExp(`^\\s*(?:${n})\\s*$`)}function v(e,t){let n=e.replace(/\n$/,"");const{language:s,magicComments:o,metastring:c}=t;if(c&&f.test(c)){const e=c.match(f).groups.range;if(0===o.length)throw new Error(`A highlight range has been given in code block's metastring (\`\`\` ${c}), but no magic comment config is available. Docusaurus applies the first magic comment entry's className for metastring ranges.`);const t=o[0].className,s=h()(e).filter((e=>e>0)).map((e=>[e-1,[t]]));return{lineClassNames:Object.fromEntries(s),code:n}}if(void 0===s)return{lineClassNames:{},code:n};const a=function(e,t){switch(e){case"js":case"javascript":case"ts":case"typescript":return j(["js","jsBlock"],t);case"jsx":case"tsx":return j(["js","jsBlock","jsx"],t);case"html":return j(["js","jsBlock","html"],t);case"python":case"py":case"bash":return j(["bash"],t);case"markdown":case"md":return j(["html","jsx","bash"],t);case"tex":case"latex":case"matlab":return j(["tex"],t);case"lua":case"haskell":case"sql":return j(["lua"],t);case"wasm":return j(["wasm"],t);case"vb":case"vba":case"visual-basic":return j(["vb","rem"],t);case"vbnet":return j(["vbnet","rem"],t);case"batch":return j(["rem"],t);case"basic":return j(["rem","f90"],t);case"fsharp":return j(["js","ml"],t);case"ocaml":case"sml":return j(["ml"],t);case"fortran":return j(["f90"],t);case"cobol":return j(["cobol"],t);default:return j(g,t)}}(s,o),r=n.split("\n"),i=Object.fromEntries(o.map((e=>[e.className,{start:0,range:""}]))),l=Object.fromEntries(o.filter((e=>e.line)).map((e=>{let{className:t,line:n}=e;return[n,t]}))),d=Object.fromEntries(o.filter((e=>e.block)).map((e=>{let{className:t,block:n}=e;return[n.start,t]}))),u=Object.fromEntries(o.filter((e=>e.block)).map((e=>{let{className:t,block:n}=e;return[n.end,t]})));for(let h=0;h void 0!==e));l[t]?i[l[t]].range+=`${h},`:d[t]?i[d[t]].start=h:u[t]&&(i[u[t]].range+=`${i[u[t]].start}-${h-1},`),r.splice(h,1)}n=r.join("\n");const m={};return Object.entries(i).forEach((e=>{let[t,{range:n}]=e;h()(n).forEach((e=>{m[e]??=[],m[e].push(t)}))})),{lineClassNames:m,code:n}}const N={codeBlockContainer:"codeBlockContainer_Ckt0"};var y=n(4848);function k(e){let{as:t,...n}=e;const s=function(e){const t={color:"--prism-color",backgroundColor:"--prism-background-color"},n={};return Object.entries(e.plain).forEach((e=>{let[s,o]=e;const c=t[s];c&&"string"==typeof o&&(n[c]=o)})),n}(d());return(0,y.jsx)(t,{...n,style:s,className:(0,r.A)(n.className,N.codeBlockContainer,u.G.common.codeBlock)})}const B={codeBlockContent:"codeBlockContent_biex",codeBlockTitle:"codeBlockTitle_Ktv7",codeBlock:"codeBlock_bY9V",codeBlockStandalone:"codeBlockStandalone_MEMb",codeBlockLines:"codeBlockLines_e6Vv",codeBlockLinesWithNumbering:"codeBlockLinesWithNumbering_o6Pm",buttonGroup:"buttonGroup__atx"};function C(e){let{children:t,className:n}=e;return(0,y.jsx)(k,{as:"pre",tabIndex:0,className:(0,r.A)(B.codeBlockStandalone,"thin-scrollbar",n),children:(0,y.jsx)("code",{className:B.codeBlockLines,children:t})})}var w=n(9532);const A={attributes:!0,characterData:!0,childList:!0,subtree:!0};function E(e,t){const[n,o]=(0,s.useState)(),c=(0,s.useCallback)((()=>{o(e.current?.closest("[role=tabpanel][hidden]"))}),[e,o]);(0,s.useEffect)((()=>{c()}),[c]),function(e,t,n){void 0===n&&(n=A);const o=(0,w._q)(t),c=(0,w.Be)(n);(0,s.useEffect)((()=>{const t=new MutationObserver(o);return e&&t.observe(e,c),()=>t.disconnect()}),[e,o,c])}(n,(e=>{e.forEach((e=>{"attributes"===e.type&&"hidden"===e.attributeName&&(t(),c())}))}),{attributes:!0,characterData:!1,childList:!1,subtree:!1})}var L=n(8181);const T={codeLine:"codeLine_lJS_",codeLineNumber:"codeLineNumber_Tfdd",codeLineContent:"codeLineContent_feaV"};function _(e){let{line:t,classNames:n,showLineNumbers:s,getLineProps:o,getTokenProps:c}=e;1===t.length&&"\n"===t[0].content&&(t[0].content="");const a=o({line:t,className:(0,r.A)(n,s&&T.codeLine)}),i=t.map(((e,t)=>(0,y.jsx)("span",{...c({token:e,key:t})},t)));return(0,y.jsxs)("span",{...a,children:[s?(0,y.jsxs)(y.Fragment,{children:[(0,y.jsx)("span",{className:T.codeLineNumber}),(0,y.jsx)("span",{className:T.codeLineContent,children:i})]}):i,(0,y.jsx)("br",{})]})}var S=n(1312);function M(e){return(0,y.jsx)("svg",{viewBox:"0 0 24 24",...e,children:(0,y.jsx)("path",{fill:"currentColor",d:"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"})})}function z(e){return(0,y.jsx)("svg",{viewBox:"0 0 24 24",...e,children:(0,y.jsx)("path",{fill:"currentColor",d:"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"})})}const H={copyButtonCopied:"copyButtonCopied_obH4",copyButtonIcons:"copyButtonIcons_eSgA",copyButtonIcon:"copyButtonIcon_y97N",copyButtonSuccessIcon:"copyButtonSuccessIcon_LjdS"};function I(e){let{code:t,className:n}=e;const[o,c]=(0,s.useState)(!1),a=(0,s.useRef)(void 0),i=(0,s.useCallback)((()=>{!function(e,t){let{target:n=document.body}=void 0===t?{}:t;if("string"!=typeof e)throw new TypeError(`Expected parameter \`text\` to be a \`string\`, got \`${typeof e}\`.`);const s=document.createElement("textarea"),o=document.activeElement;s.value=e,s.setAttribute("readonly",""),s.style.contain="strict",s.style.position="absolute",s.style.left="-9999px",s.style.fontSize="12pt";const c=document.getSelection(),a=c.rangeCount>0&&c.getRangeAt(0);n.append(s),s.select(),s.selectionStart=0,s.selectionEnd=e.length;let r=!1;try{r=document.execCommand("copy")}catch{}s.remove(),a&&(c.removeAllRanges(),c.addRange(a)),o&&o.focus()}(t),c(!0),a.current=window.setTimeout((()=>{c(!1)}),1e3)}),[t]);return(0,s.useEffect)((()=>()=>window.clearTimeout(a.current)),[]),(0,y.jsx)("button",{type:"button","aria-label":o?(0,S.T)({id:"theme.CodeBlock.copied",message:"Copied",description:"The copied button label on code blocks"}):(0,S.T)({id:"theme.CodeBlock.copyButtonAriaLabel",message:"Copy code to clipboard",description:"The ARIA label for copy code blocks button"}),title:(0,S.T)({id:"theme.CodeBlock.copy",message:"Copy",description:"The copy button label on code blocks"}),className:(0,r.A)("clean-btn",n,H.copyButton,o&&H.copyButtonCopied),onClick:i,children:(0,y.jsxs)("span",{className:H.copyButtonIcons,"aria-hidden":"true",children:[(0,y.jsx)(M,{className:H.copyButtonIcon}),(0,y.jsx)(z,{className:H.copyButtonSuccessIcon})]})})}function R(e){return(0,y.jsx)("svg",{viewBox:"0 0 24 24",...e,children:(0,y.jsx)("path",{fill:"currentColor",d:"M4 19h6v-2H4v2zM20 5H4v2h16V5zm-3 6H4v2h13.25c1.1 0 2 .9 2 2s-.9 2-2 2H15v-2l-3 3l3 3v-2h2c2.21 0 4-1.79 4-4s-1.79-4-4-4z"})})}const V={wordWrapButtonIcon:"wordWrapButtonIcon_Bwma",wordWrapButtonEnabled:"wordWrapButtonEnabled_EoeP"};function $(e){let{className:t,onClick:n,isEnabled:s}=e;const o=(0,S.T)({id:"theme.CodeBlock.wordWrapToggle",message:"Toggle word wrap",description:"The title attribute for toggle word wrapping button of code block lines"});return(0,y.jsx)("button",{type:"button",onClick:n,className:(0,r.A)("clean-btn",t,s&&V.wordWrapButtonEnabled),"aria-label":o,title:o,children:(0,y.jsx)(R,{className:V.wordWrapButtonIcon,"aria-hidden":"true"})})}function W(e){let{children:t,className:n="",metastring:o,title:c,showLineNumbers:a,language:i}=e;const{prism:{defaultLanguage:u,magicComments:m}}=(0,l.p)(),h=function(e){return e?.toLowerCase()}(i??function(e){const t=e.split(" ").find((e=>e.startsWith("language-")));return t?.replace(/language-/,"")}(n)??u),f=d(),x=function(){const[e,t]=(0,s.useState)(!1),[n,o]=(0,s.useState)(!1),c=(0,s.useRef)(null),a=(0,s.useCallback)((()=>{const n=c.current.querySelector("code");e?n.removeAttribute("style"):(n.style.whiteSpace="pre-wrap",n.style.overflowWrap="anywhere"),t((e=>!e))}),[c,e]),r=(0,s.useCallback)((()=>{const{scrollWidth:e,clientWidth:t}=c.current,n=e>t||c.current.querySelector("code").hasAttribute("style");o(n)}),[c]);return E(c,r),(0,s.useEffect)((()=>{r()}),[e,r]),(0,s.useEffect)((()=>(window.addEventListener("resize",r,{passive:!0}),()=>{window.removeEventListener("resize",r)})),[r]),{codeBlockRef:c,isEnabled:e,isCodeScrollable:n,toggle:a}}(),b=function(e){return e?.match(p)?.groups.title??""}(o)||c,{lineClassNames:g,code:j}=v(t,{metastring:o,language:h,magicComments:m}),N=a??function(e){return Boolean(e?.includes("showLineNumbers"))}(o);return(0,y.jsxs)(k,{as:"div",className:(0,r.A)(n,h&&!n.includes(`language-${h}`)&&`language-${h}`),children:[b&&(0,y.jsx)("div",{className:B.codeBlockTitle,children:b}),(0,y.jsxs)("div",{className:B.codeBlockContent,children:[(0,y.jsx)(L.f4,{theme:f,code:j,language:h??"text",children:e=>{let{className:t,style:n,tokens:s,getLineProps:o,getTokenProps:c}=e;return(0,y.jsx)("pre",{tabIndex:0,ref:x.codeBlockRef,className:(0,r.A)(t,B.codeBlock,"thin-scrollbar"),style:n,children:(0,y.jsx)("code",{className:(0,r.A)(B.codeBlockLines,N&&B.codeBlockLinesWithNumbering),children:s.map(((e,t)=>(0,y.jsx)(_,{line:e,getLineProps:o,getTokenProps:c,classNames:g[t],showLineNumbers:N},t)))})})}}),(0,y.jsxs)("div",{className:B.buttonGroup,children:[(x.isEnabled||x.isCodeScrollable)&&(0,y.jsx)($,{className:B.codeButton,onClick:()=>x.toggle(),isEnabled:x.isEnabled}),(0,y.jsx)(I,{className:B.codeButton,code:j})]})]})]})}function P(e){let{children:t,...n}=e;const o=(0,a.A)(),c=function(e){return s.Children.toArray(e).some((e=>(0,s.isValidElement)(e)))?e:Array.isArray(e)?e.join(""):e}(t),r="string"==typeof c?W:C;return(0,y.jsx)(r,{...n,children:c},String(o))}function D(e){return(0,y.jsx)("code",{...e})}var O=n(8774);var q=n(5066),G=n(3427),F=n(1422);const U={details:"details_lb9f",isBrowser:"isBrowser_bmU9",collapsibleContent:"collapsibleContent_i85q"};function J(e){return!!e&&("SUMMARY"===e.tagName||J(e.parentElement))}function Y(e,t){return!!e&&(e===t||Y(e.parentElement,t))}function Z(e){let{summary:t,children:n,...o}=e;(0,G.A)().collectAnchor(o.id);const c=(0,a.A)(),r=(0,s.useRef)(null),{collapsed:i,setCollapsed:l}=(0,F.u)({initialState:!o.open}),[d,u]=(0,s.useState)(o.open),m=s.isValidElement(t)?t:(0,y.jsx)("summary",{children:t??"Details"});return(0,y.jsxs)("details",{...o,ref:r,open:d,"data-collapsed":i,className:(0,q.A)(U.details,c&&U.isBrowser,o.className),onMouseDown:e=>{J(e.target)&&e.detail>1&&e.preventDefault()},onClick:e=>{e.stopPropagation();const t=e.target;J(t)&&Y(t,r.current)&&(e.preventDefault(),i?(l(!1),u(!0)):l(!0))},children:[m,(0,y.jsx)(F.N,{lazy:!1,collapsed:i,disableSSRStyle:!0,onCollapseTransitionEnd:e=>{l(e),u(!e)},children:(0,y.jsx)("div",{className:U.collapsibleContent,children:n})})]})}const K={details:"details_b_Ee"},Q="alert alert--info";function X(e){let{...t}=e;return(0,y.jsx)(Z,{...t,className:(0,r.A)(Q,K.details,t.className)})}function ee(e){const t=s.Children.toArray(e.children),n=t.find((e=>s.isValidElement(e)&&"summary"===e.type)),o=(0,y.jsx)(y.Fragment,{children:t.filter((e=>e!==n))});return(0,y.jsx)(X,{...e,summary:n,children:o})}var te=n(1107);function ne(e){return(0,y.jsx)(te.A,{...e})}const se={containsTaskList:"containsTaskList_mC6p"};function oe(e){if(void 0!==e)return(0,r.A)(e,e?.includes("contains-task-list")&&se.containsTaskList)}const ce={img:"img_ev3q"};var ae=n(7293);const re={Head:c.A,details:ee,Details:ee,code:function(e){return function(e){return void 0!==e.children&&s.Children.toArray(e.children).every((e=>"string"==typeof e&&!e.includes("\n")))}(e)?(0,y.jsx)(D,{...e}):(0,y.jsx)(P,{...e})},a:function(e){return(0,y.jsx)(O.A,{...e})},pre:function(e){return(0,y.jsx)(y.Fragment,{children:e.children})},ul:function(e){return(0,y.jsx)("ul",{...e,className:oe(e.className)})},li:function(e){return(0,G.A)().collectAnchor(e.id),(0,y.jsx)("li",{...e})},img:function(e){return(0,y.jsx)("img",{decoding:"async",loading:"lazy",...e,className:(t=e.className,(0,r.A)(t,ce.img))});var t},h1:e=>(0,y.jsx)(ne,{as:"h1",...e}),h2:e=>(0,y.jsx)(ne,{as:"h2",...e}),h3:e=>(0,y.jsx)(ne,{as:"h3",...e}),h4:e=>(0,y.jsx)(ne,{as:"h4",...e}),h5:e=>(0,y.jsx)(ne,{as:"h5",...e}),h6:e=>(0,y.jsx)(ne,{as:"h6",...e}),admonition:ae.A,mermaid:()=>null};function ie(e){let{children:t}=e;return(0,y.jsx)(o.x,{components:re,children:t})}},8426:(e,t)=>{function n(e){let t,n=[];for(let s of e.split(",").map((e=>e.trim())))if(/^-?\d+$/.test(s))n.push(parseInt(s,10));else if(t=s.match(/^(-?\d+)(-|\.\.\.?|\u2025|\u2026|\u22EF)(-?\d+)$/)){let[e,s,o,c]=t;if(s&&c){s=parseInt(s),c=parseInt(c);const e=s {"use strict";n.d(t,{R:()=>a,x:()=>r});var s=n(6540);const o={},c=s.createContext(o);function a(e){const t=s.useContext(c);return s.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function r(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(o):e.components||o:a(e.components),s.createElement(c.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/8eb2df80.d33c5d69.js b/assets/js/8eb2df80.b753f579.js similarity index 99% rename from assets/js/8eb2df80.d33c5d69.js rename to assets/js/8eb2df80.b753f579.js index 1e12b7bf..ab447114 100644 --- a/assets/js/8eb2df80.d33c5d69.js +++ b/assets/js/8eb2df80.b753f579.js @@ -1 +1 @@ -"use strict";(self.webpackChunkcodec_wiki=self.webpackChunkcodec_wiki||[]).push([[7796],{4582:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>l,contentTitle:()=>a,default:()=>u,frontMatter:()=>r,metadata:()=>o,toc:()=>c});var i=t(4848),s=t(8453);t(1470),t(9365);const r={title:"rav1ator-cli",sidebar_position:6,templating:!0},a="rAV1ator CLI",o={id:"utilities/rav1ator-cli",title:"rav1ator-cli",description:"rAV1ator CLI, or just rav1ator-cli, is a TUI tool that provides an interactive command line interface for encoding videos with Av1an using various different encoders including rav1e, aomenc (specifically aom-av1-lavish, as mentioned in the aomenc page), SVT-AV1, x265, and x264.",source:"@site/docs/utilities/rav1ator-cli.mdx",sourceDirName:"utilities",slug:"/utilities/rav1ator-cli",permalink:"/docs/utilities/rav1ator-cli",draft:!1,unlisted:!1,editUrl:"https://github.com/av1-community-contributors/codec-wiki/tree/main/docs/utilities/rav1ator-cli.mdx",tags:[],version:"current",sidebarPosition:6,frontMatter:{title:"rav1ator-cli",sidebar_position:6,templating:!0},sidebar:"tutorialSidebar",previous:{title:"rAV1ator",permalink:"/docs/utilities/rAV1ator"},next:{title:"NMKODER",permalink:"/docs/utilities/nmkoder"}},l={},c=[{value:"Installation",id:"installation",level:2},{value:"Linux (Arch)",id:"linux-arch",level:2},{value:"Linux (Other)",id:"linux-other",level:2},{value:"Windows",id:"windows",level:2},{value:"Basic installtion",id:"basic-installtion",level:3},{value:"Optional: Cleanup of the Ubuntu Distribution",id:"optional-cleanup-of-the-ubuntu-distribution",level:3},{value:"After the Installation and Cleanup, How Do I Start Arch?",id:"after-the-installation-and-cleanup-how-do-i-start-arch",level:3},{value:"Unlock WSL RAM Usage (Optional)",id:"unlock-wsl-ram-usage-optional",level:3},{value:"macOS",id:"macos",level:2},{value:"Troubleshooting",id:"troubleshooting",level:3}];function h(e){const n={a:"a",admonition:"admonition",br:"br",code:"code",em:"em",h1:"h1",h2:"h2",h3:"h3",img:"img",li:"li",ol:"ol",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,s.R)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(n.h1,{id:"rav1ator-cli",children:"rAV1ator CLI"}),"\n",(0,i.jsxs)(n.p,{children:["rAV1ator CLI, or just ",(0,i.jsx)(n.code,{children:"rav1ator-cli"}),", is a TUI tool that provides an interactive command line interface for encoding videos with ",(0,i.jsx)(n.a,{href:"/docs/utilities/av1an",children:"Av1an"})," using various different encoders including ",(0,i.jsx)(n.a,{href:"/docs/encoders/rav1e",children:"rav1e"}),", ",(0,i.jsx)(n.a,{href:"/docs/encoders/aomenc",children:"aomenc"})," (specifically aom-av1-lavish, as mentioned in the aomenc page), ",(0,i.jsx)(n.a,{href:"/docs/encoders/SVT-AV1",children:"SVT-AV1"}),", ",(0,i.jsx)(n.a,{href:"/docs/encoders/x265",children:"x265"}),", and ",(0,i.jsx)(n.a,{href:"/docs/encoders/x264",children:"x264"}),"."]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:'~ > rav1ator-cli -h\nrAV1ator: CLI Edition_ v0.2.0\n\nUsage:\n\trav1ator-cli [input] [output] [--offline]\n\nDependencies (Arch): \n\trust ffmpeg python mkvtoolnix-cli vapoursynth gum numactl l-smash vapoursynth-plugin-lsmashsource av1an ffms2\n\nOptions: (Currently, only one option is useful at a time)\n\t-h, --help\t\t\tPrint this help section\n\t-l, --last-used\t\tPrint last used encode settings from history\n\t-f, --full-history\tPrint full history from ".rav1ator-cli-history" file\n\t-b, --binaries\t\tJust install binaries, then exit\n\t-x, --offline\t\tDon\'t check for updates.\n\t-a, --batch\t\t\tBatch encode. All video files in a directory specified after this flag are encoded.\n'})}),"\n",(0,i.jsx)(n.p,{children:"rAV1ator CLI can:"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsx)(n.p,{children:"Check if it is installed & up to date on its own without a package manager"}),"\n"]}),"\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsx)(n.p,{children:"Download AVX2-optimized encoder binaries compiled with -O3 -flto in most cases & allow the user to install them with detailed instructions"}),"\n"]}),"\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsx)(n.p,{children:"Remember encoding history and let you view your whole history or your most recent command"}),"\n"]}),"\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsx)(n.p,{children:"Allow you to encode an entire directory of video files with the same settings"}),"\n"]}),"\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsx)(n.p,{children:"Encode with x264, x265, aomenc, SVT-AV1, or rav1e, set a speed preset, CRF/quality value, FFmpeg parameters, and encoder parameters"}),"\n"]}),"\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsx)(n.p,{children:"Generate Av1an encoding commands with the user's chosen settings & run them to encode a provided input video to an MKV output."}),"\n"]}),"\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsx)(n.p,{children:"Encode from scratch, or resume a previous rAV1ator CLI encode"}),"\n"]}),"\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsx)(n.p,{children:"Engage with rich interactivity features like spinners, prompts, & dropdowns"}),"\n"]}),"\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsx)(n.p,{children:"Automatically error check binaries with SHA256 hashes for security & convenience"}),"\n"]}),"\n"]}),"\n",(0,i.jsx)(n.p,{children:"Overall, it aims to provide an easy way to encode videos on the command line with helpful visual feedback. The interactive prompts help users pick encoding settings without needing deep encoding knowledge."}),"\n",(0,i.jsx)("img",{width:"640",height:"360",src:"https://raw.githubusercontent.com/av1-community-contributors/images/main/rav1ator_cli_demo1.avif",alt:"rAV1ator-cli: Demo 1"}),"\n",(0,i.jsx)("img",{width:"640",height:"360",src:"https://raw.githubusercontent.com/av1-community-contributors/images/main/rav1ator_cli_demo2.avif",alt:"rAV1ator-cli: Demo 2"}),"\n",(0,i.jsx)(n.h2,{id:"installation",children:"Installation"}),"\n",(0,i.jsx)(n.p,{children:"rAV1ator CLI is natively supported on Linux, & is supported on Windows via WSL2. A tutorial for setting up WSL2 is provided below. macOS is not supported."}),"\n",(0,i.jsx)(n.h2,{id:"linux-arch",children:"Linux (Arch)"}),"\n",(0,i.jsxs)(n.p,{children:["These instructions are for Arch Linux specifically. Other distros should be very similar, and packages that are Arch-specific will be labelled. If you're on Ubuntu, you should see the relevant section of the ",(0,i.jsx)(n.a,{href:"https://wiki.x266.mov/blog/av1-encoding-for-dummies",children:"AV1 for Dummies"})," blog post on this site."]}),"\n",(0,i.jsxs)(n.p,{children:["If you're on another distro and you want to be able to follow these instructions specifically, see the ",(0,i.jsx)(n.a,{href:"#linux-other",children:"Linux (Other)"})," section."]}),"\n",(0,i.jsxs)(n.ol,{start:"0",children:["\n",(0,i.jsx)(n.li,{children:"Update your system before doing anything. On Arch:"}),"\n"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:"sudo pacman -Syu\n"})}),"\n",(0,i.jsxs)(n.ol,{children:["\n",(0,i.jsxs)(n.li,{children:["Install ",(0,i.jsx)(n.code,{children:"yay"})," (Arch only) by running the following commands:"]}),"\n"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:"sudo pacman -S --needed base-devel git\ngit clone https://aur.archlinux.org/yay.git\ncd yay && makepkg -si\n"})}),"\n",(0,i.jsxs)(n.ol,{start:"2",children:["\n",(0,i.jsx)(n.li,{children:"Next, you'll want to install all of rav1ator-cli's dependencies. You can do that by running:"}),"\n"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:"yay -Syu openssl ffmpeg python mkvtoolnix-cli vapoursynth gum numactl l-smash vapoursynth-plugin-lsmashsource av1an ffms2\n"})}),"\n",(0,i.jsxs)(n.ol,{start:"3",children:["\n",(0,i.jsx)(n.li,{children:"Install rav1ator-cli:"}),"\n"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:"curl -sOJ https://raw.githubusercontent.com/gianni-rosato/rav1ator-cli/main/rav1ator-cli && chmod +x rav1ator-cli\nsudo cp rav1ator-cli /usr/local/bin\n"})}),"\n",(0,i.jsxs)(n.p,{children:["You're done! Run ",(0,i.jsx)(n.code,{children:"rav1ator-cli -h"})," to get some help getting started. Happy encoding!"]}),"\n",(0,i.jsx)(n.h2,{id:"linux-other",children:"Linux (Other)"}),"\n",(0,i.jsxs)(n.p,{children:["If you're on Ubuntu, you can see the relevant section of the ",(0,i.jsx)(n.a,{href:"https://wiki.x266.mov/blog/av1-encoding-for-dummies",children:"AV1 for Dummies"})," blog post on this site for more information about doing this ",(0,i.jsx)(n.em,{children:"without"})," a distrobox. However, a distrobox is valuable because you can use Arch's fast-paced package management on other distros. Distroboxes are generally easier than Docker for beginners, and use Docker or Podman behind the scenes anyway. This tutorial will focus on using Distrobox with Podman."]}),"\n",(0,i.jsxs)(n.ol,{start:"0",children:["\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsx)(n.p,{children:"Install Distrobox and Podman on your distro of choice. Please look up how to do this for your respective distro, and how to get everything set up properly."}),"\n"]}),"\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsxs)(n.p,{children:["If you already use Podman, are re-creating a Distrobox, or you already have other Distroboxes running from long enough ago where your Arch image is outdated, you might want to run ",(0,i.jsx)(n.code,{children:"podman image rm docker.io/archlinux/archlinux:latest"}),". It won't hurt to run it anyway if you're not sure. ",(0,i.jsx)(n.strong,{children:"Do this every time you make a new Distrobox if you're experiencing issues with Distrobox creation"}),"."]}),"\n"]}),"\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsxs)(n.p,{children:["Now, run ",(0,i.jsx)(n.code,{children:"distrobox-create --name rvcli-box --image archlinux:latest"}),". You do not need to name yours \"rvcli-box\", but that's what we're going to call the box in this tutorial."]}),"\n"]}),"\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsxs)(n.p,{children:[(0,i.jsx)(n.code,{children:"distrobox enter rvcli-box"})," to go inside. You are now using Arch Linux from within your existing distro!"]}),"\n"]}),"\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsxs)(n.p,{children:["First, run ",(0,i.jsx)(n.code,{children:"sudo pacman -Syu"})," to update your system."]}),"\n"]}),"\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsxs)(n.p,{children:["Next, run ",(0,i.jsx)(n.code,{children:"sudo pacman -S --needed base-devel git && git clone https://aur.archlinux.org/yay.git && cd yay && makepkg -si"}),"."]}),"\n"]}),"\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsxs)(n.p,{children:["Finally, ",(0,i.jsx)(n.code,{children:"yay -Syu openssl ffmpeg python mkvtoolnix-cli vapoursynth gum numactl l-smash vapoursynth-plugin-lsmashsource av1an ffms2"})," to install the necessary dependencies."]}),"\n"]}),"\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsxs)(n.p,{children:["Download rav1ator-cli: ",(0,i.jsx)(n.code,{children:"curl -sOJ https://raw.githubusercontent.com/gianni-rosato/rav1ator-cli/main/rav1ator-cli && chmod +x rav1ator-cli"})]}),"\n"]}),"\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsxs)(n.p,{children:["Copy rav1ator-cli to your /usr/local/bin: ",(0,i.jsx)(n.code,{children:"sudo cp rav1ator-cli /usr/local/bin"})]}),"\n"]}),"\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsxs)(n.p,{children:["If you'd like to exit the distrobox, just do ",(0,i.jsx)(n.code,{children:"Ctrl"})," + ",(0,i.jsx)(n.code,{children:"D"}),"."]}),"\n"]}),"\n"]}),"\n",(0,i.jsxs)(n.p,{children:["You're done! Run ",(0,i.jsx)(n.code,{children:"rav1ator-cli -h"})," to get some help getting started. Happy encoding!"]}),"\n",(0,i.jsx)(n.h2,{id:"windows",children:"Windows"}),"\n",(0,i.jsx)(n.admonition,{title:"Windows",type:"note",children:(0,i.jsxs)(n.p,{children:["The content in this entry was written by pat-e, or ",(0,i.jsx)(n.code,{children:"pate"})," on Discord. This tutorial focuses on Windows 11."]})}),"\n",(0,i.jsxs)(n.p,{children:[(0,i.jsx)(n.strong,{children:'Enable WSL2 on Windows 11 and Install "ArchWSL2"'})," by pat-e"]}),"\n",(0,i.jsx)(n.h3,{id:"basic-installtion",children:"Basic installtion"}),"\n",(0,i.jsxs)(n.ol,{children:["\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsxs)(n.p,{children:["Open the Terminal as Administrator:",(0,i.jsx)(n.br,{}),"\n",(0,i.jsx)(n.img,{src:"https://raw.githubusercontent.com/av1-community-contributors/images/main/01_wsl_rv-cli.avif",alt:""})]}),"\n"]}),"\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsx)(n.p,{children:"In the Command-Prompt, enter the following to install WSL and (temporary) Ubuntu:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-pwsh",children:"wsl.exe --install\n"})}),"\n",(0,i.jsx)(n.p,{children:(0,i.jsx)(n.img,{src:"https://raw.githubusercontent.com/av1-community-contributors/images/main/02_wsl_rv-cli.avifg",alt:""})}),"\n",(0,i.jsxs)(n.p,{children:['If the "Host Process for Windows Services" asks for allowing changes, approve it (Press "Yes"):',(0,i.jsx)(n.br,{}),"\n",(0,i.jsx)(n.img,{src:"https://raw.githubusercontent.com/av1-community-contributors/images/main/03_wsl_rv-cli.avif",alt:""})]}),"\n"]}),"\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsx)(n.p,{children:"Once the installation of WSL (and Ubuntu as Default) is finished, restart your Computer:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-pwsh",children:"shutdown -r -f -t 1\n"})}),"\n",(0,i.jsx)(n.p,{children:(0,i.jsx)(n.img,{src:"https://raw.githubusercontent.com/av1-community-contributors/images/main/04_wsl_rv-cli.avif",alt:""})}),"\n"]}),"\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsxs)(n.p,{children:["Once restarted and logged in, WSL will start with Ubuntu and ask for Username and password. Enter whatever you want as this distribution will be removed after the switch to ArchWSL2. Just exit after the Ubuntu is setup:",(0,i.jsx)(n.br,{}),"\n",(0,i.jsx)(n.img,{src:"https://raw.githubusercontent.com/av1-community-contributors/images/main/05_wsl_rv-cli.avif",alt:""})]}),"\n"]}),"\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsxs)(n.p,{children:["From ",(0,i.jsx)(n.a,{href:"https://github.com/sileshn/ArchWSL2",children:"This GitHub link"}),", download the latest release of ArchWSL2 in the Releases section:",(0,i.jsx)(n.br,{}),"\n",(0,i.jsx)(n.img,{src:"https://raw.githubusercontent.com/av1-community-contributors/images/main/06_wsl_rv-cli.avif",alt:""})]}),"\n"]}),"\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsxs)(n.p,{children:["On your SSD, create a folder where we will place the ArchWSL2 files. This folder ",(0,i.jsx)(n.strong,{children:"must be kept and never deleted"})," as this will contain the base files for this distribution. It is advised to use an SSD instead of an HDD. The storage must be local storage, not a network-share or a removable disk. In our example, we will create a folder located at C:\\Stuff\\ArchWSL2;",(0,i.jsx)(n.br,{}),"\n",(0,i.jsx)(n.img,{src:"https://raw.githubusercontent.com/av1-community-contributors/images/main/07_wsl_rv-cli.avif",alt:""})]}),"\n",(0,i.jsx)(n.p,{children:(0,i.jsx)(n.img,{src:"https://raw.githubusercontent.com/av1-community-contributors/images/main/08_wsl_rv-cli.avif",alt:""})}),"\n"]}),"\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsx)(n.p,{children:'Extract the downloaded ZIP of "ArchWSL2" into your newly created folder:'}),"\n",(0,i.jsx)(n.p,{children:(0,i.jsx)(n.img,{src:"https://raw.githubusercontent.com/av1-community-contributors/images/main/09_wsl_rv-cli.avif",alt:""})}),"\n"]}),"\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsx)(n.p,{children:'Once extracted, start the extracted "Arch.exe":'}),"\n",(0,i.jsx)(n.p,{children:(0,i.jsx)(n.img,{src:"https://raw.githubusercontent.com/av1-community-contributors/images/main/10_wsl_rv-cli.avif",alt:""})}),"\n"]}),"\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsx)(n.p,{children:'On first start, the program will create a virtual disk (VHDx). Once finished, press "Enter" to continue (it will close the window)'}),"\n",(0,i.jsx)(n.p,{children:(0,i.jsx)(n.img,{src:"https://raw.githubusercontent.com/av1-community-contributors/images/main/11_wsl_rv-cli.avif",alt:""})}),"\n"]}),"\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsxs)(n.p,{children:['Once the virtual hard disk is created, restart the "arch.exe" again. It will finish some steps and ask for creating a new user-account. ',(0,i.jsx)(n.strong,{children:"This account is completely separate from your Windows user."})," Please remember the username and password you use."]}),"\n"]}),"\n"]}),"\n",(0,i.jsx)(n.p,{children:(0,i.jsx)(n.img,{src:"https://raw.githubusercontent.com/av1-community-contributors/images/main/12_wsl_rv-cli.avif",alt:""})}),"\n",(0,i.jsx)(n.p,{children:(0,i.jsx)(n.img,{src:"https://raw.githubusercontent.com/av1-community-contributors/images/main/13_wsl_rv-cli.avif",alt:""})}),"\n",(0,i.jsxs)(n.ol,{start:"11",children:["\n",(0,i.jsx)(n.li,{children:"The Window will close and reopen again. As fist step, update all packages. As your account you created earlier is in the sudo-group, you have to enter your password again as confirmation."}),"\n"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:"sudo pacman -Syu\n"})}),"\n",(0,i.jsx)(n.p,{children:(0,i.jsx)(n.img,{src:"https://raw.githubusercontent.com/av1-community-contributors/images/main/14_wsl_rv-cli.avif",alt:""})}),"\n",(0,i.jsxs)(n.ol,{start:"12",children:["\n",(0,i.jsx)(n.li,{children:'Approve the installation of all the updates (Type "y"):'}),"\n"]}),"\n",(0,i.jsx)(n.p,{children:(0,i.jsx)(n.img,{src:"https://raw.githubusercontent.com/av1-community-contributors/images/main/15_wsl_rv-cli.avif",alt:""})}),"\n",(0,i.jsxs)(n.ol,{start:"13",children:["\n",(0,i.jsx)(n.li,{children:"Done... You can now use ArchWSL2."}),"\n"]}),"\n",(0,i.jsx)(n.h3,{id:"optional-cleanup-of-the-ubuntu-distribution",children:"Optional: Cleanup of the Ubuntu Distribution"}),"\n",(0,i.jsxs)(n.ol,{children:["\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsx)(n.p,{children:"Open the terminal as Administrator, like we did earlier."}),"\n",(0,i.jsx)(n.p,{children:(0,i.jsx)(n.img,{src:"https://raw.githubusercontent.com/av1-community-contributors/images/main/16_wsl_rv-cli.avif",alt:""})}),"\n"]}),"\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsx)(n.p,{children:"Check the current installed distributions:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-pwsh",children:"wsl --list\n"})}),"\n",(0,i.jsx)(n.p,{children:(0,i.jsx)(n.img,{src:"https://raw.githubusercontent.com/av1-community-contributors/images/main/17_wsl_rv-cli.avif",alt:""})}),"\n"]}),"\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsx)(n.p,{children:'To remove "Ubuntu" (and therefor make Arch as default), enter the following command:'}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-pwsh",children:"wsl --unregister ubuntu\n"})}),"\n",(0,i.jsx)(n.p,{children:(0,i.jsx)(n.img,{src:"https://raw.githubusercontent.com/av1-community-contributors/images/main/18_wsl_rv-cli.avif",alt:""})}),"\n"]}),"\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsx)(n.p,{children:'After the removal of Ubuntu, we can list the distributions again and verify that "Arch" is now the default:'}),"\n",(0,i.jsx)(n.p,{children:(0,i.jsx)(n.img,{src:"https://raw.githubusercontent.com/av1-community-contributors/images/main/19_wsl_rv-cli.avif",alt:""})}),"\n"]}),"\n"]}),"\n",(0,i.jsx)(n.h3,{id:"after-the-installation-and-cleanup-how-do-i-start-arch",children:"After the Installation and Cleanup, How Do I Start Arch?"}),"\n",(0,i.jsx)(n.p,{children:"For the start of Arch, there are 2 steps possible:"}),"\n",(0,i.jsxs)(n.ol,{children:["\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsx)(n.p,{children:'You can just start "wsl" form the command prompt, terminal or "Windows Search":'}),"\n",(0,i.jsx)(n.p,{children:(0,i.jsx)(n.img,{src:"https://raw.githubusercontent.com/av1-community-contributors/images/main/20_wsl_rv-cli.avif",alt:""})}),"\n",(0,i.jsx)(n.p,{children:(0,i.jsx)(n.img,{src:"https://raw.githubusercontent.com/av1-community-contributors/images/main/21_wsl_rv-cli.avif",alt:""})}),"\n"]}),"\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsx)(n.p,{children:'As another option, you can create a Shortcut to the "arch.exe" in the Installation-Folder:'}),"\n",(0,i.jsx)(n.p,{children:(0,i.jsx)(n.img,{src:"https://raw.githubusercontent.com/av1-community-contributors/images/main/22_wsl_rv-cli.avif",alt:""})}),"\n",(0,i.jsx)(n.p,{children:(0,i.jsx)(n.img,{src:"https://raw.githubusercontent.com/av1-community-contributors/images/main/23_wsl_rv-cli.avif",alt:""})}),"\n",(0,i.jsx)(n.p,{children:(0,i.jsx)(n.img,{src:"https://raw.githubusercontent.com/av1-community-contributors/images/main/24_wsl_rv-cli.avif",alt:""})}),"\n"]}),"\n"]}),"\n",(0,i.jsxs)(n.p,{children:[(0,i.jsx)(n.strong,{children:"Hint"}),': When you open the "arch.exe", you will be placed into the directory where also the "arch.exe" is located. To change to your home directory, just enter the command below:']}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:"cd ~\n"})}),"\n",(0,i.jsx)(n.p,{children:(0,i.jsx)(n.img,{src:"https://raw.githubusercontent.com/av1-community-contributors/images/main/25_wsl_rv-cli.avif",alt:""})}),"\n",(0,i.jsx)(n.h3,{id:"unlock-wsl-ram-usage-optional",children:"Unlock WSL RAM Usage (Optional)"}),"\n",(0,i.jsxs)(n.p,{children:[(0,i.jsx)(n.strong,{children:"Hint"}),": WSL caps RAM usage at 50% of the total RAM available on your system."]}),"\n",(0,i.jsx)(n.p,{children:"When you start the VM, you will see that you only will only have 50% of your total memory available:"}),"\n",(0,i.jsx)(n.p,{children:(0,i.jsx)(n.img,{src:"https://raw.githubusercontent.com/av1-community-contributors/images/main/26_wsl_rv-cli.avif",alt:""})}),"\n",(0,i.jsx)(n.p,{children:"To allow more memory, you need to place a config-file in your profile-folder in Windows. See the instructions below:"}),"\n",(0,i.jsxs)(n.ol,{children:["\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsx)(n.p,{children:'Open "notepad.exe" and enter the following:'}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-txt",children:"[wsl2]\nmemory=12GB\n"})}),"\n",(0,i.jsx)(n.p,{children:(0,i.jsx)(n.img,{src:"https://raw.githubusercontent.com/av1-community-contributors/images/main/27_wsl_rv-cli.avif",alt:""})}),"\n"]}),"\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsx)(n.p,{children:"The amount of memory should never be more than current memory. Set it to total memory minus 4GB to leave enough left over for Windows. In my example, Windows has 16GB of RAM available, so I select the memory to be 12GB."}),"\n"]}),"\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsx)(n.p,{children:"When saving the file, enter the following as filename:"}),"\n",(0,i.jsx)(n.p,{children:(0,i.jsx)(n.code,{children:"%userprofile%"})}),"\n",(0,i.jsx)(n.p,{children:(0,i.jsx)(n.img,{src:"https://raw.githubusercontent.com/av1-community-contributors/images/main/28_wsl_rv-cli.avif",alt:""})}),"\n"]}),"\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsx)(n.p,{children:"When pressing enter, the directory will switch to your user-profile folder:"}),"\n",(0,i.jsx)(n.p,{children:(0,i.jsx)(n.img,{src:"https://raw.githubusercontent.com/av1-community-contributors/images/main/29_wsl_rv-cli.avif",alt:""})}),"\n"]}),"\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsx)(n.p,{children:'Select the "Save as type" to "All files (*.*)" and save as the following filename:'}),"\n",(0,i.jsx)(n.p,{children:(0,i.jsx)(n.code,{children:".wslconfig"})}),"\n",(0,i.jsx)(n.p,{children:(0,i.jsx)(n.img,{src:"https://raw.githubusercontent.com/av1-community-contributors/images/main/30_wsl_rv-cli.avif",alt:""})}),"\n",(0,i.jsxs)(n.p,{children:["Make sure the file is saved as ",(0,i.jsx)(n.code,{children:".wslconfig"}),". Then exit notepad."]}),"\n"]}),"\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsx)(n.p,{children:"Exit any current running WSL / Arch (exit):"}),"\n",(0,i.jsx)(n.p,{children:(0,i.jsx)(n.img,{src:"https://raw.githubusercontent.com/av1-community-contributors/images/main/31_wsl_rv-cli.avif",alt:""})}),"\n"]}),"\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsx)(n.p,{children:'Open the Terminal as Administrator and "shutdown" any running WSL:'}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-pwsh",children:"wsl --shutdown\n"})}),"\n",(0,i.jsx)(n.p,{children:(0,i.jsx)(n.img,{src:"https://raw.githubusercontent.com/av1-community-contributors/images/main/32_wsl_rv-cli.avif",alt:""})}),"\n"]}),"\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsx)(n.p,{children:"Restart WSL again and check the memory settings from within Arch by running the following command:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:"free -h\n"})}),"\n",(0,i.jsx)(n.p,{children:(0,i.jsx)(n.img,{src:"https://raw.githubusercontent.com/av1-community-contributors/images/main/33_wsl_rv-cli.avif",alt:""})}),"\n"]}),"\n"]}),"\n",(0,i.jsx)(n.p,{children:"If you've made it this far, you should be more than ready to encode. We hope you enjoy rAV1ator CLI!"}),"\n",(0,i.jsx)(n.h2,{id:"macos",children:"macOS"}),"\n",(0,i.jsx)(n.p,{children:"No macOS support is provided at this time. It is definitely technically feasible, and I may produce a separate tool in the future with proper macOS binaries, though this would be a burden to keep up considering I don't currently see any demand for a port."}),"\n",(0,i.jsx)(n.h3,{id:"troubleshooting",children:"Troubleshooting"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:["If your encode features a grey screen flashing occaisonally in the output, create a lossless intermediary of your source with x264 ",(0,i.jsx)(n.code,{children:"-qp 0"}),". This happens because of VC-1 decoding errors, and is not something I can fix."]}),"\n",(0,i.jsxs)(n.li,{children:["If you have any more questions, please join the ",(0,i.jsx)(n.a,{href:"https://discord.gg/bbQD5MjDr3",children:"AV1 for Dummies Discord server"}),". There is a rAV1ator CLI channel over there, and I am always happy to talk!"]}),"\n"]})]})}function u(e={}){const{wrapper:n}={...(0,s.R)(),...e.components};return n?(0,i.jsx)(n,{...e,children:(0,i.jsx)(h,{...e})}):h(e)}},9365:(e,n,t)=>{t.d(n,{A:()=>a});t(6540);var i=t(8215);const s={tabItem:"tabItem_Ymn6"};var r=t(4848);function a(e){let{children:n,hidden:t,className:a}=e;return(0,r.jsx)("div",{role:"tabpanel",className:(0,i.A)(s.tabItem,a),hidden:t,children:n})}},1470:(e,n,t)=>{t.d(n,{A:()=>y});var i=t(6540),s=t(8215),r=t(3104),a=t(6347),o=t(205),l=t(7485),c=t(1682),h=t(9466);function u(e){return i.Children.toArray(e).filter((e=>"\n"!==e)).map((e=>{if(!e||(0,i.isValidElement)(e)&&function(e){const{props:n}=e;return!!n&&"object"==typeof n&&"value"in n}(e))return e;throw new Error(`Docusaurus error: Bad child <${"string"==typeof e.type?e.type:e.type.name}>: all children of the component should be , and every should have a unique "value" prop.`)}))?.filter(Boolean)??[]}function d(e){const{values:n,children:t}=e;return(0,i.useMemo)((()=>{const e=n??function(e){return u(e).map((e=>{let{props:{value:n,label:t,attributes:i,default:s}}=e;return{value:n,label:t,attributes:i,default:s}}))}(t);return function(e){const n=(0,c.X)(e,((e,n)=>e.value===n.value));if(n.length>0)throw new Error(`Docusaurus error: Duplicate values "${n.map((e=>e.value)).join(", ")}" found in . Every value needs to be unique.`)}(e),e}),[n,t])}function m(e){let{value:n,tabValues:t}=e;return t.some((e=>e.value===n))}function p(e){let{queryString:n=!1,groupId:t}=e;const s=(0,a.W6)(),r=function(e){let{queryString:n=!1,groupId:t}=e;if("string"==typeof n)return n;if(!1===n)return null;if(!0===n&&!t)throw new Error('Docusaurus error: The component groupId prop is required if queryString=true, because this value is used as the search param name. You can also provide an explicit value such as queryString="my-search-param".');return t??null}({queryString:n,groupId:t});return[(0,l.aZ)(r),(0,i.useCallback)((e=>{if(!r)return;const n=new URLSearchParams(s.location.search);n.set(r,e),s.replace({...s.location,search:n.toString()})}),[r,s])]}function x(e){const{defaultValue:n,queryString:t=!1,groupId:s}=e,r=d(e),[a,l]=(0,i.useState)((()=>function(e){let{defaultValue:n,tabValues:t}=e;if(0===t.length)throw new Error("Docusaurus error: the component requires at least one children component");if(n){if(!m({value:n,tabValues:t}))throw new Error(`Docusaurus error: The has a defaultValue "${n}" but none of its children has the corresponding value. Available values are: ${t.map((e=>e.value)).join(", ")}. If you intend to show no default tab, use defaultValue={null} instead.`);return n}const i=t.find((e=>e.default))??t[0];if(!i)throw new Error("Unexpected error: 0 tabValues");return i.value}({defaultValue:n,tabValues:r}))),[c,u]=p({queryString:t,groupId:s}),[x,g]=function(e){let{groupId:n}=e;const t=function(e){return e?`docusaurus.tab.${e}`:null}(n),[s,r]=(0,h.Dv)(t);return[s,(0,i.useCallback)((e=>{t&&r.set(e)}),[t,r])]}({groupId:s}),v=(()=>{const e=c??x;return m({value:e,tabValues:r})?e:null})();(0,o.A)((()=>{v&&l(v)}),[v]);return{selectedValue:a,selectValue:(0,i.useCallback)((e=>{if(!m({value:e,tabValues:r}))throw new Error(`Can't select invalid tab value=${e}`);l(e),u(e),g(e)}),[u,g,r]),tabValues:r}}var g=t(2303);const v={tabList:"tabList__CuJ",tabItem:"tabItem_LNqP"};var j=t(4848);function f(e){let{className:n,block:t,selectedValue:i,selectValue:a,tabValues:o}=e;const l=[],{blockElementScrollPositionUntilNextRender:c}=(0,r.a_)(),h=e=>{const n=e.currentTarget,t=l.indexOf(n),s=o[t].value;s!==i&&(c(n),a(s))},u=e=>{let n=null;switch(e.key){case"Enter":h(e);break;case"ArrowRight":{const t=l.indexOf(e.currentTarget)+1;n=l[t]??l[0];break}case"ArrowLeft":{const t=l.indexOf(e.currentTarget)-1;n=l[t]??l[l.length-1];break}}n?.focus()};return(0,j.jsx)("ul",{role:"tablist","aria-orientation":"horizontal",className:(0,s.A)("tabs",{"tabs--block":t},n),children:o.map((e=>{let{value:n,label:t,attributes:r}=e;return(0,j.jsx)("li",{role:"tab",tabIndex:i===n?0:-1,"aria-selected":i===n,ref:e=>l.push(e),onKeyDown:u,onClick:h,...r,className:(0,s.A)("tabs__item",v.tabItem,r?.className,{"tabs__item--active":i===n}),children:t??n},n)}))})}function b(e){let{lazy:n,children:t,selectedValue:s}=e;const r=(Array.isArray(t)?t:[t]).filter(Boolean);if(n){const e=r.find((e=>e.props.value===s));return e?(0,i.cloneElement)(e,{className:"margin-top--md"}):null}return(0,j.jsx)("div",{className:"margin-top--md",children:r.map(((e,n)=>(0,i.cloneElement)(e,{key:n,hidden:e.props.value!==s})))})}function w(e){const n=x(e);return(0,j.jsxs)("div",{className:(0,s.A)("tabs-container",v.tabList),children:[(0,j.jsx)(f,{...e,...n}),(0,j.jsx)(b,{...e,...n})]})}function y(e){const n=(0,g.A)();return(0,j.jsx)(w,{...e,children:u(e.children)},String(n))}},8453:(e,n,t)=>{t.d(n,{R:()=>a,x:()=>o});var i=t(6540);const s={},r=i.createContext(s);function a(e){const n=i.useContext(r);return i.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function o(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:a(e.components),i.createElement(r.Provider,{value:n},e.children)}}}]); \ No newline at end of file +"use strict";(self.webpackChunkcodec_wiki=self.webpackChunkcodec_wiki||[]).push([[7796],{4582:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>l,contentTitle:()=>a,default:()=>u,frontMatter:()=>r,metadata:()=>o,toc:()=>c});var i=t(4848),s=t(8453);t(1470),t(9365);const r={title:"rav1ator-cli",sidebar_position:6,templating:!0},a="rAV1ator CLI",o={id:"utilities/rav1ator-cli",title:"rav1ator-cli",description:"rAV1ator CLI, or just rav1ator-cli, is a TUI tool that provides an interactive command line interface for encoding videos with Av1an using various different encoders including rav1e, aomenc (specifically aom-av1-lavish, as mentioned in the aomenc page), SVT-AV1, x265, and x264.",source:"@site/docs/utilities/rav1ator-cli.mdx",sourceDirName:"utilities",slug:"/utilities/rav1ator-cli",permalink:"/docs/utilities/rav1ator-cli",draft:!1,unlisted:!1,editUrl:"https://github.com/av1-community-contributors/codec-wiki/tree/main/docs/utilities/rav1ator-cli.mdx",tags:[],version:"current",sidebarPosition:6,frontMatter:{title:"rav1ator-cli",sidebar_position:6,templating:!0},sidebar:"tutorialSidebar",previous:{title:"rAV1ator",permalink:"/docs/utilities/rAV1ator"},next:{title:"NMKODER",permalink:"/docs/utilities/nmkoder"}},l={},c=[{value:"Installation",id:"installation",level:2},{value:"Linux (Arch)",id:"linux-arch",level:2},{value:"Linux (Other)",id:"linux-other",level:2},{value:"Windows",id:"windows",level:2},{value:"Basic installtion",id:"basic-installtion",level:3},{value:"Optional: Cleanup of the Ubuntu Distribution",id:"optional-cleanup-of-the-ubuntu-distribution",level:3},{value:"After the Installation and Cleanup, How Do I Start Arch?",id:"after-the-installation-and-cleanup-how-do-i-start-arch",level:3},{value:"Unlock WSL RAM Usage (Optional)",id:"unlock-wsl-ram-usage-optional",level:3},{value:"macOS",id:"macos",level:2},{value:"Troubleshooting",id:"troubleshooting",level:3}];function h(e){const n={a:"a",admonition:"admonition",br:"br",code:"code",em:"em",h1:"h1",h2:"h2",h3:"h3",img:"img",li:"li",ol:"ol",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,s.R)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(n.h1,{id:"rav1ator-cli",children:"rAV1ator CLI"}),"\n",(0,i.jsxs)(n.p,{children:["rAV1ator CLI, or just ",(0,i.jsx)(n.code,{children:"rav1ator-cli"}),", is a TUI tool that provides an interactive command line interface for encoding videos with ",(0,i.jsx)(n.a,{href:"/docs/utilities/av1an",children:"Av1an"})," using various different encoders including ",(0,i.jsx)(n.a,{href:"/docs/encoders/rav1e",children:"rav1e"}),", ",(0,i.jsx)(n.a,{href:"/docs/encoders/aomenc",children:"aomenc"})," (specifically aom-av1-lavish, as mentioned in the aomenc page), ",(0,i.jsx)(n.a,{href:"/docs/encoders/SVT-AV1",children:"SVT-AV1"}),", ",(0,i.jsx)(n.a,{href:"/docs/encoders/x265",children:"x265"}),", and ",(0,i.jsx)(n.a,{href:"/docs/encoders/x264",children:"x264"}),"."]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:'~ > rav1ator-cli -h\nrAV1ator: CLI Edition_ v0.2.0\n\nUsage:\n\trav1ator-cli [input] [output] [--offline]\n\nDependencies (Arch): \n\trust ffmpeg python mkvtoolnix-cli vapoursynth gum numactl l-smash vapoursynth-plugin-lsmashsource av1an ffms2\n\nOptions: (Currently, only one option is useful at a time)\n\t-h, --help\t\t\tPrint this help section\n\t-l, --last-used\t\tPrint last used encode settings from history\n\t-f, --full-history\tPrint full history from ".rav1ator-cli-history" file\n\t-b, --binaries\t\tJust install binaries, then exit\n\t-x, --offline\t\tDon\'t check for updates.\n\t-a, --batch\t\t\tBatch encode. All video files in a directory specified after this flag are encoded.\n'})}),"\n",(0,i.jsx)(n.p,{children:"rAV1ator CLI can:"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsx)(n.p,{children:"Check if it is installed & up to date on its own without a package manager"}),"\n"]}),"\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsx)(n.p,{children:"Download AVX2-optimized encoder binaries compiled with -O3 -flto in most cases & allow the user to install them with detailed instructions"}),"\n"]}),"\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsx)(n.p,{children:"Remember encoding history and let you view your whole history or your most recent command"}),"\n"]}),"\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsx)(n.p,{children:"Allow you to encode an entire directory of video files with the same settings"}),"\n"]}),"\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsx)(n.p,{children:"Encode with x264, x265, aomenc, SVT-AV1, or rav1e, set a speed preset, CRF/quality value, FFmpeg parameters, and encoder parameters"}),"\n"]}),"\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsx)(n.p,{children:"Generate Av1an encoding commands with the user's chosen settings & run them to encode a provided input video to an MKV output."}),"\n"]}),"\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsx)(n.p,{children:"Encode from scratch, or resume a previous rAV1ator CLI encode"}),"\n"]}),"\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsx)(n.p,{children:"Engage with rich interactivity features like spinners, prompts, & dropdowns"}),"\n"]}),"\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsx)(n.p,{children:"Automatically error check binaries with SHA256 hashes for security & convenience"}),"\n"]}),"\n"]}),"\n",(0,i.jsx)(n.p,{children:"Overall, it aims to provide an easy way to encode videos on the command line with helpful visual feedback. The interactive prompts help users pick encoding settings without needing deep encoding knowledge."}),"\n",(0,i.jsx)("img",{width:"640",height:"360",src:"https://raw.githubusercontent.com/av1-community-contributors/images/main/rav1ator_cli_demo1.avif",alt:"rAV1ator-cli: Demo 1"}),"\n",(0,i.jsx)("img",{width:"640",height:"360",src:"https://raw.githubusercontent.com/av1-community-contributors/images/main/rav1ator_cli_demo2.avif",alt:"rAV1ator-cli: Demo 2"}),"\n",(0,i.jsx)(n.h2,{id:"installation",children:"Installation"}),"\n",(0,i.jsx)(n.p,{children:"rAV1ator CLI is natively supported on Linux, & is supported on Windows via WSL2. A tutorial for setting up WSL2 is provided below. macOS is not supported."}),"\n",(0,i.jsx)(n.h2,{id:"linux-arch",children:"Linux (Arch)"}),"\n",(0,i.jsxs)(n.p,{children:["These instructions are for Arch Linux specifically. Other distros should be very similar, and packages that are Arch-specific will be labelled. If you're on Ubuntu, you should see the relevant section of the ",(0,i.jsx)(n.a,{href:"https://wiki.x266.mov/blog/av1-encoding-for-dummies",children:"AV1 for Dummies"})," blog post on this site."]}),"\n",(0,i.jsxs)(n.p,{children:["If you're on another distro and you want to be able to follow these instructions specifically, see the ",(0,i.jsx)(n.a,{href:"#linux-other",children:"Linux (Other)"})," section."]}),"\n",(0,i.jsxs)(n.ol,{start:"0",children:["\n",(0,i.jsx)(n.li,{children:"Update your system before doing anything. On Arch:"}),"\n"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:"sudo pacman -Syu\n"})}),"\n",(0,i.jsxs)(n.ol,{children:["\n",(0,i.jsxs)(n.li,{children:["Install ",(0,i.jsx)(n.code,{children:"yay"})," (Arch only) by running the following commands:"]}),"\n"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:"sudo pacman -S --needed base-devel git\ngit clone https://aur.archlinux.org/yay.git\ncd yay && makepkg -si\n"})}),"\n",(0,i.jsxs)(n.ol,{start:"2",children:["\n",(0,i.jsx)(n.li,{children:"Next, you'll want to install all of rav1ator-cli's dependencies. You can do that by running:"}),"\n"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:"yay -Syu openssl ffmpeg python mkvtoolnix-cli vapoursynth gum numactl l-smash vapoursynth-plugin-lsmashsource av1an ffms2\n"})}),"\n",(0,i.jsxs)(n.ol,{start:"3",children:["\n",(0,i.jsx)(n.li,{children:"Install rav1ator-cli:"}),"\n"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:"curl -sOJ https://raw.githubusercontent.com/gianni-rosato/rav1ator-cli/main/rav1ator-cli && chmod +x rav1ator-cli\nsudo cp rav1ator-cli /usr/local/bin\n"})}),"\n",(0,i.jsxs)(n.p,{children:["You're done! Run ",(0,i.jsx)(n.code,{children:"rav1ator-cli -h"})," to get some help getting started. Happy encoding!"]}),"\n",(0,i.jsx)(n.h2,{id:"linux-other",children:"Linux (Other)"}),"\n",(0,i.jsxs)(n.p,{children:["If you're on Ubuntu, you can see the relevant section of the ",(0,i.jsx)(n.a,{href:"https://wiki.x266.mov/blog/av1-encoding-for-dummies",children:"AV1 for Dummies"})," blog post on this site for more information about doing this ",(0,i.jsx)(n.em,{children:"without"})," a distrobox. However, a distrobox is valuable because you can use Arch's fast-paced package management on other distros. Distroboxes are generally easier than Docker for beginners, and use Docker or Podman behind the scenes anyway. This tutorial will focus on using Distrobox with Podman."]}),"\n",(0,i.jsxs)(n.ol,{start:"0",children:["\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsx)(n.p,{children:"Install Distrobox and Podman on your distro of choice. Please look up how to do this for your respective distro, and how to get everything set up properly."}),"\n"]}),"\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsxs)(n.p,{children:["If you already use Podman, are re-creating a Distrobox, or you already have other Distroboxes running from long enough ago where your Arch image is outdated, you might want to run ",(0,i.jsx)(n.code,{children:"podman image rm docker.io/archlinux/archlinux:latest"}),". It won't hurt to run it anyway if you're not sure. ",(0,i.jsx)(n.strong,{children:"Do this every time you make a new Distrobox if you're experiencing issues with Distrobox creation"}),"."]}),"\n"]}),"\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsxs)(n.p,{children:["Now, run ",(0,i.jsx)(n.code,{children:"distrobox-create --name rvcli-box --image archlinux:latest"}),". You do not need to name yours \"rvcli-box\", but that's what we're going to call the box in this tutorial."]}),"\n"]}),"\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsxs)(n.p,{children:[(0,i.jsx)(n.code,{children:"distrobox enter rvcli-box"})," to go inside. You are now using Arch Linux from within your existing distro!"]}),"\n"]}),"\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsxs)(n.p,{children:["First, run ",(0,i.jsx)(n.code,{children:"sudo pacman -Syu"})," to update your system."]}),"\n"]}),"\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsxs)(n.p,{children:["Next, run ",(0,i.jsx)(n.code,{children:"sudo pacman -S --needed base-devel git && git clone https://aur.archlinux.org/yay.git && cd yay && makepkg -si"}),"."]}),"\n"]}),"\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsxs)(n.p,{children:["Finally, ",(0,i.jsx)(n.code,{children:"yay -Syu openssl ffmpeg python mkvtoolnix-cli vapoursynth gum numactl l-smash vapoursynth-plugin-lsmashsource av1an ffms2"})," to install the necessary dependencies."]}),"\n"]}),"\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsxs)(n.p,{children:["Download rav1ator-cli: ",(0,i.jsx)(n.code,{children:"curl -sOJ https://raw.githubusercontent.com/gianni-rosato/rav1ator-cli/main/rav1ator-cli && chmod +x rav1ator-cli"})]}),"\n"]}),"\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsxs)(n.p,{children:["Copy rav1ator-cli to your /usr/local/bin: ",(0,i.jsx)(n.code,{children:"sudo cp rav1ator-cli /usr/local/bin"})]}),"\n"]}),"\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsxs)(n.p,{children:["If you'd like to exit the distrobox, just do ",(0,i.jsx)(n.code,{children:"Ctrl"})," + ",(0,i.jsx)(n.code,{children:"D"}),"."]}),"\n"]}),"\n"]}),"\n",(0,i.jsxs)(n.p,{children:["You're done! Run ",(0,i.jsx)(n.code,{children:"rav1ator-cli -h"})," to get some help getting started. Happy encoding!"]}),"\n",(0,i.jsx)(n.h2,{id:"windows",children:"Windows"}),"\n",(0,i.jsx)(n.admonition,{title:"Windows",type:"note",children:(0,i.jsxs)(n.p,{children:["The content in this entry was written by pat-e, or ",(0,i.jsx)(n.code,{children:"pate"})," on Discord. This tutorial focuses on Windows 11."]})}),"\n",(0,i.jsxs)(n.p,{children:[(0,i.jsx)(n.strong,{children:'Enable WSL2 on Windows 11 and Install "ArchWSL2"'})," by pat-e"]}),"\n",(0,i.jsx)(n.h3,{id:"basic-installtion",children:"Basic installtion"}),"\n",(0,i.jsxs)(n.ol,{children:["\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsxs)(n.p,{children:["Open the Terminal as Administrator:",(0,i.jsx)(n.br,{}),"\n",(0,i.jsx)(n.img,{src:"https://raw.githubusercontent.com/av1-community-contributors/images/main/01_wsl_rv-cli.avif",alt:""})]}),"\n"]}),"\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsx)(n.p,{children:"In the Command-Prompt, enter the following to install WSL and (temporary) Ubuntu:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-pwsh",children:"wsl.exe --install\n"})}),"\n",(0,i.jsx)(n.p,{children:(0,i.jsx)(n.img,{src:"https://raw.githubusercontent.com/av1-community-contributors/images/main/02_wsl_rv-cli.avifg",alt:""})}),"\n",(0,i.jsxs)(n.p,{children:['If the "Host Process for Windows Services" asks for allowing changes, approve it (Press "Yes"):',(0,i.jsx)(n.br,{}),"\n",(0,i.jsx)(n.img,{src:"https://raw.githubusercontent.com/av1-community-contributors/images/main/03_wsl_rv-cli.avif",alt:""})]}),"\n"]}),"\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsx)(n.p,{children:"Once the installation of WSL (and Ubuntu as Default) is finished, restart your Computer:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-pwsh",children:"shutdown -r -f -t 1\n"})}),"\n",(0,i.jsx)(n.p,{children:(0,i.jsx)(n.img,{src:"https://raw.githubusercontent.com/av1-community-contributors/images/main/04_wsl_rv-cli.avif",alt:""})}),"\n"]}),"\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsxs)(n.p,{children:["Once restarted and logged in, WSL will start with Ubuntu and ask for Username and password. Enter whatever you want as this distribution will be removed after the switch to ArchWSL2. Just exit after the Ubuntu is setup:",(0,i.jsx)(n.br,{}),"\n",(0,i.jsx)(n.img,{src:"https://raw.githubusercontent.com/av1-community-contributors/images/main/05_wsl_rv-cli.avif",alt:""})]}),"\n"]}),"\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsxs)(n.p,{children:["From ",(0,i.jsx)(n.a,{href:"https://github.com/sileshn/ArchWSL2",children:"This GitHub link"}),", download the latest release of ArchWSL2 in the Releases section:",(0,i.jsx)(n.br,{}),"\n",(0,i.jsx)(n.img,{src:"https://raw.githubusercontent.com/av1-community-contributors/images/main/06_wsl_rv-cli.avif",alt:""})]}),"\n"]}),"\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsxs)(n.p,{children:["On your SSD, create a folder where we will place the ArchWSL2 files. This folder ",(0,i.jsx)(n.strong,{children:"must be kept and never deleted"})," as this will contain the base files for this distribution. It is advised to use an SSD instead of an HDD. The storage must be local storage, not a network-share or a removable disk. In our example, we will create a folder located at C:\\Stuff\\ArchWSL2;",(0,i.jsx)(n.br,{}),"\n",(0,i.jsx)(n.img,{src:"https://raw.githubusercontent.com/av1-community-contributors/images/main/07_wsl_rv-cli.avif",alt:""})]}),"\n",(0,i.jsx)(n.p,{children:(0,i.jsx)(n.img,{src:"https://raw.githubusercontent.com/av1-community-contributors/images/main/08_wsl_rv-cli.avif",alt:""})}),"\n"]}),"\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsx)(n.p,{children:'Extract the downloaded ZIP of "ArchWSL2" into your newly created folder:'}),"\n",(0,i.jsx)(n.p,{children:(0,i.jsx)(n.img,{src:"https://raw.githubusercontent.com/av1-community-contributors/images/main/09_wsl_rv-cli.avif",alt:""})}),"\n"]}),"\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsx)(n.p,{children:'Once extracted, start the extracted "Arch.exe":'}),"\n",(0,i.jsx)(n.p,{children:(0,i.jsx)(n.img,{src:"https://raw.githubusercontent.com/av1-community-contributors/images/main/10_wsl_rv-cli.avif",alt:""})}),"\n"]}),"\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsx)(n.p,{children:'On first start, the program will create a virtual disk (VHDx). Once finished, press "Enter" to continue (it will close the window)'}),"\n",(0,i.jsx)(n.p,{children:(0,i.jsx)(n.img,{src:"https://raw.githubusercontent.com/av1-community-contributors/images/main/11_wsl_rv-cli.avif",alt:""})}),"\n"]}),"\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsxs)(n.p,{children:['Once the virtual hard disk is created, restart the "arch.exe" again. It will finish some steps and ask for creating a new user-account. ',(0,i.jsx)(n.strong,{children:"This account is completely separate from your Windows user."})," Please remember the username and password you use."]}),"\n"]}),"\n"]}),"\n",(0,i.jsx)(n.p,{children:(0,i.jsx)(n.img,{src:"https://raw.githubusercontent.com/av1-community-contributors/images/main/12_wsl_rv-cli.avif",alt:""})}),"\n",(0,i.jsx)(n.p,{children:(0,i.jsx)(n.img,{src:"https://raw.githubusercontent.com/av1-community-contributors/images/main/13_wsl_rv-cli.avif",alt:""})}),"\n",(0,i.jsxs)(n.ol,{start:"11",children:["\n",(0,i.jsx)(n.li,{children:"The Window will close and reopen again. As fist step, update all packages. As your account you created earlier is in the sudo-group, you have to enter your password again as confirmation."}),"\n"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:"sudo pacman -Syu\n"})}),"\n",(0,i.jsx)(n.p,{children:(0,i.jsx)(n.img,{src:"https://raw.githubusercontent.com/av1-community-contributors/images/main/14_wsl_rv-cli.avif",alt:""})}),"\n",(0,i.jsxs)(n.ol,{start:"12",children:["\n",(0,i.jsx)(n.li,{children:'Approve the installation of all the updates (Type "y"):'}),"\n"]}),"\n",(0,i.jsx)(n.p,{children:(0,i.jsx)(n.img,{src:"https://raw.githubusercontent.com/av1-community-contributors/images/main/15_wsl_rv-cli.avif",alt:""})}),"\n",(0,i.jsxs)(n.ol,{start:"13",children:["\n",(0,i.jsx)(n.li,{children:"Done... You can now use ArchWSL2."}),"\n"]}),"\n",(0,i.jsx)(n.h3,{id:"optional-cleanup-of-the-ubuntu-distribution",children:"Optional: Cleanup of the Ubuntu Distribution"}),"\n",(0,i.jsxs)(n.ol,{children:["\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsx)(n.p,{children:"Open the terminal as Administrator, like we did earlier."}),"\n",(0,i.jsx)(n.p,{children:(0,i.jsx)(n.img,{src:"https://raw.githubusercontent.com/av1-community-contributors/images/main/16_wsl_rv-cli.avif",alt:""})}),"\n"]}),"\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsx)(n.p,{children:"Check the current installed distributions:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-pwsh",children:"wsl --list\n"})}),"\n",(0,i.jsx)(n.p,{children:(0,i.jsx)(n.img,{src:"https://raw.githubusercontent.com/av1-community-contributors/images/main/17_wsl_rv-cli.avif",alt:""})}),"\n"]}),"\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsx)(n.p,{children:'To remove "Ubuntu" (and therefor make Arch as default), enter the following command:'}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-pwsh",children:"wsl --unregister ubuntu\n"})}),"\n",(0,i.jsx)(n.p,{children:(0,i.jsx)(n.img,{src:"https://raw.githubusercontent.com/av1-community-contributors/images/main/18_wsl_rv-cli.avif",alt:""})}),"\n"]}),"\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsx)(n.p,{children:'After the removal of Ubuntu, we can list the distributions again and verify that "Arch" is now the default:'}),"\n",(0,i.jsx)(n.p,{children:(0,i.jsx)(n.img,{src:"https://raw.githubusercontent.com/av1-community-contributors/images/main/19_wsl_rv-cli.avif",alt:""})}),"\n"]}),"\n"]}),"\n",(0,i.jsx)(n.h3,{id:"after-the-installation-and-cleanup-how-do-i-start-arch",children:"After the Installation and Cleanup, How Do I Start Arch?"}),"\n",(0,i.jsx)(n.p,{children:"For the start of Arch, there are 2 steps possible:"}),"\n",(0,i.jsxs)(n.ol,{children:["\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsx)(n.p,{children:'You can just start "wsl" form the command prompt, terminal or "Windows Search":'}),"\n",(0,i.jsx)(n.p,{children:(0,i.jsx)(n.img,{src:"https://raw.githubusercontent.com/av1-community-contributors/images/main/20_wsl_rv-cli.avif",alt:""})}),"\n",(0,i.jsx)(n.p,{children:(0,i.jsx)(n.img,{src:"https://raw.githubusercontent.com/av1-community-contributors/images/main/21_wsl_rv-cli.avif",alt:""})}),"\n"]}),"\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsx)(n.p,{children:'As another option, you can create a Shortcut to the "arch.exe" in the Installation-Folder:'}),"\n",(0,i.jsx)(n.p,{children:(0,i.jsx)(n.img,{src:"https://raw.githubusercontent.com/av1-community-contributors/images/main/22_wsl_rv-cli.avif",alt:""})}),"\n",(0,i.jsx)(n.p,{children:(0,i.jsx)(n.img,{src:"https://raw.githubusercontent.com/av1-community-contributors/images/main/23_wsl_rv-cli.avif",alt:""})}),"\n",(0,i.jsx)(n.p,{children:(0,i.jsx)(n.img,{src:"https://raw.githubusercontent.com/av1-community-contributors/images/main/24_wsl_rv-cli.avif",alt:""})}),"\n"]}),"\n"]}),"\n",(0,i.jsxs)(n.p,{children:[(0,i.jsx)(n.strong,{children:"Hint"}),': When you open the "arch.exe", you will be placed into the directory where also the "arch.exe" is located. To change to your home directory, just enter the command below:']}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:"cd ~\n"})}),"\n",(0,i.jsx)(n.p,{children:(0,i.jsx)(n.img,{src:"https://raw.githubusercontent.com/av1-community-contributors/images/main/25_wsl_rv-cli.avif",alt:""})}),"\n",(0,i.jsx)(n.h3,{id:"unlock-wsl-ram-usage-optional",children:"Unlock WSL RAM Usage (Optional)"}),"\n",(0,i.jsxs)(n.p,{children:[(0,i.jsx)(n.strong,{children:"Hint"}),": WSL caps RAM usage at 50% of the total RAM available on your system."]}),"\n",(0,i.jsx)(n.p,{children:"When you start the VM, you will see that you only will only have 50% of your total memory available:"}),"\n",(0,i.jsx)(n.p,{children:(0,i.jsx)(n.img,{src:"https://raw.githubusercontent.com/av1-community-contributors/images/main/26_wsl_rv-cli.avif",alt:""})}),"\n",(0,i.jsx)(n.p,{children:"To allow more memory, you need to place a config-file in your profile-folder in Windows. See the instructions below:"}),"\n",(0,i.jsxs)(n.ol,{children:["\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsx)(n.p,{children:'Open "notepad.exe" and enter the following:'}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-txt",children:"[wsl2]\nmemory=12GB\n"})}),"\n",(0,i.jsx)(n.p,{children:(0,i.jsx)(n.img,{src:"https://raw.githubusercontent.com/av1-community-contributors/images/main/27_wsl_rv-cli.avif",alt:""})}),"\n"]}),"\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsx)(n.p,{children:"The amount of memory should never be more than current memory. Set it to total memory minus 4GB to leave enough left over for Windows. In my example, Windows has 16GB of RAM available, so I select the memory to be 12GB."}),"\n"]}),"\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsx)(n.p,{children:"When saving the file, enter the following as filename:"}),"\n",(0,i.jsx)(n.p,{children:(0,i.jsx)(n.code,{children:"%userprofile%"})}),"\n",(0,i.jsx)(n.p,{children:(0,i.jsx)(n.img,{src:"https://raw.githubusercontent.com/av1-community-contributors/images/main/28_wsl_rv-cli.avif",alt:""})}),"\n"]}),"\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsx)(n.p,{children:"When pressing enter, the directory will switch to your user-profile folder:"}),"\n",(0,i.jsx)(n.p,{children:(0,i.jsx)(n.img,{src:"https://raw.githubusercontent.com/av1-community-contributors/images/main/29_wsl_rv-cli.avif",alt:""})}),"\n"]}),"\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsx)(n.p,{children:'Select the "Save as type" to "All files (*.*)" and save as the following filename:'}),"\n",(0,i.jsx)(n.p,{children:(0,i.jsx)(n.code,{children:".wslconfig"})}),"\n",(0,i.jsx)(n.p,{children:(0,i.jsx)(n.img,{src:"https://raw.githubusercontent.com/av1-community-contributors/images/main/30_wsl_rv-cli.avif",alt:""})}),"\n",(0,i.jsxs)(n.p,{children:["Make sure the file is saved as ",(0,i.jsx)(n.code,{children:".wslconfig"}),". Then exit notepad."]}),"\n"]}),"\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsx)(n.p,{children:"Exit any current running WSL / Arch (exit):"}),"\n",(0,i.jsx)(n.p,{children:(0,i.jsx)(n.img,{src:"https://raw.githubusercontent.com/av1-community-contributors/images/main/31_wsl_rv-cli.avif",alt:""})}),"\n"]}),"\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsx)(n.p,{children:'Open the Terminal as Administrator and "shutdown" any running WSL:'}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-pwsh",children:"wsl --shutdown\n"})}),"\n",(0,i.jsx)(n.p,{children:(0,i.jsx)(n.img,{src:"https://raw.githubusercontent.com/av1-community-contributors/images/main/32_wsl_rv-cli.avif",alt:""})}),"\n"]}),"\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsx)(n.p,{children:"Restart WSL again and check the memory settings from within Arch by running the following command:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:"free -h\n"})}),"\n",(0,i.jsx)(n.p,{children:(0,i.jsx)(n.img,{src:"https://raw.githubusercontent.com/av1-community-contributors/images/main/33_wsl_rv-cli.avif",alt:""})}),"\n"]}),"\n"]}),"\n",(0,i.jsx)(n.p,{children:"If you've made it this far, you should be more than ready to encode. We hope you enjoy rAV1ator CLI!"}),"\n",(0,i.jsx)(n.h2,{id:"macos",children:"macOS"}),"\n",(0,i.jsx)(n.p,{children:"No macOS support is provided at this time. It is definitely technically feasible, and I may produce a separate tool in the future with proper macOS binaries, though this would be a burden to keep up considering I don't currently see any demand for a port."}),"\n",(0,i.jsx)(n.h3,{id:"troubleshooting",children:"Troubleshooting"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:["If your encode features a grey screen flashing occaisonally in the output, create a lossless intermediary of your source with x264 ",(0,i.jsx)(n.code,{children:"-qp 0"}),". This happens because of VC-1 decoding errors, and is not something I can fix."]}),"\n",(0,i.jsxs)(n.li,{children:["If you have any more questions, please join the ",(0,i.jsx)(n.a,{href:"https://discord.gg/bbQD5MjDr3",children:"AV1 for Dummies Discord server"}),". There is a rAV1ator CLI channel over there, and I am always happy to talk!"]}),"\n"]})]})}function u(e={}){const{wrapper:n}={...(0,s.R)(),...e.components};return n?(0,i.jsx)(n,{...e,children:(0,i.jsx)(h,{...e})}):h(e)}},9365:(e,n,t)=>{t.d(n,{A:()=>a});t(6540);var i=t(4164);const s={tabItem:"tabItem_Ymn6"};var r=t(4848);function a(e){let{children:n,hidden:t,className:a}=e;return(0,r.jsx)("div",{role:"tabpanel",className:(0,i.A)(s.tabItem,a),hidden:t,children:n})}},1470:(e,n,t)=>{t.d(n,{A:()=>y});var i=t(6540),s=t(4164),r=t(3104),a=t(6347),o=t(205),l=t(7485),c=t(1682),h=t(9466);function u(e){return i.Children.toArray(e).filter((e=>"\n"!==e)).map((e=>{if(!e||(0,i.isValidElement)(e)&&function(e){const{props:n}=e;return!!n&&"object"==typeof n&&"value"in n}(e))return e;throw new Error(`Docusaurus error: Bad child <${"string"==typeof e.type?e.type:e.type.name}>: all children of the component should be , and every should have a unique "value" prop.`)}))?.filter(Boolean)??[]}function d(e){const{values:n,children:t}=e;return(0,i.useMemo)((()=>{const e=n??function(e){return u(e).map((e=>{let{props:{value:n,label:t,attributes:i,default:s}}=e;return{value:n,label:t,attributes:i,default:s}}))}(t);return function(e){const n=(0,c.X)(e,((e,n)=>e.value===n.value));if(n.length>0)throw new Error(`Docusaurus error: Duplicate values "${n.map((e=>e.value)).join(", ")}" found in . Every value needs to be unique.`)}(e),e}),[n,t])}function m(e){let{value:n,tabValues:t}=e;return t.some((e=>e.value===n))}function p(e){let{queryString:n=!1,groupId:t}=e;const s=(0,a.W6)(),r=function(e){let{queryString:n=!1,groupId:t}=e;if("string"==typeof n)return n;if(!1===n)return null;if(!0===n&&!t)throw new Error('Docusaurus error: The component groupId prop is required if queryString=true, because this value is used as the search param name. You can also provide an explicit value such as queryString="my-search-param".');return t??null}({queryString:n,groupId:t});return[(0,l.aZ)(r),(0,i.useCallback)((e=>{if(!r)return;const n=new URLSearchParams(s.location.search);n.set(r,e),s.replace({...s.location,search:n.toString()})}),[r,s])]}function x(e){const{defaultValue:n,queryString:t=!1,groupId:s}=e,r=d(e),[a,l]=(0,i.useState)((()=>function(e){let{defaultValue:n,tabValues:t}=e;if(0===t.length)throw new Error("Docusaurus error: the component requires at least one children component");if(n){if(!m({value:n,tabValues:t}))throw new Error(`Docusaurus error: The has a defaultValue "${n}" but none of its children has the corresponding value. Available values are: ${t.map((e=>e.value)).join(", ")}. If you intend to show no default tab, use defaultValue={null} instead.`);return n}const i=t.find((e=>e.default))??t[0];if(!i)throw new Error("Unexpected error: 0 tabValues");return i.value}({defaultValue:n,tabValues:r}))),[c,u]=p({queryString:t,groupId:s}),[x,g]=function(e){let{groupId:n}=e;const t=function(e){return e?`docusaurus.tab.${e}`:null}(n),[s,r]=(0,h.Dv)(t);return[s,(0,i.useCallback)((e=>{t&&r.set(e)}),[t,r])]}({groupId:s}),v=(()=>{const e=c??x;return m({value:e,tabValues:r})?e:null})();(0,o.A)((()=>{v&&l(v)}),[v]);return{selectedValue:a,selectValue:(0,i.useCallback)((e=>{if(!m({value:e,tabValues:r}))throw new Error(`Can't select invalid tab value=${e}`);l(e),u(e),g(e)}),[u,g,r]),tabValues:r}}var g=t(2303);const v={tabList:"tabList__CuJ",tabItem:"tabItem_LNqP"};var j=t(4848);function f(e){let{className:n,block:t,selectedValue:i,selectValue:a,tabValues:o}=e;const l=[],{blockElementScrollPositionUntilNextRender:c}=(0,r.a_)(),h=e=>{const n=e.currentTarget,t=l.indexOf(n),s=o[t].value;s!==i&&(c(n),a(s))},u=e=>{let n=null;switch(e.key){case"Enter":h(e);break;case"ArrowRight":{const t=l.indexOf(e.currentTarget)+1;n=l[t]??l[0];break}case"ArrowLeft":{const t=l.indexOf(e.currentTarget)-1;n=l[t]??l[l.length-1];break}}n?.focus()};return(0,j.jsx)("ul",{role:"tablist","aria-orientation":"horizontal",className:(0,s.A)("tabs",{"tabs--block":t},n),children:o.map((e=>{let{value:n,label:t,attributes:r}=e;return(0,j.jsx)("li",{role:"tab",tabIndex:i===n?0:-1,"aria-selected":i===n,ref:e=>l.push(e),onKeyDown:u,onClick:h,...r,className:(0,s.A)("tabs__item",v.tabItem,r?.className,{"tabs__item--active":i===n}),children:t??n},n)}))})}function b(e){let{lazy:n,children:t,selectedValue:s}=e;const r=(Array.isArray(t)?t:[t]).filter(Boolean);if(n){const e=r.find((e=>e.props.value===s));return e?(0,i.cloneElement)(e,{className:"margin-top--md"}):null}return(0,j.jsx)("div",{className:"margin-top--md",children:r.map(((e,n)=>(0,i.cloneElement)(e,{key:n,hidden:e.props.value!==s})))})}function w(e){const n=x(e);return(0,j.jsxs)("div",{className:(0,s.A)("tabs-container",v.tabList),children:[(0,j.jsx)(f,{...n,...e}),(0,j.jsx)(b,{...n,...e})]})}function y(e){const n=(0,g.A)();return(0,j.jsx)(w,{...e,children:u(e.children)},String(n))}},8453:(e,n,t)=>{t.d(n,{R:()=>a,x:()=>o});var i=t(6540);const s={},r=i.createContext(s);function a(e){const n=i.useContext(r);return i.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function o(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:a(e.components),i.createElement(r.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/935f2afb.28735225.js b/assets/js/935f2afb.28735225.js deleted file mode 100644 index d4015eab..00000000 --- a/assets/js/935f2afb.28735225.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcodec_wiki=self.webpackChunkcodec_wiki||[]).push([[8581],{5610:e=>{e.exports=JSON.parse('{"pluginId":"default","version":"current","label":"Next","banner":null,"badge":false,"noIndex":false,"className":"docs-version-current","isLast":true,"docsSidebars":{"tutorialSidebar":[{"type":"category","label":"\ud83d\udca1 Introduction","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"Prologue","href":"/docs/introduction/prologue","docId":"introduction/prologue","unlisted":false},{"type":"link","label":"Terminology","href":"/docs/introduction/terminology","docId":"introduction/terminology","unlisted":false},{"type":"link","label":"Spotting Video Artifacts","href":"/docs/introduction/video-artifacts","docId":"introduction/video-artifacts","unlisted":false},{"type":"link","label":"Psychovisual","href":"/docs/introduction/psychovisual","docId":"introduction/psychovisual","unlisted":false},{"type":"link","label":"High Dynamic Range","href":"/docs/introduction/high-dynamic-range","docId":"introduction/high-dynamic-range","unlisted":false}]},{"type":"category","label":"\ud83d\udd0a Audio","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"AAC","href":"/docs/audio/AAC","docId":"audio/AAC","unlisted":false},{"type":"link","label":"Opus","href":"/docs/audio/Opus","docId":"audio/Opus","unlisted":false},{"type":"link","label":"Dolby Digital","href":"/docs/audio/Dolby","docId":"audio/Dolby","unlisted":false},{"type":"link","label":"MP3","href":"/docs/audio/MP3","docId":"audio/MP3","unlisted":false},{"type":"link","label":"Vorbis","href":"/docs/audio/Vorbis","docId":"audio/Vorbis","unlisted":false},{"type":"link","label":"Speex","href":"/docs/audio/Speex","docId":"audio/Speex","unlisted":false},{"type":"link","label":"FLAC","href":"/docs/audio/FLAC","docId":"audio/FLAC","unlisted":false},{"type":"link","label":"WavPack","href":"/docs/audio/WavPack","docId":"audio/WavPack","unlisted":false}]},{"type":"category","label":"\ud83d\udcf9\ufe0f Video","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"AVC / H.264","href":"/docs/video/AVC","docId":"video/AVC","unlisted":false},{"type":"link","label":"HEVC / H.265","href":"/docs/video/HEVC","docId":"video/HEVC","unlisted":false},{"type":"link","label":"VVC / H.266","href":"/docs/video/VVC","docId":"video/VVC","unlisted":false},{"type":"link","label":"VP8","href":"/docs/video/VP8","docId":"video/VP8","unlisted":false},{"type":"link","label":"VP9","href":"/docs/video/VP9","docId":"video/VP9","unlisted":false},{"type":"link","label":"AV1","href":"/docs/video/AV1","docId":"video/AV1","unlisted":false},{"type":"link","label":"AVS3","href":"/docs/video/AVS3","docId":"video/AVS3","unlisted":false},{"type":"link","label":"VC-1","href":"/docs/video/VC-1","docId":"video/VC-1","unlisted":false},{"type":"link","label":"Theora","href":"/docs/video/Theora","docId":"video/Theora","unlisted":false},{"type":"link","label":"FFV1","href":"/docs/video/FFV1","docId":"video/FFV1","unlisted":false},{"type":"link","label":"UT Video","href":"/docs/video/utvideo","docId":"video/utvideo","unlisted":false},{"type":"link","label":"ProRes","href":"/docs/video/prores","docId":"video/prores","unlisted":false},{"type":"link","label":"ECM","href":"/docs/video/ECM","docId":"video/ECM","unlisted":false}]},{"type":"category","label":"\ud83d\udcbd Data","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"ZIP","href":"/docs/data/zip","docId":"data/zip","unlisted":false},{"type":"link","label":"gzip","href":"/docs/data/gzip","docId":"data/gzip","unlisted":false},{"type":"link","label":"bzip2","href":"/docs/data/bzip2","docId":"data/bzip2","unlisted":false},{"type":"link","label":"7z","href":"/docs/data/7z","docId":"data/7z","unlisted":false},{"type":"link","label":"xz","href":"/docs/data/xz","docId":"data/xz","unlisted":false},{"type":"link","label":"brotli","href":"/docs/data/brotli","docId":"data/brotli","unlisted":false},{"type":"link","label":"zpaq","href":"/docs/data/zpaq","docId":"data/zpaq","unlisted":false},{"type":"link","label":"zstd","href":"/docs/data/zstd","docId":"data/zstd","unlisted":false},{"type":"link","label":"tar","href":"/docs/data/tar","docId":"data/tar","unlisted":false}]},{"type":"category","label":"\ud83c\udfde\ufe0f Images","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"JPEG","href":"/docs/images/JPEG","docId":"images/JPEG","unlisted":false},{"type":"link","label":"PNG","href":"/docs/images/PNG","docId":"images/PNG","unlisted":false},{"type":"link","label":"GIF","href":"/docs/images/GIF","docId":"images/GIF","unlisted":false},{"type":"link","label":"HEIC","href":"/docs/images/HEIC","docId":"images/HEIC","unlisted":false},{"type":"link","label":"WebP","href":"/docs/images/WebP","docId":"images/WebP","unlisted":false},{"type":"link","label":"JPEG 2000","href":"/docs/images/JPEG2000","docId":"images/JPEG2000","unlisted":false},{"type":"link","label":"AVIF","href":"/docs/images/AVIF","docId":"images/AVIF","unlisted":false},{"type":"link","label":"JPEG-XL","href":"/docs/images/JXL","docId":"images/JXL","unlisted":false},{"type":"link","label":"QOI","href":"/docs/images/QOI","docId":"images/QOI","unlisted":false}]},{"type":"category","label":"\ud83d\udcbe Encoders","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"x264","href":"/docs/encoders/x264","docId":"encoders/x264","unlisted":false},{"type":"link","label":"x265","href":"/docs/encoders/x265","docId":"encoders/x265","unlisted":false},{"type":"link","label":"x266","href":"/docs/encoders/x266","docId":"encoders/x266","unlisted":false},{"type":"link","label":"aomenc","href":"/docs/encoders/aomenc","docId":"encoders/aomenc","unlisted":false},{"type":"link","label":"SVT-AV1","href":"/docs/encoders/SVT-AV1","docId":"encoders/SVT-AV1","unlisted":false},{"type":"link","label":"rav1e","href":"/docs/encoders/rav1e","docId":"encoders/rav1e","unlisted":false},{"type":"link","label":"Aurora1 AV1","href":"/docs/encoders/Aurora1","docId":"encoders/Aurora1","unlisted":false},{"type":"link","label":"vpxenc","href":"/docs/encoders/vpxenc","docId":"encoders/vpxenc","unlisted":false},{"type":"link","label":"SVT-VP9","href":"/docs/encoders/SVT-VP9","docId":"encoders/SVT-VP9","unlisted":false},{"type":"link","label":"SVT-HEVC","href":"/docs/encoders/SVT-HEVC","docId":"encoders/SVT-HEVC","unlisted":false},{"type":"link","label":"Kvazaar","href":"/docs/encoders/Kvazaar","docId":"encoders/Kvazaar","unlisted":false},{"type":"link","label":"VVenC","href":"/docs/encoders/VVenC","docId":"encoders/VVenC","unlisted":false},{"type":"link","label":"uvg266","href":"/docs/encoders/uvg266","docId":"encoders/uvg266","unlisted":false},{"type":"link","label":"VTM","href":"/docs/encoders/VTM","docId":"encoders/VTM","unlisted":false},{"type":"link","label":"AVM","href":"/docs/encoders/AVM","docId":"encoders/AVM","unlisted":false},{"type":"link","label":"HM","href":"/docs/encoders/HM","docId":"encoders/HM","unlisted":false},{"type":"link","label":"JM","href":"/docs/encoders/JM","docId":"encoders/JM","unlisted":false}]},{"type":"category","label":"\ud83d\ude80 Hardware Encoders","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"NVENC","href":"/docs/encoders_hw/nvenc","docId":"encoders_hw/nvenc","unlisted":false},{"type":"link","label":"QSV","href":"/docs/encoders_hw/qsv","docId":"encoders_hw/qsv","unlisted":false},{"type":"link","label":"AMF","href":"/docs/encoders_hw/amf","docId":"encoders_hw/amf","unlisted":false},{"type":"link","label":"VideoToolbox","href":"/docs/encoders_hw/videotoolbox","docId":"encoders_hw/videotoolbox","unlisted":false},{"type":"link","label":"Mediacodec","href":"/docs/encoders_hw/mediacodec","docId":"encoders_hw/mediacodec","unlisted":false}]},{"type":"category","label":"\ud83d\udcac Subtitles","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"SRT","href":"/docs/subtitles/SRT","docId":"subtitles/SRT","unlisted":false},{"type":"link","label":"WebVTT","href":"/docs/subtitles/webvtt","docId":"subtitles/webvtt","unlisted":false}]},{"type":"category","label":"\ud83c\udf9e\ufe0f Filtering","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"Intro","href":"/docs/filtering/intro","docId":"filtering/intro","unlisted":false},{"type":"link","label":"Deband","href":"/docs/filtering/deband","docId":"filtering/deband","unlisted":false},{"type":"link","label":"Vapoursynth","href":"/docs/filtering/vapoursynth","docId":"filtering/vapoursynth","unlisted":false},{"type":"link","label":"Deinterlace","href":"/docs/filtering/deinterlace","docId":"filtering/deinterlace","unlisted":false},{"type":"link","label":"Denoise","href":"/docs/filtering/denoise","docId":"filtering/denoise","unlisted":false},{"type":"link","label":"Detelecine / Inverse Telecine","href":"/docs/filtering/detelecine","docId":"filtering/detelecine","unlisted":false},{"type":"link","label":"Dehalo","href":"/docs/filtering/dehalo","docId":"filtering/dehalo","unlisted":false}]},{"type":"category","label":"\ud83d\udee0\ufe0f Utilities","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"Aviator","href":"/docs/utilities/Aviator","docId":"utilities/Aviator","unlisted":false},{"type":"link","label":"Av1an","href":"/docs/utilities/av1an","docId":"utilities/av1an","unlisted":false},{"type":"link","label":"ffmpeg","href":"/docs/utilities/ffmpeg","docId":"utilities/ffmpeg","unlisted":false},{"type":"link","label":"MKVToolNix","href":"/docs/utilities/MKVToolNix","docId":"utilities/MKVToolNix","unlisted":false},{"type":"link","label":"rAV1ator","href":"/docs/utilities/rAV1ator","docId":"utilities/rAV1ator","unlisted":false},{"type":"link","label":"rav1ator-cli","href":"/docs/utilities/rav1ator-cli","docId":"utilities/rav1ator-cli","unlisted":false},{"type":"link","label":"NMKODER","href":"/docs/utilities/nmkoder","docId":"utilities/nmkoder","unlisted":false},{"type":"link","label":"FFMetrics","href":"/docs/utilities/FFMetrics","docId":"utilities/FFMetrics","unlisted":false},{"type":"link","label":"dovi_tool","href":"/docs/utilities/dovi_tool","docId":"utilities/dovi_tool","unlisted":false},{"type":"link","label":"eac3to","href":"/docs/utilities/eac3to","docId":"utilities/eac3to","unlisted":false},{"type":"link","label":"hdr10plus_tool","href":"/docs/utilities/hdr10plus_tool","docId":"utilities/hdr10plus_tool","unlisted":false},{"type":"link","label":"MP4Box","href":"/docs/utilities/mp4box","docId":"utilities/mp4box","unlisted":false},{"type":"link","label":"YUView","href":"/docs/utilities/YUView","docId":"utilities/YUView","unlisted":false},{"type":"link","label":"av1an-command-gen","href":"/docs/utilities/av1an-command-gen","docId":"utilities/av1an-command-gen","unlisted":false},{"type":"link","label":"autocompressor","href":"/docs/utilities/autocompressor","docId":"utilities/autocompressor","unlisted":false}]},{"type":"category","label":"\ud83d\udc41\ufe0f Metrics","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"PSNR","href":"/docs/metrics/PSNR","docId":"metrics/PSNR","unlisted":false},{"type":"link","label":"SSIM","href":"/docs/metrics/SSIM","docId":"metrics/SSIM","unlisted":false},{"type":"link","label":"SSIMULACRA2","href":"/docs/metrics/SSIMULACRA2","docId":"metrics/SSIMULACRA2","unlisted":false},{"type":"link","label":"VMAF","href":"/docs/metrics/VMAF","docId":"metrics/VMAF","unlisted":false},{"type":"link","label":"PSNR","href":"/docs/metrics/XPSNR","docId":"metrics/XPSNR","unlisted":false},{"type":"link","label":"Butteraugli","href":"/docs/metrics/butteraugli","docId":"metrics/butteraugli","unlisted":false}]},{"type":"link","label":"\u25b6\ufe0f Video Players","href":"/docs/video-players","docId":"video-players","unlisted":false},{"type":"link","label":"\ud83d\uddc3\ufe0f Resources","href":"/docs/resources","docId":"resources","unlisted":false},{"type":"link","label":"\u2712\ufe0f Contribution Guide","href":"/docs/contribution-guide","docId":"contribution-guide","unlisted":false},{"type":"link","label":"\u2753 FAQ","href":"/docs/FAQ","docId":"FAQ","unlisted":false},{"type":"link","label":"\ud83d\udd0f Privacy Policy","href":"/docs/privacy-policy","docId":"privacy-policy","unlisted":false},{"type":"link","label":"\ud83e\udd1d Terms of Use","href":"/docs/terms-of-use","docId":"terms-of-use","unlisted":false}]},"docs":{"audio/AAC":{"id":"audio/AAC","title":"AAC","description":"Explore the AAC audio codec, including its various profiles, encoders, & use cases.","sidebar":"tutorialSidebar"},"audio/Dolby":{"id":"audio/Dolby","title":"Dolby Digital","description":"The content in this entry is incomplete & is in the process of being completed.","sidebar":"tutorialSidebar"},"audio/FLAC":{"id":"audio/FLAC","title":"FLAC","description":"This section is in need of contributions. If you believe you can help, please see our Contribution Guide to get started as a contributor!","sidebar":"tutorialSidebar"},"audio/MP3":{"id":"audio/MP3","title":"MP3","description":"This section is in need of contributions. If you believe you can help, please see our Contribution Guide to get started as a contributor!","sidebar":"tutorialSidebar"},"audio/Opus":{"id":"audio/Opus","title":"Opus","description":"The content in this entry is incomplete & is in the process of being completed.","sidebar":"tutorialSidebar"},"audio/Speex":{"id":"audio/Speex","title":"Speex","description":"This section is in need of contributions. If you believe you can help, please see our Contribution Guide to get started as a contributor!","sidebar":"tutorialSidebar"},"audio/Vorbis":{"id":"audio/Vorbis","title":"Vorbis","description":"This section is in need of contributions. If you believe you can help, please see our Contribution Guide to get started as a contributor!","sidebar":"tutorialSidebar"},"audio/WavPack":{"id":"audio/WavPack","title":"WavPack","description":"This section is in need of contributions. If you believe you can help, please see our Contribution Guide to get started as a contributor!","sidebar":"tutorialSidebar"},"contribution-guide":{"id":"contribution-guide","title":"Contribution Guide","description":"Codec Wiki - community-maintained wiki for all things encoding.","sidebar":"tutorialSidebar"},"data/7z":{"id":"data/7z","title":"7z","description":"This section is in need of contributions. If you believe you can help, please see our Contribution Guide to get started as a contributor!","sidebar":"tutorialSidebar"},"data/brotli":{"id":"data/brotli","title":"brotli","description":"This section is in need of contributions. If you believe you can help, please see our Contribution Guide to get started as a contributor!","sidebar":"tutorialSidebar"},"data/bzip2":{"id":"data/bzip2","title":"bzip2","description":"This section is in need of contributions. If you believe you can help, please see our Contribution Guide to get started as a contributor!","sidebar":"tutorialSidebar"},"data/gzip":{"id":"data/gzip","title":"gzip","description":"Gzip is a DEFLATE implementation for use with individual files. It is popular on Unix-like systems such as Linux & macOS, and is often seen paired with tar to create .tar.gz archives. Formats like ZIP & PNG also use Deflate to different effects.","sidebar":"tutorialSidebar"},"data/tar":{"id":"data/tar","title":"tar","description":"This section is in need of contributions. If you believe you can help, please see our Contribution Guide to get started as a contributor!","sidebar":"tutorialSidebar"},"data/xz":{"id":"data/xz","title":"xz","description":"This section is in need of contributions. If you believe you can help, please see our Contribution Guide to get started as a contributor!","sidebar":"tutorialSidebar"},"data/zip":{"id":"data/zip","title":"ZIP","description":"The content in this entry may not be entirely accurate, & is pending further review to assess the quality of the information.","sidebar":"tutorialSidebar"},"data/zpaq":{"id":"data/zpaq","title":"zpaq","description":"This section is in need of contributions. If you believe you can help, please see our Contribution Guide to get started as a contributor!","sidebar":"tutorialSidebar"},"data/zstd":{"id":"data/zstd","title":"zstd","description":"This section is in need of contributions. If you believe you can help, please see our Contribution Guide to get started as a contributor!","sidebar":"tutorialSidebar"},"encoders_hw/amf":{"id":"encoders_hw/amf","title":"AMF","description":"The content in this entry may not be entirely accurate, & is pending further review to assess the quality of the information.","sidebar":"tutorialSidebar"},"encoders_hw/mediacodec":{"id":"encoders_hw/mediacodec","title":"Mediacodec","description":"The Android\'s MediaCodec framework is a part of Android\'s multimedia framework that provides access to low-level media encoder & decoder components. It is similar to VideoToolbox on Apple devices. Hardware acceleration with MediaCodec is used for processing audio, video, and compressed data.","sidebar":"tutorialSidebar"},"encoders_hw/nvenc":{"id":"encoders_hw/nvenc","title":"NVENC","description":"The content in this entry may not be entirely accurate, & is pending further review to assess the quality of the information.","sidebar":"tutorialSidebar"},"encoders_hw/qsv":{"id":"encoders_hw/qsv","title":"QSV","description":"The content in this entry may not be entirely accurate, & is pending further review to assess the quality of the information.","sidebar":"tutorialSidebar"},"encoders_hw/videotoolbox":{"id":"encoders_hw/videotoolbox","title":"VideoToolbox","description":"The content in this entry is incomplete & is in the process of being completed.","sidebar":"tutorialSidebar"},"encoders/aomenc":{"id":"encoders/aomenc","title":"aomenc","description":"aomenc, AOM-AV1, or just libaom is a command line application for encoding AV1 written in C and Assembly developed by AOMedia, which is also the reference encoder for AV1.","sidebar":"tutorialSidebar"},"encoders/Aurora1":{"id":"encoders/Aurora1","title":"Aurora1 AV1","description":"Aurora1 AV1 is a proprietary and paid software AV1 encoder developed by Visionular. Although they do provide a contact form to get a free trial, not much is known about this encoder other than cherry-picked claims and proof provided by the company themselves that it is supposedly \\"better\\" than public, FOSS encoders.","sidebar":"tutorialSidebar"},"encoders/AVM":{"id":"encoders/AVM","title":"AVM","description":"AVM (AOM Video Model) is the reference software for next codec from Alliance for Open Media.","sidebar":"tutorialSidebar"},"encoders/HM":{"id":"encoders/HM","title":"HM","description":"The content in this entry may not be entirely accurate, & is pending further review to assess the quality of the information.","sidebar":"tutorialSidebar"},"encoders/JM":{"id":"encoders/JM","title":"JM","description":"This section is in need of contributions. If you believe you can help, please see our Contribution Guide to get started as a contributor!","sidebar":"tutorialSidebar"},"encoders/Kvazaar":{"id":"encoders/Kvazaar","title":"Kvazaar","description":"Kvazaar is an open-source H.265 / HEVC software encoder Written in C, developed by Ultra Video Group and licensed under BSD 3-clause.","sidebar":"tutorialSidebar"},"encoders/rav1e":{"id":"encoders/rav1e","title":"rav1e","description":"rav1e is an open source command line application for encoding AV1 written in Assembly & Rust, co-developed by Xiph.org and Mozilla and licensed under BSD-2 Clause.","sidebar":"tutorialSidebar"},"encoders/SVT-AV1":{"id":"encoders/SVT-AV1","title":"SVT-AV1","description":"The content in this entry is incomplete & is in the process of being completed.","sidebar":"tutorialSidebar"},"encoders/SVT-HEVC":{"id":"encoders/SVT-HEVC","title":"SVT-HEVC","description":"SVT-HEVC (Scalable Video Technology for HEVC) is an open source H.265 / HEVC software encoder developed by Intel made specifically to only support x86. As the name suggests, it is part of the \\"Scalable Video Technology\\" project lineup by Intel.","sidebar":"tutorialSidebar"},"encoders/SVT-VP9":{"id":"encoders/SVT-VP9","title":"SVT-VP9","description":"The content in this entry is incomplete & is in the process of being completed.","sidebar":"tutorialSidebar"},"encoders/uvg266":{"id":"encoders/uvg266","title":"uvg266","description":"uvg266 is an open-source software encoder for encoding to the H.266 / VVC codec. Developed by the Ultra Video Group, written in C and licensed under BSD 3-clause.","sidebar":"tutorialSidebar"},"encoders/vpxenc":{"id":"encoders/vpxenc","title":"vpxenc","description":"The content in this entry is incomplete & is in the process of being completed.","sidebar":"tutorialSidebar"},"encoders/VTM":{"id":"encoders/VTM","title":"VTM","description":"This section is in need of contributions. If you believe you can help, please see our Contribution Guide to get started as a contributor!","sidebar":"tutorialSidebar"},"encoders/VVenC":{"id":"encoders/VVenC","title":"VVenC","description":"{s.r(i),s.d(i,{assets:()=>d,contentTitle:()=>l,default:()=>p,frontMatter:()=>a,metadata:()=>c,toc:()=>h});var n=s(4848),t=s(8453),r=s(1470),o=s(9365);const a={title:"JPEG-XL",sidebar_position:7},l="JPEG-XL",c={id:"images/JXL",title:"JPEG-XL",description:"JPEG-XL (JXL) is a compression format for images that was developed by the Joint Photographic Experts Group (JPEG) in 2020. It is designed to provide improved compression efficiency compared to the traditional JPEG format, while still maintaining image quality. JPEG-XL uses a combination of techniques such as perceptual color encoding, advanced entropy coding, and a new image prediction method to achieve its improved compression performance. It also has a lossless JPEG recompression mode, where an existing JPEG file can be turned into a JXL that can be decoded for a bit-for-bit exact replica of the original JPEG.",source:"@site/docs/images/JXL.mdx",sourceDirName:"images",slug:"/images/JXL",permalink:"/docs/images/JXL",draft:!1,unlisted:!1,editUrl:"https://github.com/av1-community-contributors/codec-wiki/tree/main/docs/images/JXL.mdx",tags:[],version:"current",sidebarPosition:7,frontMatter:{title:"JPEG-XL",sidebar_position:7},sidebar:"tutorialSidebar",previous:{title:"AVIF",permalink:"/docs/images/AVIF"},next:{title:"QOI",permalink:"/docs/images/QOI"}},d={},h=[{value:"Performance Checklist",id:"performance-checklist",level:2},{value:"Format Breakdown",id:"format-breakdown",level:2},{value:"Lossless Compression",id:"lossless-compression",level:3},{value:"Lossy Compression",id:"lossy-compression",level:3},{value:"Supported Bit Depth(s)",id:"supported-bit-depths",level:3},{value:"Progressive Decode",id:"progressive-decode",level:3},{value:"Lossless JPEG Re-compression",id:"lossless-jpeg-re-compression",level:3},{value:"Industry Support",id:"industry-support",level:3},{value:"Other Features",id:"other-features",level:3},{value:"Encoders",id:"encoders",level:2},{value:"libjxl",id:"libjxl",level:3},{value:"libjxl-tiny",id:"libjxl-tiny",level:3},{value:"Hydrium",id:"hydrium",level:3},{value:"zune-jpegxl",id:"zune-jpegxl",level:3}];function u(e){const i={a:"a",blockquote:"blockquote",code:"code",em:"em",h1:"h1",h2:"h2",h3:"h3",li:"li",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,t.R)(),...e.components};return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(i.h1,{id:"jpeg-xl",children:"JPEG-XL"}),"\n",(0,n.jsxs)(i.p,{children:["JPEG-XL (JXL) is a compression format for images that was developed by the Joint Photographic Experts Group (JPEG) in 2020. It is designed to provide improved compression efficiency compared to the traditional ",(0,n.jsx)(i.a,{href:"/docs/images/JPEG",children:"JPEG"})," format, while still maintaining image quality. JPEG-XL uses a combination of techniques such as perceptual color encoding, advanced entropy coding, and a new image prediction method to achieve its improved compression performance. It also has a lossless JPEG recompression mode, where an existing JPEG file can be turned into a JXL that can be decoded for a bit-for-bit exact replica of the original JPEG."]}),"\n",(0,n.jsx)(i.h2,{id:"performance-checklist",children:"Performance Checklist"}),"\n",(0,n.jsxs)(i.p,{children:["Lossless? ",(0,n.jsx)(i.em,{children:"Yes"})]}),"\n",(0,n.jsxs)(i.p,{children:["Lossy? ",(0,n.jsx)(i.em,{children:"Yes"})]}),"\n",(0,n.jsxs)(i.p,{children:["Supported Bit Depths:\n",(0,n.jsx)(i.em,{children:"Up to 32 BPC"})]}),"\n",(0,n.jsxs)(i.p,{children:["HDR/Wide Gamut? ",(0,n.jsx)(i.em,{children:"Yes"})]}),"\n",(0,n.jsxs)(i.p,{children:["Animation? ",(0,n.jsx)(i.em,{children:"Yes"})]}),"\n",(0,n.jsxs)(i.p,{children:["Transparency? ",(0,n.jsx)(i.em,{children:"Yes"})]}),"\n",(0,n.jsxs)(i.p,{children:["Progressive Decode? ",(0,n.jsx)(i.em,{children:"Yes"})]}),"\n",(0,n.jsxs)(i.p,{children:["Royalty Free? ",(0,n.jsx)(i.em,{children:"Yes"})]}),"\n",(0,n.jsx)(i.h2,{id:"format-breakdown",children:"Format Breakdown"}),"\n",(0,n.jsxs)(i.p,{children:["JPEG-XL has a number of standout features that make it an appealing image codec to work with for many use cases. From the ",(0,n.jsx)(i.a,{href:"https://jpegxl.info",children:"JPEG-XL Info page"}),", JXL has the following features:"]}),"\n",(0,n.jsxs)(i.ul,{children:["\n",(0,n.jsxs)(i.li,{children:[(0,n.jsx)(i.strong,{children:"Best lossless image compression"}),": It offers about 35% smaller file sizes than PNG (50% smaller for HDR)."]}),"\n",(0,n.jsxs)(i.li,{children:[(0,n.jsx)(i.strong,{children:"High-fidelity lossy image compression"}),": JPEG XL provides about 60% smaller file sizes than JPEG for the same visual quality."]}),"\n",(0,n.jsxs)(i.li,{children:[(0,n.jsx)(i.strong,{children:"Progressive decoding"}),": This allows an image to be displayed in lower quality before the entire file has been downloaded, improving user experience on slow connections."]}),"\n",(0,n.jsxs)(i.li,{children:[(0,n.jsx)(i.strong,{children:"Lossless JPEG transcoding"}),": JPEG images can be converted to JPEG XL without any mathematical loss, and the resulting file is about 20% smaller."]}),"\n",(0,n.jsxs)(i.li,{children:[(0,n.jsx)(i.strong,{children:"Designed for both photographic and synthetic images"}),": JPEG XL works well with a wide range of image types, including photos, graphics, and illustrations."]}),"\n",(0,n.jsxs)(i.li,{children:[(0,n.jsx)(i.strong,{children:"Fast software encoding and decoding"}),": The codec is designed to be efficient and fast, enabling quick image loading and saving."]}),"\n",(0,n.jsxs)(i.li,{children:[(0,n.jsx)(i.strong,{children:"Full support for wide gamut and HDR"}),": JPEG XL supports a wide range of colors and high dynamic range, making it suitable for modern displays."]}),"\n",(0,n.jsxs)(i.li,{children:[(0,n.jsx)(i.strong,{children:"Perceptually optimizing reference encoder"}),": The encoder is designed to optimize image quality based on how humans perceive images."]}),"\n"]}),"\n",(0,n.jsx)(i.h3,{id:"lossless-compression",children:"Lossless Compression"}),"\n",(0,n.jsx)(i.p,{children:"JPEG-XL offers excellent lossless compression capabilities. While lossless WebP was an improvement over PNG for 8-bit lossless image encoding, JPEG-XL manages not only to outdo lossless WebP in encoding efficiency but also be more versatile for bit depths greater than 8-bit (a category PNG previously dominated). 16-bit lossless imagery, especially HDR images that are becoming more popular & rarely utilize 8-bit color depth, are where JPEG-XL shines, and it is the only codec to compete with PNG in that regard while providing better coding efficiency."}),"\n",(0,n.jsxs)(i.p,{children:["Example: JPEG-XL compresses ",(0,n.jsx)(i.a,{href:"https://imgsaver.com/images/2023/10/03/16bit.png",children:"this 16-bit AdobeRGB PNG"})," better than PNG. Using: ",(0,n.jsx)(i.code,{children:"cjxl 16bit.png 16bit.jxl -d 0.0 -e 9 -I 100 -g 3 -E 11"})]}),"\n",(0,n.jsxs)(i.p,{children:["16-bit PNG: ",(0,n.jsx)(i.code,{children:"1533373"})," bytes.\n16-bit JXL: ",(0,n.jsx)(i.code,{children:"1211029"})," bytes."]}),"\n",(0,n.jsx)(i.h3,{id:"lossy-compression",children:"Lossy Compression"}),"\n",(0,n.jsx)(i.p,{children:"JPEG-XL is also adept at lossy compression, especially at quality levels that we as humans care about. It promises to be around 60% better than JPEG. While video-based codecs like AVIF can be competitive when given lots of CPU time, JPEG-XL is both fast and efficient for medium to high fidelity photographic imaging."}),"\n",(0,n.jsx)(i.h3,{id:"supported-bit-depths",children:"Supported Bit Depth(s)"}),"\n",(0,n.jsx)(i.p,{children:"JPEG-XL supports up to 32 bits per channel of bit depth, making it future proof for the increasingly popular HDR photos coming out of smartphones. There is essentially zero downside to encoding high bit depth with JXL relative to the resulting encode's size. Considering many smartphones take HDR photos now, JXL offers a compelling pipeline for these photos to make their way to the Web in the future especially as companies like Adobe & Apple have already embraced the new codec."}),"\n",(0,n.jsx)(i.h3,{id:"progressive-decode",children:"Progressive Decode"}),"\n",(0,n.jsx)(i.p,{children:"JPEG-XL provides actual progressive decode support that you can experiment with here on a supported browser like Safari, Waterfox, Thorium, Mercury, or any browser on iOS."}),"\n",(0,n.jsx)(i.p,{children:"Progressive decode is a feature only JPEG is able to offer a real implementation of, rendering low frequency transform coefficients before the rest of the image arrives to allow an image to display before the entire thing has been sent over the network. Blurhashes do not replace this technology, but rather compliment it, allowing another layer of progressive decode that can be used even before the image begins to load progressively. This is an important feature to improve the user experience on websites featuring large images, or on any website if your Internet connection isn't strong."}),"\n",(0,n.jsx)(i.h3,{id:"lossless-jpeg-re-compression",children:"Lossless JPEG Re-compression"}),"\n",(0,n.jsx)(i.p,{children:"An incredibly unique JPEG-XL feature is lossless JPEG re-compression, or the ability to take a JPEG input and provide an output with a smaller filesize (on average, 20% smaller) that is pixel-for-pixel identical. This is why companies like Meta have endorsed JPEG-XL, as it offers a path forward for the existing JPEGs on the Internet."}),"\n",(0,n.jsx)(i.h3,{id:"industry-support",children:"Industry Support"}),"\n",(0,n.jsx)(i.p,{children:"From the JPEG-XL Wikipedia page:"}),"\n",(0,n.jsxs)(i.blockquote,{children:["\n",(0,n.jsx)(i.p,{children:"Besides Cloudinary and Google originally, throughout JPEG XL's preliminary implementation in web browsers, various representatives of well-known industry brand names have publicly voiced support for JPEG XL as their preferred choice, including Facebook, Adobe, Intel and the Video Electronics Standards Association, The Guardian, Flickr and SmugMug, Shopify, the Krita Foundation, and Serif Ltd."}),"\n"]}),"\n",(0,n.jsx)(i.p,{children:"Apple also features ecosystem-wide JPEG-XL support as of iOS 17 & macOS Sonoma."}),"\n",(0,n.jsx)(i.h3,{id:"other-features",children:"Other Features"}),"\n",(0,n.jsx)(i.p,{children:"JPEG-XL has the potential to replace popular formats like TIFF for authoring workflows due to its broad feature set. From the JXL Wikipedia, some additional features include:"}),"\n",(0,n.jsxs)(i.ul,{children:["\n",(0,n.jsx)(i.li,{children:"Image dimensions of over a billion (2^30-1) pixels on each side."}),"\n",(0,n.jsx)(i.li,{children:"Up to 4099 channels, including support for alpha transparency"}),"\n",(0,n.jsx)(i.li,{children:"There can be multiple frames with zero duration, allowing support for layers in graphics software"}),"\n",(0,n.jsx)(i.li,{children:"Animation support, allowing JXL to rival GIF"}),"\n",(0,n.jsx)(i.li,{children:"Images can be stored in tiles to reduce the time needed to decode them."}),"\n",(0,n.jsx)(i.li,{children:"Graceful quality degradation across a large range of bitrates means quality loss isn't as abrupt as with older formats."}),"\n",(0,n.jsx)(i.li,{children:"Perceptually optimized reference encoder which uses a perceptual color space, adaptive quantization, and conservative default settings."}),"\n",(0,n.jsx)(i.li,{children:"Support for wide color gamut and HDR"}),"\n",(0,n.jsx)(i.li,{children:"Efficient encoding and decoding without requiring specialized hardware: JPEG XL is about as fast to encode and decode as old JPEG using libjpeg-turbo and an order of magnitude faster to encode and decode compared to HEIC with x265. It is also parallelizable."}),"\n",(0,n.jsx)(i.li,{children:"Royalty-free format with an open-source reference implementation available on GitHub."}),"\n"]}),"\n",(0,n.jsx)(i.h2,{id:"encoders",children:"Encoders"}),"\n",(0,n.jsx)(i.p,{children:"JPEG-XL has a couple of noteworthy encoders currently available to work with. Because JPEG-XL is so new, most encoders aren't yet intelligent enough to take advantage of the whole format yet. Here's a quote from Jon Sneyers in the JPEG-XL discord that sums it up nicely:"}),"\n",(0,n.jsxs)(i.blockquote,{children:["\n",(0,n.jsx)(i.p,{children:"Encode side: 80% or so of the coding tools are used in one way or another by the encoder (the 20% is splines and super large VarDCT blocks, and also the things that are not used by default without using special experimental options, such as delta palette and noise). But the coding tools that are used, are typically used in a specific, limited way that doesn't come anywhere close to exhausting the bitstream expressivity."}),"\n"]}),"\n",(0,n.jsxs)(i.p,{children:["Sneyers is talking about libjxl's ",(0,n.jsx)(i.code,{children:"cjxl"})," encoder, which will be discussed further below."]}),"\n",(0,n.jsx)(i.h3,{id:"libjxl",children:"libjxl"}),"\n",(0,n.jsxs)(i.p,{children:["The reference ",(0,n.jsx)(i.a,{href:"https://github.com/libjxl/libjxl",children:"libjxl"})," implementation has the capability to both decode and encode JPEG-XL image files. Both are discussed below."]}),"\n",(0,n.jsxs)(r.A,{children:[(0,n.jsxs)(o.A,{value:"enc",label:"Encoding",default:!0,children:[(0,n.jsxs)(i.p,{children:["libjxl's encoder ",(0,n.jsx)(i.code,{children:"cjxl"})," has more options to play around with. It takes a few primary arguments, distance (",(0,n.jsx)(i.code,{children:"-d"}),"), quality (",(0,n.jsx)(i.code,{children:"-q"}),"), and effort (",(0,n.jsx)(i.code,{children:"-e"}),")."]}),(0,n.jsx)(i.p,{children:(0,n.jsx)(i.strong,{children:"Distance and quality"})}),(0,n.jsxs)(i.p,{children:["Distance and quality are two ways of specifying ",(0,n.jsx)(i.em,{children:"how much loss"})," you are willing to tolerate, and as such, they are mutually exclusive, as they pull the same levers under the hood."]}),(0,n.jsxs)(i.ul,{children:["\n",(0,n.jsxs)(i.li,{children:["Distance is designed to map to how 'close' one must be to the source to notice any loss. It is represented as a scale between 0.0 & 25.0. 0.0 is ",(0,n.jsx)(i.strong,{children:"mathematically lossless"}),", every pixel will have the exact same value as the source. 1.0 is designed to be ",(0,n.jsx)(i.strong,{children:"visually lossless"}),", look the same at a normal viewing distance, and higher values have more loss."]}),"\n",(0,n.jsxs)(i.li,{children:["Quality is designed to roughly map to ",(0,n.jsx)(i.a,{href:"/docs/images/JPEG",children:"JPEG"}),"'s quality argument. A range 0-100, where 100 is ",(0,n.jsx)(i.strong,{children:"mathematically lossless"}),", 90 is intended to be ",(0,n.jsx)(i.strong,{children:"visually lossless"}),", and 0 is almost unrecognizable as the original image."]}),"\n"]}),(0,n.jsx)(i.p,{children:(0,n.jsx)(i.strong,{children:"Effort"})}),(0,n.jsxs)(i.p,{children:["Effort is similar to ",(0,n.jsx)(i.code,{children:"cpu-used"})," in video encoding. It specifies the amount of effort the encoder will make in order to get the smallest file size it can. It takes the form of a range 1-9, where higher numbers will spend more resources to get diminishing returns in terms of smaller size, while lower values do the opposite, leaving file size on the table for faster encoding."]}),(0,n.jsx)(i.pre,{children:(0,n.jsx)(i.code,{className:"language-bash",metastring:'title="Encoding with effort 9 and distance 1.0"',children:"cjxl -e 9 -d 1.0 example.png example.jxl\n"})}),(0,n.jsx)(i.pre,{children:(0,n.jsx)(i.code,{className:"language-bash",metastring:'title="This, by default uses lossless JPEG compression."',children:"cjxl example.jpg example.jxl\n"})})]}),(0,n.jsxs)(o.A,{value:"dec",label:"Decoding",children:[(0,n.jsxs)(i.p,{children:["Decoding a ",(0,n.jsx)(i.code,{children:".jxl"})," image is straightforward with libjxl's decoder, ",(0,n.jsx)(i.code,{children:"djxl"}),":"]}),(0,n.jsx)(i.pre,{children:(0,n.jsx)(i.code,{className:"language-bash",children:"djxl example.jxl example.png\n"})}),(0,n.jsxs)(i.p,{children:[(0,n.jsx)(i.code,{children:"djxl"})," can decode to pixels via pipes, png, apng for animated jxl, jpg, ppm, and pfm."]}),(0,n.jsxs)(i.p,{children:["By default, if the ",(0,n.jsx)(i.code,{children:".jxl"})," file was encoded with lossless jpeg recompression, ",(0,n.jsx)(i.code,{children:"djxl"})," will rebuild the exact jpeg file that was originally compressed. To avoid this, and create a new jpeg file:"]}),(0,n.jsx)(i.pre,{children:(0,n.jsx)(i.code,{className:"language-bash",children:"djxl -j example.jxl example.jpg\n"})}),(0,n.jsx)(i.p,{children:(0,n.jsxs)(i.strong,{children:["Keep in mind this is now a lossy process as ",(0,n.jsx)(i.code,{children:"djxl"})," will decode to pixels, then encode a new ",(0,n.jsx)(i.code,{children:".jpg"})," with those pixels."]})})]}),(0,n.jsxs)(o.A,{value:"build",label:"Building",children:[(0,n.jsxs)(i.p,{children:["A full build guide is provided in the ",(0,n.jsx)(i.a,{href:"https://github.com/libjxl/libjxl/blob/main/BUILDING.md",children:"libjxl build instructions"})," in the GitHub repo. This guide is simplified, and is only focused on building a working efficient encoder & decoder."]}),(0,n.jsx)(i.p,{children:"These instructions should work for macOS and Linux, although macOS support isn't guaranteed."}),(0,n.jsx)(i.pre,{children:(0,n.jsx)(i.code,{className:"language-bash",metastring:'title="1. Clone the repo"',children:"git clone https://github.com/libjxl/libjxl.git --recursive --shallow-submodules\n"})}),(0,n.jsx)(i.pre,{children:(0,n.jsx)(i.code,{className:"language-bash",metastring:'title="2. Install dependencies. May have to run these commands with root"',children:"apt install cmake pkg-config libbrotli-dev clang # Debian Linux\npacman -Syu cmake pkgconf brotli clang # Arch Linux\nbrew install cmake pkg-config brotli # macOS\n"})}),(0,n.jsx)(i.pre,{children:(0,n.jsx)(i.code,{className:"language-bash",metastring:'title="3. Set CC & CXX variables before building (Recommended)"',children:"export CC=clang CXX=clang++\n"})}),(0,n.jsx)(i.pre,{children:(0,n.jsx)(i.code,{className:"language-bash",metastring:'title="4. cjxl & djxl will be available in the build/tools directory."',children:'cd libjxl && mkdir build && cd build\ncmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_FLAGS="-O3 -march=native" -DCMAKE_C_FLAGS="-O3 -march=native" -DBUILD_TESTING=OFF -DJPEGXL_WARNINGS_AS_ERRORS=OFF -DJPEGXL_ENABLE_SJPEG=OFF ..\ncmake --build . -- -j$(nproc)\n'})}),(0,n.jsxs)(i.p,{children:["This will build ",(0,n.jsx)(i.code,{children:"cjxl"})," and ",(0,n.jsx)(i.code,{children:"djxl"})," with O3 optimization for your CPU architecture on Linux or macOS. Again, be aware that macOS support is not a priority. Via the libjxl OS X build guide:"]}),(0,n.jsxs)(i.blockquote,{children:["\n",(0,n.jsx)(i.p,{children:'OSX builds have "best effort" support, i.e. build might not work at all, some tests may fail and some sub-projects are excluded from build.'}),"\n"]})]})]}),"\n",(0,n.jsx)(i.h3,{id:"libjxl-tiny",children:"libjxl-tiny"}),"\n",(0,n.jsxs)(i.p,{children:[(0,n.jsx)(i.a,{href:"https://github.com/libjxl/libjxl-tiny",children:"libjxl-tiny"})," contains a simpler encoder implementation of JPEG XL, aimed at photographic images without an alpha channel. The goal is to guide hardware implementations of the encoder where support for the full set of encoding tools is not feasible. The color management is outside the scope of this library, the encoder input is given as a portable float map (PFM) in the linear sRGB colorspace, where individual sample values can be outside the [0.0, 1.0] range for out-of-gammut colors. For more details, see the ",(0,n.jsx)(i.a,{href:"https://github.com/libjxl/libjxl-tiny/blob/main/doc/coding_tools.md",children:"overview of the coding tools"}),"."]}),"\n",(0,n.jsx)(i.p,{children:"The last commit was ten months ago, so it is uncertain whether libjxl-tiny could be considered active."}),"\n",(0,n.jsx)(i.h3,{id:"hydrium",children:"Hydrium"}),"\n",(0,n.jsxs)(i.p,{children:[(0,n.jsx)(i.a,{href:"https://github.com/Traneptora/hydrium",children:"Hydrium"})," is a fast, ultra-low-memory, streaming JPEG XL encoder written in portable C. It is maintained by Traneptora."]}),"\n",(0,n.jsx)(i.h3,{id:"zune-jpegxl",children:"zune-jpegxl"}),"\n",(0,n.jsxs)(i.p,{children:[(0,n.jsx)(i.a,{href:"https://github.com/etemesi254/zune-image/tree/dev/crates/zune-jpegxl",children:"zune-jpegxl"})," is a simple, fast and fully safe modular JXL encoder written in Rust. It is maintained by etemesi254."]}),"\n",(0,n.jsx)(i.p,{children:"zune-jpegxl has the following features:"}),"\n",(0,n.jsxs)(i.ul,{children:["\n",(0,n.jsx)(i.li,{children:"Lossless encoding"}),"\n",(0,n.jsx)(i.li,{children:"8 bit and 16 bit support"}),"\n",(0,n.jsx)(i.li,{children:"Grayscale and RGBA encoding"}),"\n",(0,n.jsx)(i.li,{children:"Threading capabilities"}),"\n"]}),"\n","\n",(0,n.jsx)(i.p,{children:"Sources:"}),"\n",(0,n.jsxs)(i.ul,{children:["\n",(0,n.jsx)(i.li,{children:(0,n.jsx)(i.a,{href:"https://en.wikipedia.org/wiki/JPEG_XL",children:"JXL Wikipedia"})}),"\n",(0,n.jsx)(i.li,{children:(0,n.jsx)(i.a,{href:"https://jpegxl.info/why-jxl.html",children:"JPEGXL.info: Why JXL"})}),"\n",(0,n.jsx)(i.li,{children:(0,n.jsx)(i.a,{href:"https://webkit.org/blog/14205/news-from-wwdc23-webkit-features-in-safari-17-beta/#images",children:"Apple JXL Announcement"})}),"\n",(0,n.jsx)(i.li,{children:(0,n.jsx)(i.a,{href:"https://cloudinary.com/blog/jpeg-xl-how-it-started-how-its-going",children:"JPEG XL: How It Started, How It's Going"})}),"\n",(0,n.jsx)(i.li,{children:(0,n.jsx)(i.a,{href:"https://cloudinary.com/blog/the-case-for-jpeg-xl",children:"The Case for JPEG XL"})}),"\n",(0,n.jsx)(i.li,{children:(0,n.jsx)(i.a,{href:"https://cloudinary.com/blog/time_for_next_gen_codecs_to_dethrone_jpeg",children:"Time for Next-Gen Codecs to Dethrone JPEG"})}),"\n",(0,n.jsx)(i.li,{children:(0,n.jsx)(i.a,{href:"https://giannirosato.com/blog/post/image-comparison/",children:"Image Codec Comparison"})}),"\n"]})]})}function p(e={}){const{wrapper:i}={...(0,t.R)(),...e.components};return i?(0,n.jsx)(i,{...e,children:(0,n.jsx)(u,{...e})}):u(e)}},9365:(e,i,s)=>{s.d(i,{A:()=>o});s(6540);var n=s(8215);const t={tabItem:"tabItem_Ymn6"};var r=s(4848);function o(e){let{children:i,hidden:s,className:o}=e;return(0,r.jsx)("div",{role:"tabpanel",className:(0,n.A)(t.tabItem,o),hidden:s,children:i})}},1470:(e,i,s)=>{s.d(i,{A:()=>w});var n=s(6540),t=s(8215),r=s(3104),o=s(6347),a=s(205),l=s(7485),c=s(1682),d=s(9466);function h(e){return n.Children.toArray(e).filter((e=>"\n"!==e)).map((e=>{if(!e||(0,n.isValidElement)(e)&&function(e){const{props:i}=e;return!!i&&"object"==typeof i&&"value"in i}(e))return e;throw new Error(`Docusaurus error: Bad child <${"string"==typeof e.type?e.type:e.type.name}>: all children of the component should be , and every should have a unique "value" prop.`)}))?.filter(Boolean)??[]}function u(e){const{values:i,children:s}=e;return(0,n.useMemo)((()=>{const e=i??function(e){return h(e).map((e=>{let{props:{value:i,label:s,attributes:n,default:t}}=e;return{value:i,label:s,attributes:n,default:t}}))}(s);return function(e){const i=(0,c.X)(e,((e,i)=>e.value===i.value));if(i.length>0)throw new Error(`Docusaurus error: Duplicate values "${i.map((e=>e.value)).join(", ")}" found in . Every value needs to be unique.`)}(e),e}),[i,s])}function p(e){let{value:i,tabValues:s}=e;return s.some((e=>e.value===i))}function m(e){let{queryString:i=!1,groupId:s}=e;const t=(0,o.W6)(),r=function(e){let{queryString:i=!1,groupId:s}=e;if("string"==typeof i)return i;if(!1===i)return null;if(!0===i&&!s)throw new Error('Docusaurus error: The component groupId prop is required if queryString=true, because this value is used as the search param name. You can also provide an explicit value such as queryString="my-search-param".');return s??null}({queryString:i,groupId:s});return[(0,l.aZ)(r),(0,n.useCallback)((e=>{if(!r)return;const i=new URLSearchParams(t.location.search);i.set(r,e),t.replace({...t.location,search:i.toString()})}),[r,t])]}function g(e){const{defaultValue:i,queryString:s=!1,groupId:t}=e,r=u(e),[o,l]=(0,n.useState)((()=>function(e){let{defaultValue:i,tabValues:s}=e;if(0===s.length)throw new Error("Docusaurus error: the component requires at least one