reworked ffmpegg support

This commit is contained in:
q
2025-08-19 14:46:41 +03:00
parent 73cf3a3d76
commit 2a08b187c6
2 changed files with 50 additions and 37 deletions

View File

@@ -2,12 +2,21 @@ import argparse
from tsmark.video_annotator import Marker
VERSION = "0.7.6"
VERSION = "0.7.7"
class SmartFormatter(argparse.HelpFormatter):
"""Thanks to https://stackoverflow.com/users/1307905/anthon"""
def _split_lines(self, text, width):
if text.startswith("R|"):
return text[2:].splitlines()
return argparse.HelpFormatter._split_lines(self, text, width)
def get_options():
parser = argparse.ArgumentParser(description="Video timestamping tool")
parser = argparse.ArgumentParser(description="Video timestamping tool", formatter_class=SmartFormatter)
parser.add_argument(
"--ts",
action="store",
@@ -92,11 +101,17 @@ def get_options():
help="Print FFMPEG commands: Copy instead of recompress. If video is cropped, it must be recompressed",
)
parser.add_argument(
"--ffmpeg-an",
action="store_true",
default=False,
"--ffmpeg-args",
action="store",
default="-i {input} {crop} -c:v mpeg2video -q:v 3 -g 1 -c:a libmp3lame -ar 44100 -b:a 192k -ss {start_time} -to {end_time} {output}.mpeg",
required=False,
help="Print FFMPEG commands: Discard audio track",
help="""R|FFMPEG arguments.
Default: '%(default)s'
Note: {output} is without extension. -i and -ss should switch, depending on input and output formats.
Other useful arguments:
'-i {input} -c:v copy -an -ss {start_time} -to {end_time} {output}.mpeg'
'-ss {start_time} -to {end_time} -i {input} {crop} -g 250 -c:v libx264 -crf 23 -c:a aac -movflags faststart -strict -2 -y {output}.mp4'
""",
)
parser.add_argument(
"--ffmpeg-run",

View File

@@ -11,12 +11,6 @@ import cv2
import numpy as np
from scipy.interpolate import PchipInterpolator
AUDIO_COMPRESS = "-c:a libmp3lame -ar 44100 -b:a 192k".split(" ")
AUDIO_COPY = "-c:a copy".split(" ")
AUDIO_DISCARD = "-an".split(" ")
VIDEO_COMPRESS = "-c:v mpeg2video -q:v 3 -g 1".split(" ")
VIDEO_COPY = "-c:v copy".split(" ")
EXT_COMPRESS = ".mpeg"
PLUGIN_FOLDER = os.path.expanduser("~/.config/tsmark/plugins")
COLOR_PREPOST = (0, 128, 128)
@@ -988,19 +982,14 @@ class World:
cropstr = ["-vf", f"crop={w}:{h}:{x}:{y}"]
self.stamps.sort()
print("# Timestamps:")
audio_str = AUDIO_COPY if self.opts.ffmpeg_copy else AUDIO_COMPRESS
video_str = VIDEO_COPY if self.opts.ffmpeg_copy else VIDEO_COMPRESS
audio_str = AUDIO_DISCARD if self.opts.ffmpeg_an else audio_str
for i, ts in enumerate(self.stamps):
print("# {}: {} / {}".format(i + 1, self.format_time(ts), ts))
if len(self.stamps) == 0:
self.stamps.append(0)
self.stamps.append(self.frames)
padlen = len(str(self.frames))
src_name = self.opts.video.replace('"', '\\"')
tgt_name = os.path.splitext(self.opts.video)[0].replace('"', '\\"')
tgt_ext = os.path.splitext(self.opts.video)[1] if self.opts.ffmpeg_copy else EXT_COMPRESS
src_name_print = self.opts.video.replace('"', '\\"')
tgt_name_print = os.path.splitext(self.opts.video)[0].replace('"', '\\"')
for i in range(1, len(self.stamps), 2):
from_ts = self.stamps[i - 1]
@@ -1009,25 +998,34 @@ class World:
to_ft = self.format_time(to_ts)
from_str = str(from_ts).zfill(padlen)
to_str = str(to_ts).zfill(padlen)
ffmpeg_cmd = [
"ffmpeg",
"-hide_banner",
"-i",
shlex.quote(src_name),
*cropstr,
*video_str,
*audio_str,
"-ss",
f"{from_ft}",
"-to",
f"{to_ft}",
shlex.quote(f"{tgt_name}.trim.{from_str}-{to_str}{tgt_ext}"),
]
print(" ".join(ffmpeg_cmd))
ffmpeg_args_print = []
ffmpeg_args = []
for arg in shlex.split(self.opts.ffmpeg_args):
if arg == "{crop}":
ffmpeg_args_print.extend(cropstr)
ffmpeg_args.extend(cropstr)
else:
ffmpeg_args_print.append(
arg.format(
input=shlex.quote(src_name_print),
output=shlex.quote(f"{tgt_name_print}.trim.{from_str}-{to_str}"),
start_time=from_ft,
end_time=to_ft,
)
)
ffmpeg_args.append(
arg.format(
input=self.opts.video,
output=f"{os.path.splitext(self.opts.video)[0]}.trim.{from_str}-{to_str}",
start_time=from_ft,
end_time=to_ft,
)
)
print(" ".join(["ffmpeg", "-hide_banner", *ffmpeg_args_print]))
if self.opts.ffmpeg_run:
ffmpeg_cmd[3] = src_name
ffmpeg_cmd[-1] = f"{tgt_name}.trim.{from_str}-{to_str}{tgt_ext}"
subprocess.run(ffmpeg_cmd)
subprocess.run(["ffmpeg", "-hide_banner", *ffmpeg_args])
def save_timestamps(self):