2 * Copyright (C) 2014 Collabora Ltd.
3 * Author: Nicolas Dufresne <nicolas.dufresne@collabora.co.uk>
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.
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.
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.
32 #include "gstv4l2videodec.h"
33 #include "v4l2_calls.h"
36 #include <gst/gst-i18n-plugin.h>
38 #define DEFAULT_PROP_DEVICE "/dev/video0"
40 #define V4L2_VIDEO_DEC_QUARK \
41 g_quark_from_static_string("gst-v4l2-video-dec-info")
43 GST_DEBUG_CATEGORY_STATIC (gst_v4l2_video_dec_debug);
44 #define GST_CAT_DEFAULT gst_v4l2_video_dec_debug
46 static gboolean gst_v4l2_video_dec_flush (GstVideoDecoder * decoder);
53 } Gstv4l2VideoDecQData;
58 V4L2_STD_OBJECT_PROPS,
62 static void gst_v4l2_video_dec_class_init (GstV4l2VideoDecClass * klass);
63 static void gst_v4l2_video_dec_init (GstV4l2VideoDec * self, gpointer g_class);
64 static void gst_v4l2_video_dec_base_init (gpointer g_class);
66 static GstVideoDecoderClass *parent_class = NULL;
69 gst_v4l2_video_dec_get_type (void)
71 static volatile gsize type = 0;
73 if (g_once_init_enter (&type)) {
75 static const GTypeInfo info = {
76 sizeof (GstV4l2VideoDecClass),
77 gst_v4l2_video_dec_base_init,
79 (GClassInitFunc) gst_v4l2_video_dec_class_init,
82 sizeof (GstV4l2VideoDec),
84 (GInstanceInitFunc) gst_v4l2_video_dec_init,
88 _type = g_type_register_static (GST_TYPE_VIDEO_DECODER, "GstV4l2VideoDec",
91 g_once_init_leave (&type, _type);
97 gst_v4l2_video_dec_set_property (GObject * object,
98 guint prop_id, const GValue * value, GParamSpec * pspec)
100 GstV4l2VideoDec *self = GST_V4L2_VIDEO_DEC (object);
103 /* Split IO mode so output is configure through 'io-mode' and capture
104 * through 'capture-io-mode' */
106 gst_v4l2_object_set_property_helper (self->v4l2output, prop_id, value,
109 case PROP_CAPTURE_IO_MODE:
110 gst_v4l2_object_set_property_helper (self->v4l2capture, prop_id, value,
115 gst_v4l2_object_set_property_helper (self->v4l2output, prop_id, value,
117 gst_v4l2_object_set_property_helper (self->v4l2capture, prop_id, value,
121 /* By default, only set on output */
123 if (!gst_v4l2_object_set_property_helper (self->v4l2output,
124 prop_id, value, pspec)) {
125 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
132 gst_v4l2_video_dec_get_property (GObject * object,
133 guint prop_id, GValue * value, GParamSpec * pspec)
135 GstV4l2VideoDec *self = GST_V4L2_VIDEO_DEC (object);
139 gst_v4l2_object_get_property_helper (self->v4l2output, prop_id, value,
142 case PROP_CAPTURE_IO_MODE:
143 gst_v4l2_object_get_property_helper (self->v4l2output, PROP_IO_MODE,
147 /* By default read from output */
149 if (!gst_v4l2_object_get_property_helper (self->v4l2output,
150 prop_id, value, pspec)) {
151 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
158 gst_v4l2_video_dec_open (GstVideoDecoder * decoder)
160 GstV4l2VideoDec *self = GST_V4L2_VIDEO_DEC (decoder);
162 GST_DEBUG_OBJECT (self, "Opening");
164 if (!gst_v4l2_object_open (self->v4l2output))
167 if (!gst_v4l2_object_open_shared (self->v4l2capture, self->v4l2output))
170 self->probed_sinkcaps = gst_v4l2_object_get_caps (self->v4l2output,
171 gst_v4l2_object_get_codec_caps ());
173 if (gst_caps_is_empty (self->probed_sinkcaps))
174 goto no_encoded_format;
176 self->probed_srccaps = gst_v4l2_object_get_caps (self->v4l2capture,
177 gst_v4l2_object_get_raw_caps ());
179 if (gst_caps_is_empty (self->probed_srccaps))
185 GST_ELEMENT_ERROR (self, RESOURCE, SETTINGS,
186 (_("Encoder on device %s has no supported input format"),
187 self->v4l2output->videodev), (NULL));
192 GST_ELEMENT_ERROR (self, RESOURCE, SETTINGS,
193 (_("Encoder on device %s has no supported output format"),
194 self->v4l2output->videodev), (NULL));
198 if (GST_V4L2_IS_OPEN (self->v4l2output))
199 gst_v4l2_object_close (self->v4l2output);
201 if (GST_V4L2_IS_OPEN (self->v4l2capture))
202 gst_v4l2_object_close (self->v4l2capture);
204 gst_caps_replace (&self->probed_srccaps, NULL);
205 gst_caps_replace (&self->probed_sinkcaps, NULL);
211 gst_v4l2_video_dec_close (GstVideoDecoder * decoder)
213 GstV4l2VideoDec *self = GST_V4L2_VIDEO_DEC (decoder);
215 GST_DEBUG_OBJECT (self, "Closing");
217 gst_v4l2_object_close (self->v4l2output);
218 gst_v4l2_object_close (self->v4l2capture);
219 gst_caps_replace (&self->probed_srccaps, NULL);
220 gst_caps_replace (&self->probed_sinkcaps, NULL);
226 gst_v4l2_video_dec_start (GstVideoDecoder * decoder)
228 GstV4l2VideoDec *self = GST_V4L2_VIDEO_DEC (decoder);
230 GST_DEBUG_OBJECT (self, "Starting");
232 gst_v4l2_object_unlock (self->v4l2output);
233 g_atomic_int_set (&self->active, TRUE);
234 self->output_flow = GST_FLOW_OK;
240 gst_v4l2_video_dec_stop (GstVideoDecoder * decoder)
242 GstV4l2VideoDec *self = GST_V4L2_VIDEO_DEC (decoder);
244 GST_DEBUG_OBJECT (self, "Stopping");
246 /* Should have been flushed already */
247 g_assert (g_atomic_int_get (&self->active) == FALSE);
248 g_assert (g_atomic_int_get (&self->processing) == FALSE);
250 gst_v4l2_object_stop (self->v4l2output);
251 gst_v4l2_object_stop (self->v4l2capture);
253 if (self->input_state) {
254 gst_video_codec_state_unref (self->input_state);
255 self->input_state = NULL;
258 GST_DEBUG_OBJECT (self, "Stopped");
264 gst_v4l2_video_dec_set_format (GstVideoDecoder * decoder,
265 GstVideoCodecState * state)
268 GstV4l2VideoDec *self = GST_V4L2_VIDEO_DEC (decoder);
270 GST_DEBUG_OBJECT (self, "Setting format: %" GST_PTR_FORMAT, state->caps);
272 if (self->input_state) {
273 if (gst_v4l2_object_caps_equal (self->v4l2output, state->caps)) {
274 GST_DEBUG_OBJECT (self, "Compatible caps");
277 gst_video_codec_state_unref (self->input_state);
279 /* FIXME we probably need to do more work if pools are active */
282 ret = gst_v4l2_object_set_format (self->v4l2output, state->caps);
285 self->input_state = gst_video_codec_state_ref (state);
292 gst_v4l2_video_dec_flush (GstVideoDecoder * decoder)
294 GstV4l2VideoDec *self = GST_V4L2_VIDEO_DEC (decoder);
296 GST_DEBUG_OBJECT (self, "Flushing");
298 /* Wait for capture thread to stop */
299 gst_pad_stop_task (decoder->srcpad);
300 self->output_flow = GST_FLOW_OK;
302 gst_v4l2_buffer_pool_flush (GST_V4L2_BUFFER_POOL (self->v4l2output->pool));
303 gst_v4l2_buffer_pool_flush (GST_V4L2_BUFFER_POOL (self->v4l2capture->pool));
305 /* Output will remain flushing until new frame comes in */
306 gst_v4l2_object_unlock_stop (self->v4l2capture);
312 gst_v4l2_video_dec_negotiate (GstVideoDecoder * decoder)
314 return GST_VIDEO_DECODER_CLASS (parent_class)->negotiate (decoder);
318 gst_v4l2_video_dec_finish (GstVideoDecoder * decoder)
320 GstV4l2VideoDec *self = GST_V4L2_VIDEO_DEC (decoder);
321 GstFlowReturn ret = GST_FLOW_OK;
324 if (!self->input_state)
327 GST_DEBUG_OBJECT (self, "Finishing decoding");
329 /* Keep queuing empty buffers until the processing thread has stopped,
330 * _pool_process() will return FLUSHING when that happened */
331 GST_VIDEO_DECODER_STREAM_UNLOCK (decoder);
332 while (ret == GST_FLOW_OK) {
333 buffer = gst_buffer_new ();
335 gst_v4l2_buffer_pool_process (GST_V4L2_BUFFER_POOL (self->
336 v4l2output->pool), buffer);
337 gst_buffer_unref (buffer);
339 GST_VIDEO_DECODER_STREAM_LOCK (decoder);
341 g_assert (g_atomic_int_get (&self->processing) == FALSE);
343 if (ret == GST_FLOW_FLUSHING)
344 ret = self->output_flow;
346 GST_DEBUG_OBJECT (decoder, "Done draining buffers");
352 static GstVideoCodecFrame *
353 gst_v4l2_video_dec_get_oldest_frame (GstVideoDecoder * decoder)
355 GstVideoCodecFrame *frame = NULL;
359 frames = gst_video_decoder_get_frames (decoder);
361 for (l = frames; l != NULL; l = l->next) {
362 GstVideoCodecFrame *f = l->data;
364 if (!frame || frame->pts > f->pts)
371 GST_LOG_OBJECT (decoder,
372 "Oldest frame is %d %" GST_TIME_FORMAT " and %d frames left",
373 frame->system_frame_number, GST_TIME_ARGS (frame->pts), count - 1);
374 gst_video_codec_frame_ref (frame);
377 g_list_free_full (frames, (GDestroyNotify) gst_video_codec_frame_unref);
383 gst_v4l2_video_dec_loop (GstVideoDecoder * decoder)
385 GstV4l2VideoDec *self = GST_V4L2_VIDEO_DEC (decoder);
387 GstVideoCodecFrame *frame;
388 GstBuffer *buffer = NULL;
391 GST_LOG_OBJECT (decoder, "Allocate output buffer");
393 /* We cannot use the base class allotate helper since it taking the internal
394 * stream lock. we know that the acquire may need to poll until more frames
395 * comes in and holding this lock would prevent that.
397 pool = gst_video_decoder_get_buffer_pool (decoder);
398 ret = gst_buffer_pool_acquire_buffer (pool, &buffer, NULL);
399 g_object_unref (pool);
401 if (ret != GST_FLOW_OK)
404 /* Check if buffer isn't the last one */
405 if (gst_buffer_get_size (buffer) == 0)
408 GST_LOG_OBJECT (decoder, "Process output buffer");
410 gst_v4l2_buffer_pool_process (GST_V4L2_BUFFER_POOL (self->
411 v4l2capture->pool), buffer);
413 if (ret != GST_FLOW_OK)
416 frame = gst_v4l2_video_dec_get_oldest_frame (decoder);
419 frame->output_buffer = buffer;
421 ret = gst_video_decoder_finish_frame (decoder, frame);
423 if (ret != GST_FLOW_OK)
426 GST_WARNING_OBJECT (decoder, "Decoder is producing too many buffers");
427 gst_buffer_unref (buffer);
433 GST_DEBUG_OBJECT (decoder, "Leaving output thread");
435 gst_buffer_replace (&buffer, NULL);
436 self->output_flow = ret;
437 g_atomic_int_set (&self->processing, FALSE);
438 gst_v4l2_object_unlock (self->v4l2output);
439 gst_pad_pause_task (decoder->srcpad);
443 gst_v4l2_video_dec_handle_frame (GstVideoDecoder * decoder,
444 GstVideoCodecFrame * frame)
446 GstV4l2VideoDec *self = GST_V4L2_VIDEO_DEC (decoder);
447 GstFlowReturn ret = GST_FLOW_OK;
449 GST_DEBUG_OBJECT (self, "Handling frame %d", frame->system_frame_number);
451 if (G_UNLIKELY (!g_atomic_int_get (&self->active)))
454 if (G_UNLIKELY (!GST_V4L2_IS_ACTIVE (self->v4l2output))) {
455 if (!gst_v4l2_object_set_format (self->v4l2output, self->input_state->caps))
459 if (G_UNLIKELY (!GST_V4L2_IS_ACTIVE (self->v4l2capture))) {
461 GstVideoCodecState *output_state;
462 GstBuffer *codec_data;
464 GST_DEBUG_OBJECT (self, "Sending header");
466 codec_data = self->input_state->codec_data;
468 /* We are running in byte-stream mode, so we don't know the headers, but
469 * we need to send something, otherwise the decoder will refuse to
473 gst_buffer_ref (codec_data);
475 codec_data = frame->input_buffer;
476 frame->input_buffer = NULL;
479 GST_VIDEO_DECODER_STREAM_UNLOCK (decoder);
480 gst_v4l2_object_unlock_stop (self->v4l2output);
482 gst_v4l2_buffer_pool_process (GST_V4L2_BUFFER_POOL (self->
483 v4l2output->pool), codec_data);
484 gst_v4l2_object_unlock (self->v4l2output);
485 GST_VIDEO_DECODER_STREAM_LOCK (decoder);
487 gst_buffer_unref (codec_data);
489 if (!gst_v4l2_object_setup_format (self->v4l2capture, &info, &self->align))
492 output_state = gst_video_decoder_set_output_state (decoder,
493 info.finfo->format, info.width, info.height, self->input_state);
495 /* Copy the rest of the information, there might be more in the future */
496 output_state->info.interlace_mode = info.interlace_mode;
497 gst_video_codec_state_unref (output_state);
499 if (!gst_video_decoder_negotiate (decoder)) {
500 if (GST_PAD_IS_FLUSHING (decoder->srcpad))
507 if (g_atomic_int_get (&self->processing) == FALSE) {
508 /* It possible that the processing thread stopped due to an error */
509 if (self->output_flow != GST_FLOW_OK) {
510 GST_DEBUG_OBJECT (self, "Processing loop stopped with error, leaving");
511 ret = self->output_flow;
515 GST_DEBUG_OBJECT (self, "Starting decoding thread");
517 /* Enable processing input */
518 gst_v4l2_object_unlock_stop (self->v4l2output);
520 /* Start the processing task, when it quits, the task will disable input
521 * processing to unlock input if draining, or prevent potential block */
522 g_atomic_int_set (&self->processing, TRUE);
523 gst_pad_start_task (decoder->srcpad,
524 (GstTaskFunction) gst_v4l2_video_dec_loop, self, NULL);
527 if (frame->input_buffer) {
528 GST_VIDEO_DECODER_STREAM_UNLOCK (decoder);
530 gst_v4l2_buffer_pool_process (GST_V4L2_BUFFER_POOL (self->v4l2output->
531 pool), frame->input_buffer);
532 GST_VIDEO_DECODER_STREAM_LOCK (decoder);
534 if (ret == GST_FLOW_FLUSHING) {
535 if (g_atomic_int_get (&self->processing) == FALSE)
536 ret = self->output_flow;
539 /* No need to keep input arround */
540 gst_buffer_replace (&frame->input_buffer, NULL);
543 gst_video_codec_frame_unref (frame);
549 GST_ERROR_OBJECT (self, "not negotiated");
550 ret = GST_FLOW_NOT_NEGOTIATED;
555 ret = GST_FLOW_FLUSHING;
560 gst_video_decoder_drop_frame (decoder, frame);
566 gst_v4l2_video_dec_decide_allocation (GstVideoDecoder * decoder,
569 GstV4l2VideoDec *self = GST_V4L2_VIDEO_DEC (decoder);
570 GstClockTime latency;
571 gboolean ret = FALSE;
573 if (gst_v4l2_object_decide_allocation (self->v4l2capture, query))
574 ret = GST_VIDEO_DECODER_CLASS (parent_class)->decide_allocation (decoder,
577 latency = self->v4l2capture->min_buffers_for_capture *
578 self->v4l2capture->duration;
579 gst_video_decoder_set_latency (decoder, latency, latency);
585 gst_v4l2_video_dec_src_query (GstVideoDecoder * decoder, GstQuery * query)
588 GstV4l2VideoDec *self = GST_V4L2_VIDEO_DEC (decoder);
590 switch (GST_QUERY_TYPE (query)) {
591 case GST_QUERY_CAPS:{
592 GstCaps *filter, *result = NULL;
593 gst_query_parse_caps (query, &filter);
595 if (self->probed_srccaps)
596 result = gst_caps_ref (self->probed_srccaps);
598 result = gst_v4l2_object_get_raw_caps ();
601 GstCaps *tmp = result;
603 gst_caps_intersect_full (filter, tmp, GST_CAPS_INTERSECT_FIRST);
604 gst_caps_unref (tmp);
607 GST_DEBUG_OBJECT (self, "Returning src caps %" GST_PTR_FORMAT, result);
609 gst_query_set_caps_result (query, result);
610 gst_caps_unref (result);
615 ret = GST_VIDEO_DECODER_CLASS (parent_class)->src_query (decoder, query);
623 gst_v4l2_video_dec_sink_query (GstVideoDecoder * decoder, GstQuery * query)
626 GstV4l2VideoDec *self = GST_V4L2_VIDEO_DEC (decoder);
628 switch (GST_QUERY_TYPE (query)) {
629 case GST_QUERY_CAPS:{
630 GstCaps *filter, *result = NULL;
631 gst_query_parse_caps (query, &filter);
633 if (self->probed_sinkcaps)
634 result = gst_caps_ref (self->probed_sinkcaps);
636 result = gst_v4l2_object_get_codec_caps ();
639 GstCaps *tmp = result;
641 gst_caps_intersect_full (filter, tmp, GST_CAPS_INTERSECT_FIRST);
642 gst_caps_unref (tmp);
645 GST_DEBUG_OBJECT (self, "Returning sink caps %" GST_PTR_FORMAT, result);
647 gst_query_set_caps_result (query, result);
648 gst_caps_unref (result);
653 ret = GST_VIDEO_DECODER_CLASS (parent_class)->sink_query (decoder, query);
661 gst_v4l2_video_dec_sink_event (GstVideoDecoder * decoder, GstEvent * event)
663 GstV4l2VideoDec *self = GST_V4L2_VIDEO_DEC (decoder);
665 switch (GST_EVENT_TYPE (event)) {
666 case GST_EVENT_FLUSH_START:
667 gst_v4l2_object_unlock (self->v4l2output);
668 gst_v4l2_object_unlock (self->v4l2capture);
673 return GST_VIDEO_DECODER_CLASS (parent_class)->sink_event (decoder, event);
676 static GstStateChangeReturn
677 gst_v4l2_video_dec_change_state (GstElement * element,
678 GstStateChange transition)
680 GstV4l2VideoDec *self = GST_V4L2_VIDEO_DEC (element);
682 if (transition == GST_STATE_CHANGE_PAUSED_TO_READY) {
683 g_atomic_int_set (&self->active, FALSE);
684 gst_v4l2_object_unlock (self->v4l2output);
685 gst_v4l2_object_unlock (self->v4l2capture);
688 return GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
692 gst_v4l2_video_dec_dispose (GObject * object)
694 GstV4l2VideoDec *self = GST_V4L2_VIDEO_DEC (object);
696 gst_caps_replace (&self->probed_sinkcaps, NULL);
697 gst_caps_replace (&self->probed_srccaps, NULL);
699 G_OBJECT_CLASS (parent_class)->dispose (object);
703 gst_v4l2_video_dec_finalize (GObject * object)
705 GstV4l2VideoDec *self = GST_V4L2_VIDEO_DEC (object);
707 gst_v4l2_object_destroy (self->v4l2capture);
708 gst_v4l2_object_destroy (self->v4l2output);
710 G_OBJECT_CLASS (parent_class)->finalize (object);
714 gst_v4l2_video_dec_base_init (gpointer g_class)
716 GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
717 Gstv4l2VideoDecQData *qdata;
718 GstPadTemplate *templ;
720 qdata = g_type_get_qdata (G_TYPE_FROM_CLASS (g_class), V4L2_VIDEO_DEC_QUARK);
725 gst_pad_template_new ("sink", GST_PAD_SINK, GST_PAD_ALWAYS,
727 gst_element_class_add_pad_template (element_class, templ);
730 gst_pad_template_new ("src", GST_PAD_SRC, GST_PAD_ALWAYS,
732 gst_element_class_add_pad_template (element_class, templ);
736 gst_v4l2_video_dec_init (GstV4l2VideoDec * self, gpointer g_class)
738 GstVideoDecoder *decoder = (GstVideoDecoder *) self;
739 Gstv4l2VideoDecQData *qdata;
741 qdata = g_type_get_qdata (G_TYPE_FROM_CLASS (g_class), V4L2_VIDEO_DEC_QUARK);
745 gst_video_decoder_set_packetized (decoder, TRUE);
747 self->v4l2output = gst_v4l2_object_new (GST_ELEMENT (self),
748 V4L2_BUF_TYPE_VIDEO_OUTPUT, qdata->device,
749 gst_v4l2_get_output, gst_v4l2_set_output, NULL);
750 self->v4l2output->no_initial_format = TRUE;
751 self->v4l2output->keep_aspect = FALSE;
753 self->v4l2capture = gst_v4l2_object_new (GST_ELEMENT (self),
754 V4L2_BUF_TYPE_VIDEO_CAPTURE, qdata->device,
755 gst_v4l2_get_input, gst_v4l2_set_input, NULL);
756 self->v4l2capture->no_initial_format = TRUE;
757 self->v4l2output->keep_aspect = FALSE;
759 g_object_set (self, "device", qdata->device, NULL);
763 gst_v4l2_video_dec_class_init (GstV4l2VideoDecClass * klass)
765 GstElementClass *element_class;
766 GObjectClass *gobject_class;
767 GstVideoDecoderClass *video_decoder_class;
769 parent_class = g_type_class_peek_parent (klass);
771 element_class = (GstElementClass *) klass;
772 gobject_class = (GObjectClass *) klass;
773 video_decoder_class = (GstVideoDecoderClass *) klass;
775 gst_element_class_set_static_metadata (element_class,
776 "V4L2 Video Decoder",
777 "Codec/Decoder/Video",
778 "Decode video streams via V4L2 API",
779 "Nicolas Dufresne <nicolas.dufresne@collabora.co.uk>");
781 gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_v4l2_video_dec_dispose);
782 gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_v4l2_video_dec_finalize);
783 gobject_class->set_property =
784 GST_DEBUG_FUNCPTR (gst_v4l2_video_dec_set_property);
785 gobject_class->get_property =
786 GST_DEBUG_FUNCPTR (gst_v4l2_video_dec_get_property);
788 video_decoder_class->open = GST_DEBUG_FUNCPTR (gst_v4l2_video_dec_open);
789 video_decoder_class->close = GST_DEBUG_FUNCPTR (gst_v4l2_video_dec_close);
790 video_decoder_class->start = GST_DEBUG_FUNCPTR (gst_v4l2_video_dec_start);
791 video_decoder_class->stop = GST_DEBUG_FUNCPTR (gst_v4l2_video_dec_stop);
792 video_decoder_class->finish = GST_DEBUG_FUNCPTR (gst_v4l2_video_dec_finish);
793 video_decoder_class->flush = GST_DEBUG_FUNCPTR (gst_v4l2_video_dec_flush);
794 video_decoder_class->set_format =
795 GST_DEBUG_FUNCPTR (gst_v4l2_video_dec_set_format);
796 video_decoder_class->negotiate =
797 GST_DEBUG_FUNCPTR (gst_v4l2_video_dec_negotiate);
798 video_decoder_class->decide_allocation =
799 GST_DEBUG_FUNCPTR (gst_v4l2_video_dec_decide_allocation);
800 /* FIXME propose_allocation or not ? */
801 video_decoder_class->handle_frame =
802 GST_DEBUG_FUNCPTR (gst_v4l2_video_dec_handle_frame);
803 video_decoder_class->sink_query =
804 GST_DEBUG_FUNCPTR (gst_v4l2_video_dec_sink_query);
805 video_decoder_class->src_query =
806 GST_DEBUG_FUNCPTR (gst_v4l2_video_dec_src_query);
807 video_decoder_class->sink_event =
808 GST_DEBUG_FUNCPTR (gst_v4l2_video_dec_sink_event);
810 element_class->change_state =
811 GST_DEBUG_FUNCPTR (gst_v4l2_video_dec_change_state);
813 gst_v4l2_object_install_properties_helper (gobject_class,
814 DEFAULT_PROP_DEVICE);
817 * GstV4l2VideoDec:capture-io-mode
821 g_object_class_install_property (gobject_class, PROP_IO_MODE,
822 g_param_spec_enum ("capture-io-mode", "Capture IO mode",
824 GST_TYPE_V4L2_IO_MODE, GST_V4L2_IO_AUTO,
825 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
828 /* Probing functions */
830 gst_v4l2_video_dec_probe_caps (gchar * device, gint video_fd,
831 enum v4l2_buf_type type, GstCaps * filter)
834 struct v4l2_fmtdesc format;
837 GST_DEBUG ("Getting %s format enumerations", device);
838 caps = gst_caps_new_empty ();
841 GstStructure *template;
846 if (v4l2_ioctl (video_fd, VIDIOC_ENUM_FMT, &format) < 0)
847 break; /* end of enumeration */
849 GST_LOG ("index: %u", format.index);
850 GST_LOG ("type: %d", format.type);
851 GST_LOG ("flags: %08x", format.flags);
852 GST_LOG ("description: '%s'", format.description);
853 GST_LOG ("pixelformat: %" GST_FOURCC_FORMAT,
854 GST_FOURCC_ARGS (format.pixelformat));
856 template = gst_v4l2_object_v4l2fourcc_to_structure (format.pixelformat);
859 gst_caps_append_structure (caps, template);
862 caps = gst_caps_simplify (caps);
864 ret = gst_caps_intersect (filter, caps);
865 gst_caps_unref (filter);
866 gst_caps_unref (caps);
872 gst_v4l2_video_dec_register (GstPlugin * plugin)
875 gchar *device = NULL;
877 GST_DEBUG_CATEGORY_INIT (gst_v4l2_video_dec_debug, "v4l2videodec", 0,
878 "V4L2 Video Decoder");
881 GstCaps *src_caps, *sink_caps;
885 device = g_strdup_printf ("/dev/video%d", ++i);
887 if (!g_file_test (device, G_FILE_TEST_EXISTS))
890 video_fd = open (device, O_RDWR);
891 if (video_fd == -1) {
892 GST_WARNING ("Failed to open %s", device);
896 /* get sink supported format (no MPLANE for codec) */
897 sink_caps = gst_v4l2_video_dec_probe_caps (device, video_fd,
898 V4L2_BUF_TYPE_VIDEO_OUTPUT, gst_v4l2_object_get_codec_caps ());
900 /* get src supported format */
901 src_caps = gst_caps_merge (gst_v4l2_video_dec_probe_caps (device, video_fd,
902 V4L2_BUF_TYPE_VIDEO_CAPTURE, gst_v4l2_object_get_raw_caps ()),
903 gst_v4l2_video_dec_probe_caps (device, video_fd,
904 V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE,
905 gst_v4l2_object_get_raw_caps ()));
907 if (!gst_caps_is_empty (sink_caps) && !gst_caps_is_empty (src_caps)) {
908 GTypeQuery type_query;
909 GTypeInfo type_info = { 0, };
912 Gstv4l2VideoDecQData *qdata;
914 type = gst_v4l2_video_dec_get_type ();
915 g_type_query (type, &type_query);
916 memset (&type_info, 0, sizeof (type_info));
917 type_info.class_size = type_query.class_size;
918 type_info.instance_size = type_query.instance_size;
920 type_name = g_strdup_printf ("v4l2video%ddec", i);
921 subtype = g_type_register_static (type, type_name, &type_info, 0);
923 qdata = g_new0 (Gstv4l2VideoDecQData, 1);
924 qdata->device = g_strdup (device);
925 qdata->sink_caps = gst_caps_ref (sink_caps);
926 qdata->src_caps = gst_caps_ref (src_caps);
928 g_type_set_qdata (subtype, V4L2_VIDEO_DEC_QUARK, qdata);
930 gst_element_register (plugin, type_name, GST_RANK_PRIMARY + 1, subtype);
936 gst_caps_unref (src_caps);
937 gst_caps_unref (sink_caps);