11'''
2- Class to record videos from webcams using opencv
3- Author: Jacky Liang
2+ Class to record videos from webcams using ffmpeg-python
3+ Author: Mike Danielczuk
44'''
5- import cv2
6- import logging
7- from multiprocessing import Process , Queue
8- import numpy as np
9- import os
10- import skvideo .io as si
11- import sys
5+ import ffmpeg
6+ import time
127
13- class _Camera (Process ):
14- """ Private class to manage a separate webcam data collection process.
15-
16- Attributes
17- ----------
18- camera : :obj:`cv2.VideoCapture`
19- opencv video capturing object
20- cmd_q : :obj:`Queue`
21- queue for commands to the recording process
22- res : 2-tuple
23- height and width of the video stream
24- codec : :obj:`str`
25- string name of codec, e.g. XVID
26- fps : int
27- number of frames per second
28- rate : int
29- rate at which to read frames (e.g. 2 means skip every other frame)
30- """
31- def __init__ (self , camera , cmd_q , res , codec , fps , rate = 1 ):
32- Process .__init__ (self )
33-
34- self .res = res
35- self .fps = fps
36- self .codec = codec
37-
38- self .camera = camera
39- self .fourcc = cv2 .VideoWriter_fourcc (* self .codec )
40- self .rate = rate
41-
42- self .cmd_q = cmd_q
43- self .recording = False
44- self .out = None
45- self .data_buf = None
46- self .count = 0
47-
48- def run (self ):
49- """ Continually write images to the filename specified by a command queue. """
50- if not self .camera .is_running :
51- self .camera .start ()
52- while True :
53- if not self .cmd_q .empty ():
54- cmd = self .cmd_q .get ()
55- if cmd [0 ] == 'stop' :
56- self .out .close ()
57- self .recording = False
58- elif cmd [0 ] == 'start' :
59- filename = cmd [1 ]
60- self .out = si .FFmpegWriter (filename )
61- self .recording = True
62- self .count = 0
63-
64- if self .recording :
65- if self .count == 0 :
66- image , _ , _ = self .camera .frames ()
67-
68- if self .data_buf is None :
69- self .data_buf = np .zeros ([1 , image .height , image .width , image .channels ])
70- self .data_buf [0 ,...] = image .raw_data
71- self .out .writeFrame (self .data_buf )
72-
73- self .count += 1
74- if self .count == self .rate :
75- self .count = 0
76-
778class VideoRecorder :
789 """ Encapsulates video recording processes.
7910
@@ -83,71 +14,55 @@ class VideoRecorder:
8314 USB index of device
8415 res : 2-tuple
8516 resolution of recording and saving. defaults to (640, 480)
86- codec : :obj:`str`
87- codec used for encoding video. default to XVID .
17+ video_format : :obj:`str`
18+ format used for video. default to v4l2 .
8819 fps : int
8920 frames per second of video captures. defaults to 30
90- rate : int
91- rate at which to read frames (e.g. 2 means skip every other frame)
9221 """
93- def __init__ (self , camera , device_id = 0 , res = (640 , 480 ), codec = 'XVID' , fps = 30 , rate = 1 ):
22+ def __init__ (self , device_id = 0 , res = (640 , 480 ), video_format = 'v4l2' , fps = 30 ):
23+ self ._device = device_id
9424 self ._res = res
95- self ._codec = codec
25+ self ._format = video_format
9626 self ._fps = fps
97- self ._rate = rate
98-
99- self ._cmd_q = Queue ()
100-
101- self ._actual_camera = camera
10227
10328 self ._recording = False
104- self ._started = False
10529
10630 @property
10731 def is_recording (self ):
10832 return self ._recording
109-
33+
11034 @property
11135 def is_started (self ):
112- return self . _started
36+ return True
11337
11438 def start (self ):
115- """ Starts the camera recording process. """
116- self ._started = True
117- self ._camera = _Camera (self ._actual_camera , self ._cmd_q , self ._res , self ._codec , self ._fps , self ._rate )
118- self ._camera .start ()
39+ pass
11940
120- def start_recording (self , output_file ):
41+ def start_recording (self , output_file , overwrite = True ):
12142 """ Starts recording to a given output video file.
12243
12344 Parameters
12445 ----------
12546 output_file : :obj:`str`
12647 filename to write video to
12748 """
128- if not self ._started :
129- raise Exception ("Must start the video recorder first by calling .start()!" )
13049 if self ._recording :
13150 raise Exception ("Cannot record a video while one is already recording!" )
13251 self ._recording = True
133- self ._cmd_q .put (('start' , output_file ))
52+ self ._video = (
53+ ffmpeg
54+ .input ('/dev/video{}' .format (self ._device ), f = self ._format , s = '{}x{}' .format (* self ._res ), framerate = self ._fps )
55+ .output (output_file )
56+ .run_async (quiet = True , overwrite_output = overwrite )
57+ )
58+ time .sleep (2 ) # Pause until video starts
13459
13560 def stop_recording (self ):
13661 """ Stops writing video to file. """
13762 if not self ._recording :
13863 raise Exception ("Cannot stop a video recording when it's not recording!" )
139- self ._cmd_q . put (( 'stop' ,) )
64+ self ._video . terminate ( )
14065 self ._recording = False
141-
66+
14267 def stop (self ):
143- """ Stop the camera process. """
144- if not self ._started :
145- raise Exception ("Cannot stop a video recorder before starting it!" )
146- self ._started = False
147- if self ._actual_camera .is_running :
148- self ._actual_camera .stop ()
149- if self ._camera is not None :
150- try :
151- self ._camera .terminate ()
152- except :
153- pass
68+ pass
0 commit comments