Skip to content

Commit

Permalink
Add control on ffmpeg CPU threads consumption, with a default of 1
Browse files Browse the repository at this point in the history
  • Loading branch information
benoit74 committed Feb 13, 2024
1 parent 2fc4061 commit a7307d1
Show file tree
Hide file tree
Showing 3 changed files with 127 additions and 9 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Suuport for Python 3.12, drop Python 3.7 #118
- Replace "iso-369" iso639-lang by "iso639-lang" library
- Rework the VideoWebmLow preset for faster encoding and smaller file size (preset has been bumped to version 2)
- When reencoding a video, ffmpeg now uses only 1 CPU thread by default (new arg to `reencode` allows to override this default value)

## [3.2.0] - 2023-12-16

Expand Down
41 changes: 32 additions & 9 deletions src/zimscraperlib/video/encoding.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,41 +6,64 @@
import shutil
import subprocess
import tempfile
from typing import List, Optional

from zimscraperlib import logger
from zimscraperlib.logging import nicer_args_join


def _build_ffmpeg_args(
src_path: pathlib.Path,
tmp_path: pathlib.Path,
ffmpeg_args: List[str],
threads: Optional[int],
) -> List[str]:
if threads:
if "-threads" in ffmpeg_args:
raise AttributeError("Cannot set the number of threads, already set")
else:
ffmpeg_args += ["-threads", str(threads)]
args = [
"/usr/bin/env",
"ffmpeg",
"-y",
"-i",
f"file:{src_path}",
*ffmpeg_args,
f"file:{tmp_path}",
]
return args


def reencode(
src_path,
dst_path,
ffmpeg_args,
delete_src=False, # noqa: FBT002
with_process=False, # noqa: FBT002
failsafe=True, # noqa: FBT002
threads: Optional[int] = 1,
):
"""Runs ffmpeg with given ffmpeg_args
Arguments -
src_path - Path to source file
dst_path - Path to destination file
ffmpeg_args - A list of ffmpeg arguments
threads - Number of encoding threads used by ffmpeg
delete_src - Delete source file after convertion
with_process - Optionally return the output from ffmpeg (stderr and stdout)
failsafe - Run in failsafe mode
"""

with tempfile.TemporaryDirectory() as tmp_dir:
tmp_path = pathlib.Path(tmp_dir).joinpath(f"video.tmp{dst_path.suffix}")
args = [
"/usr/bin/env",
"ffmpeg",
"-y",
"-i",
f"file:{src_path}",
*ffmpeg_args,
f"file:{tmp_path}",
]
args = _build_ffmpeg_args(
src_path=src_path,
tmp_path=tmp_path,
ffmpeg_args=ffmpeg_args,
threads=threads,
)
logger.debug(
f"Encode {src_path} -> {dst_path} video format = {dst_path.suffix}"
)
Expand Down
94 changes: 94 additions & 0 deletions tests/video/test_encoding.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
import re
from pathlib import Path
from typing import List, Optional

import pytest

from zimscraperlib.video.encoding import _build_ffmpeg_args


@pytest.mark.parametrize(
"src_path,tmp_path,ffmpeg_args,threads,expected",
[
(
Path("path1/file1.mp4"),
Path("path1/fileout.mp4"),
[
"-codec:v",
"libx265",
],
None,
[
"/usr/bin/env",
"ffmpeg",
"-y",
"-i",
"file:path1/file1.mp4",
"-codec:v",
"libx265",
"file:path1/fileout.mp4",
],
),
(
Path("path2/file2.mp4"),
Path("path12/tmpfile.mp4"),
[
"-b:v",
"300k",
],
1,
[
"/usr/bin/env",
"ffmpeg",
"-y",
"-i",
"file:path2/file2.mp4",
"-b:v",
"300k",
"-threads",
"1",
"file:path12/tmpfile.mp4",
],
),
(
Path("path2/file2.mp4"),
Path("path12/tmpfile.mp4"),
[
"-b:v",
"300k",
"-threads",
"1",
],
1,
None,
),
],
)
def test_build_ffmpeg_args(
src_path: Path,
tmp_path: Path,
ffmpeg_args: List[str],
threads: Optional[int],
expected: Optional[List[str]],
):
if expected:
assert (
_build_ffmpeg_args(
src_path=src_path,
tmp_path=tmp_path,
ffmpeg_args=ffmpeg_args,
threads=threads,
)
== expected
)
else:
with pytest.raises(
AttributeError,
match=re.escape("Cannot set the number of threads, already set"),
):
_build_ffmpeg_args(
src_path=src_path,
tmp_path=tmp_path,
ffmpeg_args=ffmpeg_args,
threads=threads,
)

0 comments on commit a7307d1

Please sign in to comment.