Skip to content
This repository was archived by the owner on Apr 18, 2023. It is now read-only.

Commit 433d7a7

Browse files
authored
Merge pull request #6 from FarisR99/release-1.2.0
2 parents 4730173 + 87b2008 commit 433d7a7

13 files changed

Lines changed: 656 additions & 280 deletions

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
.idea/
12
venv/
23
venv
34
shaders

Anime4K.py

Lines changed: 35 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,14 @@
88
from extract_subs import extract_subs
99
from multi import multi
1010
from mux import mux
11+
from patch import patch
1112
from shader import shader
1213
from splitter import split_by_seconds, get_video_length
1314
from utils import __current_version__, is_tool, credz, str2dict
1415

1516
# Constant variables
16-
MODES_SUPPORTING_MULTI_INPUTS = ["shader", "multi", "encode"]
17+
MODES_SUPPORTING_MULTI_INPUTS = ["shader", "multi", "encode", "patch"]
18+
MODES_TO_IGNORE_OUTPUT_EXISTENCE = ["patch"]
1719

1820
# Print credits
1921
credz()
@@ -37,6 +39,9 @@
3739
parser.add_argument("-v", "--version", required=False,
3840
action='store_true',
3941
help="Print the current version of Anime4K-Encoder")
42+
parser.add_argument("--debug", "--verbose", required=False,
43+
action='store_true',
44+
help='Enable debug mode; print more information and no screen clearing')
4045
parser.add_argument("-m", "--mode", required=False,
4146
default="shader",
4247
help='''Modes:
@@ -46,7 +51,10 @@
4651
mux - Mux/compile a media file with audio files and subtitle files
4752
multi - Apply shader with -ss and -sa, audio, subs and mux mode in order
4853
encode - Encode media files using X265 with predefined settings
49-
split - Split a media file into parts''')
54+
split - Split a media file into parts
55+
patch - Extract audio and subs from input files then mux with already upscaled
56+
output files located in the output directory with matching file names.
57+
This is essentially a mux mode supporting multiple files.''')
5058
parser.add_argument("-ew", "--width", required=False, type=int, default=3840,
5159
help="Desired width when applying shader")
5260
parser.add_argument("-eh", "--height", required=False, type=int, default=2160,
@@ -71,6 +79,8 @@
7179
action='store_true',
7280
default=False,
7381
help="Set this flag if you want to manually mux audio when using mode shader")
82+
parser.add_argument("-fps", "--fps", required=False, type=float,
83+
help="Desired framerate when applying shader")
7484
parser.add_argument("-sm", "--skip_menus", required=False, type=str2dict,
7585
help='''Skip choice menus
7686
Examples for mode shader:
@@ -90,13 +100,17 @@
90100
default=False,
91101
help="Set this flag to delete output files that have failed to compile when using mode multi")
92102
parser.add_argument("-si", "--skip_input", required=False, action='append',
93-
help="Input file to skip when using a directory as an input for modes shader and multi")
103+
help="Input file to skip when using a directory as an input for modes shader, multi and patch")
94104

95105
args = vars(parser.parse_args())
96106
if args['version']:
97107
print("Anime4K-Encoder v" + __current_version__)
98108
sys.exit(1)
99109

110+
debug = args['debug']
111+
if debug is None:
112+
debug = False
113+
100114

101115
def exit_if_missing(file_path: str, allow_dir: bool = True):
102116
if not os.path.isdir(file_path):
@@ -151,7 +165,9 @@ def exit_if_missing(file_path: str, allow_dir: bool = True):
151165
output = output + "/"
152166
elif mode in MODES_SUPPORTING_MULTI_INPUTS:
153167
output = args['output'] or "out.mkv"
154-
if os.path.isdir(output) and not os.path.exists(output):
168+
if mode not in MODES_TO_IGNORE_OUTPUT_EXISTENCE \
169+
and os.path.isdir(output) \
170+
and not os.path.exists(output):
155171
try:
156172
os.mkdir(output)
157173
except Exception as e:
@@ -179,14 +195,14 @@ def exit_if_missing(file_path: str, allow_dir: bool = True):
179195
os.path.join(file, "*.mp4")
180196
):
181197
file_name = os.path.basename(file_in_dir)
182-
if file_name in skip_inputs:
198+
if file_in_dir in skip_inputs or file_name in skip_inputs:
183199
continue
184200
in_files.append(os.path.join(file_in_dir))
185201
else:
186202
# Only here for consistency
187203
# Why would you specify a file input then add that file
188204
# to a list of files to ignore?
189-
if file in skip_inputs:
205+
if file in skip_inputs or os.path.basename(file) in skip_inputs:
190206
continue
191207
in_files.append(os.path.join(file))
192208
file_count = len(in_files)
@@ -206,24 +222,28 @@ def exit_if_missing(file_path: str, allow_dir: bool = True):
206222

207223
# Perform action based on mode
208224
if mode == "audio":
209-
extract_audio(fn, output, skip_menus)
225+
extract_audio(debug, fn, output, skip_menus)
210226
elif mode == "subs":
211-
extract_subs(fn, output)
227+
extract_subs(debug, fn, output)
212228
elif mode == "mux":
213-
mux(fn, output)
229+
mux(debug, fn, output)
214230
elif mode == "shader":
215-
shader(in_files, args['width'], args['height'],
231+
shader(debug, in_files, args['width'], args['height'],
216232
args['shader_dir'], args['bit'], args['audio_language'],
217-
args['softsubs'], args['softaudio'], skip_menus, True, output)
233+
args['softsubs'], args['softaudio'], args['fps'], skip_menus, True,
234+
output)
218235
elif mode == "multi":
219-
multi(in_files, args['width'], args['height'],
220-
args['shader_dir'], args['bit'], skip_menus,
236+
multi(debug, in_files, args['width'], args['height'],
237+
args['shader_dir'], args['bit'], args['fps'], skip_menus,
221238
args['delete_failures'], output)
222239
elif mode == "encode":
223-
encode_to_hevc(in_files, output, skip_menus)
240+
encode_to_hevc(debug, in_files, output, skip_menus)
224241
elif mode == "split":
225242
length = get_video_length(fn)
226-
split_by_seconds(filename=fn, split_length=args['split_length'],
243+
split_by_seconds(debug=debug, filename=fn,
244+
split_length=args['split_length'],
227245
video_length=length, split_dir=output)
246+
elif mode == "patch":
247+
patch(debug, in_files, skip_menus, output)
228248
else:
229249
print("Unknown mode: {0}".format(mode))

README.md

Lines changed: 9 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,7 @@ changes. The key differences between Anime4K-Encode-4.0.1 and this repository
2424
are:
2525

2626
- Cleaned up code
27-
- Re-added NVENC support and added AMD GPU encoding support (completely
28-
untested)
27+
- Re-added NVENC support and added CPU AV1, AMD GPU and Intel QuickSync support
2928
- Re-added 10-bit toggling support
3029
- Removed official support for videos with a resolution lower than FHD
3130
- Added support for MP4 files
@@ -128,27 +127,23 @@ default is used. On my system and I'd assume most systems, this is 6.2.
128127
Requirements:
129128

130129
- Latest NVIDIA driver
131-
- Type `ffmpeg -help` and ensure ffmpeg has been built with `--enable-nvenc`.
132-
If not, manually compile ffmpeg
130+
- Type `ffmpeg` and ensure ffmpeg has been built with `--enable-nvenc`. If not, manually compile ffmpeg
133131
with [these]((https://docs.nvidia.com/video-technologies/video-codec-sdk/ffmpeg-with-nvidia-gpu/#compiling-for-linux))
134132
instructions
135133
- May
136134
need [cuda](https://docs.nvidia.com/cuda/cuda-installation-guide-linux/index.html#verify-you-have-cuda-enabled-system)
137135
installed
138136

139-
I had some issues getting NVENC working initially so if this doesn't work for
140-
you, you may need to tinker with a bunch of different packages.
141-
142137
#### AMD GPUs
143138

144-
I've added support for AMD's "Advanced Media Framework", but I've heard the
145-
quality is quite bad using this. I do not know how this encoder works nor have
146-
I tested it, so the code implementation is based on online (lack of)
147-
documentation. Feel free to raise an Issue ticket on GitHub if there are
148-
errors, I do own an AMD RX 6900XT so I can attempt to reproduce it.
139+
I've added support for AMD GPUs using VAAPI. This requires AMD drivers. I do not know how this encoder works nor have I
140+
tested it, so the code implementation is based on online (lack of) documentation. Feel free to raise an Issue ticket on
141+
GitHub if there are errors, however I cannot fix it myself.
142+
143+
#### Intel QuickSync
149144

150-
[Here's](https://gist.github.com/Brainiarc7/95c9338a737aa36d9bb2931bed379219) a
151-
Gist I found related to setting ffmpeg up to support it.
145+
Intel QuickSync is supported, but requires the desired FPS to be set. It's also very slow and is best for 1080p or
146+
lower.
152147

153148
## **[Optional]** Encoding ffmpeg progressbar
154149

ccolors.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# Taken from https://svn.blender.org/svnroot/bf-blender/trunk/blender/build_files/scons/tools/bcolors.py
2+
class ccolors:
3+
HEADER = '\033[95m'
4+
OKBLUE = '\033[94m'
5+
OKGREEN = '\033[92m'
6+
WARNING = '\033[93m'
7+
FAIL = '\033[91m'
8+
ENDC = '\033[0m'
9+
10+
def disable(self):
11+
self.HEADER = ''
12+
self.OKBLUE = ''
13+
self.OKGREEN = ''
14+
self.WARNING = ''
15+
self.FAIL = ''
16+
self.ENDC = ''

encode.py

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
from utils import current_date, is_tool, clear
88

99

10-
def encode_to_hevc(input_files: "list[str]", out: str,
10+
def encode_to_hevc(debug: bool, input_files: "list[str]", out: str,
1111
skip_menus: dict) -> dict:
1212
"""
1313
Encode a media file to HEVC using X265
@@ -28,13 +28,18 @@ def encode_to_hevc(input_files: "list[str]", out: str,
2828
if detail_choice < 0 or detail_choice > 4:
2929
detail_choice = None
3030
if detail_choice is None:
31-
detail_menu = TerminalMenu([
32-
"One setting to rule them all (Recommended if you don't know)",
33-
"Flat, slow anime (slice of life, everything is well lit, e.g. Your Name)",
34-
"Some dark scenes, some battle scenes (shonen, historical, etc., e.g. Kimetsu no Yaiba)",
35-
"[TV Series] Movie-tier dark scene, complex grain/detail (Rarely used)",
36-
"[Movie] Movie-tier dark scene, complex grain/detail (Rarely used)",
37-
], title="Choose the encode options")
31+
detail_menu = TerminalMenu(
32+
[
33+
"One setting to rule them all (Recommended if you don't know)",
34+
"Flat, slow anime (slice of life, everything is well lit, e.g. Your Name)",
35+
"Some dark scenes, some battle scenes (shonen, historical, etc., e.g. Kimetsu no Yaiba)",
36+
"[TV Series] Movie-tier dark scene, complex grain/detail (Rarely used)",
37+
"[Movie] Movie-tier dark scene, complex grain/detail (Rarely used)",
38+
],
39+
title="Choose the encode options",
40+
clear_screen=(debug is False),
41+
clear_menu_on_exit=(debug is False)
42+
)
3843
detail_choice = detail_menu.show()
3944
if detail_choice is None:
4045
print("Cancelled")

extract_audio.py

Lines changed: 44 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,40 @@
77
from pymkv import MKVFile
88
from simple_term_menu import TerminalMenu
99

10-
from utils import current_date, language_mapping
10+
from utils import current_date, language_mapping, lang_short_to_long
1111

1212

13-
def extract_audio(fn: str, out_dir: str, skip_menus: dict) -> bool:
13+
def show_convert_audio_menu(debug: bool, skip_menus: dict) -> int:
14+
convert_choice = None
15+
if "convert" in skip_menus:
16+
convert_choice = int(skip_menus['convert'])
17+
if convert_choice < 0 or convert_choice > 1:
18+
convert_choice = None
19+
else:
20+
# Flip the value, because "1" in the command line arg means
21+
# "Yes" which is at index 0 in convert_menu choice array
22+
convert_choice = 1 - convert_choice
23+
if convert_choice is None \
24+
and "recommended" in skip_menus \
25+
and skip_menus["recommended"] == "1":
26+
convert_choice = 1
27+
if convert_choice is None:
28+
convert_menu = TerminalMenu(
29+
["Yes", "No"],
30+
title="Do you want to convert every FLAC to Opus?",
31+
clear_screen=(debug is False),
32+
clear_menu_on_exit=(debug is False)
33+
)
34+
convert_choice = convert_menu.show()
35+
if convert_choice is None:
36+
print("Cancelled conversion")
37+
convert_choice = 1
38+
skip_menus['convert'] = str(1 - convert_choice)
39+
return convert_choice
40+
41+
42+
def extract_audio(debug: bool, fn: str, out_dir: str,
43+
skip_menus: dict) -> bool:
1444
"""
1545
Extract audio from a media file.
1646
@@ -35,7 +65,11 @@ def extract_audio(fn: str, out_dir: str, skip_menus: dict) -> bool:
3565
for track in tracks:
3666
if track.track_type == 'audio':
3767
ext = track._track_codec
38-
lang = language_mapping[track._language]
68+
if track._language not in language_mapping:
69+
print("WARNING: Unknown track language: {0}".format(track._language))
70+
lang = "Japanese"
71+
else:
72+
lang = lang_short_to_long(track._language)
3973
id = str(track._track_id)
4074
return_code = -1
4175
try:
@@ -51,6 +85,8 @@ def extract_audio(fn: str, out_dir: str, skip_menus: dict) -> bool:
5185
sys.exit(-1)
5286
except SystemExit:
5387
os._exit(-1)
88+
if debug:
89+
print("mkvextract exited with return code={}", return_code)
5490
if return_code != 0:
5591
success = False
5692

@@ -60,24 +96,7 @@ def extract_audio(fn: str, out_dir: str, skip_menus: dict) -> bool:
6096
for file in glob.glob(out_dir + "*.FLAC"):
6197
flacs.append(file)
6298
if len(flacs) > 0:
63-
convert_choice = None
64-
if "convert" in skip_menus:
65-
convert_choice = int(skip_menus['convert'])
66-
if convert_choice < 0 or convert_choice > 1:
67-
convert_choice = None
68-
else:
69-
# Flip the value, because "1" in the command line arg means
70-
# "Yes" which is at index 0 in convert_menu choice array
71-
convert_choice = 1 - convert_choice
72-
if convert_choice is None:
73-
convert_menu = TerminalMenu(
74-
["Yes", "No"],
75-
title="Do you want to convert every FLAC to Opus?"
76-
)
77-
convert_choice = convert_menu.show()
78-
if convert_choice is None:
79-
print("Cancelled conversion")
80-
99+
convert_choice = show_convert_audio_menu(debug, skip_menus)
81100
if convert_choice == 0:
82101
print("Conversion start time: " + current_date())
83102
for f in flacs:
@@ -90,7 +109,10 @@ def extract_audio(fn: str, out_dir: str, skip_menus: dict) -> bool:
90109
if br_choice is None:
91110
br_menu = TerminalMenu(
92111
bit_rates,
93-
title="What's the format of the file? => {0}".format(f)
112+
title="What's the format of the file? => {0}".format(
113+
f),
114+
clear_screen=(debug is False),
115+
clear_menu_on_exit=(debug is False),
94116
)
95117
br_choice = br_menu.show()
96118
if br_choice is None:

extract_subs.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55

66
from utils import current_date
77

8-
98
def genExt(codec):
109
if "PGS" in codec:
1110
return "sup"
@@ -19,7 +18,7 @@ def genExt(codec):
1918
return None
2019

2120

22-
def extract_subs(fn: str, out_dir: str) -> bool:
21+
def extract_subs(debug: bool, fn: str, out_dir: str) -> bool:
2322
"""
2423
Extract subtitles from a media file.
2524
@@ -61,6 +60,8 @@ def extract_subs(fn: str, out_dir: str) -> bool:
6160
print("Cancelled subtitles extraction.")
6261
print("Exiting program...")
6362
sys.exit(-1)
63+
if debug:
64+
print("mkvextract exited with return code={}", return_code)
6465
if return_code != 0:
6566
success = False
6667
print("Subtitle extraction end time: " + current_date())

0 commit comments

Comments
 (0)