├── .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 |
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 |
56 |
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 | 
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 |
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 |
66 |
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 | 
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 |
--------------------------------------------------------------------------------