[v4l2videodecoder] Support TBM for output buffer
[platform/upstream/gst-plugins-good.git] / sys / v4l2 / gstv4l2videodec.c
1 /*
2  * Copyright (C) 2014 Collabora Ltd.
3  *     Author: Nicolas Dufresne <nicolas.dufresne@collabora.com>
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 "gstv4l2videodec.h"
34
35 #include <string.h>
36 #include <gst/gst-i18n-plugin.h>
37
38 GST_DEBUG_CATEGORY_STATIC (gst_v4l2_video_dec_debug);
39 #define GST_CAT_DEFAULT gst_v4l2_video_dec_debug
40
41 typedef struct
42 {
43   gchar *device;
44   GstCaps *sink_caps;
45   GstCaps *src_caps;
46   const gchar *longname;
47   const gchar *description;
48 } GstV4l2VideoDecCData;
49
50 enum
51 {
52   PROP_0,
53   V4L2_STD_OBJECT_PROPS
54 };
55
56 #define gst_v4l2_video_dec_parent_class parent_class
57 G_DEFINE_ABSTRACT_TYPE (GstV4l2VideoDec, gst_v4l2_video_dec,
58     GST_TYPE_VIDEO_DECODER);
59
60 static GstFlowReturn gst_v4l2_video_dec_finish (GstVideoDecoder * decoder);
61
62 #ifdef TIZEN_FEATURE_TBM_SUPPORT_FOR_V4L2_DECODER
63 static void gst_v4l2_video_dec_flush_buffer_event (GstVideoDecoder * decoder)
64 {
65   gboolean ret = FALSE;
66
67   if (!decoder) {
68     GST_ERROR("no decoder");
69     return;
70   }
71
72   ret = gst_pad_push_event (decoder->srcpad,
73       gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM | GST_EVENT_TYPE_SERIALIZED,
74           gst_structure_new_empty("tizen/flush-buffer")));
75
76   GST_WARNING_OBJECT(decoder, "event push ret[%d] for flush-buffer", ret);
77 }
78 #endif /* TIZEN_FEATURE_TBM_SUPPORT_FOR_V4L2_DECODER */
79 static void
80 gst_v4l2_video_dec_set_property (GObject * object,
81     guint prop_id, const GValue * value, GParamSpec * pspec)
82 {
83   GstV4l2VideoDec *self = GST_V4L2_VIDEO_DEC (object);
84
85   switch (prop_id) {
86     case PROP_CAPTURE_IO_MODE:
87       if (!gst_v4l2_object_set_property_helper (self->v4l2capture,
88               prop_id, value, pspec)) {
89         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
90       }
91       break;
92
93       /* By default, only set on output */
94     default:
95       if (!gst_v4l2_object_set_property_helper (self->v4l2output,
96               prop_id, value, pspec)) {
97         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
98       }
99       break;
100   }
101 }
102
103 static void
104 gst_v4l2_video_dec_get_property (GObject * object,
105     guint prop_id, GValue * value, GParamSpec * pspec)
106 {
107   GstV4l2VideoDec *self = GST_V4L2_VIDEO_DEC (object);
108
109   switch (prop_id) {
110     case PROP_CAPTURE_IO_MODE:
111       if (!gst_v4l2_object_get_property_helper (self->v4l2capture,
112               prop_id, value, pspec)) {
113         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
114       }
115       break;
116
117       /* By default read from output */
118     default:
119       if (!gst_v4l2_object_get_property_helper (self->v4l2output,
120               prop_id, value, pspec)) {
121         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
122       }
123       break;
124   }
125 }
126
127 static gboolean
128 gst_v4l2_video_dec_open (GstVideoDecoder * decoder)
129 {
130   GstV4l2VideoDec *self = GST_V4L2_VIDEO_DEC (decoder);
131   GstCaps *codec_caps;
132
133   GST_DEBUG_OBJECT (self, "Opening");
134
135   if (!gst_v4l2_object_open (self->v4l2output))
136     goto failure;
137
138   if (!gst_v4l2_object_open_shared (self->v4l2capture, self->v4l2output))
139     goto failure;
140
141   codec_caps = gst_pad_get_pad_template_caps (decoder->sinkpad);
142   self->probed_sinkcaps = gst_v4l2_object_probe_caps (self->v4l2output,
143       codec_caps);
144   gst_caps_unref (codec_caps);
145
146   if (gst_caps_is_empty (self->probed_sinkcaps))
147     goto no_encoded_format;
148
149   return TRUE;
150
151 no_encoded_format:
152   GST_ELEMENT_ERROR (self, RESOURCE, SETTINGS,
153       (_("Decoder on device %s has no supported input format"),
154           self->v4l2output->videodev), (NULL));
155   goto failure;
156
157 failure:
158   if (GST_V4L2_IS_OPEN (self->v4l2output))
159     gst_v4l2_object_close (self->v4l2output);
160
161   if (GST_V4L2_IS_OPEN (self->v4l2capture))
162     gst_v4l2_object_close (self->v4l2capture);
163
164   gst_caps_replace (&self->probed_srccaps, NULL);
165   gst_caps_replace (&self->probed_sinkcaps, NULL);
166
167   return FALSE;
168 }
169
170 static gboolean
171 gst_v4l2_video_dec_close (GstVideoDecoder * decoder)
172 {
173   GstV4l2VideoDec *self = GST_V4L2_VIDEO_DEC (decoder);
174
175   GST_DEBUG_OBJECT (self, "Closing");
176
177   gst_v4l2_object_close (self->v4l2output);
178   gst_v4l2_object_close (self->v4l2capture);
179   gst_caps_replace (&self->probed_srccaps, NULL);
180   gst_caps_replace (&self->probed_sinkcaps, NULL);
181
182   return TRUE;
183 }
184
185 static gboolean
186 gst_v4l2_video_dec_start (GstVideoDecoder * decoder)
187 {
188   GstV4l2VideoDec *self = GST_V4L2_VIDEO_DEC (decoder);
189
190   GST_DEBUG_OBJECT (self, "Starting");
191
192   gst_v4l2_object_unlock (self->v4l2output);
193   g_atomic_int_set (&self->active, TRUE);
194   self->output_flow = GST_FLOW_OK;
195
196   return TRUE;
197 }
198
199 static gboolean
200 gst_v4l2_video_dec_stop (GstVideoDecoder * decoder)
201 {
202   GstV4l2VideoDec *self = GST_V4L2_VIDEO_DEC (decoder);
203
204   GST_DEBUG_OBJECT (self, "Stopping");
205
206   gst_v4l2_object_unlock (self->v4l2output);
207   gst_v4l2_object_unlock (self->v4l2capture);
208
209   /* Wait for capture thread to stop */
210   gst_pad_stop_task (decoder->srcpad);
211
212   GST_VIDEO_DECODER_STREAM_LOCK (decoder);
213   self->output_flow = GST_FLOW_OK;
214   GST_VIDEO_DECODER_STREAM_UNLOCK (decoder);
215
216   /* Should have been flushed already */
217   g_assert (g_atomic_int_get (&self->active) == FALSE);
218 #ifdef TIZEN_FEATURE_TBM_SUPPORT_FOR_V4L2_DECODER
219   gst_v4l2_video_dec_flush_buffer_event (decoder);
220 #endif /* TIZEN_FEATURE_TBM_SUPPORT_FOR_V4L2_DECODER */
221
222   gst_v4l2_object_stop (self->v4l2output);
223   gst_v4l2_object_stop (self->v4l2capture);
224
225   if (self->input_state) {
226     gst_video_codec_state_unref (self->input_state);
227     self->input_state = NULL;
228   }
229
230   GST_DEBUG_OBJECT (self, "Stopped");
231
232   return TRUE;
233 }
234
235 static gboolean
236 gst_v4l2_video_dec_set_format (GstVideoDecoder * decoder,
237     GstVideoCodecState * state)
238 {
239   GstV4l2Error error = GST_V4L2_ERROR_INIT;
240   gboolean ret = TRUE;
241   GstV4l2VideoDec *self = GST_V4L2_VIDEO_DEC (decoder);
242
243   GST_DEBUG_OBJECT (self, "Setting format: %" GST_PTR_FORMAT, state->caps);
244
245   if (self->input_state) {
246     if (gst_v4l2_object_caps_equal (self->v4l2output, state->caps)) {
247       GST_DEBUG_OBJECT (self, "Compatible caps");
248       goto done;
249     }
250     gst_video_codec_state_unref (self->input_state);
251     self->input_state = NULL;
252
253     gst_v4l2_video_dec_finish (decoder);
254     gst_v4l2_object_stop (self->v4l2output);
255
256     /* The renegotiation flow don't blend with the base class flow. To properly
257      * stop the capture pool, if the buffers can't be orphaned, we need to
258      * reclaim our buffers, which will happend through the allocation query.
259      * The allocation query is triggered by gst_video_decoder_negotiate() which
260      * requires the output caps to be set, but we can't know this information
261      * as we rely on the decoder, which requires the capture queue to be
262      * stopped.
263      *
264      * To workaround this issue, we simply run an allocation query with the
265      * old negotiated caps in order to drain/reclaim our buffers. That breaks
266      * the complexity and should not have much impact in performance since the
267      * following allocation query will happen on a drained pipeline and won't
268      * block. */
269     if (self->v4l2capture->pool &&
270         !gst_v4l2_buffer_pool_orphan (&self->v4l2capture->pool)) {
271       GstCaps *caps = gst_pad_get_current_caps (decoder->srcpad);
272       if (caps) {
273         GstQuery *query = gst_query_new_allocation (caps, FALSE);
274         gst_pad_peer_query (decoder->srcpad, query);
275         gst_query_unref (query);
276         gst_caps_unref (caps);
277       }
278     }
279
280     gst_v4l2_object_stop (self->v4l2capture);
281     self->output_flow = GST_FLOW_OK;
282   }
283
284   ret = gst_v4l2_object_set_format (self->v4l2output, state->caps, &error);
285
286   gst_caps_replace (&self->probed_srccaps, NULL);
287   self->probed_srccaps = gst_v4l2_object_probe_caps (self->v4l2capture,
288       gst_v4l2_object_get_raw_caps ());
289
290   if (gst_caps_is_empty (self->probed_srccaps))
291     goto no_raw_format;
292
293   if (ret)
294     self->input_state = gst_video_codec_state_ref (state);
295   else
296     gst_v4l2_error (self, &error);
297
298 done:
299   return ret;
300
301 no_raw_format:
302   GST_ELEMENT_ERROR (self, RESOURCE, SETTINGS,
303       (_("Decoder on device %s has no supported output format"),
304           self->v4l2output->videodev), (NULL));
305   return GST_FLOW_ERROR;
306 }
307
308 static gboolean
309 gst_v4l2_video_dec_flush (GstVideoDecoder * decoder)
310 {
311   GstV4l2VideoDec *self = GST_V4L2_VIDEO_DEC (decoder);
312
313   GST_DEBUG_OBJECT (self, "Flushed");
314
315   /* Ensure the processing thread has stopped for the reverse playback
316    * discount case */
317   if (gst_pad_get_task_state (decoder->srcpad) == GST_TASK_STARTED) {
318     GST_VIDEO_DECODER_STREAM_UNLOCK (decoder);
319
320     gst_v4l2_object_unlock (self->v4l2output);
321     gst_v4l2_object_unlock (self->v4l2capture);
322     gst_pad_stop_task (decoder->srcpad);
323     GST_VIDEO_DECODER_STREAM_LOCK (decoder);
324   }
325
326   self->output_flow = GST_FLOW_OK;
327
328   gst_v4l2_object_unlock_stop (self->v4l2output);
329   gst_v4l2_object_unlock_stop (self->v4l2capture);
330
331   if (self->v4l2output->pool)
332     gst_v4l2_buffer_pool_flush (self->v4l2output->pool);
333
334 #ifdef TIZEN_FEATURE_TBM_SUPPORT_FOR_V4L2_DECODER
335   gst_v4l2_video_dec_flush_buffer_event (decoder);
336 #endif /* TIZEN_FEATURE_TBM_SUPPORT_FOR_V4L2_DECODER */
337   /* gst_v4l2_buffer_pool_flush() calls streamon the capture pool and must be
338    * called after gst_v4l2_object_unlock_stop() stopped flushing the buffer
339    * pool. */
340   if (self->v4l2capture->pool)
341     gst_v4l2_buffer_pool_flush (self->v4l2capture->pool);
342
343   return TRUE;
344 }
345
346 static gboolean
347 gst_v4l2_video_dec_negotiate (GstVideoDecoder * decoder)
348 {
349   GstV4l2VideoDec *self = GST_V4L2_VIDEO_DEC (decoder);
350
351   /* We don't allow renegotiation without carefull disabling the pool */
352   if (self->v4l2capture->pool &&
353       gst_buffer_pool_is_active (GST_BUFFER_POOL (self->v4l2capture->pool)))
354     return TRUE;
355
356   return GST_VIDEO_DECODER_CLASS (parent_class)->negotiate (decoder);
357 }
358
359 static gboolean
360 gst_v4l2_decoder_cmd (GstV4l2Object * v4l2object, guint cmd, guint flags)
361 {
362   struct v4l2_decoder_cmd dcmd = { 0, };
363
364   GST_DEBUG_OBJECT (v4l2object->element,
365       "sending v4l2 decoder command %u with flags %u", cmd, flags);
366
367   if (!GST_V4L2_IS_OPEN (v4l2object))
368     return FALSE;
369
370   dcmd.cmd = cmd;
371   dcmd.flags = flags;
372   if (v4l2object->ioctl (v4l2object->video_fd, VIDIOC_DECODER_CMD, &dcmd) < 0)
373     goto dcmd_failed;
374
375   return TRUE;
376
377 dcmd_failed:
378   if (errno == ENOTTY) {
379     GST_INFO_OBJECT (v4l2object->element,
380         "Failed to send decoder command %u with flags %u for '%s'. (%s)",
381         cmd, flags, v4l2object->videodev, g_strerror (errno));
382   } else {
383     GST_ERROR_OBJECT (v4l2object->element,
384         "Failed to send decoder command %u with flags %u for '%s'. (%s)",
385         cmd, flags, v4l2object->videodev, g_strerror (errno));
386   }
387   return FALSE;
388 }
389
390 static GstFlowReturn
391 gst_v4l2_video_dec_finish (GstVideoDecoder * decoder)
392 {
393   GstV4l2VideoDec *self = GST_V4L2_VIDEO_DEC (decoder);
394   GstFlowReturn ret = GST_FLOW_OK;
395   GstBuffer *buffer;
396
397   if (gst_pad_get_task_state (decoder->srcpad) != GST_TASK_STARTED)
398     goto done;
399
400   GST_DEBUG_OBJECT (self, "Finishing decoding");
401
402   GST_VIDEO_DECODER_STREAM_UNLOCK (decoder);
403
404   if (gst_v4l2_decoder_cmd (self->v4l2output, V4L2_DEC_CMD_STOP, 0)) {
405     GstTask *task = decoder->srcpad->task;
406
407     /* If the decoder stop command succeeded, just wait until processing is
408      * finished */
409     GST_DEBUG_OBJECT (self, "Waiting for decoder stop");
410     GST_OBJECT_LOCK (task);
411     while (GST_TASK_STATE (task) == GST_TASK_STARTED)
412       GST_TASK_WAIT (task);
413     GST_OBJECT_UNLOCK (task);
414     ret = GST_FLOW_FLUSHING;
415   } else {
416     /* otherwise keep queuing empty buffers until the processing thread has
417      * stopped, _pool_process() will return FLUSHING when that happened */
418     while (ret == GST_FLOW_OK) {
419       buffer = gst_buffer_new ();
420       ret =
421           gst_v4l2_buffer_pool_process (GST_V4L2_BUFFER_POOL (self->
422               v4l2output->pool), &buffer);
423       gst_buffer_unref (buffer);
424     }
425   }
426
427   /* and ensure the processing thread has stopped in case another error
428    * occured. */
429   gst_v4l2_object_unlock (self->v4l2capture);
430   gst_pad_stop_task (decoder->srcpad);
431   GST_VIDEO_DECODER_STREAM_LOCK (decoder);
432
433   if (ret == GST_FLOW_FLUSHING)
434     ret = self->output_flow;
435
436   GST_DEBUG_OBJECT (decoder, "Done draining buffers");
437
438   /* TODO Shall we cleanup any reffed frame to workaround broken decoders ? */
439
440 done:
441   return ret;
442 }
443
444 static GstFlowReturn
445 gst_v4l2_video_dec_drain (GstVideoDecoder * decoder)
446 {
447   GstV4l2VideoDec *self = GST_V4L2_VIDEO_DEC (decoder);
448
449   GST_DEBUG_OBJECT (self, "Draining...");
450   gst_v4l2_video_dec_finish (decoder);
451   gst_v4l2_video_dec_flush (decoder);
452
453   return GST_FLOW_OK;
454 }
455
456 static GstVideoCodecFrame *
457 gst_v4l2_video_dec_get_oldest_frame (GstVideoDecoder * decoder)
458 {
459   GstVideoCodecFrame *frame = NULL;
460   GList *frames, *l;
461   gint count = 0;
462
463   frames = gst_video_decoder_get_frames (decoder);
464
465   for (l = frames; l != NULL; l = l->next) {
466     GstVideoCodecFrame *f = l->data;
467
468     if (!frame || frame->pts > f->pts)
469       frame = f;
470
471     count++;
472   }
473
474   if (frame) {
475     GST_LOG_OBJECT (decoder,
476         "Oldest frame is %d %" GST_TIME_FORMAT " and %d frames left",
477         frame->system_frame_number, GST_TIME_ARGS (frame->pts), count - 1);
478     gst_video_codec_frame_ref (frame);
479   }
480
481   g_list_free_full (frames, (GDestroyNotify) gst_video_codec_frame_unref);
482
483   return frame;
484 }
485
486 static void
487 gst_v4l2_video_dec_loop (GstVideoDecoder * decoder)
488 {
489   GstV4l2VideoDec *self = GST_V4L2_VIDEO_DEC (decoder);
490   GstV4l2BufferPool *v4l2_pool = GST_V4L2_BUFFER_POOL (self->v4l2capture->pool);
491   GstBufferPool *pool;
492   GstVideoCodecFrame *frame;
493   GstBuffer *buffer = NULL;
494   GstFlowReturn ret;
495
496   GST_LOG_OBJECT (decoder, "Allocate output buffer");
497
498   self->output_flow = GST_FLOW_OK;
499   do {
500     /* We cannot use the base class allotate helper since it taking the internal
501      * stream lock. we know that the acquire may need to poll until more frames
502      * comes in and holding this lock would prevent that.
503      */
504     pool = gst_video_decoder_get_buffer_pool (decoder);
505
506     /* Pool may be NULL if we started going to READY state */
507     if (pool == NULL) {
508       ret = GST_FLOW_FLUSHING;
509       goto beach;
510     }
511
512     ret = gst_buffer_pool_acquire_buffer (pool, &buffer, NULL);
513     g_object_unref (pool);
514
515     if (ret != GST_FLOW_OK)
516       goto beach;
517
518     GST_LOG_OBJECT (decoder, "Process output buffer");
519     ret = gst_v4l2_buffer_pool_process (v4l2_pool, &buffer);
520
521   } while (ret == GST_V4L2_FLOW_CORRUPTED_BUFFER);
522
523   if (ret != GST_FLOW_OK)
524     goto beach;
525
526   frame = gst_v4l2_video_dec_get_oldest_frame (decoder);
527
528   if (frame) {
529     frame->output_buffer = buffer;
530     buffer = NULL;
531     ret = gst_video_decoder_finish_frame (decoder, frame);
532
533     if (ret != GST_FLOW_OK)
534       goto beach;
535   } else {
536     GST_WARNING_OBJECT (decoder, "Decoder is producing too many buffers");
537     gst_buffer_unref (buffer);
538   }
539
540   return;
541
542 beach:
543   GST_DEBUG_OBJECT (decoder, "Leaving output thread: %s",
544       gst_flow_get_name (ret));
545
546   gst_buffer_replace (&buffer, NULL);
547   self->output_flow = ret;
548   gst_v4l2_object_unlock (self->v4l2output);
549   gst_pad_pause_task (decoder->srcpad);
550 }
551
552 static gboolean
553 gst_v4l2_video_remove_padding (GstCapsFeatures * features,
554     GstStructure * structure, gpointer user_data)
555 {
556   GstV4l2VideoDec *self = GST_V4L2_VIDEO_DEC (user_data);
557   GstVideoAlignment *align = &self->v4l2capture->align;
558   GstVideoInfo *info = &self->v4l2capture->info;
559   int width, height;
560
561   if (!gst_structure_get_int (structure, "width", &width))
562     return TRUE;
563
564   if (!gst_structure_get_int (structure, "height", &height))
565     return TRUE;
566
567   if (align->padding_left != 0 || align->padding_top != 0 ||
568       height != info->height + align->padding_bottom)
569     return TRUE;
570
571   if (height == info->height + align->padding_bottom) {
572     /* Some drivers may round up width to the padded with */
573     if (width == info->width + align->padding_right)
574       gst_structure_set (structure,
575           "width", G_TYPE_INT, width - align->padding_right,
576           "height", G_TYPE_INT, height - align->padding_bottom, NULL);
577     /* Some drivers may keep visible width and only round up bytesperline */
578     else if (width == info->width)
579       gst_structure_set (structure,
580           "height", G_TYPE_INT, height - align->padding_bottom, NULL);
581   }
582
583   return TRUE;
584 }
585
586 static GstFlowReturn
587 gst_v4l2_video_dec_handle_frame (GstVideoDecoder * decoder,
588     GstVideoCodecFrame * frame)
589 {
590   GstV4l2Error error = GST_V4L2_ERROR_INIT;
591   GstV4l2VideoDec *self = GST_V4L2_VIDEO_DEC (decoder);
592   GstFlowReturn ret = GST_FLOW_OK;
593   gboolean processed = FALSE;
594   GstBuffer *tmp;
595   GstTaskState task_state;
596 #ifdef TIZEN_FEATURE_TBM_SUPPORT_FOR_V4L2_DECODER
597   GstStructure *structure = NULL;
598   const gchar *caps_format = NULL;
599 #endif /* TIZEN_FEATURE_TBM_SUPPORT_FOR_V4L2_DECODER */
600
601   GST_DEBUG_OBJECT (self, "Handling frame %d", frame->system_frame_number);
602
603   if (G_UNLIKELY (!g_atomic_int_get (&self->active)))
604     goto flushing;
605
606   if (G_UNLIKELY (!GST_V4L2_IS_ACTIVE (self->v4l2output))) {
607     if (!self->input_state)
608       goto not_negotiated;
609     if (!gst_v4l2_object_set_format (self->v4l2output, self->input_state->caps,
610             &error))
611       goto not_negotiated;
612   }
613
614   if (G_UNLIKELY (!GST_V4L2_IS_ACTIVE (self->v4l2capture))) {
615     GstBufferPool *pool = GST_BUFFER_POOL (self->v4l2output->pool);
616     GstVideoInfo info;
617     GstVideoCodecState *output_state;
618     GstBuffer *codec_data;
619     GstCaps *acquired_caps, *available_caps, *caps, *filter;
620     GstStructure *st;
621
622     GST_DEBUG_OBJECT (self, "Sending header");
623
624     codec_data = self->input_state->codec_data;
625
626     /* We are running in byte-stream mode, so we don't know the headers, but
627      * we need to send something, otherwise the decoder will refuse to
628      * intialize.
629      */
630     if (codec_data) {
631       gst_buffer_ref (codec_data);
632     } else {
633       codec_data = gst_buffer_ref (frame->input_buffer);
634       processed = TRUE;
635     }
636
637     /* Ensure input internal pool is active */
638     if (!gst_buffer_pool_is_active (pool)) {
639       GstStructure *config = gst_buffer_pool_get_config (pool);
640       gst_buffer_pool_config_set_params (config, self->input_state->caps,
641           self->v4l2output->info.size, 2, 2);
642
643       /* There is no reason to refuse this config */
644       if (!gst_buffer_pool_set_config (pool, config))
645         goto activate_failed;
646
647       if (!gst_buffer_pool_set_active (pool, TRUE))
648         goto activate_failed;
649     }
650
651     GST_VIDEO_DECODER_STREAM_UNLOCK (decoder);
652     ret =
653         gst_v4l2_buffer_pool_process (GST_V4L2_BUFFER_POOL (self->
654             v4l2output->pool), &codec_data);
655     GST_VIDEO_DECODER_STREAM_LOCK (decoder);
656
657     gst_buffer_unref (codec_data);
658
659     /* For decoders G_FMT returns coded size, G_SELECTION returns visible size
660      * in the compose rectangle. gst_v4l2_object_acquire_format() checks both
661      * and returns the visible size as with/height and the coded size as
662      * padding. */
663     if (!gst_v4l2_object_acquire_format (self->v4l2capture, &info))
664       goto not_negotiated;
665
666     /* Create caps from the acquired format, remove the format field */
667     acquired_caps = gst_video_info_to_caps (&info);
668     GST_DEBUG_OBJECT (self, "Acquired caps: %" GST_PTR_FORMAT, acquired_caps);
669     st = gst_caps_get_structure (acquired_caps, 0);
670     gst_structure_remove_fields (st, "format", "colorimetry", "chroma-site",
671         NULL);
672
673     /* Probe currently available pixel formats */
674     available_caps = gst_caps_copy (self->probed_srccaps);
675     GST_DEBUG_OBJECT (self, "Available caps: %" GST_PTR_FORMAT, available_caps);
676
677     /* Replace coded size with visible size, we want to negotiate visible size
678      * with downstream, not coded size. */
679     gst_caps_map_in_place (available_caps, gst_v4l2_video_remove_padding, self);
680
681     filter = gst_caps_intersect_full (available_caps, acquired_caps,
682         GST_CAPS_INTERSECT_FIRST);
683     GST_DEBUG_OBJECT (self, "Filtered caps: %" GST_PTR_FORMAT, filter);
684     gst_caps_unref (acquired_caps);
685     gst_caps_unref (available_caps);
686     caps = gst_pad_peer_query_caps (decoder->srcpad, filter);
687     gst_caps_unref (filter);
688
689     GST_DEBUG_OBJECT (self, "Possible decoded caps: %" GST_PTR_FORMAT, caps);
690     if (gst_caps_is_empty (caps)) {
691       gst_caps_unref (caps);
692       goto not_negotiated;
693     }
694
695     /* Fixate pixel format */
696     caps = gst_caps_fixate (caps);
697
698     GST_DEBUG_OBJECT (self, "Chosen decoded caps: %" GST_PTR_FORMAT, caps);
699 #ifdef TIZEN_FEATURE_TBM_SUPPORT_FOR_V4L2_DECODER
700     structure = gst_caps_get_structure (caps, 0);
701     caps_format = gst_structure_get_string (structure, "format");
702
703     if (!strcmp (caps_format, "I420")) {
704       GST_INFO_OBJECT (self, "I420 -> S420");
705       gst_caps_set_simple (caps, "format", G_TYPE_STRING, "S420", NULL);
706     } else if (!strcmp (caps_format, "NV12")) {
707       GST_INFO_OBJECT (self, "NV12 -> SN12");
708       gst_caps_set_simple (caps, "format", G_TYPE_STRING, "SN12", NULL);
709     }
710     GST_INFO_OBJECT (self, "Updated decoded caps: %" GST_PTR_FORMAT, caps);
711 #endif /* TIZEN_FEATURE_TBM_SUPPORT_FOR_V4L2_DECODER */
712
713     /* Try to set negotiated format, on success replace acquired format */
714     if (gst_v4l2_object_set_format (self->v4l2capture, caps, &error))
715       gst_video_info_from_caps (&info, caps);
716     else
717       gst_v4l2_clear_error (&error);
718     gst_caps_unref (caps);
719
720     output_state = gst_video_decoder_set_output_state (decoder,
721         info.finfo->format, info.width, info.height, self->input_state);
722
723     /* Copy the rest of the information, there might be more in the future */
724     output_state->info.interlace_mode = info.interlace_mode;
725     gst_video_codec_state_unref (output_state);
726
727     if (!gst_video_decoder_negotiate (decoder)) {
728       if (GST_PAD_IS_FLUSHING (decoder->srcpad))
729         goto flushing;
730       else
731         goto not_negotiated;
732     }
733
734     /* Ensure our internal pool is activated */
735     if (!gst_buffer_pool_set_active (GST_BUFFER_POOL (self->v4l2capture->pool),
736             TRUE))
737       goto activate_failed;
738   }
739
740   task_state = gst_pad_get_task_state (GST_VIDEO_DECODER_SRC_PAD (self));
741   if (task_state == GST_TASK_STOPPED || task_state == GST_TASK_PAUSED) {
742     /* It's possible that the processing thread stopped due to an error */
743     if (self->output_flow != GST_FLOW_OK &&
744         self->output_flow != GST_FLOW_FLUSHING) {
745       GST_DEBUG_OBJECT (self, "Processing loop stopped with error, leaving");
746       ret = self->output_flow;
747       goto drop;
748     }
749
750     GST_DEBUG_OBJECT (self, "Starting decoding thread");
751
752     /* Start the processing task, when it quits, the task will disable input
753      * processing to unlock input if draining, or prevent potential block */
754     self->output_flow = GST_FLOW_FLUSHING;
755     if (!gst_pad_start_task (decoder->srcpad,
756             (GstTaskFunction) gst_v4l2_video_dec_loop, self, NULL))
757       goto start_task_failed;
758   }
759
760   if (!processed) {
761     GST_VIDEO_DECODER_STREAM_UNLOCK (decoder);
762     ret =
763         gst_v4l2_buffer_pool_process (GST_V4L2_BUFFER_POOL (self->v4l2output->
764             pool), &frame->input_buffer);
765     GST_VIDEO_DECODER_STREAM_LOCK (decoder);
766
767     if (ret == GST_FLOW_FLUSHING) {
768       if (gst_pad_get_task_state (GST_VIDEO_DECODER_SRC_PAD (self)) !=
769           GST_TASK_STARTED)
770         ret = self->output_flow;
771       goto drop;
772     } else if (ret != GST_FLOW_OK) {
773       goto process_failed;
774     }
775   }
776
777   /* No need to keep input arround */
778   tmp = frame->input_buffer;
779   frame->input_buffer = gst_buffer_new ();
780   gst_buffer_copy_into (frame->input_buffer, tmp,
781       GST_BUFFER_COPY_FLAGS | GST_BUFFER_COPY_TIMESTAMPS |
782       GST_BUFFER_COPY_META, 0, 0);
783   gst_buffer_unref (tmp);
784
785   gst_video_codec_frame_unref (frame);
786   return ret;
787
788   /* ERRORS */
789 not_negotiated:
790   {
791     GST_ERROR_OBJECT (self, "not negotiated");
792     ret = GST_FLOW_NOT_NEGOTIATED;
793     gst_v4l2_error (self, &error);
794     goto drop;
795   }
796 activate_failed:
797   {
798     GST_ELEMENT_ERROR (self, RESOURCE, SETTINGS,
799         (_("Failed to allocate required memory.")),
800         ("Buffer pool activation failed"));
801     ret = GST_FLOW_ERROR;
802     goto drop;
803   }
804 flushing:
805   {
806     ret = GST_FLOW_FLUSHING;
807     goto drop;
808   }
809
810 start_task_failed:
811   {
812     GST_ELEMENT_ERROR (self, RESOURCE, FAILED,
813         (_("Failed to start decoding thread.")), (NULL));
814     ret = GST_FLOW_ERROR;
815     goto drop;
816   }
817 process_failed:
818   {
819     GST_ELEMENT_ERROR (self, RESOURCE, FAILED,
820         (_("Failed to process frame.")),
821         ("Maybe be due to not enough memory or failing driver"));
822     ret = GST_FLOW_ERROR;
823     goto drop;
824   }
825 drop:
826   {
827     gst_video_decoder_drop_frame (decoder, frame);
828     return ret;
829   }
830 }
831
832 static gboolean
833 gst_v4l2_video_dec_decide_allocation (GstVideoDecoder * decoder,
834     GstQuery * query)
835 {
836   GstV4l2VideoDec *self = GST_V4L2_VIDEO_DEC (decoder);
837   GstClockTime latency;
838   gboolean ret = FALSE;
839
840   if (gst_v4l2_object_decide_allocation (self->v4l2capture, query))
841     ret = GST_VIDEO_DECODER_CLASS (parent_class)->decide_allocation (decoder,
842         query);
843
844   if (GST_CLOCK_TIME_IS_VALID (self->v4l2capture->duration)) {
845     latency = self->v4l2capture->min_buffers * self->v4l2capture->duration;
846     GST_DEBUG_OBJECT (self, "Setting latency: %" GST_TIME_FORMAT " (%"
847         G_GUINT32_FORMAT " * %" G_GUINT64_FORMAT, GST_TIME_ARGS (latency),
848         self->v4l2capture->min_buffers, self->v4l2capture->duration);
849     gst_video_decoder_set_latency (decoder, latency, latency);
850   } else {
851     GST_WARNING_OBJECT (self, "Duration invalid, not setting latency");
852   }
853
854   return ret;
855 }
856
857 static gboolean
858 gst_v4l2_video_dec_src_query (GstVideoDecoder * decoder, GstQuery * query)
859 {
860   gboolean ret = TRUE;
861   GstV4l2VideoDec *self = GST_V4L2_VIDEO_DEC (decoder);
862
863   switch (GST_QUERY_TYPE (query)) {
864     case GST_QUERY_CAPS:{
865       GstCaps *filter, *result = NULL;
866       GstPad *pad = GST_VIDEO_DECODER_SRC_PAD (decoder);
867
868       gst_query_parse_caps (query, &filter);
869
870       if (self->probed_srccaps)
871         result = gst_caps_ref (self->probed_srccaps);
872       else
873         result = gst_pad_get_pad_template_caps (pad);
874
875       if (filter) {
876         GstCaps *tmp = result;
877         result =
878             gst_caps_intersect_full (filter, tmp, GST_CAPS_INTERSECT_FIRST);
879         gst_caps_unref (tmp);
880       }
881
882       GST_DEBUG_OBJECT (self, "Returning src caps %" GST_PTR_FORMAT, result);
883
884       gst_query_set_caps_result (query, result);
885       gst_caps_unref (result);
886       break;
887     }
888
889     default:
890       ret = GST_VIDEO_DECODER_CLASS (parent_class)->src_query (decoder, query);
891       break;
892   }
893
894   return ret;
895 }
896
897 static GstCaps *
898 gst_v4l2_video_dec_sink_getcaps (GstVideoDecoder * decoder, GstCaps * filter)
899 {
900   GstV4l2VideoDec *self = GST_V4L2_VIDEO_DEC (decoder);
901   GstCaps *result;
902
903   result = gst_video_decoder_proxy_getcaps (decoder, self->probed_sinkcaps,
904       filter);
905
906   GST_DEBUG_OBJECT (self, "Returning sink caps %" GST_PTR_FORMAT, result);
907
908   return result;
909 }
910
911 static gboolean
912 gst_v4l2_video_dec_sink_event (GstVideoDecoder * decoder, GstEvent * event)
913 {
914   GstV4l2VideoDec *self = GST_V4L2_VIDEO_DEC (decoder);
915   gboolean ret;
916   GstEventType type = GST_EVENT_TYPE (event);
917
918   switch (type) {
919     case GST_EVENT_FLUSH_START:
920       GST_DEBUG_OBJECT (self, "flush start");
921       gst_v4l2_object_unlock (self->v4l2output);
922       gst_v4l2_object_unlock (self->v4l2capture);
923       break;
924     default:
925       break;
926   }
927
928   ret = GST_VIDEO_DECODER_CLASS (parent_class)->sink_event (decoder, event);
929
930   switch (type) {
931     case GST_EVENT_FLUSH_START:
932       /* The processing thread should stop now, wait for it */
933       gst_pad_stop_task (decoder->srcpad);
934       GST_DEBUG_OBJECT (self, "flush start done");
935       break;
936     default:
937       break;
938   }
939
940   return ret;
941 }
942
943 static GstStateChangeReturn
944 gst_v4l2_video_dec_change_state (GstElement * element,
945     GstStateChange transition)
946 {
947   GstV4l2VideoDec *self = GST_V4L2_VIDEO_DEC (element);
948   GstVideoDecoder *decoder = GST_VIDEO_DECODER (element);
949
950   if (transition == GST_STATE_CHANGE_PAUSED_TO_READY) {
951     g_atomic_int_set (&self->active, FALSE);
952     gst_v4l2_object_unlock (self->v4l2output);
953     gst_v4l2_object_unlock (self->v4l2capture);
954     gst_pad_stop_task (decoder->srcpad);
955   }
956
957   return GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
958 }
959
960 static void
961 gst_v4l2_video_dec_dispose (GObject * object)
962 {
963   GstV4l2VideoDec *self = GST_V4L2_VIDEO_DEC (object);
964
965   gst_caps_replace (&self->probed_sinkcaps, NULL);
966   gst_caps_replace (&self->probed_srccaps, NULL);
967
968   G_OBJECT_CLASS (parent_class)->dispose (object);
969 }
970
971 static void
972 gst_v4l2_video_dec_finalize (GObject * object)
973 {
974   GstV4l2VideoDec *self = GST_V4L2_VIDEO_DEC (object);
975
976   gst_v4l2_object_destroy (self->v4l2capture);
977   gst_v4l2_object_destroy (self->v4l2output);
978
979   G_OBJECT_CLASS (parent_class)->finalize (object);
980 }
981
982 static void
983 gst_v4l2_video_dec_init (GstV4l2VideoDec * self)
984 {
985   /* V4L2 object are created in subinstance_init */
986 }
987
988 static void
989 gst_v4l2_video_dec_subinstance_init (GTypeInstance * instance, gpointer g_class)
990 {
991   GstV4l2VideoDecClass *klass = GST_V4L2_VIDEO_DEC_CLASS (g_class);
992   GstV4l2VideoDec *self = GST_V4L2_VIDEO_DEC (instance);
993   GstVideoDecoder *decoder = GST_VIDEO_DECODER (instance);
994
995   gst_video_decoder_set_packetized (decoder, TRUE);
996
997   self->v4l2output = gst_v4l2_object_new (GST_ELEMENT (self),
998       GST_OBJECT (GST_VIDEO_DECODER_SINK_PAD (self)),
999       V4L2_BUF_TYPE_VIDEO_OUTPUT, klass->default_device,
1000       gst_v4l2_get_output, gst_v4l2_set_output, NULL);
1001   self->v4l2output->no_initial_format = TRUE;
1002   self->v4l2output->keep_aspect = FALSE;
1003
1004   self->v4l2capture = gst_v4l2_object_new (GST_ELEMENT (self),
1005       GST_OBJECT (GST_VIDEO_DECODER_SRC_PAD (self)),
1006       V4L2_BUF_TYPE_VIDEO_CAPTURE, klass->default_device,
1007       gst_v4l2_get_input, gst_v4l2_set_input, NULL);
1008 }
1009
1010 static void
1011 gst_v4l2_video_dec_class_init (GstV4l2VideoDecClass * klass)
1012 {
1013   GstElementClass *element_class;
1014   GObjectClass *gobject_class;
1015   GstVideoDecoderClass *video_decoder_class;
1016
1017   parent_class = g_type_class_peek_parent (klass);
1018
1019   element_class = (GstElementClass *) klass;
1020   gobject_class = (GObjectClass *) klass;
1021   video_decoder_class = (GstVideoDecoderClass *) klass;
1022
1023   GST_DEBUG_CATEGORY_INIT (gst_v4l2_video_dec_debug, "v4l2videodec", 0,
1024       "V4L2 Video Decoder");
1025
1026   gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_v4l2_video_dec_dispose);
1027   gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_v4l2_video_dec_finalize);
1028   gobject_class->set_property =
1029       GST_DEBUG_FUNCPTR (gst_v4l2_video_dec_set_property);
1030   gobject_class->get_property =
1031       GST_DEBUG_FUNCPTR (gst_v4l2_video_dec_get_property);
1032
1033   video_decoder_class->open = GST_DEBUG_FUNCPTR (gst_v4l2_video_dec_open);
1034   video_decoder_class->close = GST_DEBUG_FUNCPTR (gst_v4l2_video_dec_close);
1035   video_decoder_class->start = GST_DEBUG_FUNCPTR (gst_v4l2_video_dec_start);
1036   video_decoder_class->stop = GST_DEBUG_FUNCPTR (gst_v4l2_video_dec_stop);
1037   video_decoder_class->finish = GST_DEBUG_FUNCPTR (gst_v4l2_video_dec_finish);
1038   video_decoder_class->flush = GST_DEBUG_FUNCPTR (gst_v4l2_video_dec_flush);
1039   video_decoder_class->drain = GST_DEBUG_FUNCPTR (gst_v4l2_video_dec_drain);
1040   video_decoder_class->set_format =
1041       GST_DEBUG_FUNCPTR (gst_v4l2_video_dec_set_format);
1042   video_decoder_class->negotiate =
1043       GST_DEBUG_FUNCPTR (gst_v4l2_video_dec_negotiate);
1044   video_decoder_class->decide_allocation =
1045       GST_DEBUG_FUNCPTR (gst_v4l2_video_dec_decide_allocation);
1046   /* FIXME propose_allocation or not ? */
1047   video_decoder_class->handle_frame =
1048       GST_DEBUG_FUNCPTR (gst_v4l2_video_dec_handle_frame);
1049   video_decoder_class->getcaps =
1050       GST_DEBUG_FUNCPTR (gst_v4l2_video_dec_sink_getcaps);
1051   video_decoder_class->src_query =
1052       GST_DEBUG_FUNCPTR (gst_v4l2_video_dec_src_query);
1053   video_decoder_class->sink_event =
1054       GST_DEBUG_FUNCPTR (gst_v4l2_video_dec_sink_event);
1055
1056   element_class->change_state =
1057       GST_DEBUG_FUNCPTR (gst_v4l2_video_dec_change_state);
1058
1059   gst_v4l2_object_install_m2m_properties_helper (gobject_class);
1060 }
1061
1062 static void
1063 gst_v4l2_video_dec_subclass_init (gpointer g_class, gpointer data)
1064 {
1065   GstV4l2VideoDecClass *klass = GST_V4L2_VIDEO_DEC_CLASS (g_class);
1066   GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
1067   GstV4l2VideoDecCData *cdata = data;
1068
1069   klass->default_device = cdata->device;
1070
1071   /* Note: gst_pad_template_new() take the floating ref from the caps */
1072   gst_element_class_add_pad_template (element_class,
1073       gst_pad_template_new ("sink", GST_PAD_SINK, GST_PAD_ALWAYS,
1074           cdata->sink_caps));
1075   gst_element_class_add_pad_template (element_class,
1076       gst_pad_template_new ("src", GST_PAD_SRC, GST_PAD_ALWAYS,
1077           cdata->src_caps));
1078
1079   gst_element_class_set_static_metadata (element_class, cdata->longname,
1080       "Codec/Decoder/Video/Hardware", cdata->description,
1081       "Nicolas Dufresne <nicolas.dufresne@collabora.com>");
1082
1083   gst_caps_unref (cdata->sink_caps);
1084   gst_caps_unref (cdata->src_caps);
1085   g_free (cdata);
1086 }
1087
1088 /* Probing functions */
1089 gboolean
1090 gst_v4l2_is_video_dec (GstCaps * sink_caps, GstCaps * src_caps)
1091 {
1092   gboolean ret = FALSE;
1093
1094   if (gst_caps_is_subset (sink_caps, gst_v4l2_object_get_codec_caps ())
1095       && gst_caps_is_subset (src_caps, gst_v4l2_object_get_raw_caps ()))
1096     ret = TRUE;
1097
1098   return ret;
1099 }
1100
1101 static gchar *
1102 gst_v4l2_video_dec_set_metadata (GstStructure * s, GstV4l2VideoDecCData * cdata,
1103     const gchar * basename)
1104 {
1105   gchar *codec_name = NULL;
1106   gchar *type_name = NULL;
1107
1108 #define SET_META(codec) \
1109 G_STMT_START { \
1110   cdata->longname = "V4L2 " codec " Decoder"; \
1111   cdata->description = "Decodes " codec " streams via V4L2 API"; \
1112   codec_name = g_ascii_strdown (codec, -1); \
1113 } G_STMT_END
1114
1115   if (gst_structure_has_name (s, "image/jpeg")) {
1116     SET_META ("JPEG");
1117   } else if (gst_structure_has_name (s, "video/mpeg")) {
1118     gint mpegversion = 0;
1119     gst_structure_get_int (s, "mpegversion", &mpegversion);
1120
1121     if (mpegversion == 2) {
1122       SET_META ("MPEG2");
1123     } else {
1124       SET_META ("MPEG4");
1125     }
1126   } else if (gst_structure_has_name (s, "video/x-h263")) {
1127     SET_META ("H263");
1128   } else if (gst_structure_has_name (s, "video/x-fwht")) {
1129     SET_META ("FWHT");
1130   } else if (gst_structure_has_name (s, "video/x-h264")) {
1131     SET_META ("H264");
1132   } else if (gst_structure_has_name (s, "video/x-h265")) {
1133     SET_META ("H265");
1134   } else if (gst_structure_has_name (s, "video/x-wmv")) {
1135     SET_META ("VC1");
1136   } else if (gst_structure_has_name (s, "video/x-vp8")) {
1137     SET_META ("VP8");
1138   } else if (gst_structure_has_name (s, "video/x-vp9")) {
1139     SET_META ("VP9");
1140   } else if (gst_structure_has_name (s, "video/x-bayer")) {
1141     SET_META ("BAYER");
1142   } else if (gst_structure_has_name (s, "video/x-sonix")) {
1143     SET_META ("SONIX");
1144   } else if (gst_structure_has_name (s, "video/x-pwc1")) {
1145     SET_META ("PWC1");
1146   } else if (gst_structure_has_name (s, "video/x-pwc2")) {
1147     SET_META ("PWC2");
1148   } else {
1149     /* This code should be kept on sync with the exposed CODEC type of format
1150      * from gstv4l2object.c. This warning will only occure in case we forget
1151      * to also add a format here. */
1152     gchar *s_str = gst_structure_to_string (s);
1153     g_warning ("Missing fixed name mapping for caps '%s', this is a GStreamer "
1154         "bug, please report at https://bugs.gnome.org", s_str);
1155     g_free (s_str);
1156   }
1157
1158   if (codec_name) {
1159     type_name = g_strdup_printf ("v4l2%sdec", codec_name);
1160     if (g_type_from_name (type_name) != 0) {
1161       g_free (type_name);
1162       type_name = g_strdup_printf ("v4l2%s%sdec", basename, codec_name);
1163     }
1164
1165     g_free (codec_name);
1166   }
1167
1168   return type_name;
1169 #undef SET_META
1170 }
1171
1172 void
1173 gst_v4l2_video_dec_register (GstPlugin * plugin, const gchar * basename,
1174     const gchar * device_path, GstCaps * sink_caps, GstCaps * src_caps)
1175 {
1176   gint i;
1177
1178   for (i = 0; i < gst_caps_get_size (sink_caps); i++) {
1179     GstV4l2VideoDecCData *cdata;
1180     GstStructure *s;
1181     GTypeQuery type_query;
1182     GTypeInfo type_info = { 0, };
1183     GType type, subtype;
1184     gchar *type_name;
1185
1186     s = gst_caps_get_structure (sink_caps, i);
1187
1188     cdata = g_new0 (GstV4l2VideoDecCData, 1);
1189     cdata->device = g_strdup (device_path);
1190     cdata->sink_caps = gst_caps_new_empty ();
1191     gst_caps_append_structure (cdata->sink_caps, gst_structure_copy (s));
1192     cdata->src_caps = gst_caps_ref (src_caps);
1193     type_name = gst_v4l2_video_dec_set_metadata (s, cdata, basename);
1194
1195     /* Skip over if we hit an unmapped type */
1196     if (!type_name) {
1197       g_free (cdata);
1198       continue;
1199     }
1200
1201     type = gst_v4l2_video_dec_get_type ();
1202     g_type_query (type, &type_query);
1203     memset (&type_info, 0, sizeof (type_info));
1204     type_info.class_size = type_query.class_size;
1205     type_info.instance_size = type_query.instance_size;
1206     type_info.class_init = gst_v4l2_video_dec_subclass_init;
1207     type_info.class_data = cdata;
1208     type_info.instance_init = gst_v4l2_video_dec_subinstance_init;
1209
1210     subtype = g_type_register_static (type, type_name, &type_info, 0);
1211 #ifdef TIZEN_FEATURE_V4L2VIDEO_ADJ_RANK
1212     if (!gst_element_register (plugin, type_name, GST_RANK_PRIMARY,
1213             subtype))
1214       GST_WARNING ("Failed to register plugin '%s'", type_name);
1215 #else
1216     if (!gst_element_register (plugin, type_name, GST_RANK_PRIMARY + 1,
1217             subtype))
1218       GST_WARNING ("Failed to register plugin '%s'", type_name);
1219 #endif
1220
1221     g_free (type_name);
1222   }
1223 }