2 * GStreamer codec plugin for Tizen Emulator.
4 * Copyright (C) 2013 Samsung Electronics Co., Ltd. All rights reserved.
7 * KiTae Kim <kt920.kim@samsung.com>
8 * SeokYeon Hwang <syeon.hwang@samsung.com>
9 * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
11 * This library is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Library General Public
13 * License as published by the Free Software Foundation; either
14 * version 2 of the License, or (at your option) any later version.
16 * This library is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Library General Public License for more details.
21 * You should have received a copy of the GNU Library General Public
22 * License along with this library; if not, write to the
23 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
24 * Boston, MA 02111-1307, USA.
31 #include "gstemulcommon.h"
32 #include "gstemulutils.h"
33 #include "gstemulapi.h"
34 #include "gstemuldev.h"
36 #define GST_EMULDEC_PARAMS_QDATA g_quark_from_static_string("marudec-params")
38 /* indicate dts, pts, offset in the stream */
42 GstClockTime timestamp;
43 GstClockTime duration;
47 #define GST_TS_INFO_NONE &ts_info_none
48 static const GstTSInfo ts_info_none = { -1, -1, -1, -1 };
50 #define MAX_TS_MASK 0xff
52 typedef struct _GstEmulDec
59 CodecContext *context;
65 gint clip_width, clip_height;
68 gint old_fps_n, old_fps_d;
71 enum PixelFormat pix_fmt;
84 /* tracking DTS/PTS */
85 GstClockTime next_out;
89 GstClockTime earliest_time;
94 /* GstSegment can be used for two purposes:
95 * 1. performing seeks (handling seek events)
96 * 2. tracking playback regions (handling newsegment events)
100 GstTSInfo ts_info[MAX_TS_MASK + 1];
103 /* reverse playback queue */
108 typedef struct _GstEmulDecClass
110 GstElementClass parent_class;
113 GstPadTemplate *sinktempl;
114 GstPadTemplate *srctempl;
118 static GstElementClass *parent_class = NULL;
120 static void gst_emuldec_base_init (GstEmulDecClass *klass);
121 static void gst_emuldec_class_init (GstEmulDecClass *klass);
122 static void gst_emuldec_init (GstEmulDec *emuldec);
123 static void gst_emuldec_finalize (GObject *object);
125 static gboolean gst_emuldec_setcaps (GstPad *pad, GstCaps *caps);
128 static gboolean gst_emuldec_sink_event (GstPad *pad, GstEvent *event);
129 static GstFlowReturn gst_emuldec_chain (GstPad *pad, GstBuffer *buffer);
132 static gboolean gst_emuldec_src_event (GstPad *pad, GstEvent *event);
133 static GstStateChangeReturn gst_emuldec_change_state (GstElement *element,
134 GstStateChange transition);
136 static gboolean gst_emuldec_negotiate (GstEmulDec *dec, gboolean force);
138 static gint gst_emuldec_frame (GstEmulDec *emuldec, guint8 *data,
139 guint size, gint *got_data,
140 const GstTSInfo *dec_info, gint64 in_offset, GstFlowReturn *ret);
142 static gboolean gst_emuldec_open (GstEmulDec *emuldec);
143 static int gst_emuldec_close (GstEmulDec *emuldec);
146 static const GstTSInfo *
147 gst_ts_info_store (GstEmulDec *dec, GstClockTime timestamp,
148 GstClockTime duration, gint64 offset)
150 gint idx = dec->ts_idx;
151 dec->ts_info[idx].idx = idx;
152 dec->ts_info[idx].timestamp = timestamp;
153 dec->ts_info[idx].duration = duration;
154 dec->ts_info[idx].offset = offset;
155 dec->ts_idx = (idx + 1) & MAX_TS_MASK;
157 return &dec->ts_info[idx];
160 static const GstTSInfo *
161 gst_ts_info_get (GstEmulDec *dec, gint idx)
163 if (G_UNLIKELY (idx < 0 || idx > MAX_TS_MASK))
164 return GST_TS_INFO_NONE;
166 return &dec->ts_info[idx];
170 gst_emuldec_reset_ts (GstEmulDec *emuldec)
172 emuldec->next_out = GST_CLOCK_TIME_NONE;
176 gst_emuldec_update_qos (GstEmulDec *emuldec, gdouble proportion,
177 GstClockTime timestamp)
179 GST_LOG_OBJECT (emuldec, "update QOS: %f, %" GST_TIME_FORMAT,
180 proportion, GST_TIME_ARGS (timestamp));
182 GST_OBJECT_LOCK (emuldec);
183 emuldec->proportion = proportion;
184 emuldec->earliest_time = timestamp;
185 GST_OBJECT_UNLOCK (emuldec);
189 gst_emuldec_reset_qos (GstEmulDec *emuldec)
191 gst_emuldec_update_qos (emuldec, 0.5, GST_CLOCK_TIME_NONE);
192 emuldec->processed = 0;
193 emuldec->dropped = 0;
197 gst_emuldec_do_qos (GstEmulDec *emuldec, GstClockTime timestamp,
198 gboolean *mode_switch)
200 GstClockTimeDiff diff;
202 GstClockTime qostime, earliest_time;
205 *mode_switch = FALSE;
207 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (timestamp))) {
208 emuldec->processed++;
212 proportion = emuldec->proportion;
213 earliest_time = emuldec->earliest_time;
215 qostime = gst_segment_to_running_time (&emuldec->segment, GST_FORMAT_TIME,
218 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (qostime))) {
219 emuldec->processed++;
223 diff = GST_CLOCK_DIFF (qostime, earliest_time);
225 if (proportion < 0.4 && diff < 0 ){
226 emuldec->processed++;
230 // if (emuldec->waiting_for_key) {
236 GstClockTime stream_time, jitter;
241 gst_segment_to_stream_time (&emuldec->segment, GST_FORMAT_TIME,
243 jitter = GST_CLOCK_DIFF (qostime, earliest_time);
245 gst_message_new_qos (GST_OBJECT_CAST (emuldec), FALSE, qostime,
246 stream_time, timestamp, GST_CLOCK_TIME_NONE);
247 gst_message_set_qos_values (qos_msg, jitter, proportion, 1000000);
248 gst_message_set_qos_stats (qos_msg, GST_FORMAT_BUFFERS,
249 emuldec->processed, emuldec->dropped);
250 gst_element_post_message (GST_ELEMENT_CAST (emuldec), qos_msg);
256 emuldec->processed++;
261 clear_queued (GstEmulDec *emuldec)
263 g_list_foreach (emuldec->queued, (GFunc) gst_mini_object_unref, NULL);
264 g_list_free (emuldec->queued);
265 emuldec->queued = NULL;
269 flush_queued (GstEmulDec *emuldec)
271 GstFlowReturn res = GST_FLOW_OK;
273 CODEC_LOG (DEBUG, "flush queued\n");
275 while (emuldec->queued) {
276 GstBuffer *buf = GST_BUFFER_CAST (emuldec->queued->data);
278 GST_LOG_OBJECT (emuldec, "pushing buffer %p, offset %"
279 G_GUINT64_FORMAT ", timestamp %"
280 GST_TIME_FORMAT ", duration %" GST_TIME_FORMAT, buf,
281 GST_BUFFER_OFFSET (buf),
282 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)),
283 GST_TIME_ARGS (GST_BUFFER_DURATION (buf)));
285 res = gst_pad_push (emuldec->srcpad, buf);
288 g_list_delete_link (emuldec->queued, emuldec->queued);
295 gst_emuldec_drain (GstEmulDec *emuldec)
297 GstEmulDecClass *oclass;
299 oclass = (GstEmulDecClass *) (G_OBJECT_GET_CLASS (emuldec));
304 gint have_data, len, try = 0;
310 gst_emuldec_frame (emuldec, NULL, 0, &have_data, &ts_info_none, 0, &ret);
312 if (len < 0 || have_data == 0) {
315 } while (try++ < 10);
319 if (emuldec->segment.rate < 0.0) {
320 CODEC_LOG (DEBUG, "reverse playback\n");
321 flush_queued (emuldec);
329 gst_emuldec_base_init (GstEmulDecClass *klass)
331 GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
332 GstCaps *sinkcaps, *srccaps;
333 GstPadTemplate *sinktempl, *srctempl;
335 gchar *longname, *classification, *description;
338 (CodecElement *)g_type_get_qdata (G_OBJECT_CLASS_TYPE (klass),
339 GST_EMULDEC_PARAMS_QDATA);
341 longname = g_strdup_printf ("%s Decoder", codec->longname);
342 classification = g_strdup_printf ("Codec/Decoder/%s",
343 (codec->media_type == AVMEDIA_TYPE_VIDEO) ?
345 description = g_strdup_printf("%s Decoder", codec->name);
347 gst_element_class_set_details_simple (element_class,
351 "Kitae Kim <kt920.kim@samsung.com>");
354 g_free (classification);
355 g_free (description);
357 sinkcaps = gst_emul_codecname_to_caps (codec->name, NULL, FALSE);
359 sinkcaps = gst_caps_from_string ("unknown/unknown");
362 switch (codec->media_type) {
363 case AVMEDIA_TYPE_VIDEO:
364 srccaps = gst_caps_from_string ("video/x-raw-rgb; video/x-raw-yuv");
366 case AVMEDIA_TYPE_AUDIO:
367 srccaps = gst_emul_codectype_to_audio_caps (NULL, codec->name, FALSE, codec);
370 GST_LOG("unknown media type.\n");
375 srccaps = gst_caps_from_string ("unknown/unknown");
378 sinktempl = gst_pad_template_new ("sink", GST_PAD_SINK,
379 GST_PAD_ALWAYS, sinkcaps);
380 srctempl = gst_pad_template_new ("src", GST_PAD_SRC,
381 GST_PAD_ALWAYS, srccaps);
383 gst_element_class_add_pad_template (element_class, srctempl);
384 gst_element_class_add_pad_template (element_class, sinktempl);
386 klass->codec = codec;
387 klass->sinktempl = sinktempl;
388 klass->srctempl = srctempl;
392 gst_emuldec_class_init (GstEmulDecClass *klass)
394 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
395 GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
397 parent_class = g_type_class_peek_parent (klass);
400 gobject_class->set_property = gst_emuldec_set_property
401 gobject_class->get_property = gst_emuldec_get_property
404 gobject_class->finalize = gst_emuldec_finalize;
405 gstelement_class->change_state = gst_emuldec_change_state;
409 gst_emuldec_init (GstEmulDec *emuldec)
411 GstEmulDecClass *oclass;
413 oclass = (GstEmulDecClass*) (G_OBJECT_GET_CLASS(emuldec));
415 emuldec->sinkpad = gst_pad_new_from_template (oclass->sinktempl, "sink");
416 gst_pad_set_setcaps_function (emuldec->sinkpad,
417 GST_DEBUG_FUNCPTR(gst_emuldec_setcaps));
418 gst_pad_set_event_function (emuldec->sinkpad,
419 GST_DEBUG_FUNCPTR(gst_emuldec_sink_event));
420 gst_pad_set_chain_function (emuldec->sinkpad,
421 GST_DEBUG_FUNCPTR(gst_emuldec_chain));
423 emuldec->srcpad = gst_pad_new_from_template (oclass->srctempl, "src") ;
424 gst_pad_use_fixed_caps (emuldec->srcpad);
425 gst_pad_set_event_function (emuldec->srcpad,
426 GST_DEBUG_FUNCPTR(gst_emuldec_src_event));
428 gst_element_add_pad (GST_ELEMENT(emuldec), emuldec->sinkpad);
429 gst_element_add_pad (GST_ELEMENT(emuldec), emuldec->srcpad);
432 emuldec->context = g_malloc0 (sizeof(CodecContext));
433 if (!emuldec->context) {
434 CODEC_LOG (ERR, "failed to allocate memory.\n");
437 emuldec->context->video.pix_fmt = PIX_FMT_NONE;
438 emuldec->context->audio.sample_fmt = SAMPLE_FMT_NONE;
439 emuldec->dev = g_malloc0 (sizeof(CodecDevice));
441 CODEC_LOG (ERR, "failed to allocate memory.\n");
444 emuldec->opened = FALSE;
445 emuldec->format.video.par_n = -1;
446 emuldec->format.video.fps_n = -1;
447 emuldec->format.video.old_fps_n = -1;
449 emuldec->queued = NULL;
450 gst_segment_init (&emuldec->segment, GST_FORMAT_TIME);
454 gst_emuldec_finalize (GObject *object)
456 GstEmulDec *emuldec = (GstEmulDec *) object;
458 if (emuldec->context) {
459 g_free (emuldec->context);
460 emuldec->context = NULL;
463 G_OBJECT_CLASS (parent_class)->finalize (object);
467 gst_emuldec_src_event (GstPad *pad, GstEvent *event)
472 emuldec = (GstEmulDec *) gst_pad_get_parent (pad);
474 switch (GST_EVENT_TYPE (event)) {
475 /* Quality Of Service (QOS) event contains a report
476 about the current real-time performance of the stream.*/
480 GstClockTimeDiff diff;
481 GstClockTime timestamp;
483 gst_event_parse_qos (event, &proportion, &diff, ×tamp);
485 /* update our QoS values */
486 gst_emuldec_update_qos (emuldec, proportion, timestamp + diff);
493 /* forward upstream */
494 res = gst_pad_push_event (emuldec->sinkpad, event);
496 gst_object_unref (emuldec);
502 gst_emuldec_sink_event (GstPad *pad, GstEvent *event)
505 gboolean ret = FALSE;
507 emuldec = (GstEmulDec *) gst_pad_get_parent (pad);
509 GST_DEBUG_OBJECT (emuldec, "Handling %s event",
510 GST_EVENT_TYPE_NAME (event));
512 switch (GST_EVENT_TYPE (event)) {
514 gst_emuldec_drain (emuldec);
516 case GST_EVENT_FLUSH_STOP:
519 if (emuldec->opened) {
520 // TODO: what does avcodec_flush_buffers do?
521 emul_avcodec_flush_buffers (emuldec->context, emuldec->dev);
524 gst_emuldec_reset_ts (emuldec);
525 gst_emuldec_reset_qos (emuldec);
527 gst_emuldec_flush_pcache (emuldec);
528 emuldec->waiting_for_key = TRUE;
530 gst_segment_init (&emuldec->segment, GST_FORMAT_TIME);
531 clear_queued (emuldec);
534 case GST_EVENT_NEWSEGMENT:
538 gint64 start, stop, time;
541 gst_event_parse_new_segment_full (event, &update, &rate, &arate, &format,
542 &start, &stop, &time);
545 case GST_FORMAT_TIME:
547 case GST_FORMAT_BYTES:
550 bit_rate = emuldec->context->bit_rate;
553 GST_WARNING_OBJECT (emuldec, "no bitrate to convert BYTES to TIME");
554 gst_event_unref (event);
555 gst_object_unref (emuldec);
559 GST_DEBUG_OBJECT (emuldec, "bitrate: %d", bit_rate);
562 start = gst_util_uint64_scale_int (start, GST_SECOND, bit_rate);
565 stop = gst_util_uint64_scale_int (stop, GST_SECOND, bit_rate);
568 time = gst_util_uint64_scale_int (time, GST_SECOND, bit_rate);
571 gst_event_unref (event);
573 format = GST_FORMAT_TIME;
576 event = gst_event_new_new_segment (update, rate, format,
581 GST_WARNING_OBJECT (emuldec, "unknown format received in NEWSEGMENT");
582 gst_event_unref (event);
583 gst_object_unref (emuldec);
587 if (emuldec->context->codec) {
588 gst_emuldec_drain (emuldec);
591 GST_DEBUG_OBJECT (emuldec,
592 "NEWSEGMENT in time start %" GST_TIME_FORMAT " -- stop %"
593 GST_TIME_FORMAT, GST_TIME_ARGS (start), GST_TIME_ARGS (stop));
595 gst_segment_set_newsegment_full (&emuldec->segment, update,
596 rate, arate, format, start, stop, time);
603 ret = gst_pad_push_event (emuldec->srcpad, event);
605 gst_object_unref (emuldec);
613 gst_emuldec_setcaps (GstPad *pad, GstCaps *caps)
616 GstEmulDecClass *oclass;
617 GstStructure *structure;
622 GST_DEBUG_OBJECT (pad, "setcaps called.");
624 emuldec = (GstEmulDec *) (gst_pad_get_parent (pad));
625 oclass = (GstEmulDecClass *) (G_OBJECT_GET_CLASS (emuldec));
627 GST_OBJECT_LOCK (emuldec);
629 if (emuldec->opened) {
630 GST_OBJECT_UNLOCK (emuldec);
631 gst_emuldec_drain (emuldec);
632 GST_OBJECT_LOCK (emuldec);
633 gst_emuldec_close (emuldec);
636 GST_LOG_OBJECT (emuldec, "size %dx%d", emuldec->context->video.width,
637 emuldec->context->video.height);
639 gst_emul_caps_with_codecname (oclass->codec->name, oclass->codec->media_type,
640 caps, emuldec->context);
642 GST_LOG_OBJECT (emuldec, "size after %dx%d", emuldec->context->video.width,
643 emuldec->context->video.height);
645 if (!emuldec->context->video.fps_d || !emuldec->context->video.fps_n) {
646 GST_DEBUG_OBJECT (emuldec, "forcing 25/1 framerate");
647 emuldec->context->video.fps_n = 1;
648 emuldec->context->video.fps_d = 25;
651 structure = gst_caps_get_structure (caps, 0);
653 par = gst_structure_get_value (structure, "pixel-aspect-ratio");
655 GST_DEBUG_OBJECT (emuldec, "sink caps have pixel-aspect-ratio of %d:%d",
656 gst_value_get_fraction_numerator (par),
657 gst_value_get_fraction_denominator (par));
661 g_free(emuldec->par);
663 emuldec->par = g_new0 (GValue, 1);
664 gst_value_init_and_copy (emuldec->par, par);
668 fps = gst_structure_get_value (structure, "framerate");
669 if (fps != NULL && GST_VALUE_HOLDS_FRACTION (fps)) {
670 emuldec->format.video.fps_n = gst_value_get_fraction_numerator (fps);
671 emuldec->format.video.fps_d = gst_value_get_fraction_denominator (fps);
672 GST_DEBUG_OBJECT (emuldec, "Using framerate %d/%d from incoming",
673 emuldec->format.video.fps_n, emuldec->format.video.fps_d);
675 emuldec->format.video.fps_n = -1;
676 GST_DEBUG_OBJECT (emuldec, "Using framerate from codec");
680 if (strcmp (oclass->codec->name, "aac") == 0) {
681 const gchar *format = gst_structure_get_string (structure, "stream-format");
682 if (format == NULL || strcmp ("format", "raw") == 0) {
683 emuldec->turnoff_parser = TRUE;
688 if (!gst_emuldec_open (emuldec)) {
689 GST_DEBUG_OBJECT (emuldec, "Failed to open");
692 g_free(emuldec->par);
696 GST_OBJECT_UNLOCK (emuldec);
697 gst_object_unref (emuldec);
702 gst_structure_get_int (structure, "width",
703 &emuldec->format.video.clip_width);
704 gst_structure_get_int (structure, "height",
705 &emuldec->format.video.clip_height);
707 GST_DEBUG_OBJECT (pad, "clipping to %dx%d",
708 emuldec->format.video.clip_width, emuldec->format.video.clip_height);
710 GST_OBJECT_UNLOCK (emuldec);
711 gst_object_unref (emuldec);
717 gst_emuldec_open (GstEmulDec *emuldec)
719 GstEmulDecClass *oclass;
720 int width, height, buf_size;
722 oclass = (GstEmulDecClass *) (G_OBJECT_GET_CLASS (emuldec));
729 switch (oclass->codec->media_type) {
730 case AVMEDIA_TYPE_VIDEO:
731 width = emuldec->context->video.width;
732 height = emuldec->context->video.height;
733 buf_size = gst_emul_avpicture_size (0, width, height) + 100;
735 case AVMEDIA_TYPE_AUDIO:
736 buf_size = FF_MAX_AUDIO_FRAME_SIZE + 100;
747 emuldec->dev->buf_size = gst_emul_align_size(buf_size);
750 if (gst_emul_avcodec_open (emuldec->context,
751 oclass->codec, emuldec->dev) < 0) {
752 gst_emuldec_close (emuldec);
753 GST_DEBUG_OBJECT (emuldec,
754 "maru_%sdec: Failed to open codec", oclass->codec->name);
757 emuldec->opened = TRUE;
758 GST_LOG_OBJECT (emuldec, "Opened codec %s", oclass->codec->name);
760 switch (oclass->codec->media_type) {
761 case AVMEDIA_TYPE_VIDEO:
762 emuldec->format.video.width = 0;
763 emuldec->format.video.height = 0;
764 emuldec->format.video.clip_width = -1;
765 emuldec->format.video.clip_height = -1;
766 emuldec->format.video.pix_fmt = PIX_FMT_NB;
767 emuldec->format.video.interlaced = FALSE;
769 case AVMEDIA_TYPE_AUDIO:
770 emuldec->format.audio.samplerate = 0;
771 emuldec->format.audio.channels = 0;
772 emuldec->format.audio.depth = 0;
778 gst_emuldec_reset_ts (emuldec);
780 emuldec->proportion = 0.0;
781 emuldec->earliest_time = -1;
787 gst_emuldec_close (GstEmulDec *emuldec)
791 if (emuldec->context->codecdata) {
792 g_free(emuldec->context->codecdata);
793 emuldec->context->codecdata = NULL;
796 ret = gst_emul_avcodec_close (emuldec->context, emuldec->dev);
799 g_free(emuldec->dev);
808 gst_emuldec_negotiate (GstEmulDec *emuldec, gboolean force)
810 GstEmulDecClass *oclass;
813 oclass = (GstEmulDecClass *) (G_OBJECT_GET_CLASS (emuldec));
815 switch (oclass->codec->media_type) {
816 case AVMEDIA_TYPE_VIDEO:
817 if (!force && emuldec->format.video.width == emuldec->context->video.width
818 && emuldec->format.video.height == emuldec->context->video.height
819 && emuldec->format.video.fps_n == emuldec->format.video.old_fps_n
820 && emuldec->format.video.fps_d == emuldec->format.video.old_fps_d
821 && emuldec->format.video.pix_fmt == emuldec->context->video.pix_fmt
822 && emuldec->format.video.par_n == emuldec->context->video.par_n
823 && emuldec->format.video.par_d == emuldec->context->video.par_d) {
826 emuldec->format.video.width = emuldec->context->video.width;
827 emuldec->format.video.height = emuldec->context->video.height;
828 emuldec->format.video.old_fps_n = emuldec->format.video.fps_n;
829 emuldec->format.video.old_fps_d = emuldec->format.video.fps_d;
830 emuldec->format.video.pix_fmt = emuldec->context->video.pix_fmt;
831 emuldec->format.video.par_n = emuldec->context->video.par_n;
832 emuldec->format.video.par_d = emuldec->context->video.par_d;
834 case AVMEDIA_TYPE_AUDIO:
836 gint depth = gst_emul_smpfmt_depth (emuldec->context->audio.sample_fmt);
837 if (!force && emuldec->format.audio.samplerate ==
838 emuldec->context->audio.sample_rate &&
839 emuldec->format.audio.channels == emuldec->context->audio.channels &&
840 emuldec->format.audio.depth == depth) {
843 emuldec->format.audio.samplerate = emuldec->context->audio.sample_rate;
844 emuldec->format.audio.channels = emuldec->context->audio.channels;
845 emuldec->format.audio.depth = depth;
853 gst_emul_codectype_to_caps (oclass->codec->media_type, emuldec->context,
854 oclass->codec->name, FALSE);
857 GST_ELEMENT_ERROR (emuldec, CORE, NEGOTIATION,
858 ("Could not find GStreamer caps mapping for codec '%s'.",
859 oclass->codec->name), (NULL));
863 switch (oclass->codec->media_type) {
864 case AVMEDIA_TYPE_VIDEO:
869 width = emuldec->format.video.clip_width;
870 height = emuldec->format.video.clip_height;
871 interlaced = emuldec->format.video.interlaced;
873 if (width != -1 && height != -1) {
874 if (width < emuldec->context->video.width) {
875 gst_caps_set_simple (caps, "width", G_TYPE_INT, width, NULL);
877 if (height < emuldec->context->video.height) {
878 gst_caps_set_simple (caps, "height", G_TYPE_INT, height, NULL);
880 gst_caps_set_simple (caps, "interlaced", G_TYPE_BOOLEAN, interlaced,
883 if (emuldec->format.video.fps_n != -1) {
884 gst_caps_set_simple (caps, "framerate",
885 GST_TYPE_FRACTION, emuldec->format.video.fps_n,
886 emuldec->format.video.fps_d, NULL);
889 gst_emuldec_add_pixel_aspect_ratio (emuldec,
890 gst_caps_get_structure (caps, 0));
895 case AVMEDIA_TYPE_AUDIO:
901 if (!gst_pad_set_caps (emuldec->srcpad, caps)) {
902 GST_ELEMENT_ERROR (emuldec, CORE, NEGOTIATION, (NULL),
903 ("Could not set caps for decoder (%s), not fixed?",
904 oclass->codec->name));
905 gst_caps_unref (caps);
909 gst_caps_unref (caps);
915 new_aligned_buffer (gint size, GstCaps *caps)
919 buf = gst_buffer_new ();
920 GST_BUFFER_DATA (buf) = GST_BUFFER_MALLOCDATA (buf) = g_malloc0 (size);
921 GST_BUFFER_SIZE (buf) = size;
922 GST_BUFFER_FREE_FUNC (buf) = g_free;
925 gst_buffer_set_caps (buf, caps);
932 get_output_buffer (GstEmulDec *emuldec, GstBuffer **outbuf)
941 if (G_UNLIKELY (!gst_emuldec_negotiate (emuldec, FALSE))) {
942 GST_DEBUG_OBJECT (emuldec, "negotiate failed");
943 return GST_FLOW_NOT_NEGOTIATED;
946 pict_size = gst_emul_avpicture_size (emuldec->context->video.pix_fmt,
947 emuldec->context->video.width, emuldec->context->video.height);
950 gst_pad_set_bufferalloc_function(GST_PAD_PEER(emuldec->srcpad), (GstPadBufferAllocFunction) emul_buffer_alloc);
953 ret = gst_pad_alloc_buffer_and_set_caps (emuldec->srcpad,
954 GST_BUFFER_OFFSET_NONE, pict_size,
955 GST_PAD_CAPS (emuldec->srcpad), outbuf);
956 if (G_UNLIKELY (ret != GST_FLOW_OK)) {
957 GST_DEBUG_OBJECT (emuldec, "pad_alloc failed %d (%s)", ret,
958 gst_flow_get_name (ret));
962 if ((uintptr_t) GST_BUFFER_DATA (*outbuf) % 16) {
963 GST_DEBUG_OBJECT (emuldec,
964 "Downstream can't allocate aligned buffers.");
965 gst_buffer_unref (*outbuf);
966 *outbuf = new_aligned_buffer (pict_size, GST_PAD_CAPS (emuldec->srcpad));
969 gst_buffer_set_caps (*outbuf, GST_PAD_CAPS (emuldec->srcpad));
971 emul_av_picture_copy (emuldec->context, GST_BUFFER_DATA (*outbuf),
972 GST_BUFFER_SIZE (*outbuf), emuldec->dev);
975 GST_BUFFER_DATA (*outbuf) = emuldec->dev->buf;
982 clip_video_buffer (GstEmulDec *dec, GstBuffer *buf,
983 GstClockTime in_ts, GstClockTime in_dur)
991 clip_audio_buffer (GstEmulDec *dec, GstBuffer *buf,
992 GstClockTime in_ts, GstClockTime in_dur)
995 gint64 diff, cstart, cstop;
998 if (G_UNLIKELY (dec->segment.format != GST_FORMAT_TIME)) {
999 GST_LOG_OBJECT (dec, "%sdropping", (res ? "not " : ""));
1003 // in_ts: in_timestamp. check a start time.
1004 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (in_ts))) {
1005 GST_LOG_OBJECT (dec, "%sdropping", (res ? "not " : ""));
1010 GST_CLOCK_TIME_IS_VALID (in_dur) ? (in_ts + in_dur) : GST_CLOCK_TIME_NONE;
1012 res = gst_segment_clip (&dec->segment, GST_FORMAT_TIME, in_ts,
1013 stop, &cstart, &cstop);
1014 if (G_UNLIKELY (!res)) {
1015 GST_LOG_OBJECT (dec, "out of segment");
1016 GST_LOG_OBJECT (dec, "%sdropping", (res ? "not " : ""));
1020 if (G_UNLIKELY ((diff = cstart - in_ts) > 0)) {
1022 gst_util_uint64_scale_int (diff, dec->format.audio.samplerate, GST_SECOND) *
1023 (dec->format.audio.depth * dec->format.audio.channels);
1025 GST_DEBUG_OBJECT (dec, "clipping start to %" GST_TIME_FORMAT " %"
1026 G_GINT64_FORMAT " bytes", GST_TIME_ARGS (cstart), diff);
1028 GST_BUFFER_SIZE (buf) -= diff;
1029 GST_BUFFER_DATA (buf) += diff;
1033 if (G_UNLIKELY ((diff = stop - cstop) > 0)) {
1035 gst_util_uint64_scale_int (diff, dec->format.audio.samplerate, GST_SECOND) *
1036 (dec->format.audio.depth * dec->format.audio.channels);
1038 GST_DEBUG_OBJECT (dec, "clipping stop to %" GST_TIME_FORMAT " %"
1039 G_GINT64_FORMAT " bytes", GST_TIME_ARGS (cstop), diff);
1041 GST_BUFFER_SIZE (buf) -= diff;
1044 GST_BUFFER_TIMESTAMP (buf) = cstart;
1045 GST_BUFFER_DURATION (buf) = cstop - cstart;
1047 GST_LOG_OBJECT (dec, "%sdropping", (res ? "not " : ""));
1052 gst_emuldec_video_frame (GstEmulDec *emuldec, guint8 *data, guint size,
1053 const GstTSInfo *dec_info, gint64 in_offset, GstBuffer **outbuf,
1056 gint len = -1, have_data;
1057 gboolean mode_switch;
1059 GstClockTime out_timestamp, out_duration, out_pts;
1061 const GstTSInfo *out_info;
1063 decode = gst_emuldec_do_qos (emuldec, dec_info->timestamp, &mode_switch);
1065 CODEC_LOG (DEBUG, "decode video: input buffer size: %d\n", size);
1067 emul_avcodec_decode_video (emuldec->context, data, size,
1068 dec_info->idx, in_offset, outbuf,
1069 &have_data, emuldec->dev);
1075 GST_DEBUG_OBJECT (emuldec, "after decode: len %d, have_data %d",
1079 if (len < 0 && (mode_switch || emuldec->context->skip_frame)) {
1083 if (len > 0 && have_data <= 0 && (mode_switch
1084 || emuldec->context->skip_frame)) {
1085 emuldec->last_out = -1;
1089 if (len < 0 || have_data <= 0) {
1090 GST_DEBUG_OBJECT (emuldec, "return flow %d, out %p, len %d",
1091 *ret, *outbuf, len);
1095 out_info = gst_ts_info_get (emuldec, dec_info->idx);
1096 out_pts = out_info->timestamp;
1097 out_duration = out_info->duration;
1098 out_offset = out_info->offset;
1100 *ret = get_output_buffer (emuldec, outbuf);
1101 if (G_UNLIKELY (*ret != GST_FLOW_OK)) {
1102 GST_DEBUG_OBJECT (emuldec, "no output buffer");
1104 GST_DEBUG_OBJECT (emuldec, "return flow %d, out %p, len %d",
1105 *ret, *outbuf, len);
1111 if (out_pts != -1) {
1112 out_timestamp = (GstClockTime) out_pts;
1113 GST_LOG_OBJECT (emuldec, "using timestamp %" GST_TIME_FORMAT
1114 " returned by ffmpeg", GST_TIME_ARGS (out_timestamp));
1117 if (!GST_CLOCK_TIME_IS_VALID (out_timestamp) && emuldec->next_out != -1) {
1118 out_timestamp = emuldec->next_out;
1119 GST_LOG_OBJECT (emuldec, "using next timestamp %" GST_TIME_FORMAT,
1120 GST_TIME_ARGS (out_timestamp));
1123 if (!GST_CLOCK_TIME_IS_VALID (out_timestamp)) {
1124 out_timestamp = dec_info->timestamp;
1125 GST_LOG_OBJECT (emuldec, "using in timestamp %" GST_TIME_FORMAT,
1126 GST_TIME_ARGS (out_timestamp));
1128 GST_BUFFER_TIMESTAMP (*outbuf) = out_timestamp;
1131 if (out_offset != GST_BUFFER_OFFSET_NONE) {
1132 GST_LOG_OBJECT (emuldec, "Using offset returned by ffmpeg");
1133 } else if (out_timestamp != GST_CLOCK_TIME_NONE) {
1134 GstFormat out_fmt = GST_FORMAT_DEFAULT;
1135 GST_LOG_OBJECT (emuldec, "Using offset converted from timestamp");
1137 gst_pad_query_peer_convert (emuldec->sinkpad,
1138 GST_FORMAT_TIME, out_timestamp, &out_fmt, &out_offset);
1139 } else if (dec_info->offset != GST_BUFFER_OFFSET_NONE) {
1140 GST_LOG_OBJECT (emuldec, "using in_offset %" G_GINT64_FORMAT,
1142 out_offset = dec_info->offset;
1144 GST_LOG_OBJECT (emuldec, "no valid offset found");
1145 out_offset = GST_BUFFER_OFFSET_NONE;
1147 GST_BUFFER_OFFSET (*outbuf) = out_offset;
1150 if (GST_CLOCK_TIME_IS_VALID (out_duration)) {
1151 GST_LOG_OBJECT (emuldec, "Using duration returned by ffmpeg");
1152 } else if (GST_CLOCK_TIME_IS_VALID (dec_info->duration)) {
1153 GST_LOG_OBJECT (emuldec, "Using in_duration");
1154 out_duration = dec_info->duration;
1156 } else if (GST_CLOCK_TIME_IS_VALID (emuldec->last_diff)) {
1157 GST_LOG_OBJECT (emuldec, "Using last-diff");
1158 out_duration = emuldec->last_diff;
1161 if (emuldec->format.video.fps_n != -1 &&
1162 (emuldec->format.video.fps_n != 1000 &&
1163 emuldec->format.video.fps_d != 1)) {
1164 GST_LOG_OBJECT (emuldec, "using input framerate for duration");
1165 out_duration = gst_util_uint64_scale_int (GST_SECOND,
1166 emuldec->format.video.fps_d, emuldec->format.video.fps_n);
1168 if (emuldec->context->video.fps_n != 0 &&
1169 (emuldec->context->video.fps_d > 0 &&
1170 emuldec->context->video.fps_d < 1000)) {
1171 GST_LOG_OBJECT (emuldec, "using decoder's framerate for duration");
1172 out_duration = gst_util_uint64_scale_int (GST_SECOND,
1173 emuldec->context->video.fps_n * 1,
1174 emuldec->context->video.fps_d);
1176 GST_LOG_OBJECT (emuldec, "no valid duration found");
1182 if (GST_CLOCK_TIME_IS_VALID (out_duration)) {
1183 out_duration += out_duration * emuldec->picture->repeat_pict / 2;
1185 GST_BUFFER_DURATION (*outbuf) = out_duration;
1187 if (out_timestamp != -1 && out_duration != -1 && out_duration != 0) {
1188 emuldec->next_out = out_timestamp + out_duration;
1190 emuldec->next_out = -1;
1194 if (G_UNLIKELY (!clip_video_buffer (emuldec, *outbuf, out_timestamp,
1196 GST_DEBUG_OBJECT (emuldec, "buffer clipped");
1197 gst_buffer_unref (*outbuf);
1199 GST_DEBUG_OBJECT (emuldec, "return flow %d, out %p, len %d",
1200 *ret, *outbuf, len);
1204 GST_DEBUG_OBJECT (emuldec, "return flow %d, out %p, len %d",
1205 *ret, *outbuf, len);
1210 gst_emuldec_audio_frame (GstEmulDec *emuldec, CodecElement *codec,
1211 guint8 *data, guint size,
1212 const GstTSInfo *dec_info, GstBuffer **outbuf,
1216 gint have_data = FF_MAX_AUDIO_FRAME_SIZE;
1217 GstClockTime out_timestamp, out_duration;
1221 new_aligned_buffer (FF_MAX_AUDIO_FRAME_SIZE,
1222 GST_PAD_CAPS (emuldec->srcpad));
1224 CODEC_LOG (DEBUG, "decode audio, input buffer size: %d\n", size);
1226 len = emul_avcodec_decode_audio (emuldec->context,
1227 (int16_t *) GST_BUFFER_DATA (*outbuf), &have_data,
1228 data, size, emuldec->dev);
1231 GST_BUFFER_DATA (*outbuf) =
1232 (uint8_t *)emuldec->dev->buf +
1233 sizeof(emuldec->context->audio.channel_layout) +
1234 sizeof(len) + sizeof(have_data);
1237 GST_DEBUG_OBJECT (emuldec,
1238 "Decode audio: len=%d, have_data=%d", len, have_data);
1240 if (len >= 0 && have_data > 0) {
1241 GST_DEBUG_OBJECT (emuldec, "Creating output buffer");
1242 if (!gst_emuldec_negotiate (emuldec, FALSE)) {
1243 gst_buffer_unref (*outbuf);
1246 GST_DEBUG_OBJECT (emuldec, "return flow %d, out %p, len %d",
1247 *ret, *outbuf, len);
1251 GST_BUFFER_SIZE (*outbuf) = have_data;
1253 if (GST_CLOCK_TIME_IS_VALID (dec_info->timestamp)) {
1254 out_timestamp = dec_info->timestamp;
1256 out_timestamp = emuldec->next_out;
1259 /* calculate based on number of samples */
1260 out_duration = gst_util_uint64_scale (have_data, GST_SECOND,
1261 emuldec->format.audio.depth * emuldec->format.audio.channels *
1262 emuldec->format.audio.samplerate);
1264 out_offset = dec_info->offset;
1266 GST_DEBUG_OBJECT (emuldec,
1267 "Buffer created. Size: %d, timestamp: %" GST_TIME_FORMAT
1268 ", duration: %" GST_TIME_FORMAT, have_data,
1269 GST_TIME_ARGS (out_timestamp), GST_TIME_ARGS (out_duration));
1271 GST_BUFFER_TIMESTAMP (*outbuf) = out_timestamp;
1272 GST_BUFFER_DURATION (*outbuf) = out_duration;
1273 GST_BUFFER_OFFSET (*outbuf) = out_offset;
1274 gst_buffer_set_caps (*outbuf, GST_PAD_CAPS (emuldec->srcpad));
1276 if (GST_CLOCK_TIME_IS_VALID (out_timestamp)) {
1277 emuldec->next_out = out_timestamp + out_duration;
1280 if (G_UNLIKELY (!clip_audio_buffer (emuldec, *outbuf,
1281 out_timestamp, out_duration))) {
1282 GST_DEBUG_OBJECT (emuldec, "buffer_clipped");
1283 gst_buffer_unref (*outbuf);
1285 GST_DEBUG_OBJECT (emuldec, "return flow %d, out %p, len %d", *ret, *outbuf, len);
1289 gst_buffer_unref (*outbuf);
1293 if (len == -1 && !strcmp(codec->name, "aac")) {
1294 GST_ELEMENT_ERROR (emuldec, STREAM, DECODE, (NULL),
1295 ("Decoding of AAC stream by FFMPEG failed."));
1296 *ret = GST_FLOW_ERROR;
1299 GST_DEBUG_OBJECT (emuldec, "return flow %d, out %p, len %d",
1300 *ret, *outbuf, len);
1305 gst_emuldec_frame (GstEmulDec *emuldec, guint8 *data, guint size,
1306 gint *got_data, const GstTSInfo *dec_info, gint64 in_offset, GstFlowReturn *ret)
1308 GstEmulDecClass *oclass;
1309 GstBuffer *outbuf = NULL;
1310 gint have_data = 0, len = 0;
1312 if (G_UNLIKELY (emuldec->context->codec == NULL)) {
1313 GST_ERROR_OBJECT (emuldec, "no codec context");
1318 oclass = (GstEmulDecClass *) (G_OBJECT_GET_CLASS (emuldec));
1320 switch (oclass->codec->media_type) {
1321 case AVMEDIA_TYPE_VIDEO:
1322 len = gst_emuldec_video_frame (emuldec, data, size,
1323 dec_info, in_offset, &outbuf, ret);
1325 case AVMEDIA_TYPE_AUDIO:
1326 len = gst_emuldec_audio_frame (emuldec, oclass->codec, data, size,
1327 dec_info, &outbuf, ret);
1328 if (outbuf == NULL && emuldec->discont) {
1329 GST_DEBUG_OBJECT (emuldec, "no buffer but keeping timestamp");
1330 // emuldec->clear_ts = FALSE;
1334 GST_ERROR_OBJECT (emuldec, "Asked to decode non-audio/video frame!");
1335 g_assert_not_reached ();
1343 if (len < 0 || have_data < 0) {
1344 GST_WARNING_OBJECT (emuldec,
1345 "maru_%sdec: decoding error (len: %d, have_data: %d)",
1346 oclass->codec->name, len, have_data);
1349 } else if (len == 0 && have_data == 0) {
1357 GST_LOG_OBJECT (emuldec,
1358 "Decoded data, now pushing buffer %p with offset %" G_GINT64_FORMAT
1359 ", timestamp %" GST_TIME_FORMAT " and duration %" GST_TIME_FORMAT,
1360 outbuf, GST_BUFFER_OFFSET (outbuf),
1361 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)),
1362 GST_TIME_ARGS (GST_BUFFER_DURATION (outbuf)));
1364 if (emuldec->discont) {
1365 /* GST_BUFFER_FLAG_DISCONT :
1366 * the buffer marks a data discontinuity in the stream. This typically
1367 * occurs after a seek or a dropped buffer from a live or network source.
1369 GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
1370 emuldec->discont = FALSE;
1373 if (emuldec->segment.rate > 0.0) {
1375 *ret = gst_pad_push (emuldec->srcpad, outbuf);
1378 GST_DEBUG_OBJECT (emuldec, "queued frame");
1379 emuldec->queued = g_list_prepend (emuldec->queued, outbuf);
1383 GST_DEBUG_OBJECT (emuldec, "Didn't get a decoded buffer");
1389 static GstFlowReturn
1390 gst_emuldec_chain (GstPad *pad, GstBuffer *buffer)
1392 GstEmulDec *emuldec;
1393 GstEmulDecClass *oclass;
1395 gint in_size, len, have_data;
1396 GstFlowReturn ret = GST_FLOW_OK;
1397 GstClockTime in_timestamp;
1398 GstClockTime in_duration;
1401 const GstTSInfo *in_info;
1402 const GstTSInfo *dec_info;
1404 emuldec = (GstEmulDec *) (GST_PAD_PARENT (pad));
1406 if (G_UNLIKELY (!emuldec->opened)) {
1408 oclass = (GstEmulDecClass *) (G_OBJECT_GET_CLASS (emuldec));
1409 GST_ELEMENT_ERROR (emuldec, CORE, NEGOTIATION, (NULL),
1410 ("maru_%sdec: input format was not set before data start",
1411 oclass->codec->name));
1412 gst_buffer_unref (buffer);
1413 return GST_FLOW_NOT_NEGOTIATED;
1416 discont = GST_BUFFER_IS_DISCONT (buffer);
1419 if (G_UNLIKELY (discont)) {
1420 GST_DEBUG_OBJECT (emuldec, "received DISCONT");
1421 gst_emuldec_drain (emuldec);
1422 // gst_emuldec_flush_pcache (emuldec);
1423 // emul_avcodec_flush buffers (emuldec->context, emuldec->dev);
1424 emuldec->discont = TRUE;
1425 gst_emuldec_reset_ts (emuldec);
1427 // emuldec->clear_ts = TRUE;
1429 oclass = (GstEmulDecClass *) (G_OBJECT_GET_CLASS (emuldec));
1431 if (G_UNLIKELY (emuldec->waiting_for_key)) {
1432 if (GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DELTA_UNIT) &&
1433 oclass->codec->media_type != AVMEDIA_TYPE_AUDIO) {
1436 emuldec->waiting_for_key = FALSE;
1439 if (emuldec->pcache) {
1440 GST_LOG_OBJECT (emuldec, "join parse cache");
1441 buffer = gst_buffer_join (emuldec->pcache, buffer);
1442 emuldec->pcache = NULL;
1446 in_timestamp = GST_BUFFER_TIMESTAMP (buffer);
1447 in_duration = GST_BUFFER_DURATION (buffer);
1448 in_offset = GST_BUFFER_OFFSET (buffer);
1450 in_info = gst_ts_info_store (emuldec, in_timestamp, in_duration, in_offset);
1453 if (in_timestamp != -1) {
1454 if (!emuldec->reordered_in && emuldec->last_in != -1) {
1455 if (in_timestamp < emuldec->last_in) {
1456 GST_LOG_OBJECT (emuldec, "detected reordered input timestamps");
1457 emuldec->reordered_in = TRUE;
1458 emuldec->last_diff = GST_CLOCK_TIME_NONE;
1459 } else if (in_timestamp > emuldec->last_in) {
1461 diff = in_timestamp - emuldec->last_in;
1462 if (emuldec->last_frames) {
1463 diff /= emuldec->last_frames;
1466 GST_LOG_OBJECT (emuldec, "estimated duration %" GST_TIME_FORMAT " %u",
1467 GST_TIME_ARGS (diff), emuldec->last_frames);
1469 emuldec->last_diff = diff;
1472 emuldec->last_in = in_timestamp;
1473 emuldec->last_frames;
1477 GST_LOG_OBJECT (emuldec,
1478 "Received new data of size %u, offset: %" G_GUINT64_FORMAT ", ts:%"
1479 GST_TIME_FORMAT ", dur: %" GST_TIME_FORMAT ", info %d",
1480 GST_BUFFER_SIZE (buffer), GST_BUFFER_OFFSET (buffer),
1481 GST_TIME_ARGS (in_timestamp), GST_TIME_ARGS (in_duration), in_info->idx);
1483 in_buf = GST_BUFFER_DATA (buffer);
1484 in_size = GST_BUFFER_SIZE (buffer);
1489 gst_emuldec_frame (emuldec, in_buf, in_size, &have_data, dec_info, in_offset, &ret);
1492 if (emuldec->clear_ts) {
1493 in_timestamp = GST_CLOCK_TIME_NONE;
1494 in_duration = GST_CLOCK_TIME_NONE;
1495 in_offset = GST_BUFFER_OFFSET_NONE;
1496 in_info = GST_TS_INFO_NONE;
1498 emuldec->clear_ts = TRUE;
1502 gst_buffer_unref (buffer);
1507 static GstStateChangeReturn
1508 gst_emuldec_change_state (GstElement *element, GstStateChange transition)
1510 GstEmulDec *emuldec = (GstEmulDec *) element;
1511 GstStateChangeReturn ret;
1513 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
1515 switch (transition) {
1516 case GST_STATE_CHANGE_PAUSED_TO_READY:
1517 GST_OBJECT_LOCK (emuldec);
1518 gst_emuldec_close (emuldec);
1519 GST_OBJECT_UNLOCK (emuldec);
1522 clear_queued (emuldec);
1532 gst_emuldec_register (GstPlugin *plugin, GList *element)
1534 GTypeInfo typeinfo = {
1535 sizeof (GstEmulDecClass),
1536 (GBaseInitFunc) gst_emuldec_base_init,
1538 (GClassInitFunc) gst_emuldec_class_init,
1541 sizeof (GstEmulDec),
1543 (GInstanceInitFunc) gst_emuldec_init,
1548 gint rank = GST_RANK_NONE;
1549 GList *elem = element;
1550 CodecElement *codec = NULL;
1552 /* register element */
1553 // while ((elem = g_list_next (elem))) {
1555 codec = (CodecElement *)elem->data;
1560 if (codec->codec_type != CODEC_TYPE_DECODE) {
1564 type_name = g_strdup_printf ("maru_%sdec", codec->name);
1565 type = g_type_from_name (type_name);
1567 type = g_type_register_static (GST_TYPE_ELEMENT, type_name, &typeinfo, 0);
1568 g_type_set_qdata (type, GST_EMULDEC_PARAMS_QDATA, (gpointer) codec);
1571 if (!gst_element_register (plugin, type_name, rank, type)) {
1576 } while ((elem = g_list_next (elem)));