22import logging
33import selectors
44
5- from linuxpy . video . device import Device , PixelFormat , VideoCapture
5+ from OpenGL import GL
66
7+ from linuxpy .video .device import Device , PixelFormat , VideoCapture
78
8- class RGFWWindow :
9- def __init__ (self , name , x , y , width , height , flags = None ):
10- import RGFW
11-
12- self .lib = RGFW
13- self .name = name
14- self .rect = RGFW .rect (x , y , width , height )
15- self .flags = RGFW .CENTER if flags is None else flags
16- self .win = None
17-
18- def create (self ):
19- self .win = self .lib .createWindow (self .name , self .rect , self .flags )
20-
21- def swapBuffers (self ):
22- self .win .swapBuffers ()
23-
24- def handle_events (self ):
25- lib = self .lib
26- win = self .win
27- while win .checkEvent ():
28- if win .event .type == lib .quit or lib .isPressed (win , lib .Escape ):
29- return False
30- return True
31-
32- def __enter__ (self ):
33- self .create ()
34- return self
35-
36- def __exit__ (self , * args ):
37- self .win .close ()
38- self .win = None
39-
40-
41- class RGFWCaptureWindow :
42- def __init__ (self , capture , window ):
43- self .capture = capture
44- self .window = window
45-
46- def __iter__ (self ):
47- with self .capture :
48- stream = maybe_frames (self .capture )
49- while True :
50- if not self .window .handle_events ():
51- break
52- if frame := next (stream ):
53- frame .user_data = decode_frame (frame )
54- yield frame
55- self .window .swapBuffers ()
9+ OPENCV_FORMATS = {
10+ PixelFormat .MJPEG ,
11+ PixelFormat .YUYV ,
12+ PixelFormat .YVYU ,
13+ PixelFormat .UYVY ,
14+ PixelFormat .YUV420 ,
15+ PixelFormat .NV12 ,
16+ PixelFormat .NV21 ,
17+ }
5618
5719
58- def decode_frame (frame ):
59- if frame .pixel_format == PixelFormat .BGR24 :
60- return frame .data
20+ def opencv_decode_frame (frame ):
6121 import cv2
6222
63- bgr = cv2 .imdecode (frame .array , cv2 .IMREAD_COLOR )
64- return bgr # cv2.cvtColor(bgr, cv2.COLOR_BGR2RGB)
23+ data , fmt = frame .array , frame .pixel_format
24+ if fmt == PixelFormat .MJPEG :
25+ result = cv2 .imdecode (data , cv2 .IMREAD_COLOR )
26+ else :
27+ YUV_MAP = {
28+ PixelFormat .YUYV : cv2 .COLOR_YUV2RGB_YUYV ,
29+ PixelFormat .YVYU : cv2 .COLOR_YUV2RGB_YVYU ,
30+ PixelFormat .UYVY : cv2 .COLOR_YUV2RGB_UYVY ,
31+ PixelFormat .YUV420 : cv2 .COLOR_YUV2RGB_I420 ,
32+ PixelFormat .NV12 : cv2 .COLOR_YUV2RGB_NV12 ,
33+ PixelFormat .NV21 : cv2 .COLOR_YUV2RGB_NV21 ,
34+ }
35+ data = frame .array
36+ if fmt in {PixelFormat .NV12 , PixelFormat .NV21 , PixelFormat .YUV420 }:
37+ data .shape = frame .height * 3 // 2 , frame .width , - 1
38+ else :
39+ data .shape = frame .height , frame .width , - 1
40+ result = cv2 .cvtColor (data , YUV_MAP [fmt ])
41+ return result , GL .GL_BGR
42+
43+
44+ def decode_frame (frame ):
45+ fmt = frame .pixel_format
46+ if fmt == PixelFormat .RGB24 :
47+ return frame .data , GL .GL_RGB
48+ elif fmt == PixelFormat .BGR24 :
49+ return frame .data , GL .GL_BGR
50+ elif fmt in OPENCV_FORMATS :
51+ return opencv_decode_frame (frame )
6552
6653
6754def maybe_frames (capture ):
@@ -72,7 +59,9 @@ def maybe_frames(capture):
7259 try :
7360 while True :
7461 if selector .select (0 ):
75- yield next (stream )
62+ frame = next (stream )
63+ frame .user_data = decode_frame (frame )
64+ yield frame
7665 else :
7766 yield None
7867 finally :
@@ -101,7 +90,7 @@ def cli():
10190 parser .add_argument ("--nb-buffers" , type = int , default = 2 )
10291 parser .add_argument ("--frame-rate" , type = float , default = 10 )
10392 parser .add_argument ("--frame-size" , type = frame_size , default = "640x480" )
104- parser .add_argument ("--frame-format" , type = frame_format , default = "BGR24 " )
93+ parser .add_argument ("--frame-format" , type = frame_format , default = "RGB24 " )
10594 parser .add_argument ("device" , type = device_text )
10695 return parser
10796
@@ -112,12 +101,16 @@ def main(run, args=None):
112101 fmt = "%(threadName)-10s %(asctime)-15s %(levelname)-5s %(name)s: %(message)s"
113102 logging .basicConfig (level = args .log_level .upper (), format = fmt )
114103 width , height = args .frame_size
104+ aspect = height / width
115105 try :
116106 with args .device as device :
117107 device .set_input (0 )
118108 capture = VideoCapture (device , size = args .nb_buffers )
119109 capture .set_fps (args .frame_rate )
120110 capture .set_format (width , height , args .frame_format )
121- run (capture )
111+ fmt = capture .get_format ()
112+ window_width = 1980
113+ window_height = int (window_width * aspect )
114+ run (capture , fmt , window_width , window_height )
122115 except KeyboardInterrupt :
123116 logging .info ("Ctrl-C pressed. Bailing out" )
0 commit comments