reworked ffmpegg support
This commit is contained in:
@@ -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",
|
||||
|
||||
@@ -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):
|
||||
|
||||
|
||||
Reference in New Issue
Block a user