5
0

yt_common: zoning support

This commit is contained in:
louis f 2021-06-03 18:25:33 -04:00
parent e7afd856df
commit 1a96b0f09e
Signed by: louis
GPG Key ID: 44D7E1DE4E23D6F2
2 changed files with 43 additions and 9 deletions

View File

@ -11,7 +11,7 @@ import tempfile
from lvsfunc.render import clip_async_render from lvsfunc.render import clip_async_render
from typing import Any, BinaryIO, Callable, List, Optional, Sequence, Set, Tuple, cast from typing import Any, BinaryIO, Callable, List, NamedTuple, Optional, Sequence, Set, Tuple, cast
from .chapters import Chapter, Edition, make_chapters, make_qpfile from .chapters import Chapter, Edition, make_chapters, make_qpfile
from .config import Config from .config import Config
@ -39,6 +39,11 @@ def forward_signal(signum: int, frame: Any, process: Any) -> None:
process.send_signal(signum) process.send_signal(signum)
class Zone(NamedTuple):
r: Tuple[int, int]
b: float
class Encoder(): class Encoder():
clip: vs.VideoNode clip: vs.VideoNode
@ -58,6 +63,7 @@ class Encoder():
self._get_encoder_settings(settings_path) self._get_encoder_settings(settings_path)
def encode(self, clip: vs.VideoNode, filename: str, start: int = 0, end: int = 0, def encode(self, clip: vs.VideoNode, filename: str, start: int = 0, end: int = 0,
zones: Optional[List[Zone]] = None, qpfile: Optional[str] = None,
timecode_file: Optional[str] = None, want_timecodes: bool = False) -> Tuple[str, List[float]]: timecode_file: Optional[str] = None, want_timecodes: bool = False) -> Tuple[str, List[float]]:
end = end if end != 0 else clip.num_frames end = end if end != 0 else clip.num_frames
want_timecodes = True if timecode_file else want_timecodes want_timecodes = True if timecode_file else want_timecodes
@ -68,7 +74,25 @@ class Encoder():
log.warn("Existing output detected, skipping encode!") log.warn("Existing output detected, skipping encode!")
return outfile, [] return outfile, []
params = [p.format(frames=end-start, filename=filename, qpfile="qpfile.txt") for p in self.params] params: List[str] = []
for p in self.params:
if p == "$ZONES":
if zones:
zones.sort(key=lambda z: z.r[0])
params.append("--zones")
zargs: List[str] = []
for z in zones:
if z.r[0] - start >= 0 and z.r[0] < end:
s = z.r[0] - start
e = z.r[1] - start
e = e if e < end - start else end - start - 1
zargs.append(f"{s},{e},b={z.b}")
params.append("/".join(zargs))
elif p == "$QPFILE":
if qpfile:
params += ["--qpfile", qpfile]
else:
params.append(p.format(frames=end-start, filename=filename, qpfile="qpfile.txt"))
log.status("--- RUNNING ENCODE ---") log.status("--- RUNNING ENCODE ---")
@ -171,6 +195,7 @@ class SelfRunner():
audio_file: str audio_file: str
timecodes: List[float] timecodes: List[float]
timecode_file: Optional[str] timecode_file: Optional[str]
qpfile: Optional[str]
encoder: Encoder encoder: Encoder
audio: AudioGetter audio: AudioGetter
@ -180,11 +205,13 @@ class SelfRunner():
def __init__(self, config: Config, source: FileSource, final_filter: Callable[[], vs.VideoNode], def __init__(self, config: Config, source: FileSource, final_filter: Callable[[], vs.VideoNode],
workraw_filter: Optional[Callable[[], vs.VideoNode]] = None, workraw_filter: Optional[Callable[[], vs.VideoNode]] = None,
chapters: Optional[List[Chapter]] = None, chapters: Optional[List[Chapter]] = None,
editions: Optional[List[Edition]] = None) -> None: editions: Optional[List[Edition]] = None,
zones: Optional[List[Zone]] = None) -> None:
self.config = config self.config = config
self.src = source self.src = source
self.video_clean = False self.video_clean = False
self.audio_clean = False self.audio_clean = False
self.qpfile = None
parser = argparse.ArgumentParser(description=f"Encode {self.config.title} {self.config.desc}") parser = argparse.ArgumentParser(description=f"Encode {self.config.title} {self.config.desc}")
if workraw_filter: if workraw_filter:
@ -207,8 +234,10 @@ class SelfRunner():
self.workraw = args.workraw if workraw_filter else False self.workraw = args.workraw if workraw_filter else False
self.profile = "workraw" if self.workraw else "final" self.profile = "workraw" if self.workraw else "final"
self.profile = args.profile or self.profile self.profile = args.profile or self.profile
self.suffix = args.suffix if args.suffix is not None else "workraw" if self.workraw else "premux" self.suffix = args.suffix if args.suffix is not None \
self.suffix = args.profile or self.suffix else "workraw" if self.workraw \
else args.profile if args.profile \
else "premux"
self.clip = workraw_filter() if workraw_filter and self.workraw else final_filter() self.clip = workraw_filter() if workraw_filter and self.workraw else final_filter()
@ -258,9 +287,9 @@ class SelfRunner():
log.status("Comparison generated.") log.status("Comparison generated.")
return return
open("qpfile.txt", "w").close() # guarantee qpfile is created/cleared as appropriate
if (editions or chapters) and (start == 0 and end == self.clip.num_frames): if (editions or chapters) and (start == 0 and end == self.clip.num_frames):
make_qpfile("qpfile.txt", chapters=chapters, editions=editions) self.qpfile = "qpfile.txt"
make_qpfile(self.qpfile, chapters=chapters, editions=editions)
settings_path = os.path.join(self.config.datapath, f"{self.profile}-settings") settings_path = os.path.join(self.config.datapath, f"{self.profile}-settings")
if not os.path.isfile(settings_path): if not os.path.isfile(settings_path):
@ -272,7 +301,7 @@ class SelfRunner():
if self.clip.fps_den == 0 else None if self.clip.fps_den == 0 else None
self.video_file, self.timecodes = self.encoder.encode(self.clip, self.video_file, self.timecodes = self.encoder.encode(self.clip,
f"{self.config.desc}_{self.suffix}_{start}_{end}", f"{self.config.desc}_{self.suffix}_{start}_{end}",
start, end, self.timecode_file) start, end, zones, self.qpfile, self.timecode_file)
# calculate timecodes if cfr and we didn't generate any (we shouldn'tve) # calculate timecodes if cfr and we didn't generate any (we shouldn'tve)
self.timecodes = [round(float(1e9*f*(1/self.clip.fps)))/1e9 for f in range(0, self.clip.num_frames + 1)] \ self.timecodes = [round(float(1e9*f*(1/self.clip.fps)))/1e9 for f in range(0, self.clip.num_frames + 1)] \

View File

@ -112,6 +112,11 @@ def make_qpfile(qpfile: str,
chapters: Optional[List[Chapter]] = None, chapters: Optional[List[Chapter]] = None,
editions: Optional[List[Edition]] = None) -> None: editions: Optional[List[Edition]] = None) -> None:
editions = _to_edition(chapters=chapters, editions=editions) editions = _to_edition(chapters=chapters, editions=editions)
frames = set(c.frame for e in editions for c in e.chapters) frames = set()
for e in editions:
for c in e.chapters:
frames.add(c.frame)
if c.end_frame and c.end_frame > 0:
frames.add(c.end_frame)
with open(qpfile, "w", encoding="utf-8") as qp: with open(qpfile, "w", encoding="utf-8") as qp:
qp.writelines([f"{f} I\n" for f in sorted(list(frames))]) qp.writelines([f"{f} I\n" for f in sorted(list(frames))])