46
46
def add_filters (
47
47
input_dev : str ,
48
48
output_dev : str ,
49
- input_width : t . Optional [ int ] ,
50
- input_height : t . Optional [ int ] ,
51
- input_framerate : t . Optional [ str ] ,
49
+ input_width : int ,
50
+ input_height : int ,
51
+ input_framerate : Fraction ,
52
52
input_media_type : t .Optional [str ],
53
53
background_blur : t .Optional [int ],
54
54
selfie_segmentation_model : SelfieSegmentationModel ,
@@ -57,48 +57,54 @@ def add_filters(
57
57
"""
58
58
Run filters pipeline.
59
59
"""
60
- src = Gst .ElementFactory .make ("v4l2src" )
61
- src .set_property ("device" , input_dev )
62
- src .set_state (Gst .State .READY )
63
- caps = src .get_static_pad ("src" ).query_caps (None )
60
+ caps = query_device_caps (input_dev )
64
61
65
- src .set_state (Gst .State .NULL )
62
+ if caps is None :
63
+ click .echo (f"unable to determine capabilities for device { input_dev !r} " )
64
+ raise click .Abort ()
66
65
67
66
structs = []
68
- for c in caps :
69
- keep = True
70
-
71
- if input_media_type is not None and input_media_type != c .get_name ():
72
- keep = False
73
-
74
- if input_width is not None and input_width != c .get_value ("width" ):
75
- keep = False
76
-
77
- if input_height is not None and input_height != c .get_value ("height" ):
78
- keep = False
67
+ for s in caps :
68
+ if input_media_type is not None and input_media_type != s .get_name ():
69
+ continue
70
+
71
+ s .fixate_field_nearest_int ("width" , input_width )
72
+ s .fixate_field_nearest_int ("height" , input_height )
73
+ s .fixate_field_nearest_fraction (
74
+ "framerate" ,
75
+ input_framerate .numerator ,
76
+ input_framerate .denominator
77
+ )
78
+ structs .append (s )
79
+
80
+ if not structs :
81
+ click .echo ("unable to find a suitable input format" )
82
+ raise click .Abort ()
83
+
84
+ def struct_sort_key (x ):
85
+ _ , width = x .get_int ("width" )
86
+ _ , height = x .get_int ("height" )
87
+ _ , fr_numerator , fr_denomantor = x .get_fraction ("framerate" )
88
+ return (
89
+ abs (input_width - width ),
90
+ abs (input_height - height ),
91
+ abs (input_framerate - Fraction (fr_numerator , fr_denomantor or 1 ))
92
+ )
79
93
80
- if input_framerate is not None :
81
- if input_framerate != str (c .get_value ("framerate" )):
82
- keep = False
94
+ structs = sorted (structs , key = struct_sort_key )
83
95
84
- if keep :
85
- structs .append (c )
96
+ s = structs [0 ]
97
+ new_caps = Gst .Caps .new_empty ()
98
+ new_caps .append_structure (s )
86
99
87
- structs = sorted (
88
- structs ,
89
- key = lambda x : (
90
- Fraction (str (x .get_value ("framerate" ))),
91
- x .get_value ("width" ),
92
- x .get_value ("height" ),
93
- ),
94
- reverse = True
100
+ click .echo (
101
+ f"Selectd input: media-type={ s .get_name ()} , width={ s .get_value ('width' )} "
102
+ f"height={ s .get_value ('height' )} framerate={ s .get_value ('framerate' )} "
95
103
)
96
- new_caps = Gst .Caps .new_empty ()
97
- for s in structs :
98
- new_caps .append_structure (s )
99
104
100
105
pipeline = Gst .Pipeline .new ()
101
106
107
+ src = Gst .ElementFactory .make ("v4l2src" )
102
108
inputfilter = Gst .ElementFactory .make ("capsfilter" )
103
109
decodebin = Gst .ElementFactory .make ("decodebin" )
104
110
rgbconvert = Gst .ElementFactory .make ("videoconvert" )
@@ -108,6 +114,7 @@ def add_filters(
108
114
sinkfilter = Gst .ElementFactory .make ("capsfilter" )
109
115
sink = Gst .ElementFactory .make ("v4l2sink" )
110
116
117
+ src .set_property ("device" , input_dev )
111
118
inputfilter .set_property ("caps" , new_caps )
112
119
rgbfilter .set_property (
113
120
"caps" ,
@@ -212,32 +219,40 @@ def on_bus_message(
212
219
return True
213
220
214
221
215
- def print_device_caps (
216
- ctx : click .Context ,
217
- param : click .Parameter ,
218
- value : str ,
219
- ) -> None :
220
- """
221
- Print device capabilities and exit.
222
- """
223
- if not value or ctx .resilient_parsing :
224
- return
225
-
222
+ def query_device_caps (dev : str ) -> t .Optional [Gst .Caps ]:
226
223
src = Gst .ElementFactory .make ("v4l2src" )
227
- src .set_property ("device" , value )
224
+ src .set_property ("device" , dev )
228
225
229
226
src .set_state (Gst .State .READY )
230
227
res = src .get_state (1000 )
231
228
pad = src .get_static_pad ("src" )
232
229
233
230
if res .state != Gst .State .READY or pad is None :
234
- click .echo (f"unable to determine capabilities for device { value !r} " )
235
- ctx .exit (1 )
231
+ return None
236
232
237
233
caps = pad .query_caps (None )
238
234
src .set_state (Gst .State .NULL )
239
235
240
236
if caps .is_any ():
237
+ return None
238
+
239
+ return caps
240
+
241
+
242
+ def print_device_caps (
243
+ ctx : click .Context ,
244
+ param : click .Parameter ,
245
+ value : str ,
246
+ ) -> None :
247
+ """
248
+ Print device capabilities and exit.
249
+ """
250
+ if not value or ctx .resilient_parsing :
251
+ return
252
+
253
+ caps = query_device_caps (value )
254
+
255
+ if caps is None :
241
256
click .echo (f"unable to determine capabilities for device { value !r} " )
242
257
ctx .exit (1 )
243
258
0 commit comments