diff --git a/tsmark/__init__.py b/tsmark/__init__.py index e7813af..d03eb8b 100644 --- a/tsmark/__init__.py +++ b/tsmark/__init__.py @@ -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", diff --git a/tsmark/video_annotator.py b/tsmark/video_annotator.py index fcb1cce..170fe40 100755 --- a/tsmark/video_annotator.py +++ b/tsmark/video_annotator.py @@ -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):