Skip to content

Commit

Permalink
Use PyAV 14
Browse files Browse the repository at this point in the history
  • Loading branch information
WyattBlue committed Nov 21, 2024
1 parent 302ebc5 commit f3b75ea
Show file tree
Hide file tree
Showing 10 changed files with 42 additions and 103 deletions.
10 changes: 3 additions & 7 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -48,13 +48,9 @@ jobs:
uses: actions/setup-python@v5
with:
python-version: "3.10"
- name: Install FFmpeg
run: |
sudo apt update
sudo apt install ffmpeg
- name: Install Auto-Editor
run: pip install -e .
- name: Run Debug
run: auto-editor --debug
- name: Test
run: |
auto-editor --debug
auto-editor test all
run: auto-editor test all
14 changes: 13 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,15 @@
# 26.1.0

## Features
- Use PyAV 14.

## Fixes
- Remove `--ffmpeg-location` arg.
- Remove help text for recently removed args.

**Full Changelog**: https://github.com/WyattBlue/auto-editor/compare/26.0.1...26.1.0


# 26.0.1

## Fixes
Expand All @@ -7,7 +19,7 @@
- Remove the `ae-ffmpeg` package dependency.
- Remove unused args, functions.

**Full Changelog**: https://github.com/WyattBlue/auto-editor/compare/26.0.0...26.0.1
**Full Changelog**: https://github.com/WyattBlue/auto-editor/compare/26.0.0...26.0.1


# 26.0.0
Expand Down
2 changes: 1 addition & 1 deletion auto_editor/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = "26.0.1"
__version__ = "26.1.0"
18 changes: 4 additions & 14 deletions auto_editor/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -161,11 +161,6 @@ def main_options(parser: ArgumentParser) -> ArgumentParser:
metavar="PATH",
help="Set where the temporary directory is located",
)
parser.add_argument(
"--ffmpeg-location",
metavar="PATH",
help="Set a custom path to the ffmpeg location",
)
parser.add_text("Display Options:")
parser.add_argument(
"--progress",
Expand Down Expand Up @@ -251,7 +246,7 @@ def main_options(parser: ArgumentParser) -> ArgumentParser:
return parser


def download_video(my_input: str, args: Args, ffmpeg: FFmpeg, log: Log) -> str:
def download_video(my_input: str, args: Args, log: Log) -> str:
log.conwrite("Downloading video...")

def get_domain(url: str) -> str:
Expand All @@ -267,18 +262,14 @@ def get_domain(url: str) -> str:
else:
output_format = args.output_format

yt_dlp_path = args.yt_dlp_location

cmd = ["--ffmpeg-location", ffmpeg.get_path("yt-dlp", log)]

if download_format is not None:
cmd.extend(["-f", download_format])

cmd.extend(["-o", output_format, my_input])

if args.yt_dlp_extras is not None:
cmd.extend(args.yt_dlp_extras.split(" "))

yt_dlp_path = args.yt_dlp_location
try:
location = get_stdout(
[yt_dlp_path, "--get-filename", "--no-warnings"] + cmd
Expand Down Expand Up @@ -347,11 +338,10 @@ def main() -> None:
is_machine = args.progress == "machine"
log = Log(args.debug, args.quiet, args.temp_dir, is_machine, no_color)

ffmpeg = FFmpeg(args.ffmpeg_location)
paths = []
for my_input in args.input:
if my_input.startswith("http://") or my_input.startswith("https://"):
paths.append(download_video(my_input, args, ffmpeg, log))
paths.append(download_video(my_input, args, log))
else:
if not splitext(my_input)[1]:
if isdir(my_input):
Expand All @@ -365,7 +355,7 @@ def main() -> None:
paths.append(my_input)

try:
edit_media(paths, ffmpeg, args, log)
edit_media(paths, args, log)
except KeyboardInterrupt:
log.error("Keyboard Interrupt")
log.cleanup()
Expand Down
10 changes: 5 additions & 5 deletions auto_editor/edit.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
import av
from av import AudioResampler

from auto_editor.ffwrapper import FFmpeg, FileInfo, initFileInfo
from auto_editor.ffwrapper import FileInfo, initFileInfo
from auto_editor.lib.contracts import is_int, is_str
from auto_editor.make_layers import clipify, make_av, make_timeline
from auto_editor.output import Ensure, parse_bitrate
Expand Down Expand Up @@ -160,7 +160,7 @@ def parse_export(export: str, log: Log) -> dict[str, Any]:
log.error(f"'{name}': Export must be [{', '.join([s for s in parsing.keys()])}]")


def edit_media(paths: list[str], ffmpeg: FFmpeg, args: Args, log: Log) -> None:
def edit_media(paths: list[str], args: Args, log: Log) -> None:
bar = initBar(args.progress)
tl = None

Expand Down Expand Up @@ -294,7 +294,7 @@ def make_media(tl: v3, output_path: str) -> None:

if ctr.default_aud != "none":
ensure = Ensure(bar, samplerate, log)
audio_paths = make_new_audio(tl, ctr, ensure, args, ffmpeg, bar, log)
audio_paths = make_new_audio(tl, ctr, ensure, args, bar, log)
else:
audio_paths = []

Expand Down Expand Up @@ -343,8 +343,8 @@ def make_media(tl: v3, output_path: str) -> None:
for i, sub_path in enumerate(sub_paths):
subtitle_input = av.open(sub_path)
subtitle_inputs.append(subtitle_input)
subtitle_stream = output.add_stream(
template=subtitle_input.streams.subtitles[0]
subtitle_stream = output.add_stream_from_template(
subtitle_input.streams.subtitles[0]
)
if i < len(src.subtitles) and src.subtitles[i].lang is not None:
subtitle_stream.metadata["language"] = src.subtitles[i].lang # type: ignore
Expand Down
26 changes: 0 additions & 26 deletions auto_editor/ffwrapper.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,32 +11,6 @@
from auto_editor.utils.log import Log


def _get_ffmpeg(reason: str, ffloc: str | None, log: Log) -> str:
program = "ffmpeg" if ffloc is None else ffloc
if (path := which(program)) is None:
log.error(f"{reason} needs ffmpeg cli but couldn't find ffmpeg on PATH.")
return path


@dataclass(slots=True)
class FFmpeg:
ffmpeg_location: str | None
path: str | None = None

def get_path(self, reason: str, log: Log) -> str:
if self.path is not None:
return self.path

self.path = _get_ffmpeg(reason, self.ffmpeg_location, log)
return self.path

def Popen(self, reason: str, cmd: list[str], log: Log) -> Popen:
if self.path is None:
self.path = _get_ffmpeg(reason, self.ffmpeg_location, log)

return Popen([self.path] + cmd, stdout=PIPE, stderr=PIPE)


def mux(input: Path, output: Path, stream: int) -> None:
input_container = av.open(input, "r")
output_container = av.open(output, "w")
Expand Down
58 changes: 13 additions & 45 deletions auto_editor/render/audio.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@

import io
from pathlib import Path
from platform import system

import av
import numpy as np
from av.filter.loudnorm import stats

from auto_editor.ffwrapper import FFmpeg, FileInfo
from auto_editor.ffwrapper import FileInfo
from auto_editor.lang.json import Lexer, Parser
from auto_editor.lang.palet import env
from auto_editor.lib.contracts import andc, between_c, is_int_or_float
Expand Down Expand Up @@ -56,25 +56,11 @@ def parse_norm(norm: str, log: Log) -> dict | None:
log.error(e)


def parse_ebu_bytes(norm: dict, stderr: bytes, log: Log) -> tuple[str, str]:
start = end = 0
lines = stderr.splitlines()

for index, line in enumerate(lines):
if line.startswith(b"[Parsed_loudnorm"):
start = index + 1
continue
if start != 0 and line.startswith(b"}"):
end = index + 1
break

if start == 0 or end == 0:
log.error(f"Invalid loudnorm stats.\n{stderr!r}")

def parse_ebu_bytes(norm: dict, stat: bytes, log: Log) -> tuple[str, str]:
try:
parsed = Parser(Lexer("loudnorm", b"\n".join(lines[start:end]))).expr()
parsed = Parser(Lexer("loudnorm", stat)).expr()
except MyError:
log.error(f"Invalid loudnorm stats.\n{start=},{end=}\n{stderr!r}")
log.error(f"Invalid loudnorm stats.\n{stat!r}")

for key in ("input_i", "input_tp", "input_lra", "input_thresh", "target_offset"):
val = float(parsed[key])
Expand All @@ -101,29 +87,17 @@ def parse_ebu_bytes(norm: dict, stderr: bytes, log: Log) -> tuple[str, str]:


def apply_audio_normalization(
ffmpeg: FFmpeg, norm: dict, pre_master: Path, path: Path, log: Log
norm: dict, pre_master: Path, path: Path, log: Log
) -> None:
if norm["tag"] == "ebu":
first_pass = (
f"loudnorm=i={norm['i']}:lra={norm['lra']}:tp={norm['tp']}:"
f"offset={norm['gain']}:print_format=json"
f"i={norm['i']}:lra={norm['lra']}:tp={norm['tp']}:" f"offset={norm['gain']}"
)
log.debug(f"audio norm first pass: {first_pass}")
file_null = "NUL" if system() in ("Windows", "cli") else "/dev/null"
cmd = [
"-hide_banner",
"-i",
f"{pre_master}",
"-af",
first_pass,
"-vn",
"-sn",
"-f",
"null",
file_null,
]
stderr = ffmpeg.Popen("EBU", cmd, log).communicate()[1]
name, filter_args = parse_ebu_bytes(norm, stderr, log)
with av.open(f"{pre_master}") as container:
stats_ = stats(first_pass, container.streams.audio[0])
av.logging.set_level(None)
name, filter_args = parse_ebu_bytes(norm, stats_, log)
else:
assert "t" in norm

Expand Down Expand Up @@ -310,13 +284,7 @@ def mix_audio_files(sr: int, audio_paths: list[str], output_path: str) -> None:


def make_new_audio(
tl: v3,
ctr: Container,
ensure: Ensure,
args: Args,
ffmpeg: FFmpeg,
bar: Bar,
log: Log,
tl: v3, ctr: Container, ensure: Ensure, args: Args, bar: Bar, log: Log
) -> list[str]:
sr = tl.sr
tb = tl.tb
Expand Down Expand Up @@ -390,7 +358,7 @@ def make_new_audio(
with open(pre_master, "wb") as fid:
write(fid, sr, arr)

apply_audio_normalization(ffmpeg, norm, pre_master, path, log)
apply_audio_normalization(norm, pre_master, path, log)

bar.end()

Expand Down
2 changes: 1 addition & 1 deletion auto_editor/render/subtitle.py
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ def _ensure(input_: Input, format: str, stream: int) -> str:
output = av.open(output_bytes, "w", format=format)

in_stream = input_.streams.subtitles[stream]
out_stream = output.add_stream(template=in_stream)
out_stream = output.add_stream_from_template(in_stream)

for packet in input_.demux(in_stream):
if packet.dts is None:
Expand Down
1 change: 0 additions & 1 deletion auto_editor/utils/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,6 @@ class Args:
player: str | None = None
no_open: bool = False
temp_dir: str | None = None
ffmpeg_location: str | None = None
progress: str = "modern"
version: bool = False
debug: bool = False
Expand Down
4 changes: 2 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ license = { text = "Unlicense" }
authors = [{ name = "WyattBlue", email = "wyattblue@auto-editor.com" }]
requires-python = ">=3.10,<3.14"
dependencies = [
"numpy>=1.23.0,<3.0",
"pyav==13.1.*",
"numpy>=1.24,<3.0",
"pyav==14.0.0rc4",
]
keywords = [
"video", "audio", "media", "editor", "editing",
Expand Down

0 comments on commit f3b75ea

Please sign in to comment.