Skip to content

Commit baec9c1

Browse files
authored
Merge pull request #170 from openzim/videos_vp9
webm video presets: migrate from VP8 to VP9 for smaller ZIMs
2 parents f3d1b07 + fd28720 commit baec9c1

File tree

3 files changed

+46
-27
lines changed

3 files changed

+46
-27
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
88
## [Unreleased]
99

1010
### Changed
11+
12+
- Migrate the **VideoWebmLow** and **VideoWebmHigh** presets to VP9 for smaller file size #79
13+
- New preset versions are v3 and v2 respectively
1114
- Simplify type annotations by replacing Union and Optional with pipe character ("|") for improved readability and clarity
1215

1316
### Fixed

src/zimscraperlib/video/presets.py

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -37,21 +37,23 @@ class VideoWebmLow(Config):
3737
128k target video bitrate but stay within quality boundaries.
3838
48k audio bitrate"""
3939

40-
VERSION = 2
40+
VERSION = 3
4141

4242
ext = "webm"
4343
mimetype = f"{preset_type}/webm"
4444

4545
options: ClassVar[dict[str, str | bool | int | None]] = {
46-
"-codec:v": "libvpx", # video codec
47-
"-quality": "best", # codec preset
48-
"-b:v": "128k", # Adjust quantizer within min/max to target this bitrate
49-
"-qmin": "18", # Reduce the bitrate on very still videos
46+
"-codec:v": "libvpx-vp9", # video codec
47+
"-b:v": "140k", # Adjust quantizer within min/max to target this bitrate
48+
"-qmin": "30", # Reduce the bitrate on very still videos
5049
"-qmax": "40", # Increase the bitrate on very busy videos
50+
"-g": "240", # Number of frames allowed between keyframes
51+
"-quality": "good", # codec preset
52+
"-speed": "4", # Encoding speed (compromise between quality and encoding time)
5153
"-vf": "scale='480:trunc(ow/a/2)*2'", # frame size
5254
"-codec:a": "libvorbis", # audio codec
53-
"-ar": "44100", # audio sampling rate
5455
"-b:a": "48k", # target audio bitrate
56+
"-ar": "44100", # audio sampling rate
5557
}
5658

5759

@@ -88,16 +90,22 @@ class VideoWebmHigh(Config):
8890
8991
25 constant quality"""
9092

91-
VERSION = 1
93+
VERSION = 2
9294

9395
ext = "webm"
9496
mimetype = f"{preset_type}/webm"
9597

9698
options: ClassVar[dict[str, str | bool | int | None]] = {
97-
"-codec:v": "libvpx", # video codec
99+
"-codec:v": "libvpx-vp9", # video codec
100+
"-b:v": "340k", # Adjust quantizer within min/max to target this bitrate
101+
"-qmin": "26", # Reduce the bitrate on very still videos
102+
"-qmax": "54", # Increase the bitrate on very busy videos
103+
"-g": "240", # Number of frames allowed between keyframes
104+
"-quality": "good", # codec preset
105+
"-speed": "1", # Encoding speed (compromise between quality and encoding time)
98106
"-codec:a": "libvorbis", # audio codec
99-
"-crf": "25", # constant quality, lower value gives better qual and larger size
100-
"-b:v": "0", # must be passed if using constant quality mode via -cbr for codec
107+
"-b:a": "48k", # target audio bitrate
108+
"-ar": "44100", # audio sampling rate
101109
}
102110

103111

tests/video/test_video.py

Lines changed: 25 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -151,19 +151,21 @@ def test_preset_has_mime_and_ext():
151151

152152
def test_preset_video_webm_low():
153153
config = VideoWebmLow()
154-
assert config.VERSION == 2
154+
assert config.VERSION == 3
155155
args = config.to_ffmpeg_args()
156-
assert len(args) == 20
156+
assert len(args) == 24
157157
options_map = [
158-
("codec:v", "libvpx"),
158+
("codec:v", "libvpx-vp9"),
159159
("codec:a", "libvorbis"),
160-
("b:v", "128k"),
160+
("b:v", "140k"),
161161
("ar", "44100"),
162162
("b:a", "48k"),
163-
("quality", "best"),
164-
("qmin", "18"),
163+
("quality", "good"),
164+
("qmin", "30"),
165165
("qmax", "40"),
166166
("vf", "scale='480:trunc(ow/a/2)*2'"),
167+
("g", "240"),
168+
("speed", "4"),
167169
]
168170
for option, val in options_map:
169171
idx = args.index(f"-{option}")
@@ -172,35 +174,41 @@ def test_preset_video_webm_low():
172174

173175
# test updating values
174176
config = VideoWebmLow(**{"-ar": "50000"})
175-
config["-bufsize"] = "900k"
177+
config["-qmin"] = "25"
176178
args = config.to_ffmpeg_args()
177179
idx = args.index("-ar")
178180
assert idx != -1 and args[idx + 1] == "50000"
179-
idx = args.index("-bufsize")
180-
assert idx != -1 and args[idx + 1] == "900k"
181+
idx = args.index("-qmin")
182+
assert idx != -1 and args[idx + 1] == "25"
181183

182184

183185
def test_preset_video_webm_high():
184186
config = VideoWebmHigh()
185-
assert config.VERSION == 1
187+
assert config.VERSION == 2
186188
args = config.to_ffmpeg_args()
187-
assert len(args) == 10
189+
assert len(args) == 22
188190
options_map = [
189-
("codec:v", "libvpx"),
191+
("codec:v", "libvpx-vp9"),
190192
("codec:a", "libvorbis"),
191-
("b:v", "0"),
192-
("crf", "25"),
193+
("b:v", "340k"),
194+
("ar", "44100"),
195+
("b:a", "48k"),
196+
("quality", "good"),
197+
("qmin", "26"),
198+
("qmax", "54"),
199+
("g", "240"),
200+
("speed", "1"),
193201
]
194202
for option, val in options_map:
195203
idx = args.index(f"-{option}")
196204
assert idx != -1
197205
assert args[idx + 1] == val
198206

199207
# test updating values
200-
config = VideoWebmHigh(**{"-crf": "51"})
208+
config = VideoWebmHigh(**{"-qmax": "51"})
201209
config["-b:v"] = "300k"
202210
args = config.to_ffmpeg_args()
203-
idx = args.index("-crf")
211+
idx = args.index("-qmax")
204212
assert idx != -1 and args[idx + 1] == "51"
205213
idx = args.index("-b:v")
206214
assert idx != -1 and args[idx + 1] == "300k"
@@ -314,7 +322,7 @@ def test_preset_voice_mp3_low():
314322
"video.mp4",
315323
"video.webm",
316324
VideoWebmLow().to_ffmpeg_args(),
317-
{"codecs": ["vp8", "vorbis"], "duration": 2},
325+
{"codecs": ["vp9", "vorbis"], "duration": 2},
318326
),
319327
(
320328
"video.webm",

0 commit comments

Comments
 (0)