HwCodecDetect 0.2.3__tar.gz → 0.2.4__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {hwcodecdetect-0.2.3/src/HwCodecDetect.egg-info → hwcodecdetect-0.2.4}/PKG-INFO +1 -1
- hwcodecdetect-0.2.4/VERSION +1 -0
- {hwcodecdetect-0.2.3 → hwcodecdetect-0.2.4}/src/HwCodecDetect/bitdepth_chroma_detect.py +41 -11
- {hwcodecdetect-0.2.3 → hwcodecdetect-0.2.4}/src/HwCodecDetect/run_tests.py +42 -12
- hwcodecdetect-0.2.4/src/HwCodecDetect/utils.py +166 -0
- hwcodecdetect-0.2.4/src/HwCodecDetect/version.py +1 -0
- {hwcodecdetect-0.2.3 → hwcodecdetect-0.2.4/src/HwCodecDetect.egg-info}/PKG-INFO +1 -1
- {hwcodecdetect-0.2.3 → hwcodecdetect-0.2.4}/src/HwCodecDetect.egg-info/SOURCES.txt +1 -0
- hwcodecdetect-0.2.3/VERSION +0 -1
- hwcodecdetect-0.2.3/src/HwCodecDetect/version.py +0 -1
- {hwcodecdetect-0.2.3 → hwcodecdetect-0.2.4}/LICENSE +0 -0
- {hwcodecdetect-0.2.3 → hwcodecdetect-0.2.4}/MANIFEST.in +0 -0
- {hwcodecdetect-0.2.3 → hwcodecdetect-0.2.4}/README.md +0 -0
- {hwcodecdetect-0.2.3 → hwcodecdetect-0.2.4}/pyproject.toml +0 -0
- {hwcodecdetect-0.2.3 → hwcodecdetect-0.2.4}/requirements.txt +0 -0
- {hwcodecdetect-0.2.3 → hwcodecdetect-0.2.4}/setup.cfg +0 -0
- {hwcodecdetect-0.2.3 → hwcodecdetect-0.2.4}/setup.py +0 -0
- {hwcodecdetect-0.2.3 → hwcodecdetect-0.2.4}/src/HwCodecDetect/__init__.py +0 -0
- {hwcodecdetect-0.2.3 → hwcodecdetect-0.2.4}/src/HwCodecDetect/install_ffmpeg_if_needed.py +0 -0
- {hwcodecdetect-0.2.3 → hwcodecdetect-0.2.4}/src/HwCodecDetect.egg-info/dependency_links.txt +0 -0
- {hwcodecdetect-0.2.3 → hwcodecdetect-0.2.4}/src/HwCodecDetect.egg-info/entry_points.txt +0 -0
- {hwcodecdetect-0.2.3 → hwcodecdetect-0.2.4}/src/HwCodecDetect.egg-info/requires.txt +0 -0
- {hwcodecdetect-0.2.3 → hwcodecdetect-0.2.4}/src/HwCodecDetect.egg-info/top_level.txt +0 -0
- {hwcodecdetect-0.2.3 → hwcodecdetect-0.2.4}/src/HwCodecDetect.egg-info/zip-safe +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
0.2.4
|
|
@@ -12,6 +12,7 @@ from collections import defaultdict
|
|
|
12
12
|
from colorama import init, Fore, Style
|
|
13
13
|
from concurrent.futures import ThreadPoolExecutor, as_completed
|
|
14
14
|
from tqdm import tqdm
|
|
15
|
+
from .utils import check_codec_support
|
|
15
16
|
|
|
16
17
|
init(autoreset=True)
|
|
17
18
|
|
|
@@ -152,13 +153,19 @@ def _run_ffmpeg_command(command, verbose):
|
|
|
152
153
|
|
|
153
154
|
def _run_encoder_bitdepth_test(test_data):
|
|
154
155
|
"""Tests encoder support for a specific pixel format."""
|
|
155
|
-
codec, encoder, pix_fmt, bit_depth, chroma, test_dir, verbose = test_data
|
|
156
|
+
codec, encoder, pix_fmt, bit_depth, chroma, test_dir, verbose, unsupported_encoders = test_data
|
|
157
|
+
|
|
158
|
+
# Skip unsupported encoders
|
|
159
|
+
if encoder in unsupported_encoders:
|
|
160
|
+
title = ENCODER_TITLES.get((encoder, codec), f"{encoder.upper()} Encoder:")
|
|
161
|
+
return title, pix_fmt, bit_depth, chroma, "skipped"
|
|
162
|
+
|
|
156
163
|
if codec == "prores":
|
|
157
164
|
file_ext = ".mov"
|
|
158
165
|
else:
|
|
159
166
|
file_ext = ".webm" if codec in ["vp8", "vp9"] else ".mp4"
|
|
160
167
|
output_file = os.path.join(test_dir, f"{encoder}_{pix_fmt}{file_ext}")
|
|
161
|
-
|
|
168
|
+
|
|
162
169
|
# Determine pixel format for output based on input format
|
|
163
170
|
if bit_depth == 8:
|
|
164
171
|
if chroma == "4:2:0":
|
|
@@ -270,17 +277,20 @@ def _run_encoder_bitdepth_test(test_data):
|
|
|
270
277
|
return title, pix_fmt, bit_depth, chroma, status
|
|
271
278
|
|
|
272
279
|
|
|
273
|
-
def _run_encoder_bitdepth_tests(test_dir, max_workers, verbose):
|
|
280
|
+
def _run_encoder_bitdepth_tests(test_dir, max_workers, verbose, unsupported_encoders=None):
|
|
274
281
|
"""Tests encoder support for various pixel formats."""
|
|
275
282
|
results = defaultdict(dict)
|
|
276
283
|
|
|
284
|
+
if unsupported_encoders is None:
|
|
285
|
+
unsupported_encoders = set()
|
|
286
|
+
|
|
277
287
|
print("\n--- Running Bit-depth/Chroma Encoder Tests ---")
|
|
278
288
|
|
|
279
289
|
tasks = []
|
|
280
290
|
for codec, info in ENCODERS.items():
|
|
281
291
|
for encoder in info['hw_encoders']:
|
|
282
292
|
for pix_fmt, bit_depth, chroma, desc in PIXEL_FORMATS:
|
|
283
|
-
tasks.append((codec, encoder, pix_fmt, bit_depth, chroma, test_dir, verbose))
|
|
293
|
+
tasks.append((codec, encoder, pix_fmt, bit_depth, chroma, test_dir, verbose, unsupported_encoders))
|
|
284
294
|
|
|
285
295
|
with ThreadPoolExecutor(max_workers=max_workers) as executor:
|
|
286
296
|
futures = [executor.submit(_run_encoder_bitdepth_test, task) for task in tasks]
|
|
@@ -297,7 +307,13 @@ def _run_encoder_bitdepth_tests(test_dir, max_workers, verbose):
|
|
|
297
307
|
|
|
298
308
|
def _run_decoder_bitdepth_test(test_data):
|
|
299
309
|
"""Tests decoder support for a specific pixel format."""
|
|
300
|
-
codec, hw_decoder, pix_fmt, bit_depth, chroma, test_dir, verbose = test_data
|
|
310
|
+
codec, hw_decoder, pix_fmt, bit_depth, chroma, test_dir, verbose, unsupported_decoders = test_data
|
|
311
|
+
|
|
312
|
+
# Skip unsupported decoders
|
|
313
|
+
if hw_decoder in unsupported_decoders:
|
|
314
|
+
title = DECODER_TITLES.get((hw_decoder, codec), f"{hw_decoder.upper()} Decoder:")
|
|
315
|
+
return title, pix_fmt, bit_depth, chroma, "skipped"
|
|
316
|
+
|
|
301
317
|
if codec == "prores":
|
|
302
318
|
file_ext = ".mov"
|
|
303
319
|
else:
|
|
@@ -383,17 +399,20 @@ def _run_decoder_bitdepth_test(test_data):
|
|
|
383
399
|
return title, pix_fmt, bit_depth, chroma, status
|
|
384
400
|
|
|
385
401
|
|
|
386
|
-
def _run_decoder_bitdepth_tests(test_dir, max_workers, verbose):
|
|
402
|
+
def _run_decoder_bitdepth_tests(test_dir, max_workers, verbose, unsupported_decoders=None):
|
|
387
403
|
"""Tests decoder support for various pixel formats."""
|
|
388
404
|
results = defaultdict(dict)
|
|
389
405
|
|
|
406
|
+
if unsupported_decoders is None:
|
|
407
|
+
unsupported_decoders = set()
|
|
408
|
+
|
|
390
409
|
print("\n--- Running Bit-depth/Chroma Decoder Tests ---")
|
|
391
410
|
|
|
392
411
|
tasks = []
|
|
393
412
|
for codec, info in DECODERS.items():
|
|
394
413
|
for hw_decoder in info['hw_decoders']:
|
|
395
414
|
for pix_fmt, bit_depth, chroma, desc in PIXEL_FORMATS:
|
|
396
|
-
tasks.append((codec, hw_decoder, pix_fmt, bit_depth, chroma, test_dir, verbose))
|
|
415
|
+
tasks.append((codec, hw_decoder, pix_fmt, bit_depth, chroma, test_dir, verbose, unsupported_decoders))
|
|
397
416
|
|
|
398
417
|
with ThreadPoolExecutor(max_workers=max_workers) as executor:
|
|
399
418
|
futures = [executor.submit(_run_decoder_bitdepth_test, task) for task in tasks]
|
|
@@ -463,13 +482,24 @@ def _print_bitdepth_chroma_table(results, table_type="Encoder"):
|
|
|
463
482
|
def run_bitdepth_chroma_tests(encoder_count, decoder_count, verbose):
|
|
464
483
|
"""Run all bit-depth and chroma tests and return results."""
|
|
465
484
|
import shutil
|
|
466
|
-
temp_dir = os.path.join(tempfile.gettempdir(), "HwCodecDetect_BitDepth")
|
|
485
|
+
#temp_dir = os.path.join(tempfile.gettempdir(), "HwCodecDetect_BitDepth")
|
|
486
|
+
from .utils import get_temp_path
|
|
487
|
+
temp_dir = os.path.join(get_temp_path(), "HwCodecDetect_BitDepth")
|
|
467
488
|
if os.path.exists(temp_dir):
|
|
468
489
|
shutil.rmtree(temp_dir)
|
|
469
|
-
os.makedirs(temp_dir)
|
|
490
|
+
os.makedirs(temp_dir, exist_ok=True)
|
|
491
|
+
|
|
492
|
+
# Check codec support before running tests
|
|
493
|
+
print("\nChecking FFmpeg codec support for bit-depth/chroma tests...")
|
|
494
|
+
unsupported_encoders, unsupported_decoders = check_codec_support(ENCODERS, DECODERS)
|
|
495
|
+
if unsupported_encoders or unsupported_decoders:
|
|
496
|
+
print(f"\nFound {len(unsupported_encoders)} unsupported encoder(s) and {len(unsupported_decoders)} unsupported decoder(s).")
|
|
497
|
+
print("These codecs will be marked as unavailable '-' in the results.\n")
|
|
498
|
+
else:
|
|
499
|
+
print("All defined hardware codecs are supported.\n")
|
|
470
500
|
|
|
471
|
-
encoder_results = _run_encoder_bitdepth_tests(temp_dir, encoder_count, verbose)
|
|
472
|
-
decoder_results = _run_decoder_bitdepth_tests(temp_dir, decoder_count, verbose)
|
|
501
|
+
encoder_results = _run_encoder_bitdepth_tests(temp_dir, encoder_count, verbose, unsupported_encoders)
|
|
502
|
+
decoder_results = _run_decoder_bitdepth_tests(temp_dir, decoder_count, verbose, unsupported_decoders)
|
|
473
503
|
|
|
474
504
|
# Clean up
|
|
475
505
|
shutil.rmtree(temp_dir)
|
|
@@ -10,6 +10,7 @@ import argparse
|
|
|
10
10
|
from collections import defaultdict
|
|
11
11
|
from .install_ffmpeg_if_needed import install_ffmpeg_if_needed
|
|
12
12
|
from .bitdepth_chroma_detect import run_bitdepth_chroma_tests, print_bitdepth_chroma_results
|
|
13
|
+
from .utils import check_codec_support
|
|
13
14
|
from colorama import init, Fore, Style
|
|
14
15
|
from concurrent.futures import ThreadPoolExecutor, as_completed
|
|
15
16
|
from tqdm import tqdm
|
|
@@ -263,7 +264,13 @@ def _run_ffmpeg_command(command, verbose):
|
|
|
263
264
|
|
|
264
265
|
def _run_encoder_test_single(test_data):
|
|
265
266
|
"""Runs a single encoder test and returns the result."""
|
|
266
|
-
codec, encoder, res_name, res_size, test_dir, verbose = test_data
|
|
267
|
+
codec, encoder, res_name, res_size, test_dir, verbose, unsupported_encoders = test_data
|
|
268
|
+
|
|
269
|
+
# Skip unsupported encoders
|
|
270
|
+
if encoder in unsupported_encoders:
|
|
271
|
+
title = ENCODER_TITLES.get((encoder, codec), f"{encoder.upper()} Encoder:")
|
|
272
|
+
return title, res_name, "skipped"
|
|
273
|
+
|
|
267
274
|
if codec == "prores":
|
|
268
275
|
file_ext = ".mov"
|
|
269
276
|
else:
|
|
@@ -358,17 +365,20 @@ def _run_encoder_test_single(test_data):
|
|
|
358
365
|
return title, res_name, status
|
|
359
366
|
|
|
360
367
|
|
|
361
|
-
def _run_encoder_tests(test_dir, max_workers, verbose):
|
|
368
|
+
def _run_encoder_tests(test_dir, max_workers, verbose, unsupported_encoders=None):
|
|
362
369
|
"""Runs hardware encoder tests using a thread pool."""
|
|
363
370
|
results = defaultdict(dict)
|
|
364
|
-
|
|
371
|
+
|
|
372
|
+
if unsupported_encoders is None:
|
|
373
|
+
unsupported_encoders = set()
|
|
374
|
+
|
|
365
375
|
print("\n--- Running Encoder Tests ---")
|
|
366
|
-
|
|
376
|
+
|
|
367
377
|
tasks = []
|
|
368
378
|
for codec, info in ENCODERS.items():
|
|
369
379
|
for encoder in info['hw_encoders']:
|
|
370
380
|
for res_name, res_size in RESOLUTIONS.items():
|
|
371
|
-
tasks.append((codec, encoder, res_name, res_size, test_dir, verbose))
|
|
381
|
+
tasks.append((codec, encoder, res_name, res_size, test_dir, verbose, unsupported_encoders))
|
|
372
382
|
|
|
373
383
|
with ThreadPoolExecutor(max_workers=max_workers) as executor:
|
|
374
384
|
futures = [executor.submit(_run_encoder_test_single, task) for task in tasks]
|
|
@@ -381,7 +391,13 @@ def _run_encoder_tests(test_dir, max_workers, verbose):
|
|
|
381
391
|
|
|
382
392
|
def _run_decoder_test_single(test_data):
|
|
383
393
|
"""Runs a single decoder test and returns the result."""
|
|
384
|
-
codec, hw_decoder, res_name, res_size, test_dir, verbose = test_data
|
|
394
|
+
codec, hw_decoder, res_name, res_size, test_dir, verbose, unsupported_decoders = test_data
|
|
395
|
+
|
|
396
|
+
# Skip unsupported decoders
|
|
397
|
+
if hw_decoder in unsupported_decoders:
|
|
398
|
+
title = DECODER_TITLES.get((hw_decoder, codec), f"{hw_decoder.upper()} Decoder:")
|
|
399
|
+
return title, res_name, "skipped"
|
|
400
|
+
|
|
385
401
|
if codec == "prores":
|
|
386
402
|
file_ext = ".mov"
|
|
387
403
|
else:
|
|
@@ -476,17 +492,20 @@ def _run_decoder_test_single(test_data):
|
|
|
476
492
|
return title, res_name, status
|
|
477
493
|
|
|
478
494
|
|
|
479
|
-
def _run_decoder_tests(test_dir, max_workers, verbose):
|
|
495
|
+
def _run_decoder_tests(test_dir, max_workers, verbose, unsupported_decoders=None):
|
|
480
496
|
"""Runs hardware decoder tests using a thread pool."""
|
|
481
497
|
results = defaultdict(dict)
|
|
482
498
|
|
|
499
|
+
if unsupported_decoders is None:
|
|
500
|
+
unsupported_decoders = set()
|
|
501
|
+
|
|
483
502
|
print("\n--- Running Decoder Tests ---")
|
|
484
503
|
|
|
485
504
|
tasks = []
|
|
486
505
|
for codec, info in DECODERS.items():
|
|
487
506
|
for hw_decoder in info['hw_decoders']:
|
|
488
507
|
for res_name, res_size in RESOLUTIONS.items():
|
|
489
|
-
tasks.append((codec, hw_decoder, res_name, res_size, test_dir, verbose))
|
|
508
|
+
tasks.append((codec, hw_decoder, res_name, res_size, test_dir, verbose, unsupported_decoders))
|
|
490
509
|
|
|
491
510
|
with ThreadPoolExecutor(max_workers=max_workers) as executor:
|
|
492
511
|
futures = [executor.submit(_run_decoder_test_single, task) for task in tasks]
|
|
@@ -575,14 +594,25 @@ def run_all_tests(args):
|
|
|
575
594
|
print("Error: FFmpeg dependency not met. Please check installation.", file=sys.stderr)
|
|
576
595
|
return -1
|
|
577
596
|
|
|
578
|
-
|
|
597
|
+
# Check codec support before running tests
|
|
598
|
+
print("\nChecking FFmpeg codec support...")
|
|
599
|
+
unsupported_encoders, unsupported_decoders = check_codec_support(ENCODERS, DECODERS)
|
|
600
|
+
if unsupported_encoders or unsupported_decoders:
|
|
601
|
+
print(f"\nFound {len(unsupported_encoders)} unsupported encoder(s) and {len(unsupported_decoders)} unsupported decoder(s).")
|
|
602
|
+
print("These codecs will be marked as unavailable '-' in the results.\n")
|
|
603
|
+
else:
|
|
604
|
+
print("All defined hardware codecs are supported.\n")
|
|
605
|
+
|
|
606
|
+
#temp_dir = os.path.join(tempfile.gettempdir(), "HwCodecDetect")
|
|
607
|
+
from .utils import get_temp_path
|
|
608
|
+
temp_dir = os.path.join(get_temp_path(), "HwCodecDetect_cli")
|
|
579
609
|
if os.path.exists(temp_dir):
|
|
580
610
|
# Clear previous run data to ensure a fresh test
|
|
581
611
|
shutil.rmtree(temp_dir)
|
|
582
|
-
os.makedirs(temp_dir)
|
|
612
|
+
os.makedirs(temp_dir, exist_ok=True)
|
|
583
613
|
|
|
584
|
-
encoder_results = _run_encoder_tests(temp_dir, args.encoder_count, args.verbose)
|
|
585
|
-
decoder_results = _run_decoder_tests(temp_dir, args.decoder_count, args.verbose)
|
|
614
|
+
encoder_results = _run_encoder_tests(temp_dir, args.encoder_count, args.verbose, unsupported_encoders)
|
|
615
|
+
decoder_results = _run_decoder_tests(temp_dir, args.decoder_count, args.verbose, unsupported_decoders)
|
|
586
616
|
|
|
587
617
|
all_results = {}
|
|
588
618
|
all_results.update(encoder_results)
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import os.path
|
|
3
|
+
import tempfile
|
|
4
|
+
import sys
|
|
5
|
+
import re
|
|
6
|
+
import subprocess
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
|
|
9
|
+
def get_temp_path():
|
|
10
|
+
app_id = "HwCodecDetect"
|
|
11
|
+
|
|
12
|
+
candidates = []
|
|
13
|
+
|
|
14
|
+
candidates.append(os.path.join(tempfile.gettempdir(), app_id))
|
|
15
|
+
|
|
16
|
+
if sys.platform == "win32":
|
|
17
|
+
local_appdata = os.getenv("LOCALAPPDATA")
|
|
18
|
+
if local_appdata:
|
|
19
|
+
candidates.append(os.path.join(local_appdata, app_id))
|
|
20
|
+
elif sys.platform == "darwin":
|
|
21
|
+
candidates.append(os.path.expanduser(f"~/Library/Caches/{app_id}"))
|
|
22
|
+
elif sys.platform.startswith("linux"):
|
|
23
|
+
xdg_cache = os.getenv("XDG_CACHE_HOME", os.path.expanduser("~/.cache"))
|
|
24
|
+
candidates.append(os.path.join(xdg_cache, app_id))
|
|
25
|
+
|
|
26
|
+
candidates.append(os.path.expanduser(f"~/.{app_id}"))
|
|
27
|
+
|
|
28
|
+
for path in candidates:
|
|
29
|
+
if not path:
|
|
30
|
+
continue
|
|
31
|
+
|
|
32
|
+
try:
|
|
33
|
+
os.makedirs(path, mode=0o755, exist_ok=True)
|
|
34
|
+
test_file = os.path.join(path, ".perm_test")
|
|
35
|
+
with open(test_file, 'w', encoding='utf-8') as f:
|
|
36
|
+
f.write("test")
|
|
37
|
+
|
|
38
|
+
if os.path.exists(test_file):
|
|
39
|
+
os.remove(test_file)
|
|
40
|
+
return path
|
|
41
|
+
except Exception as e:
|
|
42
|
+
print(f"Warning: Attempting path {path} failed: {e}")
|
|
43
|
+
continue
|
|
44
|
+
|
|
45
|
+
return os.getcwd()
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def get_local_version():
|
|
49
|
+
if getattr(sys, 'frozen', False):
|
|
50
|
+
base_path = sys._MEIPASS
|
|
51
|
+
else:
|
|
52
|
+
base_path = os.path.dirname(os.path.abspath(__file__))
|
|
53
|
+
|
|
54
|
+
v_path = os.path.join(base_path, "VERSION")
|
|
55
|
+
|
|
56
|
+
if not os.path.exists(v_path):
|
|
57
|
+
v_path = os.path.join(base_path, "..", "..", "VERSION")
|
|
58
|
+
|
|
59
|
+
try:
|
|
60
|
+
with open(v_path, "r", encoding="utf-8") as f:
|
|
61
|
+
return f.read().strip()
|
|
62
|
+
except FileNotFoundError:
|
|
63
|
+
return "Unknown Version"
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def get_ffmpeg_supported_codecs():
|
|
67
|
+
"""Get supported encoders, decoders and hwaccels from ffmpeg.
|
|
68
|
+
|
|
69
|
+
Returns:
|
|
70
|
+
tuple: (supported_encoders, supported_decoders) - two sets containing:
|
|
71
|
+
- supported_encoders: set of supported encoder names and hwaccel methods
|
|
72
|
+
- supported_decoders: set of supported decoder names and hwaccel methods
|
|
73
|
+
"""
|
|
74
|
+
supported_encoders = set()
|
|
75
|
+
supported_decoders = set()
|
|
76
|
+
|
|
77
|
+
try:
|
|
78
|
+
# Get encoders
|
|
79
|
+
result = subprocess.run(
|
|
80
|
+
["ffmpeg", "-hide_banner", "-encoders"],
|
|
81
|
+
capture_output=True,
|
|
82
|
+
text=True,
|
|
83
|
+
encoding='utf-8',
|
|
84
|
+
errors='ignore'
|
|
85
|
+
)
|
|
86
|
+
if result.returncode == 0:
|
|
87
|
+
for line in result.stdout.split('\n'):
|
|
88
|
+
# Parse lines like: V....D av1_nvenc NVIDIA NVENC av1 encoder (codec av1)
|
|
89
|
+
# Format: [VSA][6 chars of flags] [codec name] [description]
|
|
90
|
+
match = re.search(r'^\s*[VSA].{6}\s*(\S+)', line)
|
|
91
|
+
if match:
|
|
92
|
+
supported_encoders.add(match.group(1))
|
|
93
|
+
|
|
94
|
+
# Get decoders
|
|
95
|
+
result = subprocess.run(
|
|
96
|
+
["ffmpeg", "-hide_banner", "-decoders"],
|
|
97
|
+
capture_output=True,
|
|
98
|
+
text=True,
|
|
99
|
+
encoding='utf-8',
|
|
100
|
+
errors='ignore'
|
|
101
|
+
)
|
|
102
|
+
if result.returncode == 0:
|
|
103
|
+
for line in result.stdout.split('\n'):
|
|
104
|
+
# Parse lines like: V..... av1_cuvid Nvidia CUVID AV1 decoder (codec av1)
|
|
105
|
+
match = re.search(r'^\s*[VSA].{6}\s*(\S+)', line)
|
|
106
|
+
if match:
|
|
107
|
+
supported_decoders.add(match.group(1))
|
|
108
|
+
|
|
109
|
+
# Get hardware acceleration methods
|
|
110
|
+
result = subprocess.run(
|
|
111
|
+
["ffmpeg", "-hide_banner", "-hwaccels"],
|
|
112
|
+
capture_output=True,
|
|
113
|
+
text=True,
|
|
114
|
+
encoding='utf-8',
|
|
115
|
+
errors='ignore'
|
|
116
|
+
)
|
|
117
|
+
if result.returncode == 0:
|
|
118
|
+
lines = result.stdout.split('\n')
|
|
119
|
+
for line in lines:
|
|
120
|
+
line = line.strip()
|
|
121
|
+
# Skip empty lines and header
|
|
122
|
+
if not line or line.startswith('Hardware acceleration'):
|
|
123
|
+
continue
|
|
124
|
+
# Add hwaccel methods to both encoders and decoders
|
|
125
|
+
supported_encoders.add(line)
|
|
126
|
+
supported_decoders.add(line)
|
|
127
|
+
|
|
128
|
+
except Exception as e:
|
|
129
|
+
print(f"Warning: Failed to get ffmpeg codecs: {e}", file=sys.stderr)
|
|
130
|
+
|
|
131
|
+
return supported_encoders, supported_decoders
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
def check_codec_support(encoders_dict, decoders_dict):
|
|
135
|
+
"""Check which hardware codecs are supported by current ffmpeg version.
|
|
136
|
+
|
|
137
|
+
Args:
|
|
138
|
+
encoders_dict: Dictionary of encoder definitions (like ENCODERS)
|
|
139
|
+
decoders_dict: Dictionary of decoder definitions (like DECODERS)
|
|
140
|
+
|
|
141
|
+
Returns:
|
|
142
|
+
tuple: (unsupported_encoders, unsupported_decoders) - two sets containing
|
|
143
|
+
the names of unsupported encoders and decoders
|
|
144
|
+
"""
|
|
145
|
+
from colorama import Fore, Style
|
|
146
|
+
|
|
147
|
+
supported_encoders, supported_decoders = get_ffmpeg_supported_codecs()
|
|
148
|
+
|
|
149
|
+
unsupported_encoders = set()
|
|
150
|
+
unsupported_decoders = set()
|
|
151
|
+
|
|
152
|
+
# Check encoders
|
|
153
|
+
for codec, info in encoders_dict.items():
|
|
154
|
+
for encoder in info.get('hw_encoders', []):
|
|
155
|
+
if encoder not in supported_encoders:
|
|
156
|
+
unsupported_encoders.add(encoder)
|
|
157
|
+
print(f"{Fore.YELLOW}Warning: Encoder '{encoder}' is not supported by current FFmpeg version{Style.RESET_ALL}")
|
|
158
|
+
|
|
159
|
+
# Check decoders
|
|
160
|
+
for codec, info in decoders_dict.items():
|
|
161
|
+
for decoder in info.get('hw_decoders', []):
|
|
162
|
+
if decoder not in supported_decoders:
|
|
163
|
+
unsupported_decoders.add(decoder)
|
|
164
|
+
print(f"{Fore.YELLOW}Warning: Decoder '{decoder}' is not supported by current FFmpeg version{Style.RESET_ALL}")
|
|
165
|
+
|
|
166
|
+
return unsupported_encoders, unsupported_decoders
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.2.4"
|
|
@@ -9,6 +9,7 @@ src/HwCodecDetect/__init__.py
|
|
|
9
9
|
src/HwCodecDetect/bitdepth_chroma_detect.py
|
|
10
10
|
src/HwCodecDetect/install_ffmpeg_if_needed.py
|
|
11
11
|
src/HwCodecDetect/run_tests.py
|
|
12
|
+
src/HwCodecDetect/utils.py
|
|
12
13
|
src/HwCodecDetect/version.py
|
|
13
14
|
src/HwCodecDetect.egg-info/PKG-INFO
|
|
14
15
|
src/HwCodecDetect.egg-info/SOURCES.txt
|
hwcodecdetect-0.2.3/VERSION
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
0.2.3
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = "0.2.3"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|