read frame numbers directly if input file has them. use 0 indexed frames
This commit is contained in:
@@ -1,7 +1,8 @@
|
|||||||
from tsmark.video_annotator import Marker
|
|
||||||
import argparse
|
import argparse
|
||||||
|
|
||||||
VERSION = "0.4.6"
|
from tsmark.video_annotator import Marker
|
||||||
|
|
||||||
|
VERSION = "0.4.7"
|
||||||
|
|
||||||
|
|
||||||
def get_options():
|
def get_options():
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
import sys
|
|
||||||
import os
|
import os
|
||||||
import cv2
|
import sys
|
||||||
import time
|
import time
|
||||||
|
|
||||||
|
import cv2
|
||||||
|
|
||||||
|
|
||||||
class Marker:
|
class Marker:
|
||||||
def __init__(self, opts):
|
def __init__(self, opts):
|
||||||
@@ -104,9 +105,7 @@ class Marker:
|
|||||||
)
|
)
|
||||||
|
|
||||||
for ts in self.stamps:
|
for ts in self.stamps:
|
||||||
ts_pos = int(
|
ts_pos = int(self.bar_start + ts / self.frames * (self.bar_end - self.bar_start))
|
||||||
self.bar_start + ts / self.frames * (self.bar_end - self.bar_start)
|
|
||||||
)
|
|
||||||
cv2.line(
|
cv2.line(
|
||||||
frame,
|
frame,
|
||||||
(ts_pos, self.bar_top),
|
(ts_pos, self.bar_top),
|
||||||
@@ -138,9 +137,7 @@ class Marker:
|
|||||||
(255, 255, 255),
|
(255, 255, 255),
|
||||||
)
|
)
|
||||||
end_frame = self.format_time(self.frames - 1)
|
end_frame = self.format_time(self.frames - 1)
|
||||||
(text_width, text_height) = cv2.getTextSize(
|
(text_width, text_height) = cv2.getTextSize(end_frame, cv2.FONT_HERSHEY_SIMPLEX, 0.7, 2)[0]
|
||||||
end_frame, cv2.FONT_HERSHEY_SIMPLEX, 0.7, 2
|
|
||||||
)[0]
|
|
||||||
self.shadow_text(
|
self.shadow_text(
|
||||||
frame,
|
frame,
|
||||||
end_frame,
|
end_frame,
|
||||||
@@ -163,7 +160,7 @@ class Marker:
|
|||||||
if not self.nr in self.stamps:
|
if not self.nr in self.stamps:
|
||||||
return
|
return
|
||||||
|
|
||||||
text = "{} #{}".format(self.nr + 1, self.stamps.index(self.nr) + 1)
|
text = "{} #{}".format(self.nr, self.stamps.index(self.nr) + 1)
|
||||||
bottom = 60
|
bottom = 60
|
||||||
left = 10
|
left = 10
|
||||||
self.shadow_text(frame, text, (left, bottom), 1, 2, (63, 84, 255))
|
self.shadow_text(frame, text, (left, bottom), 1, 2, (63, 84, 255))
|
||||||
@@ -242,25 +239,28 @@ class Marker:
|
|||||||
if colon_count == 2:
|
if colon_count == 2:
|
||||||
hours, mins, secstr = timestr.split(":", 2)
|
hours, mins, secstr = timestr.split(":", 2)
|
||||||
sec = float(secstr)
|
sec = float(secstr)
|
||||||
return int(self.fps * (int(hours) * 3600 + int(mins) * 60 + sec))
|
return int(self.fps * (int(hours) * 3600 + int(mins) * 60 + sec), 0)
|
||||||
raise ValueError("Cannot parse time definition {}".format(timestr))
|
raise ValueError("Cannot parse time definition {}".format(timestr))
|
||||||
|
|
||||||
def parse_timestamps(self):
|
def parse_timestamps(self):
|
||||||
|
self.stamps = []
|
||||||
if self.opts.timestamps:
|
if self.opts.timestamps:
|
||||||
if os.path.exists(self.opts.timestamps):
|
if os.path.exists(self.opts.timestamps):
|
||||||
with open(self.opts.timestamps,'rt') as fp:
|
with open(self.opts.timestamps, "rt") as fp:
|
||||||
|
for row in fp.readlines():
|
||||||
self.opts.timestamps = [x.split(",")[0] for x in fp.readlines()]
|
# if row has 3 cols, pick the frame number directly
|
||||||
|
splitted = row.split(",")
|
||||||
|
if len(splitted) == 3:
|
||||||
|
self.stamps.append(int(splitted[2]))
|
||||||
|
if len(splitted) < 3:
|
||||||
|
self.opts.timestamps.append(splitted[0])
|
||||||
else:
|
else:
|
||||||
self.opts.timestamps = self.opts.timestamps.split(",")
|
self.opts.timestamps = self.opts.timestamps.split(",")
|
||||||
|
|
||||||
self.stamps = sorted(
|
if len(self.stamps) > 0:
|
||||||
[
|
self.stamps.sort()
|
||||||
self.parse_time(ts.strip())
|
else:
|
||||||
for ts in self.opts.timestamps
|
self.stamps = sorted([self.parse_time(ts.strip()) for ts in self.opts.timestamps if ts.strip() != ""])
|
||||||
if ts.strip() != ""
|
|
||||||
]
|
|
||||||
)
|
|
||||||
self.stamps = [x for x in self.stamps if 0 <= x < self.frames]
|
self.stamps = [x for x in self.stamps if 0 <= x < self.frames]
|
||||||
self.nr = self.stamps[0]
|
self.nr = self.stamps[0]
|
||||||
else:
|
else:
|
||||||
@@ -274,7 +274,7 @@ class Marker:
|
|||||||
self.stamps.sort()
|
self.stamps.sort()
|
||||||
print("# Timestamps:")
|
print("# Timestamps:")
|
||||||
for i, ts in enumerate(self.stamps):
|
for i, ts in enumerate(self.stamps):
|
||||||
print("# {}: {} / {}".format(i + 1, self.format_time(ts), ts + 1))
|
print("# {}: {} / {}".format(i + 1, self.format_time(ts), ts))
|
||||||
if len(self.stamps) > 0:
|
if len(self.stamps) > 0:
|
||||||
print(
|
print(
|
||||||
'ffmpeg -ss {} -to {} -i "{}" -c copy "{}.trimmed.mp4"'.format(
|
'ffmpeg -ss {} -to {} -i "{}" -c copy "{}.trimmed.mp4"'.format(
|
||||||
@@ -291,7 +291,7 @@ class Marker:
|
|||||||
return
|
return
|
||||||
with open(self.opts.output, "wt") as fp:
|
with open(self.opts.output, "wt") as fp:
|
||||||
for i, ts in enumerate(self.stamps):
|
for i, ts in enumerate(self.stamps):
|
||||||
fp.write("{},{},{}\n".format(self.format_time(ts), i + 1, ts + 1))
|
fp.write("{},{},{}\n".format(self.format_time(ts), i + 1, ts))
|
||||||
|
|
||||||
def shadow_text(self, frame, text, pos, size, thicc, color):
|
def shadow_text(self, frame, text, pos, size, thicc, color):
|
||||||
|
|
||||||
@@ -456,11 +456,7 @@ class Marker:
|
|||||||
if self.read_next:
|
if self.read_next:
|
||||||
self.video_reader.set(cv2.CAP_PROP_POS_FRAMES, self.nr)
|
self.video_reader.set(cv2.CAP_PROP_POS_FRAMES, self.nr)
|
||||||
|
|
||||||
time_to_wait = (
|
time_to_wait = FPS_modifiers[FPS_modifier] * self.viewer_spf - time.time() + show_time
|
||||||
FPS_modifiers[FPS_modifier] * self.viewer_spf
|
|
||||||
- time.time()
|
|
||||||
+ show_time
|
|
||||||
)
|
|
||||||
if time_to_wait > 0:
|
if time_to_wait > 0:
|
||||||
time.sleep(time_to_wait)
|
time.sleep(time_to_wait)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user