├── .gitignore ├── setup_py_vp_environment.bat ├── cmd_with_path.bat ├── setup_py_vp_environment.ps1 ├── README_RAV1E.md ├── Av1anStaxRipWrapperRav1e.py ├── README.md └── Av1anStaxRipWrapper.py /.gitignore: -------------------------------------------------------------------------------- 1 | .vscode/settings.json 2 | VapourSynth 3 | -------------------------------------------------------------------------------- /setup_py_vp_environment.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | REM Place me in StaxRip\Apps\Encoders\Av1anStaxRipWrapper 3 | powershell -ExecutionPolicy Bypass -File "%~dp0setup_py_vp_environment.ps1" -------------------------------------------------------------------------------- /cmd_with_path.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | REM This batch script needs to be run in StaxRip\Apps\Encoders\Av1anStaxRipWrapper! 3 | echo. 4 | echo This batch script needs to be run in StaxRip\Apps\Encoders\Av1anStaxRipWrapper! 5 | SET PATH=..\Av1an;..\aomenc;..\rav1e;..\SVT-AV1;..\SvtAv1EncApp;..\x264;..\x265;..\..\Support\MKVToolNix;.\VapourSynth;%PATH% 6 | echo ================================================= 7 | echo Av1anStaxRipWrapper 8 | echo https://github.com/Kidsnd274/Av1anStaxRipWrapper 9 | echo. 10 | echo Path set, you can now access encoder tools 11 | echo No need to use -s flag for scripts 12 | echo ================================================= 13 | echo. 14 | cmd /K 15 | exit -------------------------------------------------------------------------------- /setup_py_vp_environment.ps1: -------------------------------------------------------------------------------- 1 | # Place me in StaxRip\Apps\Encoders\Av1anStaxRipWrapper 2 | echo "Creating Portable VapourSynth install..." 3 | mkdir temp 4 | cd temp 5 | Invoke-WebRequest -Uri "https://www.7-zip.org/a/7zr.exe" -OutFile "7z.exe" 6 | Invoke-WebRequest -Uri "https://github.com/vapoursynth/vapoursynth/releases/download/R61/VapourSynth64-Portable-R61.7z" -OutFile "VapourSynth64-Portable-R61.7z" 7 | Invoke-WebRequest -Uri "https://www.python.org/ftp/python/3.10.9/python-3.10.9-embed-amd64.zip" -OutFile "python-3.10.9-embed-amd64.zip" 8 | mkdir ..\VapourSynth 9 | cd ..\VapourSynth 10 | ..\temp\7z.exe x ..\temp\VapourSynth64-Portable-R61.7z -y 11 | Expand-Archive ..\temp\python-3.10.9-embed-amd64.zip -DestinationPath . -Force 12 | Remove-Item -Recurse -Force ..\temp 13 | echo "Setting up Python modules psutil" 14 | Invoke-WebRequest -Uri "https://bootstrap.pypa.io/get-pip.py" -OutFile "get-pip.py" 15 | .\python.exe get-pip.py 16 | (Get-Content python310._pth) -replace '#import site', 'import site' | Out-File -encoding ASCII python310._pth 17 | .\Scripts\pip.exe install psutil 18 | echo "Copying lsmas ffms2 to VapourSynth plugin directory" 19 | copy ..\..\..\Plugins\Dual\FFMS2\ffms2.dll .\vapoursynth64\plugins 20 | copy ..\..\..\Plugins\Dual\L-Smash-Works\LSMASHSource.dll .\vapoursynth64\plugins 21 | pause -------------------------------------------------------------------------------- /README_RAV1E.md: -------------------------------------------------------------------------------- 1 | # Av1anStaxRipWrapperRav1e 2 | Python wrapper script to use Av1an and rav1e with StaxRip 3 | 4 | **This script is more specialized for rav1e. Use the [generic script](README.md) for other encoders.** 5 | 6 | The generic script is capable to using rav1e as well and has the capability to use any arguments that the selected encoder and Av1an allows. 7 | This script is less flexible but the command line arguments are neater as it is more focused on rav1e. 8 | 9 | [INSTALL AND USAGE GUIDE (YouTube)](https://www.youtube.com/watch?v=lMfTwd0qDC8) for rav1e Script 10 | 11 | ## Contents 12 | - [Av1anStaxRipWrapperRav1e](#av1anstaxripwrapper) 13 | - [Contents](#contents) 14 | - [Usage](#usage) 15 | - [Requirements](#requirements) 16 | - [Setup](#setup) 17 | - [Portable Installation](#portable-installation) 18 | - [Alternative Installation (install tools to system PATH)](#alternative-installation-install-tools-to-system-path) 19 | - [Command Line Options](#command-line-options) 20 | - [Automatic Thread Detection](#automatic-thread-detection) 21 | 22 | ## Usage 23 | This script makes use of the Command Line option in StaxRip. There are some required arguments needed in the command that allows Av1an to work with StaxRip. Namely `-i "%source_file%" -o "%encoder_out_file%" -t "%temp_dir%av1an_temp"`. `-s "%startup_dir%"` is needed if you want a portable installation. Portable installation is described in more detail at the [Setup](#setup) section. 24 | 25 | staxrip_image 26 | 27 | A good starting command would be: 28 | 29 | ``` 30 | "%startup_dir%\Apps\Encoders\Av1anStaxRipWrapper\VapourSynth\python.exe" "%startup_dir%\Apps\Encoders\Av1anStaxRipWrapper\Av1anStaxRipWrapperRav1e.py" -s "%startup_dir%" -i "%source_file%" -o "%encoder_out_file%" -t "%temp_dir%av1an_temp" --pix-format yuv420p10le --quantizer 60 --speed 6 --tiles 2 --threads 2 --photon-noise 2 --chroma-noise --sc-downscale-height 540 31 | ``` 32 | Everything after the `-t` parameter will affect the encoding parameters (either Av1an or rav1e). Refer to [Command Line Options](#command-line-options) section for more information. 33 | 34 | ## Requirements 35 | - [ffmpeg](https://ffmpeg.org/download.html) (with shared libraries) (Av1an requirement) 36 | - [rav1e](https://github.com/xiph/rav1e/releases) 37 | - [StaxRip](https://github.com/staxrip/staxrip/releases) 38 | 39 | This script also requires the `psutil` module in Python to automatically detect CPU core counts to pass into av1an. 40 | - You can run with the `--disable-automatic-thread-detection` flag to disable this feature and requirement 41 | 42 | ## Setup 43 | ### Portable Installation 44 | Since Av1an requires `ffmpeg`, `rav1e`, `VapourSynth` to be in PATH, this script can automatically help you add important folders (from StaxRip) temporarily to PATH when it's being run (for portable installation). In this way, your actual system PATH is not affected when running Av1an. However, this means that you need to install the tools in specific folders in StaxRip as the wrapper script looks for them there. 45 | 46 | Portable mode is enabled when the `-s` flag is used with the StaxRip startup directory. 47 | 48 | 1. Ensure encoders, Av1an and the wrapper script are extracted in the right directories 49 | - Av1an: `StaxRip\Apps\Encoders\Av1an` 50 | - rav1e: `StaxRip\Apps\Encoders\rav1e` 51 | - FFMPEG: `StaxRip\Apps\Encoders\Av1an` (moving it to an `ffmpeg` folder would interfere with StaxRip's own ffmpeg) 52 | - Wrapper Script: `StaxRip\Apps\Encoders\Av1anStaxRipWrapper` 53 | 2. Run the `setup_py_vp_environment.bat` script from the Av1anStaxRipWrapper folder to install required Python modules and VapourSynth plugins 54 | 3. Use the **Command Line** encoder profile to create an Av1an Encoder Profile 55 | staxrip_image 56 | staxrip_image 57 | 58 | Good starting command: (make sure to change **Output File Type** to `mkv`) 59 | ``` 60 | "%startup_dir%\Apps\Encoders\Av1anStaxRipWrapper\VapourSynth\python.exe" "%startup_dir%\Apps\Encoders\Av1anStaxRipWrapper\Av1anStaxRipWrapperRav1e.py" -s "%startup_dir%" -i "%source_file%" -o "%encoder_out_file%" -t "%temp_dir%av1an_temp" --pix-format yuv420p10le --quantizer 60 --speed 6 --tiles 2 --threads 2 --photon-noise 2 --chroma-noise --sc-downscale-height 540 61 | ``` 62 | 63 | 4. Save this Encoder Profile with the name `AV1 | av1an rav1e`, and it will appear in the AV1 drop-down menu. 64 | ![image](https://user-images.githubusercontent.com/1343896/209458707-bca3edda-36af-4d3d-b4a5-899160a5e8d9.png) 65 | 66 | 67 | ### Alternative Installation (install tools to system PATH) 68 | Basically, just make sure `Av1an`, `ffmpeg`, `rav1e`, `Python`, `VapourSynth` are all accessible from PATH and follow the steps above from Step 2. 69 | 70 | The command in StaxRip used is\ 71 | `python "%startup_dir%\Apps\Encoders\Av1anStaxRipWrapper\Av1anStaxRipWrapperRav1e.py" -i "%source_file%" -o "%encoder_out_file%" -t "%temp_dir%av1an_temp" --pix-format yuv420p10le --quantizer 60 --speed 6 --tiles 2 --threads 2 --photon-noise 2 --chroma-noise --sc-downscale-height 540` 72 | 73 | ## Command Line Options 74 | ``` 75 | optional arguments: 76 | -h, --help show this help message and exit 77 | --version Print Av1an, ffmpeg and rav1e versions 78 | -i INPUT Input File (for StaxRip) 79 | -o OUTPUT Output File (for StaxRip) 80 | -t TEMPDIR Temp Directory (for StaxRip) 81 | -s STAXRIP_STARTUP_DIR, --staxrip-startup-dir STAXRIP_STARTUP_DIR 82 | Specify StaxRip Startup Directory so that the wrapper script will automatically add important 83 | folders to PATH for av1an to detect (only needed for portable installations) 84 | 85 | # Av1an parameters 86 | --photon-noise PHOTON_NOISE 87 | Generates a photon noise table and applies it using grain synthesis [strength: 0-64] (disabled 88 | by default) (Av1an parameter) 89 | --chroma-noise Adds chroma grain synthesis to the grain table generated by `--photon-noise`. (Default: false) 90 | (Av1an parameter) 91 | --sc-downscale-height SC_DOWNSCALE_HEIGHT 92 | Optional downscaling for scene detection. By default, no downscaling is performed. (Av1an 93 | parameter) 94 | --pix-format PIX_FORMAT 95 | FFmpeg pixel format 96 | 97 | # Threading parameters (Using any of these would disable the wrapper's Automatic Thread Detection feature) 98 | --workers WORKERS Number of workers to spawn [0 = automatic] (Av1an Paramter) 99 | --set-thread-affinity SET_THREAD_AFFINITY 100 | Pin each worker to a specific set of threads of this size (disabled by default) (Av1an 101 | parameter) 102 | --disable-automatic-thread-detection 103 | Disable the wrapper's automatic thread detection 104 | 105 | # rav1e parameters 106 | --quantizer QUANTIZER 107 | Quantizer (0-255), smaller values are higher quality (default: 100) (rav1e parameter) 108 | --speed SPEED Speed level (0 is best quality, 10 is fastest) Speeds 10 and 0 are extremes and are generally 109 | not recommended [default: 6] (rav1e parameter) 110 | --tiles TILES Number of tiles. Tile-cols and tile-rows are overridden so that the video has at least this 111 | many tiles (rav1e parameter) 112 | --threads THREADS Set the threadpool size. If 0, will use the number of logical CPUs. rav1e will use up to this 113 | many threads. Additional tiles may be needed to increase thread utilization [default: 0] 114 | (rav1e parameter) 115 | ``` 116 | 117 | ## Automatic Thread Detection 118 | In my testing, I found that I get the best utilization and encoding speeds when creating the same number of workers as the number of physical cores available in your system. Along with having the number of threads per worker be 2 if your system supports hyperthreading/SMT and 1 if your system does not. 119 | 120 | With automatic thread detection, the wrapper script will automatically detect and pass in the relevant parameters to Av1an. For example, 121 | 122 | ``` 123 | Ryzen 7 5800X 124 | Physical Cores: 8 cores 125 | Logical Cores: 16 cores 126 | Hyperthreading/SMT: Enabled 127 | Threading Parameters: --workers 8 --set-thread--affinity 2 128 | 129 | Intel i5-6600K 130 | Physical Cores: 4 cores 131 | Logical Cores: 4 cores 132 | Hyperthreading/SMT: Disabled 133 | Threading Parameters: --workers 4 --set-thread-affinity 1 134 | ``` 135 | 136 | If your system uses an Intel 12th Gen chip and above (with the new hybrid architecture with P-cores and E-cores), this feature is disabled. 137 | 138 | If you do not want to use this feature, you can use the `--disable-automatic-thread-detection` flag or any of the Threading parameters under [Command Line Options](#command-line-options). Using any the Threading parameters would disable this feature. 139 | -------------------------------------------------------------------------------- /Av1anStaxRipWrapperRav1e.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | import subprocess 3 | import sys 4 | 5 | sys.stdout.reconfigure(encoding='utf-8') 6 | 7 | # This script is more specialized for rav1e. 8 | # Use the generic script for other encoders. https://github.com/Kidsnd274/Av1anStaxRipWrapper 9 | 10 | # Functions 11 | def add_argument(curr, new): 12 | return_string = curr 13 | if curr == "": 14 | return_string = new 15 | else: 16 | return_string += (" " + new) 17 | return return_string 18 | 19 | def set_path(path): 20 | import os 21 | import pathlib 22 | staxrip_path = pathlib.Path(path) 23 | av1an_path = staxrip_path / "Apps" / "Encoders" / "Av1an" 24 | rav1e_path = staxrip_path / "Apps" / "Encoders" / "rav1e" 25 | vp_path = staxrip_path / "Apps" / "Encoders" / "Av1anStaxRipWrapper" / "VapourSynth" 26 | environ = os.environ 27 | environ["PATH"] = f"{str(av1an_path)};{str(rav1e_path)};{str(vp_path)};{environ['PATH']}" 28 | return environ 29 | 30 | def print_welcome(): 31 | print("=================================================") 32 | print("Av1anStaxRipWrapperRav1e") 33 | print("https://github.com/Kidsnd274/Av1anStaxRipWrapper\n") 34 | print("This script is more specialized for rav1e") 35 | print("Use the generic script for other encoders") 36 | print("=================================================") 37 | print("") 38 | 39 | def print_version(parser_args): 40 | if parser_args.staxrip_startup_dir is not None: 41 | my_env = set_path(parser_args.staxrip_startup_dir) 42 | else: 43 | import os 44 | my_env = os.environ 45 | try: 46 | subprocess.run("ffmpeg -version", shell=False, env=my_env) 47 | except FileNotFoundError: 48 | print("ffmpeg not found!") 49 | print("\n--------------------------------\n") 50 | try: 51 | subprocess.run("av1an --version", shell=False, env=my_env) 52 | except FileNotFoundError: 53 | print("Av1an not found!") 54 | print("\n--------------------------------\n") 55 | try: 56 | subprocess.run("rav1e --version", shell=False, env=my_env) 57 | except FileNotFoundError: 58 | print("rav1e not found!") 59 | print("\n--------------------------------\n") 60 | exit(0) 61 | 62 | # Command Line Arguments 63 | parser = argparse.ArgumentParser(description="Av1an wrapper for StaxRip") 64 | 65 | parser.add_argument('--version', action='store_true', help="Print Av1an, ffmpeg and rav1e versions") 66 | parser.add_argument('-i', dest="input", type=str, help="Input File (for StaxRip)") 67 | parser.add_argument('-o', dest="output", type=str, help="Output File (for StaxRip)") 68 | parser.add_argument('-t', dest="tempdir", type=str, help="Temp Directory (for StaxRip)") 69 | parser.add_argument('-s', '--staxrip-startup-dir', dest="staxrip_startup_dir", type=str, required=False, help="Specify StaxRip Startup Directory so that the wrapper script will automatically add important folders to PATH for av1an to detect (only needed for portable installations)") 70 | parser.add_argument('--photon-noise', dest="photon_noise", type=str, required=False, help="Generates a photon noise table and applies it using grain synthesis [strength: 0-64] (disabled by default) (Av1an parameter)") 71 | parser.add_argument('--chroma-noise', dest="chroma_noise", action='store_true', help="Adds chroma grain synthesis to the grain table generated by `--photon-noise`. (Default: false) (Av1an parameter)") 72 | parser.add_argument('--sc-downscale-height', dest="sc_downscale_height", type=str, required=False, help="Optional downscaling for scene detection. By default, no downscaling is performed. (Av1an parameter)") 73 | parser.add_argument('--pix-format', dest="pix_format", type=str, required=False, help="FFmpeg pixel format") 74 | # Threading Arguments (do not specify these commands if you want to use Automatic Thread Detection) 75 | parser.add_argument('--workers', type=str, required=False, help="Number of workers to spawn [0 = automatic] (Av1an Paramter)") 76 | parser.add_argument('--set-thread-affinity', dest="set_thread_affinity", type=str, required=False, help="Pin each worker to a specific set of threads of this size (disabled by default) (Av1an parameter)") 77 | parser.add_argument('--disable-automatic-thread-detection', dest="disable_automatic_thread_detection", action='store_true', help="Disable the wrapper's automatic thread detection") 78 | # Rav1e arguments 79 | parser.add_argument('--quantizer', type=str, required=False, help="Quantizer (0-255), smaller values are higher quality (default: 100) (rav1e parameter)") # Quantizer (0-255), smaller values are higher quality (default: 100) 80 | parser.add_argument('--speed', type=str, required=False, help="Speed level (0 is best quality, 10 is fastest)\nSpeeds 10 and 0 are extremes and are generally not recommended\n[default: 6] (rav1e parameter)") # Speed level 0-10 (0 is best quality, 10 is fastest) (default: 6) 81 | parser.add_argument('--tiles', type=str, required=False, help="Number of tiles. Tile-cols and tile-rows are overridden so that the video has at least this many tiles (rav1e parameter)") 82 | parser.add_argument('--threads', type=str, required=False, help="Set the threadpool size. If 0, will use the number of logical CPUs. rav1e will use up to this many threads.\nAdditional tiles may be needed to increase thread utilization\n[default: 0] (rav1e parameter)") 83 | parser_args = parser.parse_args() 84 | 85 | print_welcome() 86 | 87 | if parser_args.version: 88 | print_version(parser_args) 89 | 90 | if parser_args.input is None or parser_args.output is None or parser_args.tempdir is None: 91 | print("The arguments, -i, -o, -t are required to work!") 92 | print("Run --help for more information") 93 | exit(1) 94 | 95 | input_file = parser_args.input 96 | output_file = parser_args.output 97 | tempdir = parser_args.tempdir 98 | 99 | # # Parsing rav1e arguments 100 | rav1e_argument_string = "" 101 | 102 | if parser_args.speed is not None: 103 | rav1e_argument_string = add_argument(rav1e_argument_string, f"--speed {parser_args.speed}") 104 | if parser_args.quantizer is not None: 105 | rav1e_argument_string = add_argument(rav1e_argument_string, f"--quantizer {parser_args.quantizer}") 106 | if parser_args.tiles is not None: 107 | rav1e_argument_string = add_argument(rav1e_argument_string, f"--tiles {parser_args.tiles}") 108 | if parser_args.threads is not None: 109 | rav1e_argument_string = add_argument(rav1e_argument_string, f"--threads {parser_args.threads}") 110 | 111 | # Automatic Thread Detection 112 | thread_detection = False 113 | if not parser_args.disable_automatic_thread_detection and parser_args.workers is None and parser_args.set_thread_affinity is None: 114 | thread_detection = True 115 | 116 | if thread_detection: # Checking for new Intel architecture 117 | import psutil 118 | logical_count = psutil.cpu_count(logical = True) 119 | physical_count = psutil.cpu_count(logical = False) 120 | if (logical_count / physical_count) % 1 != 0: 121 | thread_detection = False # Intel CPU detected 122 | print("New Intel CPU architecture with performance and efficiency cores detected!\nNot passing thread detection to av1an...\n") 123 | 124 | if thread_detection: # Checking for Hyperthreading or SMT 125 | import psutil 126 | logical_count = psutil.cpu_count(logical = True) 127 | physical_count = psutil.cpu_count(logical = False) 128 | if (logical_count / physical_count) == 2: 129 | hyperthreading = True 130 | else: 131 | hyperthreading = False 132 | 133 | if thread_detection: # Setting values 134 | if hyperthreading: 135 | cpu_workers = physical_count 136 | cpu_thread_affinity = 2 137 | else: 138 | cpu_workers = physical_count 139 | cpu_thread_affinity = 1 140 | print(f"THREADING INFORMATION:\n Hyperthreading / SMT: {hyperthreading}\n Workers: {cpu_workers}\n Thread Affinity: {cpu_thread_affinity}\n\n") 141 | else: 142 | print("THREADING INFORMATION:\n Automatic Thread Detection: DISABLED\n\n") 143 | 144 | # If StaxRip path given, automatically add important folders to PATH 145 | if parser_args.staxrip_startup_dir is not None: 146 | my_env = set_path(parser_args.staxrip_startup_dir) 147 | 148 | av1an_exec = "av1an.exe" 149 | 150 | command = av1an_exec 151 | command = add_argument(command, "--verbose -y --resume -a=\"-an\" -e rav1e") 152 | 153 | # Thread arguments 154 | if thread_detection: 155 | command = add_argument(command, f"--workers {cpu_workers} --set-thread-affinity {cpu_thread_affinity}") 156 | else: 157 | if parser_args.workers is not None: 158 | command = add_argument(command, f"--workers {parser_args.workers}") 159 | if parser_args.set_thread_affinity is not None: 160 | command = add_argument(command, f"--set-thread-affinity {parser_args.set_thread_affinity}") 161 | 162 | if parser_args.photon_noise is not None: 163 | command = add_argument(command, f"--photon-noise {parser_args.photon_noise}") 164 | if parser_args.chroma_noise: 165 | command = add_argument(command, f"--chroma-noise") 166 | if parser_args.sc_downscale_height is not None: 167 | command = add_argument(command, f"--sc-downscale-height {parser_args.sc_downscale_height}") 168 | if parser_args.pix_format is not None: 169 | command = add_argument(command, f"--pix-format {parser_args.pix_format}") 170 | 171 | if rav1e_argument_string != "": 172 | command = add_argument(command, f"-v=\"{rav1e_argument_string} --no-scene-detection\"") 173 | 174 | command = add_argument(command, f"-i \"{input_file}\" -o \"{output_file}\" --temp \"{tempdir}\"") 175 | 176 | sys.stdout.write("Starting av1an... Check new console window for progress\n") 177 | sys.stdout.write("Command: " + str(command) + "\n") 178 | sys.stdout.flush() 179 | 180 | if parser_args.staxrip_startup_dir is not None: 181 | process = subprocess.run(command, shell=False, creationflags=subprocess.CREATE_NEW_CONSOLE, env=my_env) 182 | else: 183 | process = subprocess.run(command, shell=False, creationflags=subprocess.CREATE_NEW_CONSOLE) # Assume everything is in PATH 184 | 185 | if process.returncode != 0: 186 | print(process.stderr) 187 | print("Error occurred when transcoding with av1an. Check logs") 188 | exit(1) 189 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Av1anStaxRipWrapper 2 | Python wrapper script to use Av1an with StaxRip 3 | 4 | [Av1anStaxRipWrapperRav1e](README_RAV1E.md) (OUTDATED rav1e specialized script README)\ 5 | [INSTALL AND USAGE GUIDE (YouTube)](https://youtu.be/a7IPQcNVwTY) 6 | 7 | ## Contents 8 | - [Av1anStaxRipWrapper](#av1anstaxripwrapper) 9 | - [Contents](#contents) 10 | - [Usage](#usage) 11 | - [Requirements](#requirements) 12 | - [Setup](#setup) 13 | - [Portable Installation (Recommended)](#portable-installation-recommended) 14 | - [Alternative Installation (install tools to system PATH)](#alternative-installation-install-tools-to-system-path) 15 | - [Command Line Options](#command-line-options) 16 | - [Automatic Thread Detection](#automatic-thread-detection) 17 | - [Override Worker Count and Threads Per Local Machine](#override-worker-count-and-threads-per-local-machine) 18 | - [Setting the override worker count](#setting-the-override-worker-count) 19 | - [Check to see if it's working](#check-to-see-if-its-working) 20 | - [Structure of override-workers.json](#structure-of-override-workersjson) 21 | 22 | ## Usage 23 | This script makes use of the Command Line option in StaxRip. There are some required arguments needed in the command that allows Av1an to work with StaxRip. Namely `-i "%source_file%" -o "%encoder_out_file%" -t "%temp_dir%av1an_temp"`. `-s "%startup_dir%"` is needed if you want a portable installation. Portable installation is described in more detail at the [Setup](#setup) section. 24 | 25 | staxrip_image 26 | 27 | A good starting command would be: 28 | 29 | ``` 30 | "%startup_dir%\Apps\Encoders\Av1anStaxRipWrapper\VapourSynth\python.exe" "%startup_dir%\Apps\Encoders\Av1anStaxRipWrapper\Av1anStaxRipWrapper.py" -s "%startup_dir%" -i "%source_file%" -o "%encoder_out_file%" -t "%temp_dir%av1an_temp" --pix-format yuv420p10le -e rav1e --photon-noise 2 --chroma-noise --sc-downscale-height 540 -v "--quantizer 60 --speed 6 --tiles 2 --threads 2" 31 | ``` 32 | Everything after the `-t` parameter will affect the encoding parameters (either Av1an or the selected encoder). Refer to [Command Line Options](#command-line-options) section for more information. 33 | 34 | This starting command uses the rav1e encoder and uses the encoding parameters passed in by the argument `-v`. 35 | 36 | ## Requirements 37 | - [ffmpeg](https://ffmpeg.org/download.html) (with shared libraries) (Av1an requirement) 38 | - [aomenc](https://aomedia.googlesource.com/aom/) or 39 | - [rav1e](https://github.com/xiph/rav1e/releases) or 40 | - [SVT-AV1](https://gitlab.com/AOMediaCodec/SVT-AV1) 41 | - [StaxRip](https://github.com/staxrip/staxrip/releases) 42 | 43 | This script also requires the `psutil` module in Python to automatically detect CPU core counts to pass into av1an. 44 | - You can run with the `--disable-automatic-thread-detection` flag to disable this feature and requirement 45 | 46 | ## Setup 47 | ### Portable Installation (Recommended) 48 | Since Av1an requires `ffmpeg`, `aomenc` or `rav1e` or `SVT-AV1`, `VapourSynth` to be in PATH, this script can automatically help you add important folders (from StaxRip) temporarily to PATH when it's being run (for portable installation). In this way, your actual system PATH is not affected when running Av1an. However, this means that you need to install the tools in specific folders in StaxRip as the wrapper script looks for them there. 49 | 50 | Portable mode is enabled when the `-s` flag is used with the StaxRip startup directory. 51 | 52 | 1. **Clone** this repository (or download the files) into `StaxRip\Apps\Encoders\Av1anStaxRipWrapper` 53 | 54 | You can run `git clone https://github.com/Kidsnd274/Av1anStaxRipWrapper.git"` in `StaxRip\Apps\Encoders` 55 | 56 | 2. Ensure encoders, **Av1an and the wrapper script** are extracted in the right directories 57 | - Av1an: `StaxRip\Apps\Encoders\Av1an` (IMPORTANT) 58 | - aomenc: `StaxRip\Apps\Encoders\aomenc` 59 | - rav1e: `StaxRip\Apps\Encoders\rav1e` 60 | - SVT-AV1: `StaxRip\Apps\Encoders\SVT-AV1` or `StaxRip\Apps\Encoders\SVT-AV1\SvtAv1EncApp` 61 | - FFMPEG: `StaxRip\Apps\Encoders\Av1an` (moving it to an `ffmpeg` folder would interfere with StaxRip's own ffmpeg) 62 | - Wrapper Script: `StaxRip\Apps\Encoders\Av1anStaxRipWrapper` 63 | 3. Run the `setup_py_vp_environment.bat` script from the Av1anStaxRipWrapper folder to install required Python modules and VapourSynth plugins 64 | 4. Use the **Command Line** encoder profile to create an Av1an Encoder Profile 65 | staxrip_image 66 | staxrip_image 67 | 68 | Good starting command (v2.40.0 and above): 69 | ``` 70 | "%startup_dir%\Apps\Encoders\Av1anStaxRipWrapper\VapourSynth\python.exe" "%startup_dir%\Apps\Encoders\Av1anStaxRipWrapper\Av1anStaxRipWrapper.py" -s "%startup_dir%" -i "%source_file%" -o "%encoder_out_file%" -t "%temp_dir%\av1an_temp" --pix-format yuv420p10le -e rav1e --photon-noise 2 --chroma-noise --sc-downscale-height 540 -v "--quantizer 60 --speed 6 --tiles 2 --threads 2" 71 | ``` 72 | Below v2.40.0 73 | ``` 74 | "%startup_dir%\Apps\Encoders\Av1anStaxRipWrapper\VapourSynth\python.exe" "%startup_dir%\Apps\Encoders\Av1anStaxRipWrapper\Av1anStaxRipWrapper.py" -s "%startup_dir%" -i "%source_file%" -o "%encoder_out_file%" -t "%temp_dir%av1an_temp" --pix-format yuv420p10le -e rav1e --photon-noise 2 --chroma-noise --sc-downscale-height 540 -v "--quantizer 60 --speed 6 --tiles 2 --threads 2" 75 | ``` 76 | 77 | **IMPORTANT**: Make sure to change **Output File Type** to `mkv`! 78 | 79 | 5. Save this Encoder Profile with the name `AV1 | av1an`, and it will appear in the AV1 drop-down menu. 80 | ![image](https://user-images.githubusercontent.com/1343896/209458707-bca3edda-36af-4d3d-b4a5-899160a5e8d9.png) 81 | 82 | 83 | ### Alternative Installation (install tools to system PATH) 84 | Basically, just make sure `Av1an`, `ffmpeg`, `aomenc`, `rav1e`, `SVT-AV1`, `Python`, `VapourSynth` are all accessible from PATH and follow the steps above from Step 2. 85 | 86 | The command in StaxRip used is\ 87 | `python "%startup_dir%\Apps\Encoders\Av1anStaxRipWrapper\Av1anStaxRipWrapperRav1e.py" -i "%source_file%" -o "%encoder_out_file%" -t "%temp_dir%av1an_temp" --pix-format yuv420p10le -e rav1e --photon-noise 2 --chroma-noise --sc-downscale-height 540 -v "--quantizer 60 --speed 6 --tiles 2 --threads 2"` 88 | 89 | ## Command Line Options 90 | ``` 91 | options: 92 | Av1an wrapper for StaxRip 93 | 94 | optional arguments: 95 | -h, --help show this help message and exit 96 | --version Print Av1an, ffmpeg and the encoders' versions 97 | -i INPUT Input File (for StaxRip) 98 | -o OUTPUT Output File (for StaxRip) 99 | -t TEMPDIR Temp Directory (for StaxRip) 100 | -s STAXRIP_STARTUP_DIR, --staxrip-startup-dir STAXRIP_STARTUP_DIR 101 | Specify StaxRip Startup Directory so that the wrapper script will automatically add important 102 | folders to PATH for av1an to detect (only needed for portable installations) 103 | 104 | # Av1an parameters 105 | -e ENCODER, --encoder ENCODER 106 | Video encoder to use. [default: aom][possible values: aom, rav1e, vpx, svt-av1, x264, x265] 107 | -v ENCODER_ARGS, --video-params ENCODER_ARGS 108 | Arguments passed to video encoder 109 | -a OTHER_ARGS, --other-args OTHER_ARGS 110 | Other Av1an arguments 111 | -f FFMPEG_OPTIONS, --ffmpeg FFMPEG_OPTIONS 112 | FFmpeg filter options 113 | --photon-noise PHOTON_NOISE 114 | Generates a photon noise table and applies it using grain synthesis [strength: 0-64] (disabled 115 | by default) (Av1an parameter) 116 | --chroma-noise Adds chroma grain synthesis to the grain table generated by `--photon-noise`. (Default: false) 117 | (Av1an parameter) 118 | --sc-downscale-height SC_DOWNSCALE_HEIGHT 119 | Optional downscaling for scene detection. By default, no downscaling is performed. (Av1an 120 | parameter) 121 | --pix-format PIX_FORMAT 122 | FFmpeg pixel format 123 | 124 | # Threading parameters (Using any of these would disable the wrapper's Automatic Thread Detection feature) 125 | --workers WORKERS Number of workers to spawn [0 = automatic] (Av1an Paramter) 126 | --set-thread-affinity SET_THREAD_AFFINITY 127 | Pin each worker to a specific set of threads of this size (disabled by default) (Av1an 128 | parameter) 129 | --disable-automatic-thread-detection 130 | Disable the wrapper's automatic thread detection 131 | --set-worker-override 132 | Set the override workers count and thread affinity count for local computer 133 | ``` 134 | 135 | ## Automatic Thread Detection 136 | In my testing, I found that I get the best utilization and encoding speeds when creating the same number of workers as the number of physical cores available in your system. Along with having the number of threads per worker be 2 if your system supports hyperthreading/SMT and 1 if your system does not. 137 | 138 | With automatic thread detection, the wrapper script will automatically detect and pass in the relevant parameters to Av1an. For example, 139 | 140 | ``` 141 | Ryzen 7 5800X 142 | Physical Cores: 8 cores 143 | Logical Cores: 16 cores 144 | Hyperthreading/SMT: Enabled 145 | Threading Parameters: --workers 8 --set-thread--affinity 2 146 | 147 | Intel i5-6600K 148 | Physical Cores: 4 cores 149 | Logical Cores: 4 cores 150 | Hyperthreading/SMT: Disabled 151 | Threading Parameters: --workers 4 --set-thread-affinity 1 152 | ``` 153 | 154 | If your system uses an Intel 12th Gen chip and above (with the new hybrid architecture with P-cores and E-cores), this feature is disabled. 155 | 156 | If you do not want to use this feature, you can use the `--disable-automatic-thread-detection` flag or any of the Threading parameters under [Command Line Options](#command-line-options). Using any the Threading parameters would disable this feature. 157 | 158 | ## Override Worker Count and Threads Per Local Machine 159 | When using StaxRip in a networked environment (where multiple computers access the same StaxRip install), you might want to override the Automatic Thread Detection feature for some computers, but not affect other machines. This feature allows you to do so without modifying the command line option, by storing a configuration file in a local computer. 160 | 161 | * Note that this will override the `--workers` and `--set-thread-affinity` flags for the script. If you include these flags in the `--other-args` flag, both of them will be sent to Av1an. Not sure what will happen there but you are welcome to find out. 162 | 163 | ### Setting the override worker count 164 | To set the override feature, run the script with the `--set-worker-override` flag. 165 | ``` 166 | python Av1anStaxRipWrapper.py --set-worker-override 167 | ``` 168 | Follow the instructions shown in the cmd window and the script should store a configuration file in this location. `%LOCALAPPDATA%\Av1anStaxRipWrapper\override-workers.json` 169 | 170 | ### Check to see if it's working 171 | The next time a job is being run, the script will show in its logs that the override file is found. For example: 172 | ``` 173 | ================================================= 174 | Av1anStaxRipWrapper 175 | https://github.com/Kidsnd274/Av1anStaxRipWrapper 176 | ================================================= 177 | [INFO] Found override-workers.json 178 | [INFO] Overriding CPU Workers = 4 and CPU Thread Affinity = 2 179 | [INFO] Automatic Thread Detection Disabled 180 | THREADING INFORMATION: 181 | Automatic Thread Detection: DISABLED 182 | Starting av1an... Check new console window for progress 183 | ``` 184 | 185 | ### Structure of override-workers.json 186 | The json file stores two keys for worker count and thread affinity (at the moment both keys must exist). The values must be in integers. 187 | Example: 188 | ``` 189 | { 190 | "cpu_workers": 4, 191 | "cpu_thread_affinity": 4 192 | } 193 | ``` 194 | -------------------------------------------------------------------------------- /Av1anStaxRipWrapper.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | import os 3 | import pathlib 4 | import subprocess 5 | import sys 6 | 7 | sys.stdout.reconfigure(encoding='utf-8') 8 | 9 | # This script allows the usage of any encoders supported by Av1an. 10 | # Use the -e flag to specify the encoder and make sure .exe is in the specific folders. https://github.com/Kidsnd274/Av1anStaxRipWrapper 11 | 12 | 13 | # Developer Notes: 14 | # Add a check to see what encoders are available. Make a nice opening message saying 15 | # Av1anStaxRip, Supported Encoders.... 16 | # FileNotFoundError is the error when using subprocess.run 17 | # TODO: Allow separate override for workers and affinity 18 | # TODO: Force close av1an when StaxRip terminates the script 19 | 20 | 21 | # Functions 22 | def add_argument(curr, new): 23 | return_string = curr 24 | if curr == "": 25 | return_string = new 26 | else: 27 | return_string += (" " + new) 28 | return return_string 29 | 30 | def set_path(path): 31 | staxrip_path = pathlib.Path(path) 32 | av1an_path = staxrip_path / "Apps" / "Encoders" / "Av1an" 33 | aomenc_path = staxrip_path / "Apps" / "Encoders" / "aomenc" 34 | rav1e_path = staxrip_path / "Apps" / "Encoders" / "rav1e" 35 | svtav1_path = staxrip_path / "Apps" / "Encoders" / "SVT-AV1" 36 | svtav1_path2 = staxrip_path / "Apps" / "Encoders" / "SvtAv1EncApp" 37 | x264_path = staxrip_path / "Apps" / "Encoders" / "x264" 38 | x265_path = staxrip_path / "Apps" / "Encoders" / "x265" 39 | vp_path = staxrip_path / "Apps" / "Encoders" / "Av1anStaxRipWrapper" / "VapourSynth" 40 | mkvmerge_path = staxrip_path / "Apps" / "Support" / "MKVToolNix" 41 | environ = os.environ 42 | environ["PATH"] = f"{str(av1an_path)};{str(aomenc_path)};{str(rav1e_path)};{str(svtav1_path)};{str(svtav1_path2)};{str(x264_path)};{str(x265_path)};{str(vp_path)};{str(mkvmerge_path)};{environ['PATH']}" 43 | return environ 44 | 45 | def print_welcome(): 46 | print("=================================================") 47 | print("Av1anStaxRipWrapper") 48 | print("https://github.com/Kidsnd274/Av1anStaxRipWrapper") 49 | print("=================================================") 50 | print("") 51 | 52 | def print_version(parser_args): 53 | if parser_args.staxrip_startup_dir is not None: 54 | my_env = set_path(parser_args.staxrip_startup_dir) 55 | else: 56 | my_env = os.environ 57 | try: 58 | subprocess.run("ffmpeg -version", shell=False, env=my_env) 59 | except FileNotFoundError: 60 | print("ffmpeg not found!") 61 | print("\n--------------------------------\n") 62 | try: 63 | subprocess.run("av1an --version", shell=False, env=my_env) 64 | except FileNotFoundError: 65 | print("Av1an not found!") 66 | print("\n--------------------------------\n") 67 | try: 68 | aomenc_process = subprocess.Popen("aomenc --help", shell=False, stdout=subprocess.PIPE) 69 | out, err = aomenc_process.communicate() 70 | out = out.decode("utf-8") 71 | for line in out.splitlines()[-6:-3]: 72 | print(line) 73 | except FileNotFoundError: 74 | print("aomenc not found!") 75 | print("\n--------------------------------\n") 76 | try: 77 | subprocess.run("rav1e --version", shell=False, env=my_env) 78 | except FileNotFoundError: 79 | print("rav1e not found!") 80 | print("\n--------------------------------\n") 81 | try: 82 | subprocess.run("SvtAv1EncApp", shell=False, env=my_env) 83 | except FileNotFoundError: 84 | print("SvtAv1EncApp not found!") 85 | print("\n--------------------------------\n") 86 | exit(0) 87 | 88 | def get_worker_override(): 89 | # Check for override-workers.json 90 | # eg. cpu_workers = 2, cpu_thread_affinity = 2 91 | local_app_data_path = pathlib.Path(str(os.getenv('LOCALAPPDATA'))) 92 | config_path = local_app_data_path / "Av1anStaxRipWrapper" / "override-workers.json" 93 | if config_path.is_file(): 94 | print("[INFO] Found override-workers.json") 95 | import json 96 | try: 97 | with config_path.open() as f: 98 | config = json.load(f) 99 | workers = config.get('cpu_workers') 100 | affinity = config.get('cpu_thread_affinity') 101 | if workers is None or affinity is None: 102 | raise KeyError("[ERROR] override-workers.json is does not contain cpu_workers or cpu_thread_affinity") 103 | if not isinstance(workers, int) or not isinstance(affinity, int): 104 | raise ValueError("[ERROR] override-workers.json is not formatted correctly") 105 | print(f"[INFO] Overriding CPU Workers = {str(workers)} and CPU Thread Affinity = {str(affinity)}") 106 | return (True, workers, affinity) 107 | except Exception as error: 108 | print("[ERROR] Failed to read override-workers.json. Skipping...") 109 | print(error) 110 | return (False, 0, 0) 111 | 112 | def set_worker_override(): # Function to create override-workers.json 113 | print("Setting override workers and thread affinity for local computer...") 114 | print("") 115 | print("How many workers do you want to spawn? (Put 0 for disabled)") 116 | while True: 117 | workers = input("cpu_workers = ") 118 | try: 119 | workers_int = int(workers) 120 | if workers_int < 0: 121 | raise ValueError 122 | except ValueError: 123 | print("Invalid input, please enter a positive number") 124 | continue 125 | else: 126 | break 127 | print("How many threads do you want to pin each worker to? (Put 0 for disabled)") 128 | while True: 129 | affinity = input("cpu_thread_affinity = ") 130 | try: 131 | affinity_int = int(affinity) 132 | if affinity_int < 0: 133 | raise ValueError 134 | except ValueError: 135 | print("Invalid input, please enter a positive number") 136 | continue 137 | else: 138 | break 139 | 140 | config = {} 141 | if workers_int != 0: 142 | config['cpu_workers'] = workers_int 143 | if affinity_int != 0: 144 | config['cpu_thread_affinity'] = affinity_int 145 | 146 | import json 147 | local_app_data_path = pathlib.Path(str(os.getenv('LOCALAPPDATA'))) 148 | config_path = local_app_data_path / "Av1anStaxRipWrapper" / "override-workers.json" 149 | 150 | # Creating proper folders and files 151 | config_path.parent.mkdir(parents=False, exist_ok=True) 152 | config_path.touch(exist_ok=True) 153 | with config_path.open('w') as f: 154 | json.dump(config, f, indent=4) 155 | print(f"Successfully written to {str(config_path)}") 156 | exit() 157 | 158 | # Command Line Arguments 159 | parser = argparse.ArgumentParser(description="Av1an wrapper for StaxRip") 160 | 161 | parser.add_argument('--version', action='store_true', help="Print Av1an, ffmpeg and the encoders' versions") 162 | parser.add_argument('-i', dest="input", type=str, help="Input File (for StaxRip)") 163 | parser.add_argument('-o', dest="output", type=str, help="Output File (for StaxRip)") 164 | parser.add_argument('-t', dest="tempdir", type=str, help="Temp Directory (for StaxRip)") 165 | parser.add_argument('-s', '--staxrip-startup-dir', dest="staxrip_startup_dir", type=str, required=False, help="Specify StaxRip Startup Directory so that the wrapper script will automatically add important folders to PATH for av1an to detect (only needed for portable installations)") 166 | parser.add_argument('-e', '--encoder', type=str, required=False, help="Video encoder to use. [default: aom][possible values: aom, rav1e, vpx, svt-av1, x264, x265]") 167 | parser.add_argument('-v', '--video-params', dest="encoder_args", type=str, required=False, help="Arguments passed to video encoder") 168 | parser.add_argument('-a', '--other-args', dest="other_args", type=str, required=False, help="Other Av1an arguments") 169 | parser.add_argument('-f', '--ffmpeg', dest="ffmpeg_options", type=str, required=False, help="FFmpeg filter options") 170 | parser.add_argument('--photon-noise', dest="photon_noise", type=str, required=False, help="Generates a photon noise table and applies it using grain synthesis [strength: 0-64] (disabled by default) (Av1an parameter)") 171 | parser.add_argument('--chroma-noise', dest="chroma_noise", action='store_true', help="Adds chroma grain synthesis to the grain table generated by `--photon-noise`. (Default: false) (Av1an parameter)") 172 | parser.add_argument('--sc-downscale-height', dest="sc_downscale_height", type=str, required=False, help="Optional downscaling for scene detection. By default, no downscaling is performed. (Av1an parameter)") 173 | parser.add_argument('--pix-format', dest="pix_format", type=str, required=False, help="FFmpeg pixel format") 174 | # Threading Arguments (do not specify these commands if you want to use Automatic Thread Detection) 175 | parser.add_argument('--workers', type=str, required=False, help="Number of workers to spawn [0 = automatic] (Av1an Paramter)") 176 | parser.add_argument('--set-thread-affinity', dest="set_thread_affinity", type=str, required=False, help="Pin each worker to a specific set of threads of this size (disabled by default) (Av1an parameter)") 177 | parser.add_argument('--disable-automatic-thread-detection', dest="disable_automatic_thread_detection", action='store_true', help="Disable the wrapper's automatic thread detection") 178 | parser.add_argument('--set-worker-override', dest="override_mode", action='store_true', help="Set the override workers count and thread affinity count for local computer") 179 | parser_args = parser.parse_args() 180 | 181 | print_welcome() 182 | 183 | if parser_args.override_mode: 184 | set_worker_override() 185 | exit() 186 | 187 | if parser_args.version: 188 | print_version(parser_args) 189 | 190 | if parser_args.input is None or parser_args.output is None or parser_args.tempdir is None: 191 | print("The arguments, -i, -o, -t are required to work!") 192 | print("Run --help for more information") 193 | exit(1) 194 | 195 | input_file = parser_args.input 196 | output_file = parser_args.output 197 | tempdir = parser_args.tempdir 198 | 199 | # Automatic Thread Detection 200 | thread_detection = False 201 | override_workers, cpu_workers, cpu_thread_affinity = get_worker_override() 202 | 203 | if not parser_args.disable_automatic_thread_detection and parser_args.workers is None and parser_args.set_thread_affinity is None and not override_workers: 204 | thread_detection = True 205 | else: 206 | print("[INFO] Automatic Thread Detection Disabled") 207 | 208 | if thread_detection: # Checking for new Intel architecture 209 | import psutil 210 | logical_count = psutil.cpu_count(logical = True) 211 | physical_count = psutil.cpu_count(logical = False) 212 | if (logical_count / physical_count) % 1 != 0: 213 | thread_detection = False # Intel CPU detected 214 | print("[INFO] New Intel CPU architecture with P and E cores detected! Not passing thread detection to av1an...\n") 215 | print("[INFO] Automatic Thread Detection Disabled") 216 | 217 | if thread_detection: # Checking for Hyperthreading or SMT 218 | import psutil 219 | logical_count = psutil.cpu_count(logical = True) 220 | physical_count = psutil.cpu_count(logical = False) 221 | if (logical_count / physical_count) == 2: 222 | hyperthreading = True 223 | else: 224 | hyperthreading = False 225 | 226 | if thread_detection: # Setting values 227 | if hyperthreading: 228 | cpu_workers = physical_count 229 | cpu_thread_affinity = 2 230 | else: 231 | cpu_workers = physical_count 232 | cpu_thread_affinity = 1 233 | print(f"THREADING INFORMATION:\n Hyperthreading / SMT: {hyperthreading}\n Workers: {cpu_workers}\n Thread Affinity: {cpu_thread_affinity}\n\n") 234 | else: 235 | print("THREADING INFORMATION:\n Automatic Thread Detection: DISABLED\n\n") 236 | 237 | # If StaxRip path given, automatically add important folders to PATH 238 | if parser_args.staxrip_startup_dir is not None: 239 | my_env = set_path(parser_args.staxrip_startup_dir) 240 | 241 | av1an_exec = "av1an.exe" 242 | 243 | command = av1an_exec 244 | command = add_argument(command, "--verbose -y --resume -a=\"-an\"") 245 | 246 | # Thread arguments 247 | if thread_detection or override_workers: 248 | command = add_argument(command, f"--workers {cpu_workers} --set-thread-affinity {cpu_thread_affinity}") 249 | else: 250 | if parser_args.workers is not None: 251 | command = add_argument(command, f"--workers {parser_args.workers}") 252 | if parser_args.set_thread_affinity is not None: 253 | command = add_argument(command, f"--set-thread-affinity {parser_args.set_thread_affinity}") 254 | 255 | if parser_args.encoder is not None: 256 | command = add_argument(command, f"--encoder {parser_args.encoder}") 257 | if parser_args.encoder_args is not None: 258 | command = add_argument(command, f"-v \"{parser_args.encoder_args}\"") 259 | if parser_args.photon_noise is not None: 260 | command = add_argument(command, f"--photon-noise {parser_args.photon_noise}") 261 | if parser_args.chroma_noise: 262 | command = add_argument(command, f"--chroma-noise") 263 | if parser_args.sc_downscale_height is not None: 264 | command = add_argument(command, f"--sc-downscale-height {parser_args.sc_downscale_height}") 265 | if parser_args.pix_format is not None: 266 | command = add_argument(command, f"--pix-format {parser_args.pix_format}") 267 | if parser_args.other_args is not None: 268 | command = add_argument(command, f"{parser_args.other_args}") 269 | if parser_args.ffmpeg_options is not None: 270 | command = add_argument(command, f"-f \"{parser_args.ffmpeg_options}\"") 271 | 272 | command = add_argument(command, f"-i \"{input_file}\" -o \"{output_file}\" --temp \"{tempdir}\"") 273 | 274 | sys.stdout.write("Starting av1an... Check new console window for progress\n") 275 | sys.stdout.write("Command: " + str(command) + "\n") 276 | sys.stdout.flush() 277 | 278 | if parser_args.staxrip_startup_dir is not None: 279 | process = subprocess.run(command, shell=False, creationflags=subprocess.CREATE_NEW_CONSOLE, env=my_env) 280 | else: 281 | process = subprocess.run(command, shell=False, creationflags=subprocess.CREATE_NEW_CONSOLE) # Assume everything is in PATH 282 | 283 | if process.returncode != 0: 284 | print(process.stderr) 285 | print("[ERROR] Error occurred when transcoding with av1an. Check logs") 286 | exit(1) 287 | --------------------------------------------------------------------------------