object format of the program
This commit is contained in:
@@ -1,3 +1,3 @@
|
||||
from tsmark.video_annotator import main
|
||||
|
||||
VERSION = "0.1"
|
||||
VERSION = "0.2"
|
||||
|
||||
@@ -5,142 +5,171 @@ import time
|
||||
import argparse
|
||||
|
||||
|
||||
def draw_time(frame, nr, fps, paused):
|
||||
class Marker:
|
||||
def __init__(self):
|
||||
self.get_options()
|
||||
if not os.path.exists(self.opts.video):
|
||||
raise FileNotFoundError("Video file missing!")
|
||||
|
||||
self.paused = False
|
||||
self.read_next = False
|
||||
self.show_info = True
|
||||
self.auto_step = True
|
||||
self.font = cv2.FONT_HERSHEY_SIMPLEX
|
||||
self.frame_visu = []
|
||||
self.max_res = (1280, 720)
|
||||
|
||||
try:
|
||||
self.open()
|
||||
self.calculate_res()
|
||||
self.parse_timestamps()
|
||||
self.loop()
|
||||
except Exception as e:
|
||||
exc_type, exc_obj, exc_tb = sys.exc_info()
|
||||
fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
|
||||
print(exc_type, fname, exc_tb.tb_lineno)
|
||||
raise e
|
||||
|
||||
def open(self):
|
||||
|
||||
self.video_reader = cv2.VideoCapture(self.opts.video)
|
||||
self.frames = int(self.video_reader.get(cv2.CAP_PROP_FRAME_COUNT))
|
||||
self.fps = self.video_reader.get(cv2.CAP_PROP_FPS)
|
||||
self.spf = 1 / self.fps
|
||||
self.video_length = self.frames * self.fps
|
||||
|
||||
def calculate_res(self):
|
||||
|
||||
self.video_res = [
|
||||
int(self.video_reader.get(cv2.CAP_PROP_FRAME_WIDTH)),
|
||||
int(self.video_reader.get(cv2.CAP_PROP_FRAME_HEIGHT)),
|
||||
]
|
||||
video_aspect = self.video_res[0] / self.video_res[1]
|
||||
if self.video_res[0] > self.max_res[0]:
|
||||
self.video_res[0] = int(self.max_res[0])
|
||||
self.video_res[1] = int(self.video_res[0] / video_aspect)
|
||||
|
||||
if self.video_res[1] > self.max_res[1]:
|
||||
self.video_res[1] = int(self.max_res[1])
|
||||
self.video_res[0] = int(self.video_res[1] * video_aspect)
|
||||
self.video_res = tuple(self.video_res)
|
||||
self.bar_start = int(self.video_res[0] * 0.05)
|
||||
self.bar_end = int(self.video_res[0] * 0.95)
|
||||
self.bar_top = int(self.video_res[1] * 0.90)
|
||||
self.bar_bottom = int(self.video_res[1] * 0.95)
|
||||
|
||||
def calculate_step(self):
|
||||
|
||||
now = time.time()
|
||||
self.last_move = [x for x in self.last_move if x[1] > now - 3]
|
||||
if len(self.last_move) == 0:
|
||||
self.step = 1
|
||||
self.last_move = []
|
||||
return
|
||||
lefts = sum([1 for x in self.last_move if x[0] == "l"])
|
||||
rights = sum([1 for x in self.last_move if x[0] == "r"])
|
||||
if lefts > 0 and rights > 0:
|
||||
self.step = 1
|
||||
self.last_move = []
|
||||
return
|
||||
count = max(lefts, rights)
|
||||
if count < 5:
|
||||
self.step = 1
|
||||
else:
|
||||
# x2 poly from 5:5 -> 15:180
|
||||
self.step = 45 - 16.5 * count + 1.7 * count * count
|
||||
self.step = min(self.step, 0.1 * self.video_length)
|
||||
self.step = int(self.step)
|
||||
|
||||
def draw_bar(self, frame):
|
||||
|
||||
position = self.nr / self.frames
|
||||
bar_position = int(self.bar_start + position * (self.bar_end - self.bar_start))
|
||||
|
||||
cv2.rectangle(
|
||||
frame,
|
||||
(self.bar_start, self.bar_top),
|
||||
(self.bar_end, self.bar_bottom),
|
||||
(255, 255, 255),
|
||||
2,
|
||||
)
|
||||
|
||||
for ts in self.stamps:
|
||||
ts_pos = int(
|
||||
self.bar_start + ts / self.frames * (self.bar_end - self.bar_start)
|
||||
)
|
||||
cv2.line(
|
||||
frame,
|
||||
(ts_pos, self.bar_top),
|
||||
(ts_pos, self.bar_bottom),
|
||||
(32, 32, 32),
|
||||
3,
|
||||
)
|
||||
cv2.line(
|
||||
frame,
|
||||
(ts_pos, self.bar_top),
|
||||
(ts_pos, self.bar_bottom),
|
||||
(84, 255, 63),
|
||||
1,
|
||||
)
|
||||
# cv2.line(frame, (bar_position, top), (bar_position, bottom), (32,32,32), 3)
|
||||
cv2.line(
|
||||
frame,
|
||||
(bar_position, self.bar_top),
|
||||
(bar_position, self.bar_bottom),
|
||||
(63, 84, 255),
|
||||
1,
|
||||
)
|
||||
|
||||
self.shadow_text(
|
||||
frame,
|
||||
"1",
|
||||
(self.bar_start - 7, self.bar_bottom + 20),
|
||||
0.7,
|
||||
2,
|
||||
(255, 255, 255),
|
||||
)
|
||||
end_frame = self.format_time(self.frames - 1)
|
||||
(text_width, text_height) = cv2.getTextSize(
|
||||
end_frame, cv2.FONT_HERSHEY_SIMPLEX, 0.7, 2
|
||||
)[0]
|
||||
self.shadow_text(
|
||||
frame,
|
||||
end_frame,
|
||||
(self.bar_end - text_width, self.bar_bottom + 20),
|
||||
0.7,
|
||||
2,
|
||||
(255, 255, 255),
|
||||
)
|
||||
|
||||
def draw_label(self, frame):
|
||||
|
||||
if not self.nr in self.stamps:
|
||||
return
|
||||
|
||||
text = "{} #{}".format(self.nr + 1, self.stamps.index(self.nr) + 1)
|
||||
bottom = 60
|
||||
left = 10
|
||||
self.shadow_text(frame, text, (left, bottom), 1, 2, (63, 84, 255))
|
||||
|
||||
def draw_time(self, frame):
|
||||
left = 10
|
||||
bottom = 30
|
||||
|
||||
formatted = "{} {}".format(
|
||||
format_time(nr, fps),
|
||||
"||" if paused else "",
|
||||
self.format_time(self.nr),
|
||||
"||" if self.paused else "",
|
||||
)
|
||||
shadow_text(frame, formatted, (left, bottom), 1.1, 2, (255, 255, 255))
|
||||
self.shadow_text(frame, formatted, (left, bottom), 1.1, 2, (255, 255, 255))
|
||||
|
||||
def format_time(self, nframe):
|
||||
|
||||
def shadow_text(frame, text, pos, size, thicc, color):
|
||||
font = cv2.FONT_HERSHEY_SIMPLEX
|
||||
cv2.putText(
|
||||
frame,
|
||||
text,
|
||||
pos,
|
||||
font,
|
||||
size,
|
||||
(0, 0, 0),
|
||||
2 * thicc,
|
||||
cv2.LINE_AA,
|
||||
)
|
||||
cv2.putText(
|
||||
frame,
|
||||
text,
|
||||
pos,
|
||||
font,
|
||||
size,
|
||||
color,
|
||||
thicc,
|
||||
cv2.LINE_AA,
|
||||
)
|
||||
|
||||
|
||||
def draw_bar(frame, nr, frames, fps, stamps):
|
||||
|
||||
position = nr / frames
|
||||
bar_start = int(frame.shape[1] * 0.05)
|
||||
bar_end = int(frame.shape[1] * 0.95)
|
||||
bar_position = int(bar_start + position * (bar_end - bar_start))
|
||||
top = int(frame.shape[0] * 0.90)
|
||||
bottom = int(frame.shape[0] * 0.95)
|
||||
|
||||
cv2.rectangle(frame, (bar_start, top), (bar_end, bottom), (255, 255, 255), 2)
|
||||
|
||||
for ts in stamps:
|
||||
ts_pos = int(bar_start + ts / frames * (bar_end - bar_start))
|
||||
cv2.line(frame, (ts_pos, top), (ts_pos, bottom), (32, 32, 32), 3)
|
||||
cv2.line(frame, (ts_pos, top), (ts_pos, bottom), (84, 255, 63), 1)
|
||||
# cv2.line(frame, (bar_position, top), (bar_position, bottom), (32,32,32), 3)
|
||||
cv2.line(frame, (bar_position, top), (bar_position, bottom), (63, 84, 255), 1)
|
||||
|
||||
shadow_text(frame, "1", (bar_start - 7, bottom + 20), 0.7, 2, (255, 255, 255))
|
||||
end_frame = format_time(frames - 1, fps)
|
||||
(text_width, text_height) = cv2.getTextSize(
|
||||
end_frame, cv2.FONT_HERSHEY_SIMPLEX, 0.7, 2
|
||||
)[0]
|
||||
shadow_text(
|
||||
frame, end_frame, (bar_end - text_width, bottom + 20), 0.7, 2, (255, 255, 255)
|
||||
)
|
||||
|
||||
|
||||
def draw_label(frame, nr, stamps):
|
||||
|
||||
if not nr in stamps:
|
||||
return
|
||||
|
||||
text = "{} #{}".format(nr + 1, stamps.index(nr) + 1)
|
||||
bottom = 60
|
||||
left = 10
|
||||
shadow_text(frame, text, (left, bottom), 1, 2, (63, 84, 255))
|
||||
|
||||
|
||||
def calculate_step(step, last_move, video_length):
|
||||
|
||||
now = time.time()
|
||||
last_move = [x for x in last_move if x[1] > now - 3]
|
||||
if len(last_move) == 0:
|
||||
return 1, []
|
||||
lefts = sum([1 for x in last_move if x[0] == "l"])
|
||||
rights = sum([1 for x in last_move if x[0] == "r"])
|
||||
if lefts > 0 and rights > 0:
|
||||
return 1, []
|
||||
count = max(lefts, rights)
|
||||
if count < 5:
|
||||
step = 1
|
||||
else:
|
||||
# x2 poly from 5:5 -> 15:180
|
||||
step = 45 - 16.5 * count + 1.7 * count * count
|
||||
step = min(step, 0.1 * video_length)
|
||||
return int(step), last_move
|
||||
|
||||
|
||||
def format_time(nframe, fps):
|
||||
|
||||
seconds = int(nframe / fps)
|
||||
frame = nframe % fps
|
||||
parts = int(100 * (frame / fps))
|
||||
seconds = int(nframe / self.fps)
|
||||
frame = nframe % self.fps
|
||||
parts = int(100 * (frame / self.fps))
|
||||
return time.strftime("%H:%M:%S", time.gmtime(seconds)) + ".%02d" % (parts)
|
||||
|
||||
|
||||
def parse_time(timestr, fps):
|
||||
"""return frames"""
|
||||
|
||||
colon_count = len(timestr.split(":")) - 1
|
||||
if colon_count == 0:
|
||||
secs = float(timestr)
|
||||
return int(secs * fps)
|
||||
if colon_count == 1:
|
||||
mins, secstr = timestr.split(":", 1)
|
||||
sec = float(secstr)
|
||||
return int(fps * (int(mins) * 60 + sec))
|
||||
if colon_count == 2:
|
||||
hours, mins, secstr = timestr.split(":", 2)
|
||||
sec = float(secstr)
|
||||
return int(fps * (int(hours) * 3600 + int(mins) * 60 + sec))
|
||||
raise ValueError("Cannot parse time definition {}".format(timestr))
|
||||
|
||||
|
||||
def print_timestamps(stamps, fps, filename):
|
||||
stamps.sort()
|
||||
print("# Timestamps:")
|
||||
for i, ts in enumerate(stamps):
|
||||
print("# {}: {} / {}".format(i + 1, format_time(ts, fps), ts + 1))
|
||||
if len(stamps) > 0:
|
||||
print(
|
||||
"ffmpeg -i '{}' -ss {} -to {} -c copy trimmed.mp4".format(
|
||||
filename,
|
||||
format_time(stamps[0], fps),
|
||||
format_time(stamps[-1], fps),
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def get_options():
|
||||
def get_options(self):
|
||||
|
||||
parser = argparse.ArgumentParser(description="Video timestamping tool")
|
||||
parser.add_argument(
|
||||
@@ -152,175 +181,226 @@ def get_options():
|
||||
help="Comma separated list of predefined timestamps, in frame numbers, or HH:MM:SS.FF",
|
||||
)
|
||||
parser.add_argument(action="store", dest="video")
|
||||
return parser.parse_args()
|
||||
self.opts = parser.parse_args()
|
||||
|
||||
def mouse_click(self, event, x, y, flags, param):
|
||||
|
||||
def calculate_res(max_res, video_reader):
|
||||
in_bar = all(
|
||||
(
|
||||
x < self.bar_end,
|
||||
x > self.bar_start,
|
||||
y < self.bar_bottom,
|
||||
y > self.bar_top,
|
||||
)
|
||||
)
|
||||
if event == cv2.EVENT_LBUTTONDOWN:
|
||||
if in_bar:
|
||||
click_relative = (x - self.bar_start) / (self.bar_end - self.bar_start)
|
||||
self.nr = int(click_relative * self.frames)
|
||||
self.read_next = True
|
||||
|
||||
video_res = [
|
||||
int(video_reader.get(cv2.CAP_PROP_FRAME_WIDTH)),
|
||||
int(video_reader.get(cv2.CAP_PROP_FRAME_HEIGHT)),
|
||||
]
|
||||
video_aspect = video_res[0] / video_res[1]
|
||||
if video_res[0] > max_res[0]:
|
||||
video_res[0] = int(max_res[0])
|
||||
video_res[1] = int(video_res[0] / video_aspect)
|
||||
if event == cv2.EVENT_LBUTTONDBLCLK:
|
||||
if not in_bar:
|
||||
self.toggle_stamp()
|
||||
# doubleclick (toggle?)
|
||||
# ~ print("double", x, y)
|
||||
|
||||
if video_res[1] > max_res[1]:
|
||||
video_res[1] = int(max_res[1])
|
||||
video_res[0] = int(video_res[1] * video_aspect)
|
||||
return tuple(video_res)
|
||||
def parse_time(self, timestr):
|
||||
"""return frames"""
|
||||
|
||||
colon_count = len(timestr.split(":")) - 1
|
||||
if colon_count == 0:
|
||||
secs = float(timestr)
|
||||
return int(secs * self.fps)
|
||||
if colon_count == 1:
|
||||
mins, secstr = timestr.split(":", 1)
|
||||
sec = float(secstr)
|
||||
return int(self.fps * (int(mins) * 60 + sec))
|
||||
if colon_count == 2:
|
||||
hours, mins, secstr = timestr.split(":", 2)
|
||||
sec = float(secstr)
|
||||
return int(self.fps * (int(hours) * 3600 + int(mins) * 60 + sec))
|
||||
raise ValueError("Cannot parse time definition {}".format(timestr))
|
||||
|
||||
def print_help():
|
||||
def parse_timestamps(self):
|
||||
if self.opts.timestamps:
|
||||
self.stamps = sorted(
|
||||
[self.parse_time(ts.strip()) for ts in self.opts.timestamps.split(",")]
|
||||
)
|
||||
self.stamps = [x for x in self.stamps if 0 <= x < self.frames]
|
||||
self.nr = self.stamps[0]
|
||||
else:
|
||||
self.stamps = []
|
||||
self.nr = 0
|
||||
|
||||
def print_help(self):
|
||||
print(
|
||||
"""Keyboard help:
|
||||
|
||||
Arrows left and right, Home, End
|
||||
(Note: after mouse click, arrows stop working due to unknown bug: use j,k)
|
||||
Arrows left and right, Home, End or click mouse in position bar
|
||||
j and k
|
||||
jump in video. Tap frequently to increase time step
|
||||
, and . move one frame at a time
|
||||
z and c move to previous or next mark
|
||||
x mark frame
|
||||
x or double click in the video
|
||||
mark frame
|
||||
space pause
|
||||
i toggle HUD
|
||||
q quit
|
||||
"""
|
||||
)
|
||||
|
||||
|
||||
def main():
|
||||
try:
|
||||
opts = get_options()
|
||||
if not os.path.exists(opts.video):
|
||||
raise FileNotFoundError("Video file missing!")
|
||||
|
||||
max_res = (1280, 720)
|
||||
video_reader = cv2.VideoCapture(opts.video)
|
||||
frames = int(video_reader.get(cv2.CAP_PROP_FRAME_COUNT))
|
||||
fps = video_reader.get(cv2.CAP_PROP_FPS)
|
||||
spf = 1.0 / fps
|
||||
video_res = calculate_res(max_res, video_reader)
|
||||
if opts.timestamps:
|
||||
stamps = sorted(
|
||||
[parse_time(ts.strip(), fps) for ts in opts.timestamps.split(",")]
|
||||
def print_timestamps(self):
|
||||
self.stamps.sort()
|
||||
print("# Timestamps:")
|
||||
for i, ts in enumerate(self.stamps):
|
||||
print("# {}: {} / {}".format(i + 1, self.format_time(ts), ts + 1))
|
||||
if len(self.stamps) > 0:
|
||||
print(
|
||||
"ffmpeg -i '{}' -ss {} -to {} -c copy trimmed.mp4".format(
|
||||
self.opts.video,
|
||||
self.format_time(self.stamps[0]),
|
||||
self.format_time(self.stamps[-1]),
|
||||
)
|
||||
stamps = [x for x in stamps if 0 <= x < frames]
|
||||
nr = stamps[0]
|
||||
)
|
||||
|
||||
def shadow_text(self, frame, text, pos, size, thicc, color):
|
||||
|
||||
cv2.putText(
|
||||
frame,
|
||||
text,
|
||||
pos,
|
||||
self.font,
|
||||
size,
|
||||
(0, 0, 0),
|
||||
2 * thicc,
|
||||
cv2.LINE_AA,
|
||||
)
|
||||
cv2.putText(
|
||||
frame,
|
||||
text,
|
||||
pos,
|
||||
self.font,
|
||||
size,
|
||||
color,
|
||||
thicc,
|
||||
cv2.LINE_AA,
|
||||
)
|
||||
|
||||
def toggle_stamp(self):
|
||||
if self.nr in self.stamps:
|
||||
self.stamps.remove(self.nr)
|
||||
else:
|
||||
stamps = []
|
||||
nr = 0
|
||||
self.stamps.append(self.nr)
|
||||
self.stamps.sort()
|
||||
|
||||
paused = False
|
||||
read_next = False
|
||||
show_info = True
|
||||
frame_visu = []
|
||||
step = 1
|
||||
last_move = []
|
||||
video_length = frames * fps
|
||||
auto_step = True
|
||||
video_reader.set(cv2.CAP_PROP_POS_FRAMES, nr)
|
||||
def loop(self):
|
||||
|
||||
print_help()
|
||||
self.step = 1
|
||||
self.last_move = []
|
||||
self.video_reader.set(cv2.CAP_PROP_POS_FRAMES, self.nr)
|
||||
|
||||
while video_reader.isOpened():
|
||||
self.print_help()
|
||||
cv2.namedWindow("tsmark")
|
||||
cv2.setMouseCallback("tsmark", self.mouse_click)
|
||||
while self.video_reader.isOpened():
|
||||
show_time = time.time()
|
||||
if (not paused) or read_next:
|
||||
ret, frame = video_reader.read()
|
||||
if (not self.paused) or self.read_next:
|
||||
ret, frame = self.video_reader.read()
|
||||
if ret == True:
|
||||
if paused:
|
||||
if self.paused:
|
||||
draw_wait = 200
|
||||
else:
|
||||
draw_wait = 1
|
||||
if (not paused) or read_next:
|
||||
read_next = False
|
||||
frame_visu = cv2.resize(frame.copy(), video_res)
|
||||
nr_time = nr / fps
|
||||
if show_info:
|
||||
draw_time(frame_visu, nr, fps, paused)
|
||||
draw_bar(frame_visu, nr, frames, fps, stamps)
|
||||
draw_label(frame_visu, nr, stamps)
|
||||
if (not self.paused) or self.read_next:
|
||||
self.read_next = False
|
||||
frame_visu = cv2.resize(frame.copy(), self.video_res)
|
||||
nr_time = self.nr / self.fps
|
||||
if self.show_info:
|
||||
self.draw_time(frame_visu)
|
||||
self.draw_bar(frame_visu)
|
||||
self.draw_label(frame_visu)
|
||||
|
||||
cv2.imshow("tsmark", frame_visu)
|
||||
k = cv2.waitKey(draw_wait)
|
||||
if k & 0xFF == ord("q") or k & 0xFF == 27:
|
||||
break
|
||||
if k & 0xFF == 32: # space
|
||||
paused = not paused
|
||||
self.paused = not self.paused
|
||||
|
||||
if k & 0xFF == 80: # home key
|
||||
nr = 0
|
||||
self.nr = -1
|
||||
self.read_next = True
|
||||
|
||||
if k & 0xFF == 87: # end key
|
||||
nr = frames - 1
|
||||
paused = True
|
||||
self.nr = self.frames - 1
|
||||
self.paused = True
|
||||
self.read_next = True
|
||||
|
||||
if k & 0xFF == 83: # right arrow
|
||||
last_move.append(("r", time.time()))
|
||||
if auto_step:
|
||||
step, last_move = calculate_step(step, last_move, video_length)
|
||||
nr = int((nr_time + step) * fps) - 1
|
||||
read_next = True
|
||||
if k & 0xFF == 83 or k & 0xFF == ord("k"): # right arrow
|
||||
self.last_move.append(("r", time.time()))
|
||||
if self.auto_step:
|
||||
self.calculate_step()
|
||||
self.nr = int((nr_time + self.step) * self.fps) - 1
|
||||
self.read_next = True
|
||||
if k & 0xFF == ord("."):
|
||||
paused = True
|
||||
read_next = True
|
||||
if k & 0xFF == 81: # left arrow
|
||||
last_move.append(("l", time.time()))
|
||||
if auto_step:
|
||||
step, last_move = calculate_step(step, last_move, video_length)
|
||||
nr = int((nr_time - step) * fps) - 1
|
||||
read_next = True
|
||||
self.paused = True
|
||||
self.read_next = True
|
||||
if k & 0xFF == 81 or k & 0xFF == ord("j"): # left arrow
|
||||
self.last_move.append(("l", time.time()))
|
||||
if self.auto_step:
|
||||
self.calculate_step()
|
||||
self.nr = int((nr_time - self.step) * self.fps) - 1
|
||||
self.read_next = True
|
||||
if k & 0xFF == ord(","):
|
||||
paused = True
|
||||
nr -= 2
|
||||
read_next = True
|
||||
self.paused = True
|
||||
self.nr -= 2
|
||||
self.read_next = True
|
||||
|
||||
if k & 0xFF == ord("z"): # move to previous ts
|
||||
for ts in reversed(sorted(stamps)):
|
||||
if ts < nr - 1:
|
||||
nr = ts - 1
|
||||
read_next = True
|
||||
for ts in reversed(sorted(self.stamps)):
|
||||
if ts < self.nr - 1:
|
||||
self.nr = ts - 1
|
||||
self.read_next = True
|
||||
break
|
||||
if k & 0xFF == ord("c"): # move to previous ts
|
||||
for ts in sorted(stamps):
|
||||
if ts > nr:
|
||||
nr = ts - 1
|
||||
read_next = True
|
||||
for ts in sorted(self.stamps):
|
||||
if ts > self.nr:
|
||||
self.nr = ts - 1
|
||||
self.read_next = True
|
||||
break
|
||||
|
||||
if k & 0xFF == ord("x"): # toggle ts
|
||||
if nr in stamps:
|
||||
stamps.remove(nr)
|
||||
else:
|
||||
stamps.append(nr)
|
||||
stamps.sort()
|
||||
self.toggle_stamp()
|
||||
|
||||
if k & 0xFF == ord("i"):
|
||||
show_info = not show_info
|
||||
self.show_info = not self.show_info
|
||||
if k & 0xFF == ord("h"):
|
||||
print_help()
|
||||
self.print_help()
|
||||
|
||||
if (not paused) or read_next:
|
||||
nr += 1
|
||||
if nr < 0:
|
||||
nr = 0
|
||||
if nr >= frames:
|
||||
nr = frames - 1
|
||||
paused = True
|
||||
if read_next:
|
||||
video_reader.set(cv2.CAP_PROP_POS_FRAMES, nr)
|
||||
if (not self.paused) or self.read_next:
|
||||
self.nr += 1
|
||||
if self.nr < 0:
|
||||
self.nr = 0
|
||||
if self.nr >= self.frames:
|
||||
self.nr = self.frames - 1
|
||||
self.paused = True
|
||||
if self.read_next:
|
||||
self.video_reader.set(cv2.CAP_PROP_POS_FRAMES, self.nr)
|
||||
|
||||
time_to_wait = spf - time.time() + show_time
|
||||
time_to_wait = self.spf - time.time() + show_time
|
||||
if time_to_wait > 0:
|
||||
time.sleep(time_to_wait)
|
||||
|
||||
else:
|
||||
nr = frames - 2
|
||||
video_reader.set(cv2.CAP_PROP_POS_FRAMES, nr)
|
||||
paused = True
|
||||
read_next = True
|
||||
self.nr = self.frames - 2
|
||||
self.video_reader.set(cv2.CAP_PROP_POS_FRAMES, self.nr)
|
||||
self.paused = True
|
||||
self.read_next = True
|
||||
|
||||
video_reader.release()
|
||||
print_timestamps(stamps, fps, opts.video)
|
||||
except Exception:
|
||||
exc_type, exc_obj, exc_tb = sys.exc_info()
|
||||
fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
|
||||
print(exc_type, fname, exc_tb.tb_lineno)
|
||||
self.video_reader.release()
|
||||
self.print_timestamps()
|
||||
|
||||
|
||||
def main():
|
||||
mark = Marker()
|
||||
|
||||
Reference in New Issue
Block a user