v4l2object: Add a method to try and import buffers
[platform/upstream/gst-plugins-good.git] / sys / v4l2 / gstv4l2transform.c
1 /*
2  * Copyright (C) 2014 Collabora Ltd.
3  *     Author: Nicolas Dufresne <nicolas.dufresne@collabora.co.uk>
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Library General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Library General Public License for more details.
14  *
15  * You should have received a copy of the GNU Library General Public
16  * License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
18  * Boston, MA 02110-1301, USA.
19  *
20  */
21
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25
26 #include <sys/stat.h>
27 #include <fcntl.h>
28 #include <errno.h>
29 #include <unistd.h>
30 #include <string.h>
31
32 #include "gstv4l2object.h"
33 #include "gstv4l2transform.h"
34
35 #include <string.h>
36 #include <gst/gst-i18n-plugin.h>
37
38 #define DEFAULT_PROP_DEVICE "/dev/video10"
39
40 #define V4L2_TRANSFORM_QUARK \
41         g_quark_from_static_string("gst-v4l2-transform-info")
42
43 GST_DEBUG_CATEGORY_STATIC (gst_v4l2_transform_debug);
44 #define GST_CAT_DEFAULT gst_v4l2_transform_debug
45
46
47 enum
48 {
49   PROP_0,
50   V4L2_STD_OBJECT_PROPS
51 };
52
53 typedef struct
54 {
55   gchar *device;
56   GstCaps *sink_caps;
57   GstCaps *src_caps;
58 } GstV4l2TransformCData;
59
60 #define gst_v4l2_transform_parent_class parent_class
61 G_DEFINE_ABSTRACT_TYPE (GstV4l2Transform, gst_v4l2_transform,
62     GST_TYPE_BASE_TRANSFORM);
63
64 static void
65 gst_v4l2_transform_set_property (GObject * object,
66     guint prop_id, const GValue * value, GParamSpec * pspec)
67 {
68   GstV4l2Transform *self = GST_V4L2_TRANSFORM (object);
69
70   switch (prop_id) {
71     case PROP_CAPTURE_IO_MODE:
72       gst_v4l2_object_set_property_helper (self->v4l2capture, prop_id, value,
73           pspec);
74       break;
75
76       /* By default, only set on output */
77     default:
78       if (!gst_v4l2_object_set_property_helper (self->v4l2output,
79               prop_id, value, pspec)) {
80         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
81       }
82       break;
83   }
84 }
85
86 static void
87 gst_v4l2_transform_get_property (GObject * object,
88     guint prop_id, GValue * value, GParamSpec * pspec)
89 {
90   GstV4l2Transform *self = GST_V4L2_TRANSFORM (object);
91
92   switch (prop_id) {
93     case PROP_CAPTURE_IO_MODE:
94       gst_v4l2_object_get_property_helper (self->v4l2capture, prop_id, value,
95           pspec);
96       break;
97
98       /* By default read from output */
99     default:
100       if (!gst_v4l2_object_get_property_helper (self->v4l2output,
101               prop_id, value, pspec)) {
102         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
103       }
104       break;
105   }
106 }
107
108 static gboolean
109 gst_v4l2_transform_open (GstV4l2Transform * self)
110 {
111   GST_DEBUG_OBJECT (self, "Opening");
112
113   if (!gst_v4l2_object_open (self->v4l2output))
114     goto failure;
115
116   if (!gst_v4l2_object_open_shared (self->v4l2capture, self->v4l2output))
117     goto failure;
118
119   self->probed_sinkcaps = gst_v4l2_object_get_caps (self->v4l2output,
120       gst_v4l2_object_get_raw_caps ());
121
122   if (gst_caps_is_empty (self->probed_sinkcaps))
123     goto no_input_format;
124
125   self->probed_srccaps = gst_v4l2_object_get_caps (self->v4l2capture,
126       gst_v4l2_object_get_raw_caps ());
127
128   if (gst_caps_is_empty (self->probed_srccaps))
129     goto no_output_format;
130
131   return TRUE;
132
133 no_input_format:
134   GST_ELEMENT_ERROR (self, RESOURCE, SETTINGS,
135       (_("Converter on device %s has no supported input format"),
136           self->v4l2output->videodev), (NULL));
137   goto failure;
138
139
140 no_output_format:
141   GST_ELEMENT_ERROR (self, RESOURCE, SETTINGS,
142       (_("Converter on device %s has no supported output format"),
143           self->v4l2output->videodev), (NULL));
144   goto failure;
145
146 failure:
147   if (GST_V4L2_IS_OPEN (self->v4l2output))
148     gst_v4l2_object_close (self->v4l2output);
149
150   if (GST_V4L2_IS_OPEN (self->v4l2capture))
151     gst_v4l2_object_close (self->v4l2capture);
152
153   gst_caps_replace (&self->probed_srccaps, NULL);
154   gst_caps_replace (&self->probed_sinkcaps, NULL);
155
156   return FALSE;
157 }
158
159 static void
160 gst_v4l2_transform_close (GstV4l2Transform * self)
161 {
162   GST_DEBUG_OBJECT (self, "Closing");
163
164   gst_v4l2_object_close (self->v4l2output);
165   gst_v4l2_object_close (self->v4l2capture);
166
167   gst_caps_replace (&self->probed_srccaps, NULL);
168   gst_caps_replace (&self->probed_sinkcaps, NULL);
169 }
170
171 static gboolean
172 gst_v4l2_transform_stop (GstBaseTransform * trans)
173 {
174   GstV4l2Transform *self = GST_V4L2_TRANSFORM (trans);
175
176   GST_DEBUG_OBJECT (self, "Stop");
177
178   gst_v4l2_object_stop (self->v4l2output);
179   gst_v4l2_object_stop (self->v4l2capture);
180   gst_caps_replace (&self->incaps, NULL);
181   gst_caps_replace (&self->outcaps, NULL);
182
183   return TRUE;
184 }
185
186 static gboolean
187 gst_v4l2_transform_set_caps (GstBaseTransform * trans, GstCaps * incaps,
188     GstCaps * outcaps)
189 {
190   GstV4l2Error error = GST_V4L2_ERROR_INIT;
191   GstV4l2Transform *self = GST_V4L2_TRANSFORM (trans);
192
193   if (self->incaps && self->outcaps) {
194     if (gst_caps_is_equal (incaps, self->incaps) &&
195         gst_caps_is_equal (outcaps, self->outcaps)) {
196       GST_DEBUG_OBJECT (trans, "Caps did not changed");
197       return TRUE;
198     }
199   }
200
201   /* TODO Add renegotiation support */
202   g_return_val_if_fail (!GST_V4L2_IS_ACTIVE (self->v4l2output), FALSE);
203   g_return_val_if_fail (!GST_V4L2_IS_ACTIVE (self->v4l2capture), FALSE);
204
205   gst_caps_replace (&self->incaps, incaps);
206   gst_caps_replace (&self->outcaps, outcaps);
207
208   if (!gst_v4l2_object_set_format (self->v4l2output, incaps, &error))
209     goto incaps_failed;
210
211   if (!gst_v4l2_object_set_format (self->v4l2capture, outcaps, &error))
212     goto outcaps_failed;
213
214   /* FIXME implement fallback if crop not supported */
215   if (!gst_v4l2_object_set_crop (self->v4l2output))
216     goto failed;
217
218   if (!gst_v4l2_object_set_crop (self->v4l2capture))
219     goto failed;
220
221   return TRUE;
222
223 incaps_failed:
224   {
225     GST_ERROR_OBJECT (self, "failed to set input caps: %" GST_PTR_FORMAT,
226         incaps);
227     gst_v4l2_error (self, &error);
228     goto failed;
229   }
230 outcaps_failed:
231   {
232     gst_v4l2_object_stop (self->v4l2output);
233     GST_ERROR_OBJECT (self, "failed to set output caps: %" GST_PTR_FORMAT,
234         outcaps);
235     gst_v4l2_error (self, &error);
236     goto failed;
237   }
238 failed:
239   return FALSE;
240 }
241
242 static gboolean
243 gst_v4l2_transform_query (GstBaseTransform * trans, GstPadDirection direction,
244     GstQuery * query)
245 {
246   GstV4l2Transform *self = GST_V4L2_TRANSFORM (trans);
247   gboolean ret = TRUE;
248
249   switch (GST_QUERY_TYPE (query)) {
250     case GST_QUERY_CAPS:{
251       GstCaps *filter, *caps = NULL, *result = NULL;
252       GstPad *pad, *otherpad;
253
254       gst_query_parse_caps (query, &filter);
255
256       if (direction == GST_PAD_SRC) {
257         pad = GST_BASE_TRANSFORM_SRC_PAD (trans);
258         otherpad = GST_BASE_TRANSFORM_SINK_PAD (trans);
259         if (self->probed_srccaps)
260           caps = gst_caps_ref (self->probed_srccaps);
261       } else {
262         pad = GST_BASE_TRANSFORM_SINK_PAD (trans);
263         otherpad = GST_BASE_TRANSFORM_SRC_PAD (trans);
264         if (self->probed_sinkcaps)
265           caps = gst_caps_ref (self->probed_sinkcaps);
266       }
267
268       if (!caps)
269         caps = gst_pad_get_pad_template_caps (pad);
270
271       if (filter) {
272         GstCaps *tmp = caps;
273         caps = gst_caps_intersect_full (filter, tmp, GST_CAPS_INTERSECT_FIRST);
274         gst_caps_unref (tmp);
275       }
276
277       result = gst_pad_peer_query_caps (otherpad, caps);
278       result = gst_caps_make_writable (result);
279       gst_caps_append (result, caps);
280
281       GST_DEBUG_OBJECT (self, "Returning %s caps %" GST_PTR_FORMAT,
282           GST_PAD_NAME (pad), result);
283
284       gst_query_set_caps_result (query, result);
285       gst_caps_unref (result);
286       break;
287     }
288
289     default:
290       ret = GST_BASE_TRANSFORM_CLASS (parent_class)->query (trans, direction,
291           query);
292       break;
293   }
294
295   return ret;
296 }
297
298 static gboolean
299 gst_v4l2_transform_decide_allocation (GstBaseTransform * trans,
300     GstQuery * query)
301 {
302   GstV4l2Transform *self = GST_V4L2_TRANSFORM (trans);
303   gboolean ret = FALSE;
304
305   GST_DEBUG_OBJECT (self, "called");
306
307   if (gst_v4l2_object_decide_allocation (self->v4l2capture, query)) {
308     GstBufferPool *pool = GST_BUFFER_POOL (self->v4l2capture->pool);
309
310     ret = GST_BASE_TRANSFORM_CLASS (parent_class)->decide_allocation (trans,
311         query);
312
313     if (!gst_buffer_pool_set_active (pool, TRUE))
314       goto activate_failed;
315   }
316
317   return ret;
318
319 activate_failed:
320   GST_ELEMENT_ERROR (self, RESOURCE, SETTINGS,
321       ("failed to activate bufferpool"), ("failed to activate bufferpool"));
322   return TRUE;
323 }
324
325 static gboolean
326 gst_v4l2_transform_propose_allocation (GstBaseTransform * trans,
327     GstQuery * decide_query, GstQuery * query)
328 {
329   GstV4l2Transform *self = GST_V4L2_TRANSFORM (trans);
330   gboolean ret = FALSE;
331
332   GST_DEBUG_OBJECT (self, "called");
333
334   if (decide_query == NULL)
335     ret = TRUE;
336   else
337     ret = gst_v4l2_object_propose_allocation (self->v4l2output, query);
338
339   if (ret)
340     ret = GST_BASE_TRANSFORM_CLASS (parent_class)->propose_allocation (trans,
341         decide_query, query);
342
343   return ret;
344 }
345
346 /* copies the given caps */
347 static GstCaps *
348 gst_v4l2_transform_caps_remove_format_info (GstCaps * caps)
349 {
350   GstStructure *st;
351   GstCapsFeatures *f;
352   gint i, n;
353   GstCaps *res;
354
355   res = gst_caps_new_empty ();
356
357   n = gst_caps_get_size (caps);
358   for (i = 0; i < n; i++) {
359     st = gst_caps_get_structure (caps, i);
360     f = gst_caps_get_features (caps, i);
361
362     /* If this is already expressed by the existing caps
363      * skip this structure */
364     if (i > 0 && gst_caps_is_subset_structure_full (res, st, f))
365       continue;
366
367     st = gst_structure_copy (st);
368     /* Only remove format info for the cases when we can actually convert */
369     if (!gst_caps_features_is_any (f)
370         && gst_caps_features_is_equal (f,
371             GST_CAPS_FEATURES_MEMORY_SYSTEM_MEMORY))
372       gst_structure_remove_fields (st, "format", "colorimetry", "chroma-site",
373           "width", "height", "pixel-aspect-ratio", NULL);
374
375     gst_caps_append_structure_full (res, st, gst_caps_features_copy (f));
376   }
377
378   return res;
379 }
380
381 /* The caps can be transformed into any other caps with format info removed.
382  * However, we should prefer passthrough, so if passthrough is possible,
383  * put it first in the list. */
384 static GstCaps *
385 gst_v4l2_transform_transform_caps (GstBaseTransform * btrans,
386     GstPadDirection direction, GstCaps * caps, GstCaps * filter)
387 {
388   GstCaps *tmp, *tmp2;
389   GstCaps *result;
390
391   /* Get all possible caps that we can transform to */
392   tmp = gst_v4l2_transform_caps_remove_format_info (caps);
393
394   if (filter) {
395     tmp2 = gst_caps_intersect_full (filter, tmp, GST_CAPS_INTERSECT_FIRST);
396     gst_caps_unref (tmp);
397     tmp = tmp2;
398   }
399
400   result = tmp;
401
402   GST_DEBUG_OBJECT (btrans, "transformed %" GST_PTR_FORMAT " into %"
403       GST_PTR_FORMAT, caps, result);
404
405   return result;
406 }
407
408 static GstCaps *
409 gst_v4l2_transform_fixate_caps (GstBaseTransform * trans,
410     GstPadDirection direction, GstCaps * caps, GstCaps * othercaps)
411 {
412   GstStructure *ins, *outs;
413   const GValue *from_par, *to_par;
414   GValue fpar = { 0, }, tpar = {
415   0,};
416
417   othercaps = gst_caps_truncate (othercaps);
418   othercaps = gst_caps_make_writable (othercaps);
419
420   GST_DEBUG_OBJECT (trans, "trying to fixate othercaps %" GST_PTR_FORMAT
421       " based on caps %" GST_PTR_FORMAT, othercaps, caps);
422
423   ins = gst_caps_get_structure (caps, 0);
424   outs = gst_caps_get_structure (othercaps, 0);
425
426   {
427     const gchar *in_format;
428
429     in_format = gst_structure_get_string (ins, "format");
430     if (in_format) {
431       /* Try to set output format for pass through */
432       gst_structure_fixate_field_string (outs, "format", in_format);
433     }
434
435   }
436
437   from_par = gst_structure_get_value (ins, "pixel-aspect-ratio");
438   to_par = gst_structure_get_value (outs, "pixel-aspect-ratio");
439
440   /* If we're fixating from the sinkpad we always set the PAR and
441    * assume that missing PAR on the sinkpad means 1/1 and
442    * missing PAR on the srcpad means undefined
443    */
444   if (direction == GST_PAD_SINK) {
445     if (!from_par) {
446       g_value_init (&fpar, GST_TYPE_FRACTION);
447       gst_value_set_fraction (&fpar, 1, 1);
448       from_par = &fpar;
449     }
450     if (!to_par) {
451       g_value_init (&tpar, GST_TYPE_FRACTION_RANGE);
452       gst_value_set_fraction_range_full (&tpar, 1, G_MAXINT, G_MAXINT, 1);
453       to_par = &tpar;
454     }
455   } else {
456     if (!to_par) {
457       g_value_init (&tpar, GST_TYPE_FRACTION);
458       gst_value_set_fraction (&tpar, 1, 1);
459       to_par = &tpar;
460
461       gst_structure_set (outs, "pixel-aspect-ratio", GST_TYPE_FRACTION, 1, 1,
462           NULL);
463     }
464     if (!from_par) {
465       g_value_init (&fpar, GST_TYPE_FRACTION);
466       gst_value_set_fraction (&fpar, 1, 1);
467       from_par = &fpar;
468     }
469   }
470
471   /* we have both PAR but they might not be fixated */
472   {
473     gint from_w, from_h, from_par_n, from_par_d, to_par_n, to_par_d;
474     gint w = 0, h = 0;
475     gint from_dar_n, from_dar_d;
476     gint num, den;
477
478     /* from_par should be fixed */
479     g_return_val_if_fail (gst_value_is_fixed (from_par), othercaps);
480
481     from_par_n = gst_value_get_fraction_numerator (from_par);
482     from_par_d = gst_value_get_fraction_denominator (from_par);
483
484     gst_structure_get_int (ins, "width", &from_w);
485     gst_structure_get_int (ins, "height", &from_h);
486
487     gst_structure_get_int (outs, "width", &w);
488     gst_structure_get_int (outs, "height", &h);
489
490     /* if both width and height are already fixed, we can't do anything
491      * about it anymore */
492     if (w && h) {
493       guint n, d;
494
495       GST_DEBUG_OBJECT (trans, "dimensions already set to %dx%d, not fixating",
496           w, h);
497       if (!gst_value_is_fixed (to_par)) {
498         if (gst_video_calculate_display_ratio (&n, &d, from_w, from_h,
499                 from_par_n, from_par_d, w, h)) {
500           GST_DEBUG_OBJECT (trans, "fixating to_par to %dx%d", n, d);
501           if (gst_structure_has_field (outs, "pixel-aspect-ratio"))
502             gst_structure_fixate_field_nearest_fraction (outs,
503                 "pixel-aspect-ratio", n, d);
504           else if (n != d)
505             gst_structure_set (outs, "pixel-aspect-ratio", GST_TYPE_FRACTION,
506                 n, d, NULL);
507         }
508       }
509       goto done;
510     }
511
512     /* Calculate input DAR */
513     if (!gst_util_fraction_multiply (from_w, from_h, from_par_n, from_par_d,
514             &from_dar_n, &from_dar_d)) {
515       GST_ELEMENT_ERROR (trans, CORE, NEGOTIATION, (NULL),
516           ("Error calculating the output scaled size - integer overflow"));
517       goto done;
518     }
519
520     GST_DEBUG_OBJECT (trans, "Input DAR is %d/%d", from_dar_n, from_dar_d);
521
522     /* If either width or height are fixed there's not much we
523      * can do either except choosing a height or width and PAR
524      * that matches the DAR as good as possible
525      */
526     if (h) {
527       GstStructure *tmp;
528       gint set_w, set_par_n, set_par_d;
529
530       GST_DEBUG_OBJECT (trans, "height is fixed (%d)", h);
531
532       /* If the PAR is fixed too, there's not much to do
533        * except choosing the width that is nearest to the
534        * width with the same DAR */
535       if (gst_value_is_fixed (to_par)) {
536         to_par_n = gst_value_get_fraction_numerator (to_par);
537         to_par_d = gst_value_get_fraction_denominator (to_par);
538
539         GST_DEBUG_OBJECT (trans, "PAR is fixed %d/%d", to_par_n, to_par_d);
540
541         if (!gst_util_fraction_multiply (from_dar_n, from_dar_d, to_par_d,
542                 to_par_n, &num, &den)) {
543           GST_ELEMENT_ERROR (trans, CORE, NEGOTIATION, (NULL),
544               ("Error calculating the output scaled size - integer overflow"));
545           goto done;
546         }
547
548         w = (guint) gst_util_uint64_scale_int (h, num, den);
549         gst_structure_fixate_field_nearest_int (outs, "width", w);
550
551         goto done;
552       }
553
554       /* The PAR is not fixed and it's quite likely that we can set
555        * an arbitrary PAR. */
556
557       /* Check if we can keep the input width */
558       tmp = gst_structure_copy (outs);
559       gst_structure_fixate_field_nearest_int (tmp, "width", from_w);
560       gst_structure_get_int (tmp, "width", &set_w);
561
562       /* Might have failed but try to keep the DAR nonetheless by
563        * adjusting the PAR */
564       if (!gst_util_fraction_multiply (from_dar_n, from_dar_d, h, set_w,
565               &to_par_n, &to_par_d)) {
566         GST_ELEMENT_ERROR (trans, CORE, NEGOTIATION, (NULL),
567             ("Error calculating the output scaled size - integer overflow"));
568         gst_structure_free (tmp);
569         goto done;
570       }
571
572       if (!gst_structure_has_field (tmp, "pixel-aspect-ratio"))
573         gst_structure_set_value (tmp, "pixel-aspect-ratio", to_par);
574       gst_structure_fixate_field_nearest_fraction (tmp, "pixel-aspect-ratio",
575           to_par_n, to_par_d);
576       gst_structure_get_fraction (tmp, "pixel-aspect-ratio", &set_par_n,
577           &set_par_d);
578       gst_structure_free (tmp);
579
580       /* Check if the adjusted PAR is accepted */
581       if (set_par_n == to_par_n && set_par_d == to_par_d) {
582         if (gst_structure_has_field (outs, "pixel-aspect-ratio") ||
583             set_par_n != set_par_d)
584           gst_structure_set (outs, "width", G_TYPE_INT, set_w,
585               "pixel-aspect-ratio", GST_TYPE_FRACTION, set_par_n, set_par_d,
586               NULL);
587         goto done;
588       }
589
590       /* Otherwise scale the width to the new PAR and check if the
591        * adjusted with is accepted. If all that fails we can't keep
592        * the DAR */
593       if (!gst_util_fraction_multiply (from_dar_n, from_dar_d, set_par_d,
594               set_par_n, &num, &den)) {
595         GST_ELEMENT_ERROR (trans, CORE, NEGOTIATION, (NULL),
596             ("Error calculating the output scaled size - integer overflow"));
597         goto done;
598       }
599
600       w = (guint) gst_util_uint64_scale_int (h, num, den);
601       gst_structure_fixate_field_nearest_int (outs, "width", w);
602       if (gst_structure_has_field (outs, "pixel-aspect-ratio") ||
603           set_par_n != set_par_d)
604         gst_structure_set (outs, "pixel-aspect-ratio", GST_TYPE_FRACTION,
605             set_par_n, set_par_d, NULL);
606
607       goto done;
608     } else if (w) {
609       GstStructure *tmp;
610       gint set_h, set_par_n, set_par_d;
611
612       GST_DEBUG_OBJECT (trans, "width is fixed (%d)", w);
613
614       /* If the PAR is fixed too, there's not much to do
615        * except choosing the height that is nearest to the
616        * height with the same DAR */
617       if (gst_value_is_fixed (to_par)) {
618         to_par_n = gst_value_get_fraction_numerator (to_par);
619         to_par_d = gst_value_get_fraction_denominator (to_par);
620
621         GST_DEBUG_OBJECT (trans, "PAR is fixed %d/%d", to_par_n, to_par_d);
622
623         if (!gst_util_fraction_multiply (from_dar_n, from_dar_d, to_par_d,
624                 to_par_n, &num, &den)) {
625           GST_ELEMENT_ERROR (trans, CORE, NEGOTIATION, (NULL),
626               ("Error calculating the output scaled size - integer overflow"));
627           goto done;
628         }
629
630         h = (guint) gst_util_uint64_scale_int (w, den, num);
631         gst_structure_fixate_field_nearest_int (outs, "height", h);
632
633         goto done;
634       }
635
636       /* The PAR is not fixed and it's quite likely that we can set
637        * an arbitrary PAR. */
638
639       /* Check if we can keep the input height */
640       tmp = gst_structure_copy (outs);
641       gst_structure_fixate_field_nearest_int (tmp, "height", from_h);
642       gst_structure_get_int (tmp, "height", &set_h);
643
644       /* Might have failed but try to keep the DAR nonetheless by
645        * adjusting the PAR */
646       if (!gst_util_fraction_multiply (from_dar_n, from_dar_d, set_h, w,
647               &to_par_n, &to_par_d)) {
648         GST_ELEMENT_ERROR (trans, CORE, NEGOTIATION, (NULL),
649             ("Error calculating the output scaled size - integer overflow"));
650         gst_structure_free (tmp);
651         goto done;
652       }
653       if (!gst_structure_has_field (tmp, "pixel-aspect-ratio"))
654         gst_structure_set_value (tmp, "pixel-aspect-ratio", to_par);
655       gst_structure_fixate_field_nearest_fraction (tmp, "pixel-aspect-ratio",
656           to_par_n, to_par_d);
657       gst_structure_get_fraction (tmp, "pixel-aspect-ratio", &set_par_n,
658           &set_par_d);
659       gst_structure_free (tmp);
660
661       /* Check if the adjusted PAR is accepted */
662       if (set_par_n == to_par_n && set_par_d == to_par_d) {
663         if (gst_structure_has_field (outs, "pixel-aspect-ratio") ||
664             set_par_n != set_par_d)
665           gst_structure_set (outs, "height", G_TYPE_INT, set_h,
666               "pixel-aspect-ratio", GST_TYPE_FRACTION, set_par_n, set_par_d,
667               NULL);
668         goto done;
669       }
670
671       /* Otherwise scale the height to the new PAR and check if the
672        * adjusted with is accepted. If all that fails we can't keep
673        * the DAR */
674       if (!gst_util_fraction_multiply (from_dar_n, from_dar_d, set_par_d,
675               set_par_n, &num, &den)) {
676         GST_ELEMENT_ERROR (trans, CORE, NEGOTIATION, (NULL),
677             ("Error calculating the output scaled size - integer overflow"));
678         goto done;
679       }
680
681       h = (guint) gst_util_uint64_scale_int (w, den, num);
682       gst_structure_fixate_field_nearest_int (outs, "height", h);
683       if (gst_structure_has_field (outs, "pixel-aspect-ratio") ||
684           set_par_n != set_par_d)
685         gst_structure_set (outs, "pixel-aspect-ratio", GST_TYPE_FRACTION,
686             set_par_n, set_par_d, NULL);
687
688       goto done;
689     } else if (gst_value_is_fixed (to_par)) {
690       GstStructure *tmp;
691       gint set_h, set_w, f_h, f_w;
692
693       to_par_n = gst_value_get_fraction_numerator (to_par);
694       to_par_d = gst_value_get_fraction_denominator (to_par);
695
696       GST_DEBUG_OBJECT (trans, "PAR is fixed %d/%d", to_par_n, to_par_d);
697
698       /* Calculate scale factor for the PAR change */
699       if (!gst_util_fraction_multiply (from_dar_n, from_dar_d, to_par_d,
700               to_par_n, &num, &den)) {
701         GST_ELEMENT_ERROR (trans, CORE, NEGOTIATION, (NULL),
702             ("Error calculating the output scaled size - integer overflow"));
703         goto done;
704       }
705
706       /* Try to keep the input height (because of interlacing) */
707       tmp = gst_structure_copy (outs);
708       gst_structure_fixate_field_nearest_int (tmp, "height", from_h);
709       gst_structure_get_int (tmp, "height", &set_h);
710
711       /* This might have failed but try to scale the width
712        * to keep the DAR nonetheless */
713       w = (guint) gst_util_uint64_scale_int (set_h, num, den);
714       gst_structure_fixate_field_nearest_int (tmp, "width", w);
715       gst_structure_get_int (tmp, "width", &set_w);
716       gst_structure_free (tmp);
717
718       /* We kept the DAR and the height is nearest to the original height */
719       if (set_w == w) {
720         gst_structure_set (outs, "width", G_TYPE_INT, set_w, "height",
721             G_TYPE_INT, set_h, NULL);
722         goto done;
723       }
724
725       f_h = set_h;
726       f_w = set_w;
727
728       /* If the former failed, try to keep the input width at least */
729       tmp = gst_structure_copy (outs);
730       gst_structure_fixate_field_nearest_int (tmp, "width", from_w);
731       gst_structure_get_int (tmp, "width", &set_w);
732
733       /* This might have failed but try to scale the width
734        * to keep the DAR nonetheless */
735       h = (guint) gst_util_uint64_scale_int (set_w, den, num);
736       gst_structure_fixate_field_nearest_int (tmp, "height", h);
737       gst_structure_get_int (tmp, "height", &set_h);
738       gst_structure_free (tmp);
739
740       /* We kept the DAR and the width is nearest to the original width */
741       if (set_h == h) {
742         gst_structure_set (outs, "width", G_TYPE_INT, set_w, "height",
743             G_TYPE_INT, set_h, NULL);
744         goto done;
745       }
746
747       /* If all this failed, keep the height that was nearest to the orignal
748        * height and the nearest possible width. This changes the DAR but
749        * there's not much else to do here.
750        */
751       gst_structure_set (outs, "width", G_TYPE_INT, f_w, "height", G_TYPE_INT,
752           f_h, NULL);
753       goto done;
754     } else {
755       GstStructure *tmp;
756       gint set_h, set_w, set_par_n, set_par_d, tmp2;
757
758       /* width, height and PAR are not fixed but passthrough is not possible */
759
760       /* First try to keep the height and width as good as possible
761        * and scale PAR */
762       tmp = gst_structure_copy (outs);
763       gst_structure_fixate_field_nearest_int (tmp, "height", from_h);
764       gst_structure_get_int (tmp, "height", &set_h);
765       gst_structure_fixate_field_nearest_int (tmp, "width", from_w);
766       gst_structure_get_int (tmp, "width", &set_w);
767
768       if (!gst_util_fraction_multiply (from_dar_n, from_dar_d, set_h, set_w,
769               &to_par_n, &to_par_d)) {
770         GST_ELEMENT_ERROR (trans, CORE, NEGOTIATION, (NULL),
771             ("Error calculating the output scaled size - integer overflow"));
772         gst_structure_free (tmp);
773         goto done;
774       }
775
776       if (!gst_structure_has_field (tmp, "pixel-aspect-ratio"))
777         gst_structure_set_value (tmp, "pixel-aspect-ratio", to_par);
778       gst_structure_fixate_field_nearest_fraction (tmp, "pixel-aspect-ratio",
779           to_par_n, to_par_d);
780       gst_structure_get_fraction (tmp, "pixel-aspect-ratio", &set_par_n,
781           &set_par_d);
782       gst_structure_free (tmp);
783
784       if (set_par_n == to_par_n && set_par_d == to_par_d) {
785         gst_structure_set (outs, "width", G_TYPE_INT, set_w, "height",
786             G_TYPE_INT, set_h, NULL);
787
788         if (gst_structure_has_field (outs, "pixel-aspect-ratio") ||
789             set_par_n != set_par_d)
790           gst_structure_set (outs, "pixel-aspect-ratio", GST_TYPE_FRACTION,
791               set_par_n, set_par_d, NULL);
792         goto done;
793       }
794
795       /* Otherwise try to scale width to keep the DAR with the set
796        * PAR and height */
797       if (!gst_util_fraction_multiply (from_dar_n, from_dar_d, set_par_d,
798               set_par_n, &num, &den)) {
799         GST_ELEMENT_ERROR (trans, CORE, NEGOTIATION, (NULL),
800             ("Error calculating the output scaled size - integer overflow"));
801         goto done;
802       }
803
804       w = (guint) gst_util_uint64_scale_int (set_h, num, den);
805       tmp = gst_structure_copy (outs);
806       gst_structure_fixate_field_nearest_int (tmp, "width", w);
807       gst_structure_get_int (tmp, "width", &tmp2);
808       gst_structure_free (tmp);
809
810       if (tmp2 == w) {
811         gst_structure_set (outs, "width", G_TYPE_INT, tmp2, "height",
812             G_TYPE_INT, set_h, NULL);
813         if (gst_structure_has_field (outs, "pixel-aspect-ratio") ||
814             set_par_n != set_par_d)
815           gst_structure_set (outs, "pixel-aspect-ratio", GST_TYPE_FRACTION,
816               set_par_n, set_par_d, NULL);
817         goto done;
818       }
819
820       /* ... or try the same with the height */
821       h = (guint) gst_util_uint64_scale_int (set_w, den, num);
822       tmp = gst_structure_copy (outs);
823       gst_structure_fixate_field_nearest_int (tmp, "height", h);
824       gst_structure_get_int (tmp, "height", &tmp2);
825       gst_structure_free (tmp);
826
827       if (tmp2 == h) {
828         gst_structure_set (outs, "width", G_TYPE_INT, set_w, "height",
829             G_TYPE_INT, tmp2, NULL);
830         if (gst_structure_has_field (outs, "pixel-aspect-ratio") ||
831             set_par_n != set_par_d)
832           gst_structure_set (outs, "pixel-aspect-ratio", GST_TYPE_FRACTION,
833               set_par_n, set_par_d, NULL);
834         goto done;
835       }
836
837       /* If all fails we can't keep the DAR and take the nearest values
838        * for everything from the first try */
839       gst_structure_set (outs, "width", G_TYPE_INT, set_w, "height",
840           G_TYPE_INT, set_h, NULL);
841       if (gst_structure_has_field (outs, "pixel-aspect-ratio") ||
842           set_par_n != set_par_d)
843         gst_structure_set (outs, "pixel-aspect-ratio", GST_TYPE_FRACTION,
844             set_par_n, set_par_d, NULL);
845     }
846   }
847
848 done:
849   GST_DEBUG_OBJECT (trans, "fixated othercaps to %" GST_PTR_FORMAT, othercaps);
850
851   if (from_par == &fpar)
852     g_value_unset (&fpar);
853   if (to_par == &tpar)
854     g_value_unset (&tpar);
855
856   /* fixate remaining fields */
857   othercaps = gst_caps_fixate (othercaps);
858
859   if (direction == GST_PAD_SINK) {
860     if (gst_caps_is_subset (caps, othercaps)) {
861       gst_caps_replace (&othercaps, caps);
862     }
863   }
864
865   return othercaps;
866 }
867
868 static GstFlowReturn
869 gst_v4l2_transform_prepare_output_buffer (GstBaseTransform * trans,
870     GstBuffer * inbuf, GstBuffer ** outbuf)
871 {
872   GstV4l2Transform *self = GST_V4L2_TRANSFORM (trans);
873   GstBufferPool *pool = GST_BUFFER_POOL (self->v4l2output->pool);
874   GstFlowReturn ret = GST_FLOW_OK;
875   GstBaseTransformClass *bclass = GST_BASE_TRANSFORM_CLASS (parent_class);
876
877   if (gst_base_transform_is_passthrough (trans)) {
878     GST_DEBUG_OBJECT (self, "Passthrough, no need to do anything");
879     *outbuf = inbuf;
880     goto beach;
881   }
882
883   /* Ensure input internal pool is active */
884   if (!gst_buffer_pool_is_active (pool)) {
885     GstStructure *config = gst_buffer_pool_get_config (pool);
886     gint min = self->v4l2output->min_buffers == 0 ? GST_V4L2_MIN_BUFFERS :
887         self->v4l2output->min_buffers;
888     gst_buffer_pool_config_set_params (config, self->incaps,
889         self->v4l2output->info.size, min, min);
890
891     /* There is no reason to refuse this config */
892     if (!gst_buffer_pool_set_config (pool, config))
893       goto activate_failed;
894
895     if (!gst_buffer_pool_set_active (pool, TRUE))
896       goto activate_failed;
897   }
898
899   GST_DEBUG_OBJECT (self, "Queue input buffer");
900   ret = gst_v4l2_buffer_pool_process (GST_V4L2_BUFFER_POOL (pool), &inbuf);
901   if (G_UNLIKELY (ret != GST_FLOW_OK))
902     goto beach;
903
904   do {
905     pool = gst_base_transform_get_buffer_pool (trans);
906
907     if (!gst_buffer_pool_set_active (pool, TRUE))
908       goto activate_failed;
909
910     GST_DEBUG_OBJECT (self, "Dequeue output buffer");
911     ret = gst_buffer_pool_acquire_buffer (pool, outbuf, NULL);
912     g_object_unref (pool);
913
914     if (ret != GST_FLOW_OK)
915       goto alloc_failed;
916
917     pool = self->v4l2capture->pool;
918     ret = gst_v4l2_buffer_pool_process (GST_V4L2_BUFFER_POOL (pool), outbuf);
919
920   } while (ret == GST_V4L2_FLOW_CORRUPTED_BUFFER);
921
922   if (ret != GST_FLOW_OK) {
923     gst_buffer_unref (*outbuf);
924     *outbuf = NULL;
925   }
926
927   if (bclass->copy_metadata)
928     if (!bclass->copy_metadata (trans, inbuf, *outbuf)) {
929       /* something failed, post a warning */
930       GST_ELEMENT_WARNING (self, STREAM, NOT_IMPLEMENTED,
931           ("could not copy metadata"), (NULL));
932     }
933
934 beach:
935   return ret;
936
937 activate_failed:
938   GST_ELEMENT_ERROR (self, RESOURCE, SETTINGS,
939       ("failed to activate bufferpool"), ("failed to activate bufferpool"));
940   g_object_unref (pool);
941   return GST_FLOW_ERROR;
942
943 alloc_failed:
944   GST_DEBUG_OBJECT (self, "could not allocate buffer from pool");
945   return ret;
946 }
947
948 static GstFlowReturn
949 gst_v4l2_transform_transform (GstBaseTransform * trans, GstBuffer * inbuf,
950     GstBuffer * outbuf)
951 {
952   /* Nothing to do */
953   return GST_FLOW_OK;
954 }
955
956 static gboolean
957 gst_v4l2_transform_sink_event (GstBaseTransform * trans, GstEvent * event)
958 {
959   GstV4l2Transform *self = GST_V4L2_TRANSFORM (trans);
960   gboolean ret;
961
962   /* Nothing to flush in passthrough */
963   if (gst_base_transform_is_passthrough (trans))
964     return GST_BASE_TRANSFORM_CLASS (parent_class)->sink_event (trans, event);
965
966   switch (GST_EVENT_TYPE (event)) {
967     case GST_EVENT_FLUSH_START:
968       GST_DEBUG_OBJECT (self, "flush start");
969       gst_v4l2_object_unlock (self->v4l2output);
970       gst_v4l2_object_unlock (self->v4l2capture);
971       break;
972     default:
973       break;
974   }
975
976   ret = GST_BASE_TRANSFORM_CLASS (parent_class)->sink_event (trans, event);
977
978   switch (GST_EVENT_TYPE (event)) {
979     case GST_EVENT_FLUSH_STOP:
980       /* Buffer should be back now */
981       GST_DEBUG_OBJECT (self, "flush stop");
982       gst_v4l2_object_unlock_stop (self->v4l2capture);
983       gst_v4l2_object_unlock_stop (self->v4l2output);
984       gst_v4l2_buffer_pool_flush (self->v4l2output->pool);
985       gst_v4l2_buffer_pool_flush (self->v4l2capture->pool);
986       break;
987     default:
988       break;
989   }
990
991   return ret;
992 }
993
994 static GstStateChangeReturn
995 gst_v4l2_transform_change_state (GstElement * element,
996     GstStateChange transition)
997 {
998   GstV4l2Transform *self = GST_V4L2_TRANSFORM (element);
999   GstStateChangeReturn ret;
1000
1001   switch (transition) {
1002     case GST_STATE_CHANGE_NULL_TO_READY:
1003       if (!gst_v4l2_transform_open (self))
1004         return GST_STATE_CHANGE_FAILURE;
1005       break;
1006     case GST_STATE_CHANGE_PAUSED_TO_READY:
1007       gst_v4l2_object_unlock (self->v4l2output);
1008       gst_v4l2_object_unlock (self->v4l2capture);
1009       break;
1010     default:
1011       break;
1012   }
1013
1014   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
1015
1016   switch (transition) {
1017     case GST_STATE_CHANGE_READY_TO_NULL:
1018       gst_v4l2_transform_close (self);
1019       break;
1020     default:
1021       break;
1022   }
1023
1024   return ret;
1025 }
1026
1027 static void
1028 gst_v4l2_transform_dispose (GObject * object)
1029 {
1030   GstV4l2Transform *self = GST_V4L2_TRANSFORM (object);
1031
1032   gst_caps_replace (&self->probed_sinkcaps, NULL);
1033   gst_caps_replace (&self->probed_srccaps, NULL);
1034
1035   G_OBJECT_CLASS (parent_class)->dispose (object);
1036 }
1037
1038 static void
1039 gst_v4l2_transform_finalize (GObject * object)
1040 {
1041   GstV4l2Transform *self = GST_V4L2_TRANSFORM (object);
1042
1043   gst_v4l2_object_destroy (self->v4l2capture);
1044   gst_v4l2_object_destroy (self->v4l2output);
1045
1046   G_OBJECT_CLASS (parent_class)->finalize (object);
1047 }
1048
1049 static void
1050 gst_v4l2_transform_init (GstV4l2Transform * self)
1051 {
1052   /* V4L2 object are created in subinstance_init */
1053   /* enable QoS */
1054   gst_base_transform_set_qos_enabled (GST_BASE_TRANSFORM (self), TRUE);
1055 }
1056
1057 static void
1058 gst_v4l2_transform_subinstance_init (GTypeInstance * instance, gpointer g_class)
1059 {
1060   GstV4l2TransformClass *klass = GST_V4L2_TRANSFORM_CLASS (g_class);
1061   GstV4l2Transform *self = GST_V4L2_TRANSFORM (instance);
1062
1063   self->v4l2output = gst_v4l2_object_new (GST_ELEMENT (self),
1064       GST_OBJECT (GST_BASE_TRANSFORM_SINK_PAD (self)),
1065       V4L2_BUF_TYPE_VIDEO_OUTPUT, klass->default_device,
1066       gst_v4l2_get_output, gst_v4l2_set_output, NULL);
1067   self->v4l2output->no_initial_format = TRUE;
1068   self->v4l2output->keep_aspect = FALSE;
1069
1070   self->v4l2capture = gst_v4l2_object_new (GST_ELEMENT (self),
1071       GST_OBJECT (GST_BASE_TRANSFORM_SRC_PAD (self)),
1072       V4L2_BUF_TYPE_VIDEO_CAPTURE, klass->default_device,
1073       gst_v4l2_get_input, gst_v4l2_set_input, NULL);
1074 }
1075
1076 static void
1077 gst_v4l2_transform_class_init (GstV4l2TransformClass * klass)
1078 {
1079   GstElementClass *element_class;
1080   GObjectClass *gobject_class;
1081   GstBaseTransformClass *base_transform_class;
1082
1083   element_class = (GstElementClass *) klass;
1084   gobject_class = (GObjectClass *) klass;
1085   base_transform_class = (GstBaseTransformClass *) klass;
1086
1087   GST_DEBUG_CATEGORY_INIT (gst_v4l2_transform_debug, "v4l2transform", 0,
1088       "V4L2 Converter");
1089
1090   gst_element_class_set_static_metadata (element_class,
1091       "V4L2 Video Converter",
1092       "Filter/Converter/Video/Scaler",
1093       "Transform streams via V4L2 API",
1094       "Nicolas Dufresne <nicolas.dufresne@collabora.com>");
1095
1096   gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_v4l2_transform_dispose);
1097   gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_v4l2_transform_finalize);
1098   gobject_class->set_property =
1099       GST_DEBUG_FUNCPTR (gst_v4l2_transform_set_property);
1100   gobject_class->get_property =
1101       GST_DEBUG_FUNCPTR (gst_v4l2_transform_get_property);
1102
1103   base_transform_class->stop = GST_DEBUG_FUNCPTR (gst_v4l2_transform_stop);
1104   base_transform_class->set_caps =
1105       GST_DEBUG_FUNCPTR (gst_v4l2_transform_set_caps);
1106   base_transform_class->query = GST_DEBUG_FUNCPTR (gst_v4l2_transform_query);
1107   base_transform_class->sink_event =
1108       GST_DEBUG_FUNCPTR (gst_v4l2_transform_sink_event);
1109   base_transform_class->decide_allocation =
1110       GST_DEBUG_FUNCPTR (gst_v4l2_transform_decide_allocation);
1111   base_transform_class->propose_allocation =
1112       GST_DEBUG_FUNCPTR (gst_v4l2_transform_propose_allocation);
1113   base_transform_class->transform_caps =
1114       GST_DEBUG_FUNCPTR (gst_v4l2_transform_transform_caps);
1115   base_transform_class->fixate_caps =
1116       GST_DEBUG_FUNCPTR (gst_v4l2_transform_fixate_caps);
1117   base_transform_class->prepare_output_buffer =
1118       GST_DEBUG_FUNCPTR (gst_v4l2_transform_prepare_output_buffer);
1119   base_transform_class->transform =
1120       GST_DEBUG_FUNCPTR (gst_v4l2_transform_transform);
1121
1122   base_transform_class->passthrough_on_same_caps = TRUE;
1123
1124   element_class->change_state =
1125       GST_DEBUG_FUNCPTR (gst_v4l2_transform_change_state);
1126
1127   gst_v4l2_object_install_m2m_properties_helper (gobject_class);
1128 }
1129
1130 static void
1131 gst_v4l2_transform_subclass_init (gpointer g_class, gpointer data)
1132 {
1133   GstV4l2TransformClass *klass = GST_V4L2_TRANSFORM_CLASS (g_class);
1134   GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
1135   GstV4l2TransformCData *cdata = data;
1136
1137   klass->default_device = cdata->device;
1138
1139   /* Note: gst_pad_template_new() take the floating ref from the caps */
1140   gst_element_class_add_pad_template (element_class,
1141       gst_pad_template_new ("sink", GST_PAD_SINK, GST_PAD_ALWAYS,
1142           cdata->sink_caps));
1143   gst_element_class_add_pad_template (element_class,
1144       gst_pad_template_new ("src", GST_PAD_SRC, GST_PAD_ALWAYS,
1145           cdata->src_caps));
1146
1147   g_free (cdata);
1148 }
1149
1150 /* Probing functions */
1151 gboolean
1152 gst_v4l2_is_transform (GstCaps * sink_caps, GstCaps * src_caps)
1153 {
1154   gboolean ret = FALSE;
1155
1156   if (gst_caps_is_subset (sink_caps, gst_v4l2_object_get_raw_caps ())
1157       && gst_caps_is_subset (src_caps, gst_v4l2_object_get_raw_caps ()))
1158     ret = TRUE;
1159
1160   return ret;
1161 }
1162
1163 void
1164 gst_v4l2_transform_register (GstPlugin * plugin, const gchar * basename,
1165     const gchar * device_path, GstCaps * sink_caps, GstCaps * src_caps)
1166 {
1167   GTypeQuery type_query;
1168   GTypeInfo type_info = { 0, };
1169   GType type, subtype;
1170   gchar *type_name;
1171   GstV4l2TransformCData *cdata;
1172
1173   cdata = g_new0 (GstV4l2TransformCData, 1);
1174   cdata->device = g_strdup (device_path);
1175   cdata->sink_caps = gst_caps_ref (sink_caps);
1176   cdata->src_caps = gst_caps_ref (src_caps);
1177
1178   type = gst_v4l2_transform_get_type ();
1179   g_type_query (type, &type_query);
1180   memset (&type_info, 0, sizeof (type_info));
1181   type_info.class_size = type_query.class_size;
1182   type_info.instance_size = type_query.instance_size;
1183   type_info.class_init = gst_v4l2_transform_subclass_init;
1184   type_info.class_data = cdata;
1185   type_info.instance_init = gst_v4l2_transform_subinstance_init;
1186
1187   if (g_type_from_name ("v4l2convert") != 0)
1188     type_name = g_strdup_printf ("v4l2%sconvert", basename);
1189   else
1190     type_name = g_strdup ("v4l2convert");
1191   subtype = g_type_register_static (type, type_name, &type_info, 0);
1192
1193   if (!gst_element_register (plugin, type_name, GST_RANK_NONE, subtype))
1194     GST_WARNING ("Failed to register plugin '%s'", type_name);
1195
1196   g_free (type_name);
1197 }