forked from christian-skjetne/kattvhask
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathkeyclipwriter.py
126 lines (105 loc) · 4.1 KB
/
keyclipwriter.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
# import the necessary packages
from collections import deque
from threading import Thread
from queue import Queue
import time
import cv2
import os
import pendulum
class KeyClipWriter:
def __init__(self, base_outputdir, bufSize=64, timeout=0.01):
# store the maximum buffer size of frames to be kept
# in memory along with the sleep timeout during threading
self.bufSize = bufSize
self.timeout = timeout
# initialize the buffer of frames, queue of frames that
# need to be written to file, video writer, writer thread,
# and boolean indicating whether recording has started or not
self.frames = deque(maxlen=bufSize)
self.Q = None
self.writer = None
self.thread = None
self.recording = False
self._time_start_record = None
self.base_outputdir = base_outputdir
if not os.path.isdir(self.base_outputdir):
os.mkdir(self.base_outputdir)
self._today = pendulum.today().date()
self.path = os.path.join(self.base_outputdir, str(self._today))
self.mkpath()
def update(self, frame):
# update the frames buffer
self.frames.appendleft(frame)
# if we are recording, update the queue as well
if self.recording:
self.Q.put(frame)
def mkpath(self):
if not os.path.isdir(self.path):
os.mkdir(self.path)
return True
return False
def start(self, fourcc, fps):
# indicate that we are recording, start the video writer,
# and initialize the queue of frames that need to be written
# to the video file
self.recording = True
# Group messages based on the current date
self._time_start_record = pendulum.now()
now_date = self.start_time.date()
if self._today < now_date:
# New date - need to create a new folder
self._today = now_date
self.path = os.path.join(self.base_outputdir, str(self._today))
self.mkpath()
filename = ".".join([self.start_time.strftime("%H:%m:%S"), "mkv"])
output_file = os.path.join(self.path, filename)
self.writer = cv2.VideoWriter(output_file, fourcc, fps,
(self.frames[0].shape[1], self.frames[0].shape[0]), True)
self.Q = Queue()
# loop over the frames in the deque structure and add them
# to the queue
for i in range(len(self.frames), 0, -1):
self.Q.put(self.frames[i - 1])
# start a thread write frames to the video file
self.thread = Thread(target=self.write, args=())
self.thread.daemon = True
self.thread.start()
def write(self):
# keep looping
while self.recording:
# if we are done recording, exit the thread
#if not self.recording:
# return
# check to see if there are entries in the queue
if not self.Q.empty():
# grab the next frame in the queue and write it
# to the video file
frame = self.Q.get()
self.writer.write(frame)
# otherwise, the queue is empty, so sleep for a bit
# so we don't waste CPU cycles
else:
time.sleep(self.timeout)
self.flush()
self.writer.release()
def flush(self):
# empty the queue by flushing all remaining frames to file
while not self.Q.empty():
frame = self.Q.get()
self.writer.write(frame)
@property
def start_time(self):
return self._time_start_record
@property
def record_time(self):
return self._time_stop_record - self._time_start_record
def finish(self):
# indicate that we are done recording, join the thread,
# flush all remaining frames in the queue to file, and
# release the writer pointer
self._time_stop_record = pendulum.now()
print("Done recording. {} seconds".format(self.record_time))
self.recording = False
self.thread.join()
self.flush()
self.writer.release()