|
1 /* GStreamer |
|
2 * |
|
3 * gstv4lsrc.c: BT8x8/V4L source element |
|
4 * |
|
5 * Copyright (C) 2001-2002 Ronald Bultje <rbultje@ronald.bitfreak.net> |
|
6 * |
|
7 * This library is free software; you can redistribute it and/or |
|
8 * modify it under the terms of the GNU Library General Public |
|
9 * License as published by the Free Software Foundation; either |
|
10 * version 2 of the License, or (at your option) any later version. |
|
11 * |
|
12 * This library is distributed in the hope that it will be useful, |
|
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|
15 * Library General Public License for more details. |
|
16 * |
|
17 * You should have received a copy of the GNU Library General Public |
|
18 * License along with this library; if not, write to the |
|
19 * Free Software Foundation, Inc., 59 Temple Place - Suite 330, |
|
20 * Boston, MA 02111-1307, USA. |
|
21 */ |
|
22 |
|
23 #ifdef HAVE_CONFIG_H |
|
24 #include <config.h> |
|
25 #endif |
|
26 |
|
27 #include <string.h> |
|
28 #include <sys/time.h> |
|
29 #include "v4lsrc_calls.h" |
|
30 #include <sys/ioctl.h> |
|
31 |
|
32 |
|
33 static const GstElementDetails gst_v4lsrc_details = |
|
34 GST_ELEMENT_DETAILS ("Video (video4linux/raw) Source", |
|
35 "Source/Video", |
|
36 "Reads raw frames from a video4linux device", |
|
37 "Ronald Bultje <rbultje@ronald.bitfreak.net>"); |
|
38 |
|
39 |
|
40 GST_DEBUG_CATEGORY_STATIC (v4lsrc_debug); |
|
41 #define GST_CAT_DEFAULT v4lsrc_debug |
|
42 |
|
43 |
|
44 enum |
|
45 { |
|
46 PROP_0, |
|
47 PROP_AUTOPROBE, |
|
48 PROP_AUTOPROBE_FPS, |
|
49 PROP_COPY_MODE, |
|
50 PROP_TIMESTAMP_OFFSET |
|
51 }; |
|
52 |
|
53 |
|
54 GST_BOILERPLATE (GstV4lSrc, gst_v4lsrc, GstV4lElement, GST_TYPE_V4LELEMENT); |
|
55 |
|
56 |
|
57 /* basesrc methods */ |
|
58 static gboolean gst_v4lsrc_start (GstBaseSrc * src); |
|
59 static gboolean gst_v4lsrc_stop (GstBaseSrc * src); |
|
60 static gboolean gst_v4lsrc_set_caps (GstBaseSrc * src, GstCaps * caps); |
|
61 static GstCaps *gst_v4lsrc_get_caps (GstBaseSrc * src); |
|
62 static GstFlowReturn gst_v4lsrc_create (GstPushSrc * src, GstBuffer ** out); |
|
63 static gboolean gst_v4lsrc_query (GstBaseSrc * bsrc, GstQuery * query); |
|
64 static void gst_v4lsrc_fixate (GstBaseSrc * bsrc, GstCaps * caps); |
|
65 |
|
66 static void gst_v4lsrc_set_property (GObject * object, |
|
67 guint prop_id, const GValue * value, GParamSpec * pspec); |
|
68 static void gst_v4lsrc_get_property (GObject * object, |
|
69 guint prop_id, GValue * value, GParamSpec * pspec); |
|
70 |
|
71 |
|
72 static void |
|
73 gst_v4lsrc_base_init (gpointer g_class) |
|
74 { |
|
75 GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class); |
|
76 |
|
77 gst_element_class_set_details (gstelement_class, &gst_v4lsrc_details); |
|
78 |
|
79 gst_element_class_add_pad_template (gstelement_class, |
|
80 gst_pad_template_new ("src", GST_PAD_SRC, GST_PAD_ALWAYS, |
|
81 gst_caps_new_any ())); |
|
82 } |
|
83 |
|
84 static void |
|
85 gst_v4lsrc_class_init (GstV4lSrcClass * klass) |
|
86 { |
|
87 GObjectClass *gobject_class; |
|
88 GstBaseSrcClass *basesrc_class; |
|
89 GstPushSrcClass *pushsrc_class; |
|
90 |
|
91 gobject_class = (GObjectClass *) klass; |
|
92 basesrc_class = (GstBaseSrcClass *) klass; |
|
93 pushsrc_class = (GstPushSrcClass *) klass; |
|
94 |
|
95 gobject_class->set_property = gst_v4lsrc_set_property; |
|
96 gobject_class->get_property = gst_v4lsrc_get_property; |
|
97 |
|
98 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_AUTOPROBE, |
|
99 g_param_spec_boolean ("autoprobe", "Autoprobe", |
|
100 "Whether the device should be probed for all possible features", |
|
101 TRUE, G_PARAM_READWRITE)); |
|
102 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_AUTOPROBE_FPS, |
|
103 g_param_spec_boolean ("autoprobe-fps", "Autoprobe FPS", |
|
104 "Whether the device should be probed for framerates", |
|
105 TRUE, G_PARAM_READWRITE)); |
|
106 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_COPY_MODE, |
|
107 g_param_spec_boolean ("copy-mode", "Copy mode", |
|
108 "Whether to send out copies of buffers, or direct pointers to the mmap region", |
|
109 TRUE, G_PARAM_READWRITE)); |
|
110 g_object_class_install_property (G_OBJECT_CLASS (klass), |
|
111 PROP_TIMESTAMP_OFFSET, g_param_spec_int64 ("timestamp-offset", |
|
112 "Timestamp offset", |
|
113 "A time offset subtracted from timestamps set on buffers (in ns)", |
|
114 G_MININT64, G_MAXINT64, 0, G_PARAM_READWRITE)); |
|
115 |
|
116 GST_DEBUG_CATEGORY_INIT (v4lsrc_debug, "v4lsrc", 0, "V4L source element"); |
|
117 |
|
118 basesrc_class->get_caps = gst_v4lsrc_get_caps; |
|
119 basesrc_class->set_caps = gst_v4lsrc_set_caps; |
|
120 basesrc_class->start = gst_v4lsrc_start; |
|
121 basesrc_class->stop = gst_v4lsrc_stop; |
|
122 basesrc_class->fixate = gst_v4lsrc_fixate; |
|
123 basesrc_class->query = gst_v4lsrc_query; |
|
124 |
|
125 pushsrc_class->create = gst_v4lsrc_create; |
|
126 } |
|
127 |
|
128 static void |
|
129 gst_v4lsrc_init (GstV4lSrc * v4lsrc, GstV4lSrcClass * klass) |
|
130 { |
|
131 v4lsrc->buffer_size = 0; |
|
132 |
|
133 /* no colorspaces */ |
|
134 v4lsrc->colorspaces = NULL; |
|
135 |
|
136 v4lsrc->is_capturing = FALSE; |
|
137 v4lsrc->autoprobe = TRUE; |
|
138 v4lsrc->autoprobe_fps = TRUE; |
|
139 v4lsrc->copy_mode = TRUE; |
|
140 |
|
141 v4lsrc->timestamp_offset = 0; |
|
142 |
|
143 v4lsrc->fps_list = NULL; |
|
144 |
|
145 gst_base_src_set_format (GST_BASE_SRC (v4lsrc), GST_FORMAT_TIME); |
|
146 gst_base_src_set_live (GST_BASE_SRC (v4lsrc), TRUE); |
|
147 } |
|
148 |
|
149 static void |
|
150 gst_v4lsrc_set_property (GObject * object, |
|
151 guint prop_id, const GValue * value, GParamSpec * pspec) |
|
152 { |
|
153 GstV4lSrc *v4lsrc = GST_V4LSRC (object); |
|
154 |
|
155 switch (prop_id) { |
|
156 case PROP_AUTOPROBE: |
|
157 g_return_if_fail (!GST_V4L_IS_ACTIVE (GST_V4LELEMENT (v4lsrc))); |
|
158 v4lsrc->autoprobe = g_value_get_boolean (value); |
|
159 break; |
|
160 case PROP_AUTOPROBE_FPS: |
|
161 g_return_if_fail (!GST_V4L_IS_ACTIVE (GST_V4LELEMENT (v4lsrc))); |
|
162 v4lsrc->autoprobe_fps = g_value_get_boolean (value); |
|
163 break; |
|
164 case PROP_COPY_MODE: |
|
165 v4lsrc->copy_mode = g_value_get_boolean (value); |
|
166 break; |
|
167 case PROP_TIMESTAMP_OFFSET: |
|
168 v4lsrc->timestamp_offset = g_value_get_int64 (value); |
|
169 break; |
|
170 default: |
|
171 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); |
|
172 break; |
|
173 } |
|
174 } |
|
175 |
|
176 |
|
177 static void |
|
178 gst_v4lsrc_get_property (GObject * object, |
|
179 guint prop_id, GValue * value, GParamSpec * pspec) |
|
180 { |
|
181 GstV4lSrc *v4lsrc = GST_V4LSRC (object); |
|
182 |
|
183 switch (prop_id) { |
|
184 case PROP_AUTOPROBE: |
|
185 g_value_set_boolean (value, v4lsrc->autoprobe); |
|
186 break; |
|
187 case PROP_AUTOPROBE_FPS: |
|
188 g_value_set_boolean (value, v4lsrc->autoprobe_fps); |
|
189 break; |
|
190 case PROP_COPY_MODE: |
|
191 g_value_set_boolean (value, v4lsrc->copy_mode); |
|
192 break; |
|
193 case PROP_TIMESTAMP_OFFSET: |
|
194 g_value_set_int64 (value, v4lsrc->timestamp_offset); |
|
195 break; |
|
196 default: |
|
197 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); |
|
198 break; |
|
199 } |
|
200 } |
|
201 |
|
202 /* this function is a bit of a last resort */ |
|
203 static void |
|
204 gst_v4lsrc_fixate (GstBaseSrc * bsrc, GstCaps * caps) |
|
205 { |
|
206 GstStructure *structure; |
|
207 int i; |
|
208 int targetwidth, targetheight; |
|
209 GstV4lSrc *v4lsrc = GST_V4LSRC (bsrc); |
|
210 struct video_capability *vcap = &GST_V4LELEMENT (v4lsrc)->vcap; |
|
211 struct video_window *vwin = &GST_V4LELEMENT (v4lsrc)->vwin; |
|
212 |
|
213 if (GST_V4L_IS_OPEN (GST_V4LELEMENT (v4lsrc))) { |
|
214 GST_DEBUG_OBJECT (v4lsrc, "device reported w: %d-%d, h: %d-%d", |
|
215 vcap->minwidth, vcap->maxwidth, vcap->minheight, vcap->maxheight); |
|
216 targetwidth = vcap->minwidth; |
|
217 targetheight = vcap->minheight; |
|
218 /* if we can get the current vwin settings, we use those to fixate */ |
|
219 if (!gst_v4l_get_capabilities (GST_V4LELEMENT (v4lsrc))) |
|
220 GST_DEBUG_OBJECT (v4lsrc, "failed getting capabilities"); |
|
221 else { |
|
222 targetwidth = vwin->width; |
|
223 targetheight = vwin->height; |
|
224 } |
|
225 } else { |
|
226 GST_DEBUG_OBJECT (v4lsrc, "device closed, guessing"); |
|
227 targetwidth = 320; |
|
228 targetheight = 200; |
|
229 } |
|
230 |
|
231 GST_DEBUG_OBJECT (v4lsrc, "targetting %dx%d", targetwidth, targetheight); |
|
232 |
|
233 for (i = 0; i < gst_caps_get_size (caps); ++i) { |
|
234 const GValue *v; |
|
235 |
|
236 structure = gst_caps_get_structure (caps, i); |
|
237 gst_structure_fixate_field_nearest_int (structure, "width", targetwidth); |
|
238 gst_structure_fixate_field_nearest_int (structure, "height", targetheight); |
|
239 gst_structure_fixate_field_nearest_fraction (structure, "framerate", 15, 2); |
|
240 |
|
241 v = gst_structure_get_value (structure, "format"); |
|
242 if (v && G_VALUE_TYPE (v) != GST_TYPE_FOURCC) { |
|
243 guint32 fourcc; |
|
244 |
|
245 g_return_if_fail (G_VALUE_TYPE (v) == GST_TYPE_LIST); |
|
246 |
|
247 fourcc = gst_value_get_fourcc (gst_value_list_get_value (v, 0)); |
|
248 gst_structure_set (structure, "format", GST_TYPE_FOURCC, fourcc, NULL); |
|
249 } |
|
250 } |
|
251 } |
|
252 |
|
253 static gint all_palettes[] = { |
|
254 VIDEO_PALETTE_YUV422, |
|
255 VIDEO_PALETTE_YUV420P, |
|
256 VIDEO_PALETTE_UYVY, |
|
257 VIDEO_PALETTE_YUV411P, |
|
258 VIDEO_PALETTE_YUV422P, |
|
259 VIDEO_PALETTE_YUV410P, |
|
260 VIDEO_PALETTE_YUV411, |
|
261 VIDEO_PALETTE_RGB555, |
|
262 VIDEO_PALETTE_RGB565, |
|
263 VIDEO_PALETTE_RGB24, |
|
264 VIDEO_PALETTE_RGB32, |
|
265 -1 |
|
266 }; |
|
267 |
|
268 static GstCaps * |
|
269 gst_v4lsrc_palette_to_caps (int palette) |
|
270 { |
|
271 guint32 fourcc; |
|
272 GstCaps *caps; |
|
273 |
|
274 switch (palette) { |
|
275 case VIDEO_PALETTE_YUV422: |
|
276 case VIDEO_PALETTE_YUYV: |
|
277 fourcc = GST_MAKE_FOURCC ('Y', 'U', 'Y', '2'); |
|
278 break; |
|
279 case VIDEO_PALETTE_YUV420P: |
|
280 fourcc = GST_MAKE_FOURCC ('I', '4', '2', '0'); |
|
281 break; |
|
282 case VIDEO_PALETTE_UYVY: |
|
283 fourcc = GST_MAKE_FOURCC ('U', 'Y', 'V', 'Y'); |
|
284 break; |
|
285 case VIDEO_PALETTE_YUV411P: |
|
286 fourcc = GST_MAKE_FOURCC ('Y', '4', '1', 'B'); |
|
287 break; |
|
288 case VIDEO_PALETTE_YUV411: |
|
289 fourcc = GST_MAKE_FOURCC ('Y', '4', '1', 'P'); |
|
290 break; |
|
291 case VIDEO_PALETTE_YUV422P: |
|
292 fourcc = GST_MAKE_FOURCC ('Y', '4', '2', 'B'); |
|
293 break; |
|
294 case VIDEO_PALETTE_YUV410P: |
|
295 fourcc = GST_MAKE_FOURCC ('Y', 'U', 'V', '9'); |
|
296 break; |
|
297 case VIDEO_PALETTE_RGB555: |
|
298 case VIDEO_PALETTE_RGB565: |
|
299 case VIDEO_PALETTE_RGB24: |
|
300 case VIDEO_PALETTE_RGB32: |
|
301 fourcc = GST_MAKE_FOURCC ('R', 'G', 'B', ' '); |
|
302 break; |
|
303 default: |
|
304 return NULL; |
|
305 } |
|
306 |
|
307 if (fourcc == GST_MAKE_FOURCC ('R', 'G', 'B', ' ')) { |
|
308 switch (palette) { |
|
309 case VIDEO_PALETTE_RGB555: |
|
310 caps = gst_caps_from_string ("video/x-raw-rgb, " |
|
311 "bpp = (int) 16, " |
|
312 "depth = (int) 15, " |
|
313 "endianness = (int) BYTE_ORDER, " |
|
314 "red_mask = 0x7c00, " "green_mask = 0x03e0, " "blue_mask = 0x001f"); |
|
315 break; |
|
316 case VIDEO_PALETTE_RGB565: |
|
317 caps = gst_caps_from_string ("video/x-raw-rgb, " |
|
318 "bpp = (int) 16, " |
|
319 "depth = (int) 16, " |
|
320 "endianness = (int) BYTE_ORDER, " |
|
321 "red_mask = 0xf800, " "green_mask = 0x07f0, " "blue_mask = 0x001f"); |
|
322 break; |
|
323 case VIDEO_PALETTE_RGB24: |
|
324 caps = gst_caps_from_string ("video/x-raw-rgb, " |
|
325 "bpp = (int) 24, " |
|
326 "depth = (int) 24, " |
|
327 "endianness = (int) BIG_ENDIAN, " |
|
328 "red_mask = 0xFF0000, " |
|
329 "green_mask = 0x00FF00, " "blue_mask = 0x0000FF"); |
|
330 break; |
|
331 case VIDEO_PALETTE_RGB32: |
|
332 caps = gst_caps_from_string ("video/x-raw-rgb, " |
|
333 "bpp = (int) 32, " |
|
334 "depth = (int) 24, " |
|
335 "endianness = (int) BIG_ENDIAN, " |
|
336 "red_mask = 0xFF000000, " |
|
337 "green_mask = 0x00FF0000, " "blue_mask = 0x0000FF00"); |
|
338 break; |
|
339 default: |
|
340 g_assert_not_reached (); |
|
341 return NULL; |
|
342 } |
|
343 } else { |
|
344 caps = gst_caps_new_simple ("video/x-raw-yuv", |
|
345 "format", GST_TYPE_FOURCC, fourcc, NULL); |
|
346 } |
|
347 |
|
348 return caps; |
|
349 } |
|
350 |
|
351 static GstCaps * |
|
352 gst_v4lsrc_get_any_caps (void) |
|
353 { |
|
354 gint i; |
|
355 GstCaps *caps = gst_caps_new_empty (), *one; |
|
356 |
|
357 for (i = 0; all_palettes[i] != -1; i++) { |
|
358 one = gst_v4lsrc_palette_to_caps (all_palettes[i]); |
|
359 gst_caps_append (caps, one); |
|
360 } |
|
361 |
|
362 return caps; |
|
363 } |
|
364 |
|
365 static GstCaps * |
|
366 gst_v4lsrc_get_caps (GstBaseSrc * src) |
|
367 { |
|
368 GstCaps *list; |
|
369 GstV4lSrc *v4lsrc = GST_V4LSRC (src); |
|
370 struct video_capability *vcap = &GST_V4LELEMENT (v4lsrc)->vcap; |
|
371 gint width = GST_V4LELEMENT (src)->vcap.minwidth; |
|
372 gint height = GST_V4LELEMENT (src)->vcap.minheight; |
|
373 gint i; |
|
374 gint fps_n, fps_d; |
|
375 GList *item; |
|
376 |
|
377 if (!GST_V4L_IS_OPEN (GST_V4LELEMENT (v4lsrc))) { |
|
378 return gst_v4lsrc_get_any_caps (); |
|
379 } |
|
380 |
|
381 if (!v4lsrc->autoprobe) { |
|
382 /* FIXME: query current caps and return those, with _any appended */ |
|
383 return gst_v4lsrc_get_any_caps (); |
|
384 } |
|
385 |
|
386 if (!v4lsrc->colorspaces) { |
|
387 GST_DEBUG_OBJECT (v4lsrc, "Checking supported palettes"); |
|
388 for (i = 0; all_palettes[i] != -1; i++) { |
|
389 /* try palette out */ |
|
390 if (!gst_v4lsrc_try_capture (v4lsrc, width, height, all_palettes[i])) |
|
391 continue; |
|
392 GST_DEBUG_OBJECT (v4lsrc, "Added palette %d (%s) to supported list", |
|
393 all_palettes[i], gst_v4lsrc_palette_name (all_palettes[i])); |
|
394 v4lsrc->colorspaces = g_list_append (v4lsrc->colorspaces, |
|
395 GINT_TO_POINTER (all_palettes[i])); |
|
396 } |
|
397 GST_DEBUG_OBJECT (v4lsrc, "%d palette(s) supported", |
|
398 g_list_length (v4lsrc->colorspaces)); |
|
399 if (v4lsrc->autoprobe_fps) { |
|
400 GST_DEBUG_OBJECT (v4lsrc, "autoprobing framerates"); |
|
401 v4lsrc->fps_list = gst_v4lsrc_get_fps_list (v4lsrc); |
|
402 } |
|
403 } |
|
404 |
|
405 |
|
406 if (!gst_v4lsrc_get_fps (v4lsrc, &fps_n, &fps_d)) { |
|
407 fps_n = 0; |
|
408 fps_d = 1; |
|
409 } |
|
410 |
|
411 list = gst_caps_new_empty (); |
|
412 for (item = v4lsrc->colorspaces; item != NULL; item = item->next) { |
|
413 GstCaps *one; |
|
414 |
|
415 one = gst_v4lsrc_palette_to_caps (GPOINTER_TO_INT (item->data)); |
|
416 if (!one) { |
|
417 GST_WARNING_OBJECT (v4lsrc, "Palette %d gave no caps\n", |
|
418 GPOINTER_TO_INT (item->data)); |
|
419 continue; |
|
420 } |
|
421 |
|
422 GST_DEBUG_OBJECT (v4lsrc, |
|
423 "Device reports w: %d-%d, h: %d-%d, fps: %d/%d for palette %d", |
|
424 vcap->minwidth, vcap->maxwidth, vcap->minheight, vcap->maxheight, |
|
425 fps_n, fps_d, GPOINTER_TO_INT (item->data)); |
|
426 |
|
427 if (vcap->minwidth < vcap->maxwidth) { |
|
428 gst_caps_set_simple (one, "width", GST_TYPE_INT_RANGE, vcap->minwidth, |
|
429 vcap->maxwidth, NULL); |
|
430 } else { |
|
431 gst_caps_set_simple (one, "width", G_TYPE_INT, vcap->minwidth, NULL); |
|
432 } |
|
433 if (vcap->minheight < vcap->maxheight) { |
|
434 gst_caps_set_simple (one, "height", GST_TYPE_INT_RANGE, vcap->minheight, |
|
435 vcap->maxheight, NULL); |
|
436 } else { |
|
437 gst_caps_set_simple (one, "height", G_TYPE_INT, vcap->minheight, NULL); |
|
438 } |
|
439 |
|
440 if (v4lsrc->autoprobe_fps) { |
|
441 GstStructure *structure = gst_caps_get_structure (one, 0); |
|
442 |
|
443 if (v4lsrc->fps_list) { |
|
444 gst_structure_set_value (structure, "framerate", v4lsrc->fps_list); |
|
445 } else { |
|
446 gst_structure_set (structure, "framerate", GST_TYPE_FRACTION, |
|
447 fps_n, fps_d, NULL); |
|
448 } |
|
449 } else { |
|
450 gst_caps_set_simple (one, "framerate", GST_TYPE_FRACTION_RANGE, |
|
451 1, 1, 100, 1, NULL); |
|
452 } |
|
453 |
|
454 GST_DEBUG_OBJECT (v4lsrc, "caps: %" GST_PTR_FORMAT, one); |
|
455 gst_caps_append (list, one); |
|
456 } |
|
457 |
|
458 return list; |
|
459 } |
|
460 |
|
461 static gboolean |
|
462 gst_v4lsrc_set_caps (GstBaseSrc * src, GstCaps * caps) |
|
463 { |
|
464 GstV4lSrc *v4lsrc; |
|
465 guint32 fourcc; |
|
466 gint bpp, depth, w, h, palette = -1; |
|
467 const GValue *new_fps; |
|
468 gint cur_fps_n, cur_fps_d; |
|
469 GstStructure *structure; |
|
470 struct video_window *vwin; |
|
471 |
|
472 v4lsrc = GST_V4LSRC (src); |
|
473 vwin = &GST_V4LELEMENT (v4lsrc)->vwin; |
|
474 |
|
475 /* if we're not open, punt -- we'll get setcaps'd later via negotiate */ |
|
476 if (!GST_V4L_IS_OPEN (v4lsrc)) |
|
477 return FALSE; |
|
478 |
|
479 /* make sure we stop capturing and dealloc buffers */ |
|
480 if (GST_V4L_IS_ACTIVE (v4lsrc)) { |
|
481 if (!gst_v4lsrc_capture_stop (v4lsrc)) |
|
482 return FALSE; |
|
483 if (!gst_v4lsrc_capture_deinit (v4lsrc)) |
|
484 return FALSE; |
|
485 } |
|
486 |
|
487 /* it's fixed, one struct */ |
|
488 structure = gst_caps_get_structure (caps, 0); |
|
489 |
|
490 if (strcmp (gst_structure_get_name (structure), "video/x-raw-yuv") == 0) |
|
491 gst_structure_get_fourcc (structure, "format", &fourcc); |
|
492 else |
|
493 fourcc = GST_MAKE_FOURCC ('R', 'G', 'B', ' '); |
|
494 |
|
495 gst_structure_get_int (structure, "width", &w); |
|
496 gst_structure_get_int (structure, "height", &h); |
|
497 new_fps = gst_structure_get_value (structure, "framerate"); |
|
498 |
|
499 /* set framerate if it's not already correct */ |
|
500 if (!gst_v4lsrc_get_fps (v4lsrc, &cur_fps_n, &cur_fps_d)) |
|
501 return FALSE; |
|
502 |
|
503 if (new_fps) { |
|
504 GST_DEBUG_OBJECT (v4lsrc, "linking with %dx%d at %d/%d fps", w, h, |
|
505 gst_value_get_fraction_numerator (new_fps), |
|
506 gst_value_get_fraction_denominator (new_fps)); |
|
507 |
|
508 if (gst_value_get_fraction_numerator (new_fps) != cur_fps_n || |
|
509 gst_value_get_fraction_denominator (new_fps) != cur_fps_d) { |
|
510 int fps_index = (gst_value_get_fraction_numerator (new_fps) * 16) / |
|
511 (gst_value_get_fraction_denominator (new_fps) * 15); |
|
512 |
|
513 GST_DEBUG_OBJECT (v4lsrc, "Trying to set fps index %d", fps_index); |
|
514 /* set bits 16 to 21 to 0 */ |
|
515 vwin->flags &= (0x3F00 - 1); |
|
516 /* set bits 16 to 21 to the index */ |
|
517 vwin->flags |= fps_index << 16; |
|
518 if (!gst_v4l_set_window_properties (GST_V4LELEMENT (v4lsrc))) { |
|
519 return FALSE; |
|
520 } |
|
521 } |
|
522 } |
|
523 |
|
524 switch (fourcc) { |
|
525 case GST_MAKE_FOURCC ('I', '4', '2', '0'): |
|
526 palette = VIDEO_PALETTE_YUV420P; |
|
527 v4lsrc->buffer_size = ((w + 1) & ~1) * ((h + 1) & ~1) * 1.5; |
|
528 break; |
|
529 case GST_MAKE_FOURCC ('Y', 'U', 'Y', '2'): |
|
530 palette = VIDEO_PALETTE_YUV422; |
|
531 v4lsrc->buffer_size = ((w + 1) & ~1) * h * 2; |
|
532 break; |
|
533 case GST_MAKE_FOURCC ('U', 'Y', 'V', 'Y'): |
|
534 palette = VIDEO_PALETTE_UYVY; |
|
535 v4lsrc->buffer_size = ((w + 1) & ~1) * h * 2; |
|
536 break; |
|
537 case GST_MAKE_FOURCC ('Y', '4', '1', 'B'): |
|
538 palette = VIDEO_PALETTE_YUV411P; |
|
539 v4lsrc->buffer_size = ((w + 3) & ~3) * h * 1.5; |
|
540 break; |
|
541 case GST_MAKE_FOURCC ('Y', '4', '1', 'P'): |
|
542 palette = VIDEO_PALETTE_YUV411; |
|
543 v4lsrc->buffer_size = ((w + 3) & ~3) * h * 1.5; |
|
544 break; |
|
545 case GST_MAKE_FOURCC ('Y', 'U', 'V', '9'): |
|
546 palette = VIDEO_PALETTE_YUV410P; |
|
547 v4lsrc->buffer_size = ((w + 3) & ~3) * ((h + 3) & ~3) * 1.125; |
|
548 break; |
|
549 case GST_MAKE_FOURCC ('Y', '4', '2', 'B'): |
|
550 palette = VIDEO_PALETTE_YUV422P; |
|
551 v4lsrc->buffer_size = ((w + 1) & ~1) * h * 2; |
|
552 break; |
|
553 case GST_MAKE_FOURCC ('R', 'G', 'B', ' '): |
|
554 gst_structure_get_int (structure, "depth", &depth); |
|
555 switch (depth) { |
|
556 case 15: |
|
557 palette = VIDEO_PALETTE_RGB555; |
|
558 v4lsrc->buffer_size = w * h * 2; |
|
559 break; |
|
560 case 16: |
|
561 palette = VIDEO_PALETTE_RGB565; |
|
562 v4lsrc->buffer_size = w * h * 2; |
|
563 break; |
|
564 case 24: |
|
565 gst_structure_get_int (structure, "bpp", &bpp); |
|
566 switch (bpp) { |
|
567 case 24: |
|
568 palette = VIDEO_PALETTE_RGB24; |
|
569 v4lsrc->buffer_size = w * h * 3; |
|
570 break; |
|
571 case 32: |
|
572 palette = VIDEO_PALETTE_RGB32; |
|
573 v4lsrc->buffer_size = w * h * 4; |
|
574 break; |
|
575 default: |
|
576 break; |
|
577 } |
|
578 break; |
|
579 default: |
|
580 break; |
|
581 } |
|
582 break; |
|
583 default: |
|
584 break; |
|
585 } |
|
586 |
|
587 if (palette == -1) { |
|
588 GST_WARNING_OBJECT (v4lsrc, "palette for fourcc %" GST_FOURCC_FORMAT |
|
589 " is -1, refusing link", GST_FOURCC_ARGS (fourcc)); |
|
590 return FALSE; |
|
591 } |
|
592 |
|
593 GST_DEBUG_OBJECT (v4lsrc, "trying to set_capture %dx%d, palette %d", |
|
594 w, h, palette); |
|
595 /* this only fills in v4lsrc->mmap values */ |
|
596 if (!gst_v4lsrc_set_capture (v4lsrc, w, h, palette)) { |
|
597 GST_WARNING_OBJECT (v4lsrc, "could not set_capture %dx%d, palette %d", |
|
598 w, h, palette); |
|
599 return FALSE; |
|
600 } |
|
601 |
|
602 /* first try the negotiated settings using try_capture */ |
|
603 if (!gst_v4lsrc_try_capture (v4lsrc, w, h, palette)) { |
|
604 GST_DEBUG_OBJECT (v4lsrc, "failed trying palette %d for %dx%d", palette, |
|
605 w, h); |
|
606 return FALSE; |
|
607 } |
|
608 |
|
609 if (!gst_v4lsrc_capture_init (v4lsrc)) |
|
610 return FALSE; |
|
611 |
|
612 if (!gst_v4lsrc_capture_start (v4lsrc)) |
|
613 return FALSE; |
|
614 |
|
615 return TRUE; |
|
616 } |
|
617 |
|
618 static gboolean |
|
619 gst_v4lsrc_query (GstBaseSrc * bsrc, GstQuery * query) |
|
620 { |
|
621 GstV4lSrc *v4lsrc; |
|
622 gboolean res = FALSE; |
|
623 |
|
624 v4lsrc = GST_V4LSRC (bsrc); |
|
625 |
|
626 switch (GST_QUERY_TYPE (query)) { |
|
627 case GST_QUERY_LATENCY: |
|
628 { |
|
629 GstClockTime min_latency, max_latency; |
|
630 gint fps_n, fps_d; |
|
631 |
|
632 /* device must be open */ |
|
633 if (!GST_V4L_IS_OPEN (v4lsrc)) |
|
634 goto done; |
|
635 |
|
636 /* we must have a framerate */ |
|
637 if (!(res = gst_v4lsrc_get_fps (v4lsrc, &fps_n, &fps_d))) |
|
638 goto done; |
|
639 |
|
640 /* min latency is the time to capture one frame */ |
|
641 min_latency = gst_util_uint64_scale_int (GST_SECOND, fps_d, fps_n); |
|
642 |
|
643 /* max latency is total duration of the frame buffer */ |
|
644 max_latency = v4lsrc->mbuf.frames * min_latency; |
|
645 |
|
646 GST_DEBUG_OBJECT (bsrc, |
|
647 "report latency min %" GST_TIME_FORMAT " max %" GST_TIME_FORMAT, |
|
648 GST_TIME_ARGS (min_latency), GST_TIME_ARGS (max_latency)); |
|
649 |
|
650 /* we are always live, the min latency is 1 frame and the max latency is |
|
651 * the complete buffer of frames. */ |
|
652 gst_query_set_latency (query, TRUE, min_latency, max_latency); |
|
653 |
|
654 res = TRUE; |
|
655 break; |
|
656 } |
|
657 default: |
|
658 res = GST_BASE_SRC_CLASS (parent_class)->query (bsrc, query); |
|
659 break; |
|
660 } |
|
661 done: |
|
662 return res; |
|
663 } |
|
664 |
|
665 /* start and stop are not symmetric -- start will open the device, but not start |
|
666 capture. it's setcaps that will start capture, which is called via basesrc's |
|
667 negotiate method. stop will both stop capture and close the device. |
|
668 */ |
|
669 static gboolean |
|
670 gst_v4lsrc_start (GstBaseSrc * src) |
|
671 { |
|
672 GstV4lSrc *v4lsrc = GST_V4LSRC (src); |
|
673 |
|
674 if (!GST_BASE_SRC_CLASS (parent_class)->start (src)) |
|
675 return FALSE; |
|
676 |
|
677 v4lsrc->offset = 0; |
|
678 |
|
679 return TRUE; |
|
680 } |
|
681 |
|
682 static gboolean |
|
683 gst_v4lsrc_stop (GstBaseSrc * src) |
|
684 { |
|
685 GstV4lSrc *v4lsrc = GST_V4LSRC (src); |
|
686 |
|
687 if (GST_V4L_IS_ACTIVE (v4lsrc) && !gst_v4lsrc_capture_stop (v4lsrc)) |
|
688 return FALSE; |
|
689 |
|
690 if (GST_V4LELEMENT (v4lsrc)->buffer != NULL) { |
|
691 if (!gst_v4lsrc_capture_deinit (v4lsrc)) |
|
692 return FALSE; |
|
693 } |
|
694 |
|
695 if (!GST_BASE_SRC_CLASS (parent_class)->stop (src)) |
|
696 return FALSE; |
|
697 |
|
698 g_list_free (v4lsrc->colorspaces); |
|
699 v4lsrc->colorspaces = NULL; |
|
700 |
|
701 if (v4lsrc->fps_list) { |
|
702 g_value_unset (v4lsrc->fps_list); |
|
703 g_free (v4lsrc->fps_list); |
|
704 v4lsrc->fps_list = NULL; |
|
705 } |
|
706 |
|
707 return TRUE; |
|
708 } |
|
709 |
|
710 static GstFlowReturn |
|
711 gst_v4lsrc_create (GstPushSrc * src, GstBuffer ** buf) |
|
712 { |
|
713 GstV4lSrc *v4lsrc; |
|
714 gint num; |
|
715 |
|
716 v4lsrc = GST_V4LSRC (src); |
|
717 |
|
718 /* grab a frame from the device */ |
|
719 if (!gst_v4lsrc_grab_frame (v4lsrc, &num)) |
|
720 return GST_FLOW_ERROR; |
|
721 |
|
722 *buf = gst_v4lsrc_buffer_new (v4lsrc, num); |
|
723 |
|
724 if (v4lsrc->copy_mode) { |
|
725 GstBuffer *copy = gst_buffer_copy (*buf); |
|
726 |
|
727 gst_buffer_unref (*buf); |
|
728 *buf = copy; |
|
729 } |
|
730 |
|
731 return GST_FLOW_OK; |
|
732 } |