avtb 0.0.1__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.
- avtb-0.0.1/PKG-INFO +88 -0
- avtb-0.0.1/README.md +57 -0
- avtb-0.0.1/avtb/__init__.py +5 -0
- avtb-0.0.1/avtb/benchmark/ffmpeg_encoder.py +159 -0
- avtb-0.0.1/avtb/benchmark/ffmpeg_encoder_plot.py +555 -0
- avtb-0.0.1/avtb/benchmark/ffmpeg_encoders.py +61 -0
- avtb-0.0.1/avtb/benchmark/ffmpeg_hwaccels.py +93 -0
- avtb-0.0.1/avtb/benchmark/video2x.py +107 -0
- avtb-0.0.1/avtb/device.py +187 -0
- avtb-0.0.1/avtb/engines/ffmpeg.py +69 -0
- avtb-0.0.1/avtb/engines/ffmpeg_cmd_builder.py +643 -0
- avtb-0.0.1/avtb/engines/ffmpeg_out_parser.py +37 -0
- avtb-0.0.1/avtb/engines/ffprobe.py +153 -0
- avtb-0.0.1/avtb/engines/utils.py +8 -0
- avtb-0.0.1/avtb/engines/video2x.py +70 -0
- avtb-0.0.1/avtb/engines/video2x_cmd_builder.py +231 -0
- avtb-0.0.1/avtb/tools/ass_merge.py +158 -0
- avtb-0.0.1/avtb/tools/audio_annotator.py +1087 -0
- avtb-0.0.1/avtb/tools/audio_player_with_resample.py +586 -0
- avtb-0.0.1/avtb/tools/folder_add_prefix.py +22 -0
- avtb-0.0.1/avtb/tools/preprocess_video.py +201 -0
- avtb-0.0.1/avtb/tools/video_sr.py +194 -0
- avtb-0.0.1/avtb/tools/vmaf.py +17 -0
- avtb-0.0.1/avtb/tools/xcode_audio.py +130 -0
- avtb-0.0.1/avtb/utils.py +52 -0
- avtb-0.0.1/avtb.egg-info/PKG-INFO +88 -0
- avtb-0.0.1/avtb.egg-info/SOURCES.txt +29 -0
- avtb-0.0.1/avtb.egg-info/dependency_links.txt +1 -0
- avtb-0.0.1/avtb.egg-info/top_level.txt +1 -0
- avtb-0.0.1/setup.cfg +4 -0
- avtb-0.0.1/setup.py +126 -0
avtb-0.0.1/PKG-INFO
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: avtb
|
|
3
|
+
Version: 0.0.1
|
|
4
|
+
Summary: Just handy python wrappers to call ffmpeg/video2x executables :)
|
|
5
|
+
Home-page: https://gitee.com/kahsolt/avtb
|
|
6
|
+
Author: Kahsolt
|
|
7
|
+
Author-email: kahsolt@qq.com
|
|
8
|
+
License: MIT
|
|
9
|
+
Classifier: Development Status :: 3 - Alpha
|
|
10
|
+
Classifier: Environment :: Console
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: Natural Language :: English
|
|
13
|
+
Classifier: Programming Language :: Python
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Topic :: Multimedia
|
|
16
|
+
Classifier: Topic :: Multimedia :: Sound/Audio
|
|
17
|
+
Classifier: Topic :: Multimedia :: Video
|
|
18
|
+
Classifier: Topic :: Utilities
|
|
19
|
+
Requires-Python: >=3.10.0
|
|
20
|
+
Description-Content-Type: text/markdown
|
|
21
|
+
Dynamic: author
|
|
22
|
+
Dynamic: author-email
|
|
23
|
+
Dynamic: classifier
|
|
24
|
+
Dynamic: description
|
|
25
|
+
Dynamic: description-content-type
|
|
26
|
+
Dynamic: home-page
|
|
27
|
+
Dynamic: license
|
|
28
|
+
Dynamic: requires-python
|
|
29
|
+
Dynamic: summary
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
### Audio/Video ToolBox (avtb)
|
|
33
|
+
|
|
34
|
+
Just handy python wrappers to call ffmpeg/video2x executables :)
|
|
35
|
+
|
|
36
|
+
----
|
|
37
|
+
|
|
38
|
+
### Install
|
|
39
|
+
|
|
40
|
+
```shell
|
|
41
|
+
# install from PyPI
|
|
42
|
+
pip install avtb
|
|
43
|
+
|
|
44
|
+
# or install as local repo
|
|
45
|
+
git clone https://gitee.com/kahsolt/avtb.git
|
|
46
|
+
cd avtb
|
|
47
|
+
pip install -e .
|
|
48
|
+
|
|
49
|
+
# download ffmpeg & video2x, add to PATH
|
|
50
|
+
# ffmpeg: https://ffmpeg.org/download.html
|
|
51
|
+
# video2x: https://docs.video2x.org/installing/windows-qt6.html
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### Usage
|
|
55
|
+
|
|
56
|
+
⚪ Use via command line
|
|
57
|
+
|
|
58
|
+
```shell
|
|
59
|
+
# benchmark with ffmepg
|
|
60
|
+
python -m avtb.benchmark.ffmpeg_encoder -I 1080p.mp4 -C libx264
|
|
61
|
+
python -m avtb.benchmark.ffmpeg_encoder -I 1080p.mp4 -C h264_nvenc
|
|
62
|
+
python -m avtb.benchmark.ffmpeg_encoder -I 1080p.mp4 -C h264_amf
|
|
63
|
+
|
|
64
|
+
# benchmark with video2x
|
|
65
|
+
python -m avtb.benchmark.video2x -S 720p.mp4 -F 1080p.mp4 -C libx264 --x2_only
|
|
66
|
+
python -m avtb.benchmark.video2x -S 720p.mp4 -F 1080p.mp4 -C h264_nvenc --x2_only
|
|
67
|
+
|
|
68
|
+
# batch video super-resolution
|
|
69
|
+
python -m avtb.tools.video_sr -I src/ -O out/ -P realcugan -M models-se -S 1080p
|
|
70
|
+
# video quality assessment
|
|
71
|
+
python -m avtb.tools.vmaf original.mp4 compressed.mp4
|
|
72
|
+
# merge ass subtitle (JP + CN)
|
|
73
|
+
python -m avtb.tools.ass_merge jp.ass cn.ass -O merged.ass
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
⚪ Use via API
|
|
77
|
+
|
|
78
|
+
```python
|
|
79
|
+
from avtb import *
|
|
80
|
+
|
|
81
|
+
print(get_ffmpeg_version())
|
|
82
|
+
|
|
83
|
+
run_ffmpeg_libx264('fin.mp4', 'fpout.mp4', preset='slower', crf=23)
|
|
84
|
+
metrics = run_ffmpeg_evaluate('fin.mp4', 'fpout.mp4')
|
|
85
|
+
print(metrics)
|
|
86
|
+
|
|
87
|
+
run_video2x_realesrgan('lowres.mp4', 'hires.mp4', model='realesr-animevideov3', factor=2)
|
|
88
|
+
```
|
avtb-0.0.1/README.md
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
### Audio/Video ToolBox (avtb)
|
|
2
|
+
|
|
3
|
+
Just handy python wrappers to call ffmpeg/video2x executables :)
|
|
4
|
+
|
|
5
|
+
----
|
|
6
|
+
|
|
7
|
+
### Install
|
|
8
|
+
|
|
9
|
+
```shell
|
|
10
|
+
# install from PyPI
|
|
11
|
+
pip install avtb
|
|
12
|
+
|
|
13
|
+
# or install as local repo
|
|
14
|
+
git clone https://gitee.com/kahsolt/avtb.git
|
|
15
|
+
cd avtb
|
|
16
|
+
pip install -e .
|
|
17
|
+
|
|
18
|
+
# download ffmpeg & video2x, add to PATH
|
|
19
|
+
# ffmpeg: https://ffmpeg.org/download.html
|
|
20
|
+
# video2x: https://docs.video2x.org/installing/windows-qt6.html
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
### Usage
|
|
24
|
+
|
|
25
|
+
⚪ Use via command line
|
|
26
|
+
|
|
27
|
+
```shell
|
|
28
|
+
# benchmark with ffmepg
|
|
29
|
+
python -m avtb.benchmark.ffmpeg_encoder -I 1080p.mp4 -C libx264
|
|
30
|
+
python -m avtb.benchmark.ffmpeg_encoder -I 1080p.mp4 -C h264_nvenc
|
|
31
|
+
python -m avtb.benchmark.ffmpeg_encoder -I 1080p.mp4 -C h264_amf
|
|
32
|
+
|
|
33
|
+
# benchmark with video2x
|
|
34
|
+
python -m avtb.benchmark.video2x -S 720p.mp4 -F 1080p.mp4 -C libx264 --x2_only
|
|
35
|
+
python -m avtb.benchmark.video2x -S 720p.mp4 -F 1080p.mp4 -C h264_nvenc --x2_only
|
|
36
|
+
|
|
37
|
+
# batch video super-resolution
|
|
38
|
+
python -m avtb.tools.video_sr -I src/ -O out/ -P realcugan -M models-se -S 1080p
|
|
39
|
+
# video quality assessment
|
|
40
|
+
python -m avtb.tools.vmaf original.mp4 compressed.mp4
|
|
41
|
+
# merge ass subtitle (JP + CN)
|
|
42
|
+
python -m avtb.tools.ass_merge jp.ass cn.ass -O merged.ass
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
⚪ Use via API
|
|
46
|
+
|
|
47
|
+
```python
|
|
48
|
+
from avtb import *
|
|
49
|
+
|
|
50
|
+
print(get_ffmpeg_version())
|
|
51
|
+
|
|
52
|
+
run_ffmpeg_libx264('fin.mp4', 'fpout.mp4', preset='slower', crf=23)
|
|
53
|
+
metrics = run_ffmpeg_evaluate('fin.mp4', 'fpout.mp4')
|
|
54
|
+
print(metrics)
|
|
55
|
+
|
|
56
|
+
run_video2x_realesrgan('lowres.mp4', 'hires.mp4', model='realesr-animevideov3', factor=2)
|
|
57
|
+
```
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# Author: Armit
|
|
3
|
+
# Create Time: 2026/09/15
|
|
4
|
+
|
|
5
|
+
# 穷举指定编码器的配置参数,并绘制质量-体积-速度参考图
|
|
6
|
+
# libx264: 用于最终成品导出,以取得最高质量+最大压缩,速度x1.5/x4
|
|
7
|
+
# h264_nvenc: 用于素材预处理,质量与libx264极其相近,文件略大10%,速度x7
|
|
8
|
+
# h264_amf: 用于快速预览,质量垃圾,体积大,速度x4;纯废物
|
|
9
|
+
|
|
10
|
+
import json
|
|
11
|
+
import shutil
|
|
12
|
+
from pathlib import Path
|
|
13
|
+
from pprint import pprint
|
|
14
|
+
from datetime import datetime
|
|
15
|
+
from time import perf_counter
|
|
16
|
+
from dataclasses import asdict
|
|
17
|
+
from argparse import ArgumentParser
|
|
18
|
+
from traceback import print_exc
|
|
19
|
+
from typing import Callable
|
|
20
|
+
|
|
21
|
+
from avtb.engines.ffprobe import get_video_info
|
|
22
|
+
from avtb.engines.ffmpeg import run_ffmpeg_libx264, run_ffmpeg_h264_nvenc, run_ffmpeg_h264_amf
|
|
23
|
+
from avtb.engines.ffmpeg import get_ffmpeg_version, run_ffmpeg_evaluate
|
|
24
|
+
from avtb.engines.ffmpeg_out_parser import parse_bench_stats
|
|
25
|
+
from avtb.utils import TMP_PATH, DATA_PATH, HOSTNAME
|
|
26
|
+
|
|
27
|
+
ENCODERS = [
|
|
28
|
+
# h264
|
|
29
|
+
'libx264',
|
|
30
|
+
'h264_nvenc',
|
|
31
|
+
'h264_amf',
|
|
32
|
+
# h265
|
|
33
|
+
'libx265',
|
|
34
|
+
'hevc_nvenc',
|
|
35
|
+
'hevc_amf',
|
|
36
|
+
# av1
|
|
37
|
+
'av1_nvenc',
|
|
38
|
+
'av1_amf',
|
|
39
|
+
# vp8
|
|
40
|
+
'libvpx',
|
|
41
|
+
# vp9
|
|
42
|
+
'libvpx_vp9',
|
|
43
|
+
]
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def iter_libx264_cfgs():
|
|
47
|
+
for preset in ['faster', 'fast', 'medium', 'slow', 'slower', 'veryslow']:
|
|
48
|
+
for crf in list(range(13, 51+1, 2)):
|
|
49
|
+
cfgs = (preset, crf)
|
|
50
|
+
runcmd_gen = lambda fpi, fpo: run_ffmpeg_libx264(fpi, fpo, preset=preset, crf=crf, benchmark=True)
|
|
51
|
+
yield cfgs, runcmd_gen
|
|
52
|
+
|
|
53
|
+
def iter_h264_nvenc_cfgs():
|
|
54
|
+
for preset in ['medium', 'slow', 'p4', 'p5', 'p6', 'p7']:
|
|
55
|
+
for cq in list(range(17, 51+1, 2)):
|
|
56
|
+
cfgs = (preset, cq)
|
|
57
|
+
runcmd_gen = lambda fpi, fpo: run_ffmpeg_h264_nvenc(fpi, fpo, preset=preset, cq=cq, benchmark=True)
|
|
58
|
+
yield cfgs, runcmd_gen
|
|
59
|
+
|
|
60
|
+
def iter_h264_amf_cfgs():
|
|
61
|
+
for preset in ['balanced', 'quality']:
|
|
62
|
+
for qvbr_quality_level in [0] + list(range(1, 51+1, 2)):
|
|
63
|
+
cfgs = (preset, qvbr_quality_level)
|
|
64
|
+
runcmd_gen = lambda fpi, fpo: run_ffmpeg_h264_amf(fpi, fpo, preset=preset, qvbr_quality_level=qvbr_quality_level, benchmark=True)
|
|
65
|
+
yield cfgs, runcmd_gen
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def run_xcode_and_eval(fpi:Path, fpo:Path, cfgs:tuple, runcmd_gen:Callable):
|
|
69
|
+
ts_start = perf_counter()
|
|
70
|
+
p = runcmd_gen(fpi, fpo)
|
|
71
|
+
ts_end = perf_counter()
|
|
72
|
+
timecost = ts_end - ts_start
|
|
73
|
+
|
|
74
|
+
bench_stats = parse_bench_stats(p)
|
|
75
|
+
|
|
76
|
+
vinfo_fpi = get_video_info(fpi)
|
|
77
|
+
vinfo_fpo = get_video_info(fpo)
|
|
78
|
+
metrics = run_ffmpeg_evaluate(fpi, fpo, fast_mode=args.fast_eval)
|
|
79
|
+
metrics = asdict(metrics)
|
|
80
|
+
metrics['bitr'] = vinfo_fpo.bit_rate / vinfo_fpi.bit_rate
|
|
81
|
+
metrics['zipr'] = vinfo_fpo.fsize / vinfo_fpi.fsize
|
|
82
|
+
|
|
83
|
+
Path(fpo).unlink(missing_ok=True)
|
|
84
|
+
|
|
85
|
+
return {
|
|
86
|
+
'cfgs': cfgs,
|
|
87
|
+
'timecost': timecost,
|
|
88
|
+
'metrics': metrics,
|
|
89
|
+
'bench_stats': bench_stats,
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
def run(args):
|
|
93
|
+
ffmpeg_ver = get_ffmpeg_version()
|
|
94
|
+
|
|
95
|
+
# 测试文件拷贝到临时目录(内存盘)
|
|
96
|
+
fp = args.input
|
|
97
|
+
fpi = TMP_PATH / f'benchmark_ffmpeg_encoder{fp.suffix}'
|
|
98
|
+
if fpi.exists(): fpi.unlink()
|
|
99
|
+
shutil.copyfile(fp, fpi)
|
|
100
|
+
fpo = fpi.with_name('benchmark_ffmpeg_encoder-xcode.mp4')
|
|
101
|
+
fpo.unlink(missing_ok=True)
|
|
102
|
+
|
|
103
|
+
# 枚举各种参数
|
|
104
|
+
iter_cfgs = globals()[f'iter_{args.encoder}_cfgs']
|
|
105
|
+
n_cases = len(list(iter_cfgs()))
|
|
106
|
+
records: list[dict] = []
|
|
107
|
+
try:
|
|
108
|
+
for i_case, (cfgs, runcmd_gen) in enumerate(iter_cfgs(), start=1):
|
|
109
|
+
print(f'\n[{i_case} / {n_cases}]')
|
|
110
|
+
try:
|
|
111
|
+
ts_start = perf_counter()
|
|
112
|
+
res = run_xcode_and_eval(fpi, fpo, cfgs, runcmd_gen)
|
|
113
|
+
ts_end = perf_counter()
|
|
114
|
+
pprint(res)
|
|
115
|
+
print(f'>> ts: {ts_end - ts_start:.3f}s')
|
|
116
|
+
records.append(res)
|
|
117
|
+
except Exception as e:
|
|
118
|
+
print(f'>> failed: {e}')
|
|
119
|
+
except KeyboardInterrupt:
|
|
120
|
+
print('Exit by Ctrl+C')
|
|
121
|
+
except:
|
|
122
|
+
print_exc()
|
|
123
|
+
|
|
124
|
+
# 删除临时文件
|
|
125
|
+
fpi.unlink(missing_ok=True)
|
|
126
|
+
|
|
127
|
+
# 保存测试数据
|
|
128
|
+
if records:
|
|
129
|
+
args.output.mkdir(exist_ok=True)
|
|
130
|
+
fpout: Path = args.output / 'benchmark_ffmpeg_encoder.json'
|
|
131
|
+
if fpout.exists():
|
|
132
|
+
with open(fpout, 'r', encoding='utf-8') as fh:
|
|
133
|
+
runs = json.load(fh)
|
|
134
|
+
else:
|
|
135
|
+
runs = []
|
|
136
|
+
runs.append({
|
|
137
|
+
'ts': str(datetime.now()),
|
|
138
|
+
'host': HOSTNAME,
|
|
139
|
+
'ffmepg': ffmpeg_ver,
|
|
140
|
+
'encoder': args.encoder,
|
|
141
|
+
'input': args.input.name,
|
|
142
|
+
'records': records,
|
|
143
|
+
})
|
|
144
|
+
with open(fpout, 'w', encoding='utf-8') as fh:
|
|
145
|
+
json.dump(runs, fh, ensure_ascii=False, indent=2)
|
|
146
|
+
print(f'>> save file: {fpout}')
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
if __name__ == '__main__':
|
|
150
|
+
parser = ArgumentParser()
|
|
151
|
+
parser.add_argument('-I', '--input', default=DATA_PATH / '1080p_AMV-90s.mp4', type=Path)
|
|
152
|
+
parser.add_argument('-O', '--output', default='./log', type=Path)
|
|
153
|
+
parser.add_argument('-C', '--encoder', default='libx264', choices=ENCODERS)
|
|
154
|
+
parser.add_argument('--fast_eval', action='store_true', help='fast metric eval, skip vmaf')
|
|
155
|
+
args = parser.parse_args()
|
|
156
|
+
|
|
157
|
+
assert args.input.is_file()
|
|
158
|
+
|
|
159
|
+
run(args)
|