Seperate decode and picture_copy if no pix_fmt is specified
[platform/adaptation/emulator/gst-plugins-emulator.git] / src / gstmarudec.c
1 /* GStreamer
2  * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
3  * Copyright (C) 2013 Samsung Electronics Co., Ltd.
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., 59 Temple Place - Suite 330,
18  * Boston, MA 02111-1307, USA.
19  */
20
21 /* Modifications by Samsung Electronics Co., Ltd.
22  * 1. Provide a hardware buffer in order to avoid additional memcpy operations.
23  */
24
25 #include "gstmarudevice.h"
26 #include "gstmaruutils.h"
27 #include "gstmaruinterface.h"
28
29 #define GST_MARUDEC_PARAMS_QDATA g_quark_from_static_string("marudec-params")
30
31 /* indicate dts, pts, offset in the stream */
32 #define GST_TS_INFO_NONE &ts_info_none
33 static const GstTSInfo ts_info_none = { -1, -1, -1, -1 };
34
35 typedef struct _GstMaruDecClass
36 {
37   GstElementClass parent_class;
38
39   CodecElement *codec;
40   GstPadTemplate *sinktempl;
41   GstPadTemplate *srctempl;
42 } GstMaruDecClass;
43
44
45 static GstElementClass *parent_class = NULL;
46
47 static void gst_marudec_base_init (GstMaruDecClass *klass);
48 static void gst_marudec_class_init (GstMaruDecClass *klass);
49 static void gst_marudec_init (GstMaruDec *marudec);
50 static void gst_marudec_finalize (GObject *object);
51
52 static gboolean gst_marudec_setcaps (GstPad *pad, GstCaps *caps);
53
54 // sinkpad
55 static gboolean gst_marudec_sink_event (GstPad *pad, GstEvent *event);
56 static GstFlowReturn gst_marudec_chain (GstPad *pad, GstBuffer *buffer);
57
58 // srcpad
59 static gboolean gst_marudec_src_event (GstPad *pad, GstEvent *event);
60 static GstStateChangeReturn gst_marudec_change_state (GstElement *element,
61                                                 GstStateChange transition);
62
63 static gboolean gst_marudec_negotiate (GstMaruDec *dec, gboolean force);
64
65 static gint gst_marudec_frame (GstMaruDec *marudec, guint8 *data,
66                               guint size, gint *got_data,
67                               const GstTSInfo *dec_info, gint64 in_offset, GstFlowReturn *ret);
68
69 static gboolean gst_marudec_open (GstMaruDec *marudec);
70 static int gst_marudec_close (GstMaruDec *marudec);
71
72
73 static const GstTSInfo *
74 gst_ts_info_store (GstMaruDec *dec, GstClockTime timestamp,
75     GstClockTime duration, gint64 offset)
76 {
77   gint idx = dec->ts_idx;
78   dec->ts_info[idx].idx = idx;
79   dec->ts_info[idx].timestamp = timestamp;
80   dec->ts_info[idx].duration = duration;
81   dec->ts_info[idx].offset = offset;
82   dec->ts_idx = (idx + 1) & MAX_TS_MASK;
83
84   return &dec->ts_info[idx];
85 }
86
87 static const GstTSInfo *
88 gst_ts_info_get (GstMaruDec *dec, gint idx)
89 {
90   if (G_UNLIKELY (idx < 0 || idx > MAX_TS_MASK))
91     return GST_TS_INFO_NONE;
92
93   return &dec->ts_info[idx];
94 }
95
96 static void
97 gst_marudec_reset_ts (GstMaruDec *marudec)
98 {
99   marudec->next_out = GST_CLOCK_TIME_NONE;
100 }
101
102 static void
103 gst_marudec_update_qos (GstMaruDec *marudec, gdouble proportion,
104   GstClockTime timestamp)
105 {
106   GST_LOG_OBJECT (marudec, "update QOS: %f, %" GST_TIME_FORMAT,
107       proportion, GST_TIME_ARGS (timestamp));
108
109   GST_OBJECT_LOCK (marudec);
110   marudec->proportion = proportion;
111   marudec->earliest_time = timestamp;
112   GST_OBJECT_UNLOCK (marudec);
113 }
114
115 static void
116 gst_marudec_reset_qos (GstMaruDec *marudec)
117 {
118   gst_marudec_update_qos (marudec, 0.5, GST_CLOCK_TIME_NONE);
119   marudec->processed = 0;
120   marudec->dropped = 0;
121 }
122
123 static gboolean
124 gst_marudec_do_qos (GstMaruDec *marudec, GstClockTime timestamp,
125   gboolean *mode_switch)
126 {
127   GstClockTimeDiff diff;
128   gdouble proportion;
129   GstClockTime qostime, earliest_time;
130   gboolean res = TRUE;
131
132   *mode_switch = FALSE;
133
134   if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (timestamp))) {
135     marudec->processed++;
136     return TRUE;
137   }
138
139   proportion = marudec->proportion;
140   earliest_time = marudec->earliest_time;
141
142   qostime = gst_segment_to_running_time (&marudec->segment, GST_FORMAT_TIME,
143     timestamp);
144
145   if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (qostime))) {
146     marudec->processed++;
147     return TRUE;
148   }
149
150   diff = GST_CLOCK_DIFF (qostime, earliest_time);
151
152   if (proportion < 0.4 && diff < 0 ){
153     marudec->processed++;
154     return TRUE;
155   } else {
156     if (diff >= 0) {
157 //      if (marudec->waiting_for_key) {
158       if (0) {
159         res = FALSE;
160       }
161 #if 0
162       else {
163       }
164 #endif
165
166       GstClockTime stream_time, jitter;
167       GstMessage *qos_msg;
168
169       marudec->dropped++;
170       stream_time =
171           gst_segment_to_stream_time (&marudec->segment, GST_FORMAT_TIME,
172                   timestamp);
173       jitter = GST_CLOCK_DIFF (qostime, earliest_time);
174       qos_msg =
175           gst_message_new_qos (GST_OBJECT_CAST (marudec), FALSE, qostime,
176                   stream_time, timestamp, GST_CLOCK_TIME_NONE);
177       gst_message_set_qos_values (qos_msg, jitter, proportion, 1000000);
178       gst_message_set_qos_stats (qos_msg, GST_FORMAT_BUFFERS,
179               marudec->processed, marudec->dropped);
180       gst_element_post_message (GST_ELEMENT_CAST (marudec), qos_msg);
181
182       return res;
183     }
184   }
185
186   marudec->processed++;
187   return TRUE;
188 }
189
190 static void
191 clear_queued (GstMaruDec *marudec)
192 {
193   g_list_foreach (marudec->queued, (GFunc) gst_mini_object_unref, NULL);
194   g_list_free (marudec->queued);
195   marudec->queued = NULL;
196 }
197
198 static GstFlowReturn
199 flush_queued (GstMaruDec *marudec)
200 {
201   GstFlowReturn res = GST_FLOW_OK;
202
203   GST_DEBUG_OBJECT (marudec, "flush queued");
204
205   while (marudec->queued) {
206     GstBuffer *buf = GST_BUFFER_CAST (marudec->queued->data);
207
208     GST_LOG_OBJECT (marudec, "pushing buffer %p, offset %"
209       G_GUINT64_FORMAT ", timestamp %"
210       GST_TIME_FORMAT ", duration %" GST_TIME_FORMAT, buf,
211       GST_BUFFER_OFFSET (buf),
212       GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)),
213       GST_TIME_ARGS (GST_BUFFER_DURATION (buf)));
214
215     res = gst_pad_push (marudec->srcpad, buf);
216
217     marudec->queued =
218       g_list_delete_link (marudec->queued, marudec->queued);
219   }
220
221   return res;
222 }
223
224 static void
225 gst_marudec_drain (GstMaruDec *marudec)
226 {
227 #if 0
228   GstMaruDecClass *oclass;
229   oclass = (GstMaruDecClass *) (G_OBJECT_GET_CLASS (marudec));
230 #endif
231
232   GST_DEBUG_OBJECT (marudec, "drain frame");
233   {
234     gint have_data, len, try = 0;
235
236     do {
237       GstFlowReturn ret;
238
239       len =
240         gst_marudec_frame (marudec, NULL, 0, &have_data, &ts_info_none, 0, &ret);
241
242       if (len < 0 || have_data == 0) {
243         break;
244       }
245     } while (try++ < 10);
246   }
247
248   if (marudec->segment.rate < 0.0) {
249     GST_DEBUG_OBJECT (marudec, "reverse playback");
250     flush_queued (marudec);
251   }
252 }
253
254 /*
255  * Implementation
256  */
257 static void
258 gst_marudec_base_init (GstMaruDecClass *klass)
259 {
260   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
261   GstCaps *sinkcaps = NULL, *srccaps = NULL;
262   GstPadTemplate *sinktempl, *srctempl;
263   CodecElement *codec;
264   gchar *longname, *classification, *description;
265
266   codec =
267       (CodecElement *)g_type_get_qdata (G_OBJECT_CLASS_TYPE (klass),
268                                       GST_MARUDEC_PARAMS_QDATA);
269
270   longname = g_strdup_printf ("%s Decoder", codec->longname);
271   classification = g_strdup_printf ("Codec/Decoder/%s",
272                     (codec->media_type == AVMEDIA_TYPE_VIDEO) ?
273                     "Video" : "Audio");
274   description = g_strdup_printf("%s Decoder", codec->name);
275
276   gst_element_class_set_details_simple (element_class,
277             longname,
278             classification,
279             description,
280             "Kitae Kim <kt920.kim@samsung.com>");
281
282   g_free (longname);
283   g_free (classification);
284   g_free (description);
285
286   sinkcaps = gst_maru_codecname_to_caps (codec->name, NULL, FALSE);
287   if (!sinkcaps) {
288     sinkcaps = gst_caps_from_string ("unknown/unknown");
289   }
290
291   switch (codec->media_type) {
292   case AVMEDIA_TYPE_VIDEO:
293     srccaps = gst_caps_from_string ("video/x-raw-rgb; video/x-raw-yuv");
294     break;
295   case AVMEDIA_TYPE_AUDIO:
296     srccaps = gst_maru_codectype_to_audio_caps (NULL, codec->name, FALSE, codec);
297     break;
298   default:
299     GST_LOG("unknown media type.\n");
300     break;
301   }
302
303   if (!srccaps) {
304     srccaps = gst_caps_from_string ("unknown/unknown");
305   }
306
307   sinktempl = gst_pad_template_new ("sink", GST_PAD_SINK,
308                 GST_PAD_ALWAYS, sinkcaps);
309   srctempl = gst_pad_template_new ("src", GST_PAD_SRC,
310                 GST_PAD_ALWAYS, srccaps);
311
312   gst_element_class_add_pad_template (element_class, srctempl);
313   gst_element_class_add_pad_template (element_class, sinktempl);
314
315   klass->codec = codec;
316   klass->sinktempl = sinktempl;
317   klass->srctempl = srctempl;
318 }
319
320 static void
321 gst_marudec_class_init (GstMaruDecClass *klass)
322 {
323   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
324   GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
325
326   parent_class = g_type_class_peek_parent (klass);
327
328 #if 0
329   gobject_class->set_property = gst_marudec_set_property
330   gobject_class->get_property = gst_marudec_get_property
331 #endif
332
333   gobject_class->finalize = gst_marudec_finalize;
334   gstelement_class->change_state = gst_marudec_change_state;
335 }
336
337 static void
338 gst_marudec_init (GstMaruDec *marudec)
339 {
340   GstMaruDecClass *oclass;
341
342   oclass = (GstMaruDecClass*) (G_OBJECT_GET_CLASS(marudec));
343
344   marudec->sinkpad = gst_pad_new_from_template (oclass->sinktempl, "sink");
345   gst_pad_set_setcaps_function (marudec->sinkpad,
346     GST_DEBUG_FUNCPTR(gst_marudec_setcaps));
347   gst_pad_set_event_function (marudec->sinkpad,
348     GST_DEBUG_FUNCPTR(gst_marudec_sink_event));
349   gst_pad_set_chain_function (marudec->sinkpad,
350     GST_DEBUG_FUNCPTR(gst_marudec_chain));
351
352   marudec->srcpad = gst_pad_new_from_template (oclass->srctempl, "src") ;
353   gst_pad_use_fixed_caps (marudec->srcpad);
354   gst_pad_set_event_function (marudec->srcpad,
355     GST_DEBUG_FUNCPTR(gst_marudec_src_event));
356
357   gst_element_add_pad (GST_ELEMENT(marudec), marudec->sinkpad);
358   gst_element_add_pad (GST_ELEMENT(marudec), marudec->srcpad);
359
360   marudec->context = g_malloc0 (sizeof(CodecContext));
361   marudec->context->video.pix_fmt = PIX_FMT_NONE;
362   marudec->context->audio.sample_fmt = SAMPLE_FMT_NONE;
363
364   marudec->opened = FALSE;
365   marudec->format.video.par_n = -1;
366   marudec->format.video.fps_n = -1;
367   marudec->format.video.old_fps_n = -1;
368
369   marudec->queued = NULL;
370   gst_segment_init (&marudec->segment, GST_FORMAT_TIME);
371
372   marudec->dev = g_malloc0 (sizeof(CodecDevice));
373   if (!marudec->dev) {
374     GST_ERROR_OBJECT (marudec, "failed to allocate memory for CodecDevice");
375   }
376 }
377
378 static void
379 gst_marudec_finalize (GObject *object)
380 {
381   GstMaruDec *marudec = (GstMaruDec *) object;
382
383   if (marudec->context) {
384     g_free (marudec->context);
385     marudec->context = NULL;
386   }
387
388   G_OBJECT_CLASS (parent_class)->finalize (object);
389 }
390
391 static gboolean
392 gst_marudec_src_event (GstPad *pad, GstEvent *event)
393 {
394   GstMaruDec *marudec;
395   gboolean res;
396
397   marudec = (GstMaruDec *) gst_pad_get_parent (pad);
398
399   switch (GST_EVENT_TYPE (event)) {
400     /* Quality Of Service (QOS) event contains a report
401       about the current real-time performance of the stream.*/
402   case GST_EVENT_QOS:
403   {
404     gdouble proportion;
405     GstClockTimeDiff diff;
406     GstClockTime timestamp;
407
408     gst_event_parse_qos (event, &proportion, &diff, &timestamp);
409
410     /* update our QoS values */
411     gst_marudec_update_qos (marudec, proportion, timestamp + diff);
412     break;
413   }
414   default:
415     break;
416   }
417
418   /* forward upstream */
419   res = gst_pad_push_event (marudec->sinkpad, event);
420
421   gst_object_unref (marudec);
422
423   return res;
424 }
425
426 static gboolean
427 gst_marudec_sink_event (GstPad *pad, GstEvent *event)
428 {
429   GstMaruDec *marudec;
430   gboolean ret = FALSE;
431
432   marudec = (GstMaruDec *) gst_pad_get_parent (pad);
433
434   GST_DEBUG_OBJECT (marudec, "Handling %s event",
435     GST_EVENT_TYPE_NAME (event));
436
437   switch (GST_EVENT_TYPE (event)) {
438   case GST_EVENT_EOS:
439     gst_marudec_drain (marudec);
440     break;
441   case GST_EVENT_FLUSH_STOP:
442   {
443     if (marudec->opened) {
444       codec_flush_buffers (marudec->context, marudec->dev);
445     }
446
447     gst_marudec_reset_ts (marudec);
448     gst_marudec_reset_qos (marudec);
449 #if 0
450     gst_marudec_flush_pcache (marudec);
451     marudec->waiting_for_key = TRUE;
452 #endif
453     gst_segment_init (&marudec->segment, GST_FORMAT_TIME);
454     clear_queued (marudec);
455   }
456     break;
457   case GST_EVENT_NEWSEGMENT:
458   {
459     gboolean update;
460     GstFormat format;
461     gint64 start, stop, time;
462     gdouble rate, arate;
463
464     gst_event_parse_new_segment_full (event, &update, &rate, &arate, &format,
465         &start, &stop, &time);
466
467     switch (format) {
468     case GST_FORMAT_TIME:
469       break;
470     case GST_FORMAT_BYTES:
471     {
472       gint bit_rate;
473       bit_rate = marudec->context->bit_rate;
474
475       if (!bit_rate) {
476         GST_WARNING_OBJECT (marudec, "no bitrate to convert BYTES to TIME");
477         gst_event_unref (event);
478         gst_object_unref (marudec);
479         return ret;
480       }
481
482       GST_DEBUG_OBJECT (marudec, "bitrate: %d", bit_rate);
483
484       if (start != -1) {
485         start = gst_util_uint64_scale_int (start, GST_SECOND, bit_rate);
486       }
487       if (stop != -1) {
488         stop = gst_util_uint64_scale_int (stop, GST_SECOND, bit_rate);
489       }
490       if (time != -1) {
491         time = gst_util_uint64_scale_int (time, GST_SECOND, bit_rate);
492       }
493
494       gst_event_unref (event);
495
496       format = GST_FORMAT_TIME;
497
498       stop = -1;
499       event = gst_event_new_new_segment (update, rate, format,
500           start, stop, time);
501       break;
502     }
503     default:
504       GST_WARNING_OBJECT (marudec, "unknown format received in NEWSEGMENT");
505       gst_event_unref (event);
506       gst_object_unref (marudec);
507       return ret;
508     }
509
510     if (marudec->context->codec) {
511       gst_marudec_drain (marudec);
512     }
513
514     GST_DEBUG_OBJECT (marudec,
515       "NEWSEGMENT in time start %" GST_TIME_FORMAT " -- stop %"
516       GST_TIME_FORMAT, GST_TIME_ARGS (start), GST_TIME_ARGS (stop));
517
518     gst_segment_set_newsegment_full (&marudec->segment, update,
519         rate, arate, format, start, stop, time);
520     break;
521   }
522   default:
523     break;
524   }
525
526   ret = gst_pad_push_event (marudec->srcpad, event);
527
528   gst_object_unref (marudec);
529
530   return ret;
531 }
532
533
534
535 static gboolean
536 gst_marudec_setcaps (GstPad *pad, GstCaps *caps)
537 {
538   GstMaruDec *marudec;
539   GstMaruDecClass *oclass;
540   GstStructure *structure;
541   const GValue *par;
542   const GValue *fps;
543   gboolean ret = TRUE;
544
545   GST_DEBUG_OBJECT (pad, "setcaps called.");
546
547   marudec = (GstMaruDec *) (gst_pad_get_parent (pad));
548   oclass = (GstMaruDecClass *) (G_OBJECT_GET_CLASS (marudec));
549
550   GST_OBJECT_LOCK (marudec);
551
552   if (marudec->opened) {
553     GST_OBJECT_UNLOCK (marudec);
554     gst_marudec_drain (marudec);
555     GST_OBJECT_LOCK (marudec);
556     gst_marudec_close (marudec);
557   }
558
559   GST_LOG_OBJECT (marudec, "size %dx%d", marudec->context->video.width,
560       marudec->context->video.height);
561
562   if (!strcmp(oclass->codec->name, "wmv3") ||
563       !strcmp(oclass->codec->name, "vc1")) {
564     gst_maru_caps_to_codecname (caps, oclass->codec->name, NULL);
565   }
566
567   gst_maru_caps_with_codecname (oclass->codec->name, oclass->codec->media_type,
568                                 caps, marudec->context);
569
570   GST_LOG_OBJECT (marudec, "size after %dx%d", marudec->context->video.width,
571       marudec->context->video.height);
572
573   if (!marudec->context->video.fps_d || !marudec->context->video.fps_n) {
574     GST_DEBUG_OBJECT (marudec, "forcing 25/1 framerate");
575     marudec->context->video.fps_n = 1;
576     marudec->context->video.fps_d = 25;
577   }
578
579   structure = gst_caps_get_structure (caps, 0);
580
581   par = gst_structure_get_value (structure, "pixel-aspect-ratio");
582   if (par) {
583     GST_DEBUG_OBJECT (marudec, "sink caps have pixel-aspect-ratio of %d:%d",
584         gst_value_get_fraction_numerator (par),
585         gst_value_get_fraction_denominator (par));
586
587 #if 0 // TODO
588     if (marudec->par) {
589       g_free(marudec->par);
590     }
591     marudec->par = g_new0 (GValue, 1);
592     gst_value_init_and_copy (marudec->par, par);
593 #endif
594   }
595
596   fps = gst_structure_get_value (structure, "framerate");
597   if (fps != NULL && GST_VALUE_HOLDS_FRACTION (fps)) {
598     marudec->format.video.fps_n = gst_value_get_fraction_numerator (fps);
599     marudec->format.video.fps_d = gst_value_get_fraction_denominator (fps);
600     GST_DEBUG_OBJECT (marudec, "Using framerate %d/%d from incoming",
601         marudec->format.video.fps_n, marudec->format.video.fps_d);
602   } else {
603     marudec->format.video.fps_n = -1;
604     GST_DEBUG_OBJECT (marudec, "Using framerate from codec");
605   }
606
607 #if 0
608   if (strcmp (oclass->codec->name, "aac") == 0) {
609     const gchar *format = gst_structure_get_string (structure, "stream-format");
610     if (format == NULL || strcmp ("format", "raw") == 0) {
611       marudec->turnoff_parser = TRUE;
612     }
613   }
614 #endif
615
616   if (!gst_marudec_open (marudec)) {
617     GST_DEBUG_OBJECT (marudec, "Failed to open");
618 #if 0
619     if (marudec->par) {
620       g_free(marudec->par);
621       marudec->par = NULL;
622     }
623 #endif
624     GST_OBJECT_UNLOCK (marudec);
625     gst_object_unref (marudec);
626
627     return FALSE;
628   }
629
630   gst_structure_get_int (structure, "width",
631     &marudec->format.video.clip_width);
632   gst_structure_get_int (structure, "height",
633     &marudec->format.video.clip_height);
634
635   GST_DEBUG_OBJECT (pad, "clipping to %dx%d",
636     marudec->format.video.clip_width, marudec->format.video.clip_height);
637
638   GST_OBJECT_UNLOCK (marudec);
639   gst_object_unref (marudec);
640
641   return ret;
642 }
643
644 static gboolean
645 gst_marudec_open (GstMaruDec *marudec)
646 {
647   GstMaruDecClass *oclass;
648
649   oclass = (GstMaruDecClass *) (G_OBJECT_GET_CLASS (marudec));
650
651   if (!marudec->dev) {
652     return FALSE;
653   }
654
655   if (gst_maru_avcodec_open (marudec->context,
656                             oclass->codec, marudec->dev) < 0) {
657     gst_marudec_close (marudec);
658     GST_ERROR_OBJECT (marudec,
659       "maru_%sdec: Failed to open codec", oclass->codec->name);
660     return FALSE;
661   }
662
663   marudec->opened = TRUE;
664   GST_LOG_OBJECT (marudec, "Opened codec %s", oclass->codec->name);
665
666   switch (oclass->codec->media_type) {
667   case AVMEDIA_TYPE_VIDEO:
668     marudec->format.video.width = 0;
669     marudec->format.video.height = 0;
670     marudec->format.video.clip_width = -1;
671     marudec->format.video.clip_height = -1;
672     marudec->format.video.pix_fmt = PIX_FMT_NB;
673     marudec->format.video.interlaced = FALSE;
674     break;
675   case AVMEDIA_TYPE_AUDIO:
676     marudec->format.audio.samplerate = 0;
677     marudec->format.audio.channels = 0;
678     marudec->format.audio.depth = 0;
679     break;
680   default:
681     break;
682   }
683
684   gst_marudec_reset_ts (marudec);
685
686   marudec->proportion = 0.0;
687   marudec->earliest_time = -1;
688
689   return TRUE;
690 }
691
692 static int
693 gst_marudec_close (GstMaruDec *marudec)
694 {
695   int ret = 0;
696
697   if (marudec->context->codecdata) {
698     g_free(marudec->context->codecdata);
699     marudec->context->codecdata = NULL;
700   }
701
702   if (!marudec->dev) {
703     return -1;
704   }
705
706   ret = gst_maru_avcodec_close (marudec->context, marudec->dev);
707
708   if (marudec->dev) {
709     g_free(marudec->dev);
710     marudec->dev = NULL;
711   }
712
713   return ret;
714 }
715
716
717 static gboolean
718 gst_marudec_negotiate (GstMaruDec *marudec, gboolean force)
719 {
720   GstMaruDecClass *oclass;
721   GstCaps *caps;
722
723   oclass = (GstMaruDecClass *) (G_OBJECT_GET_CLASS (marudec));
724
725   switch (oclass->codec->media_type) {
726   case AVMEDIA_TYPE_VIDEO:
727     if (!force && marudec->format.video.width == marudec->context->video.width
728       && marudec->format.video.height == marudec->context->video.height
729       && marudec->format.video.fps_n == marudec->format.video.old_fps_n
730       && marudec->format.video.fps_d == marudec->format.video.old_fps_d
731       && marudec->format.video.pix_fmt == marudec->context->video.pix_fmt
732       && marudec->format.video.par_n == marudec->context->video.par_n
733       && marudec->format.video.par_d == marudec->context->video.par_d) {
734       return TRUE;
735     }
736     marudec->format.video.width = marudec->context->video.width;
737     marudec->format.video.height = marudec->context->video.height;
738     marudec->format.video.old_fps_n = marudec->format.video.fps_n;
739     marudec->format.video.old_fps_d = marudec->format.video.fps_d;
740     marudec->format.video.pix_fmt = marudec->context->video.pix_fmt;
741     marudec->format.video.par_n = marudec->context->video.par_n;
742     marudec->format.video.par_d = marudec->context->video.par_d;
743     break;
744   case AVMEDIA_TYPE_AUDIO:
745   {
746     gint depth = gst_maru_smpfmt_depth (marudec->context->audio.sample_fmt);
747     if (!force && marudec->format.audio.samplerate ==
748       marudec->context->audio.sample_rate &&
749       marudec->format.audio.channels == marudec->context->audio.channels &&
750       marudec->format.audio.depth == depth) {
751       return TRUE;
752     }
753     marudec->format.audio.samplerate = marudec->context->audio.sample_rate;
754     marudec->format.audio.channels = marudec->context->audio.channels;
755     marudec->format.audio.depth = depth;
756   }
757     break;
758   default:
759     break;
760   }
761
762   caps =
763     gst_maru_codectype_to_caps (oclass->codec->media_type, marudec->context,
764       oclass->codec->name, FALSE);
765
766   if (caps == NULL) {
767     GST_ELEMENT_ERROR (marudec, CORE, NEGOTIATION,
768       ("Could not find GStreamer caps mapping for codec '%s'.",
769       oclass->codec->name), (NULL));
770     return FALSE;
771   }
772
773   switch (oclass->codec->media_type) {
774   case AVMEDIA_TYPE_VIDEO:
775   {
776     gint width, height;
777     gboolean interlaced;
778
779     width = marudec->format.video.clip_width;
780     height = marudec->format.video.clip_height;
781     interlaced = marudec->format.video.interlaced;
782
783     if (width != -1 && height != -1) {
784       if (width < marudec->context->video.width) {
785         gst_caps_set_simple (caps, "width", G_TYPE_INT, width, NULL);
786       }
787       if (height < marudec->context->video.height) {
788           gst_caps_set_simple (caps, "height", G_TYPE_INT, height, NULL);
789       }
790       gst_caps_set_simple (caps, "interlaced", G_TYPE_BOOLEAN, interlaced,
791         NULL);
792
793       if (marudec->format.video.fps_n != -1) {
794           gst_caps_set_simple (caps, "framerate",
795             GST_TYPE_FRACTION, marudec->format.video.fps_n,
796             marudec->format.video.fps_d, NULL);
797       }
798 #if 0
799       gst_marudec_add_pixel_aspect_ratio (marudec,
800         gst_caps_get_structure (caps, 0));
801 #endif
802     }
803   }
804     break;
805   case AVMEDIA_TYPE_AUDIO:
806     break;
807   default:
808     break;
809   }
810
811   if (!gst_pad_set_caps (marudec->srcpad, caps)) {
812     GST_ELEMENT_ERROR (marudec, CORE, NEGOTIATION, (NULL),
813       ("Could not set caps for decoder (%s), not fixed?",
814       oclass->codec->name));
815     gst_caps_unref (caps);
816     return FALSE;
817   }
818
819   gst_caps_unref (caps);
820
821   return TRUE;
822 }
823
824 GstBuffer *
825 new_aligned_buffer (gint size, GstCaps *caps)
826 {
827   GstBuffer *buf;
828
829   buf = gst_buffer_new ();
830   GST_BUFFER_DATA (buf) = GST_BUFFER_MALLOCDATA (buf) = g_malloc0 (size);
831   GST_BUFFER_SIZE (buf) = size;
832   GST_BUFFER_FREE_FUNC (buf) = g_free;
833
834   if (caps) {
835     gst_buffer_set_caps (buf, caps);
836   }
837
838   return buf;
839 }
840
841 static GstFlowReturn
842 get_output_buffer (GstMaruDec *marudec, GstBuffer **outbuf)
843 {
844   gint pict_size;
845   GstFlowReturn ret;
846
847   ret = GST_FLOW_OK;
848
849   *outbuf = NULL;
850
851   if (G_UNLIKELY (!gst_marudec_negotiate (marudec, FALSE))) {
852     GST_DEBUG_OBJECT (marudec, "negotiate failed");
853     return GST_FLOW_NOT_NEGOTIATED;
854   }
855
856   pict_size = gst_maru_avpicture_size (marudec->context->video.pix_fmt,
857     marudec->context->video.width, marudec->context->video.height);
858   if (pict_size < 0) {
859     GST_DEBUG_OBJECT (marudec, "size of a picture is negative. "
860       "pixel format: %d, width: %d, height: %d",
861       marudec->context->video.pix_fmt, marudec->context->video.width,
862       marudec->context->video.height);
863     return GST_FLOW_ERROR;
864   }
865
866   GST_DEBUG_OBJECT (marudec, "outbuf size of decoded video %d", pict_size);
867
868   gst_pad_set_element_private(GST_PAD_PEER(marudec->srcpad), (gpointer)marudec);
869
870   /* GstPadBufferAllocFunction is mostly overridden by elements that can
871    * provide a hardware buffer in order to avoid additional memcpy operations.
872    */
873   gst_pad_set_bufferalloc_function(
874     GST_PAD_PEER(marudec->srcpad),
875     (GstPadBufferAllocFunction) codec_buffer_alloc_and_copy);
876
877   ret = gst_pad_alloc_buffer_and_set_caps (marudec->srcpad,
878     GST_BUFFER_OFFSET_NONE, pict_size,
879     GST_PAD_CAPS (marudec->srcpad), outbuf);
880   if (G_UNLIKELY (ret != GST_FLOW_OK)) {
881     GST_DEBUG_OBJECT (marudec, "pad_alloc failed %d (%s)", ret,
882       gst_flow_get_name (ret));
883     return ret;
884   }
885
886   return ret;
887 }
888
889 static gboolean
890 clip_video_buffer (GstMaruDec *dec, GstBuffer *buf,
891     GstClockTime in_ts, GstClockTime in_dur)
892 {
893   gboolean res = TRUE;
894
895   return res;
896 }
897
898 static gboolean
899 clip_audio_buffer (GstMaruDec *dec, GstBuffer *buf,
900     GstClockTime in_ts, GstClockTime in_dur)
901 {
902   GstClockTime stop;
903   gint64 diff, cstart, cstop;
904   gboolean res = TRUE;
905
906   if (G_UNLIKELY (dec->segment.format != GST_FORMAT_TIME)) {
907     GST_LOG_OBJECT (dec, "%sdropping", (res ? "not " : ""));
908     return res;
909   }
910
911   // in_ts: in_timestamp. check a start time.
912   if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (in_ts))) {
913     GST_LOG_OBJECT (dec, "%sdropping", (res ? "not " : ""));
914     return res;
915   }
916
917   stop =
918     GST_CLOCK_TIME_IS_VALID (in_dur) ? (in_ts + in_dur) : GST_CLOCK_TIME_NONE;
919
920   res = gst_segment_clip (&dec->segment, GST_FORMAT_TIME, in_ts,
921                           stop, &cstart, &cstop);
922   if (G_UNLIKELY (!res)) {
923     GST_LOG_OBJECT (dec, "out of segment");
924     GST_LOG_OBJECT (dec, "%sdropping", (res ? "not " : ""));
925     return res;
926   }
927
928   if (G_UNLIKELY ((diff = cstart - in_ts) > 0)) {
929     diff =
930       gst_util_uint64_scale_int (diff, dec->format.audio.samplerate, GST_SECOND) *
931         (dec->format.audio.depth * dec->format.audio.channels);
932
933     GST_DEBUG_OBJECT (dec, "clipping start to %" GST_TIME_FORMAT " %"
934         G_GINT64_FORMAT " bytes", GST_TIME_ARGS (cstart), diff);
935
936     GST_BUFFER_SIZE (buf) -= diff;
937     GST_BUFFER_DATA (buf) += diff;
938
939   }
940
941   if (G_UNLIKELY ((diff = stop - cstop) > 0)) {
942     diff =
943       gst_util_uint64_scale_int (diff, dec->format.audio.samplerate, GST_SECOND) *
944         (dec->format.audio.depth * dec->format.audio.channels);
945
946     GST_DEBUG_OBJECT (dec, "clipping stop to %" GST_TIME_FORMAT " %"
947         G_GINT64_FORMAT " bytes", GST_TIME_ARGS (cstop), diff);
948
949     GST_BUFFER_SIZE (buf) -= diff;
950   }
951
952   GST_BUFFER_TIMESTAMP (buf) = cstart;
953   GST_BUFFER_DURATION (buf) = cstop - cstart;
954
955   GST_LOG_OBJECT (dec, "%sdropping", (res ? "not " : ""));
956   return res;
957 }
958
959 static gint
960 gst_marudec_video_frame (GstMaruDec *marudec, guint8 *data, guint size,
961     const GstTSInfo *dec_info, gint64 in_offset, GstBuffer **outbuf,
962     GstFlowReturn *ret)
963 {
964   gint len = -1;
965   gboolean mode_switch;
966   gboolean decode;
967   GstClockTime out_timestamp, out_duration, out_pts;
968   gint64 out_offset;
969   const GstTSInfo *out_info;
970   int have_data;
971
972   decode = gst_marudec_do_qos (marudec, dec_info->timestamp, &mode_switch);
973
974   if (decode) {
975     // FIXME
976   }
977
978   GST_DEBUG_OBJECT (marudec, "decode video: input buffer size %d", size);
979
980   len = codec_decode_video (marudec, data, size,
981         dec_info->idx, in_offset, outbuf, &have_data);
982   if (len < 0 || !have_data) {
983     return len;
984   }
985
986   *ret = get_output_buffer (marudec, outbuf);
987
988   if (G_UNLIKELY (*ret != GST_FLOW_OK)) {
989     GST_DEBUG_OBJECT (marudec, "no output buffer");
990     len = -1;
991     GST_DEBUG_OBJECT (marudec, "return flow %d, out %p, len %d",
992         *ret, *outbuf, len);
993     return len;
994   }
995
996   out_info = gst_ts_info_get (marudec, dec_info->idx);
997   out_pts = out_info->timestamp;
998   out_duration = out_info->duration;
999   out_offset = out_info->offset;
1000
1001   /* Timestamps */
1002   out_timestamp = -1;
1003   if (out_pts != -1) {
1004     out_timestamp = (GstClockTime) out_pts;
1005     GST_LOG_OBJECT (marudec, "using timestamp %" GST_TIME_FORMAT
1006       " returned by ffmpeg", GST_TIME_ARGS (out_timestamp));
1007   }
1008
1009   if (!GST_CLOCK_TIME_IS_VALID (out_timestamp) && marudec->next_out != -1) {
1010     out_timestamp = marudec->next_out;
1011     GST_LOG_OBJECT (marudec, "using next timestamp %" GST_TIME_FORMAT,
1012       GST_TIME_ARGS (out_timestamp));
1013   }
1014
1015   if (!GST_CLOCK_TIME_IS_VALID (out_timestamp)) {
1016     out_timestamp = dec_info->timestamp;
1017     GST_LOG_OBJECT (marudec, "using in timestamp %" GST_TIME_FORMAT,
1018       GST_TIME_ARGS (out_timestamp));
1019   }
1020   GST_BUFFER_TIMESTAMP (*outbuf) = out_timestamp;
1021
1022   /* Offset */
1023   if (out_offset != GST_BUFFER_OFFSET_NONE) {
1024     GST_LOG_OBJECT (marudec, "Using offset returned by ffmpeg");
1025   } else if (out_timestamp != GST_CLOCK_TIME_NONE) {
1026     GstFormat out_fmt = GST_FORMAT_DEFAULT;
1027     GST_LOG_OBJECT (marudec, "Using offset converted from timestamp");
1028
1029     gst_pad_query_peer_convert (marudec->sinkpad,
1030       GST_FORMAT_TIME, out_timestamp, &out_fmt, &out_offset);
1031   } else if (dec_info->offset != GST_BUFFER_OFFSET_NONE) {
1032     GST_LOG_OBJECT (marudec, "using in_offset %" G_GINT64_FORMAT,
1033       dec_info->offset);
1034     out_offset = dec_info->offset;
1035   } else {
1036     GST_LOG_OBJECT (marudec, "no valid offset found");
1037     out_offset = GST_BUFFER_OFFSET_NONE;
1038   }
1039   GST_BUFFER_OFFSET (*outbuf) = out_offset;
1040
1041   /* Duration */
1042   if (GST_CLOCK_TIME_IS_VALID (out_duration)) {
1043     GST_LOG_OBJECT (marudec, "Using duration returned by ffmpeg");
1044   } else if (GST_CLOCK_TIME_IS_VALID (dec_info->duration)) {
1045     GST_LOG_OBJECT (marudec, "Using in_duration");
1046     out_duration = dec_info->duration;
1047   } else {
1048     if (marudec->format.video.fps_n != -1 &&
1049         (marudec->format.video.fps_n != 1000 &&
1050         marudec->format.video.fps_d != 1)) {
1051       GST_LOG_OBJECT (marudec, "using input framerate for duration");
1052       out_duration = gst_util_uint64_scale_int (GST_SECOND,
1053         marudec->format.video.fps_d, marudec->format.video.fps_n);
1054     } else {
1055       if (marudec->context->video.fps_n != 0 &&
1056           (marudec->context->video.fps_d > 0 &&
1057             marudec->context->video.fps_d < 1000)) {
1058         GST_LOG_OBJECT (marudec, "using decoder's framerate for duration");
1059         out_duration = gst_util_uint64_scale_int (GST_SECOND,
1060           marudec->context->video.fps_n * 1,
1061           marudec->context->video.fps_d);
1062       } else {
1063         GST_LOG_OBJECT (marudec, "no valid duration found");
1064       }
1065     }
1066   }
1067
1068   if (G_UNLIKELY (!clip_video_buffer (marudec, *outbuf, out_timestamp,
1069       out_duration))) {
1070     GST_DEBUG_OBJECT (marudec, "buffer clipped");
1071     gst_buffer_unref (*outbuf);
1072     *outbuf = NULL;
1073     GST_DEBUG_OBJECT (marudec, "return flow %d, out %p, len %d",
1074       *ret, *outbuf, len);
1075     return len;
1076   }
1077
1078   GST_DEBUG_OBJECT (marudec, "return flow %d, out %p, len %d",
1079     *ret, *outbuf, len);
1080   return len;
1081 }
1082
1083 static gint
1084 gst_marudec_audio_frame (GstMaruDec *marudec, CodecElement *codec,
1085                           guint8 *data, guint size,
1086                           const GstTSInfo *dec_info, GstBuffer **outbuf,
1087                           GstFlowReturn *ret)
1088 {
1089   gint len = -1;
1090   gint have_data = FF_MAX_AUDIO_FRAME_SIZE;
1091   GstClockTime out_timestamp, out_duration;
1092   gint64 out_offset;
1093
1094   *outbuf =
1095       new_aligned_buffer (FF_MAX_AUDIO_FRAME_SIZE,
1096           GST_PAD_CAPS (marudec->srcpad));
1097
1098   GST_DEBUG_OBJECT (marudec, "decode audio, input buffer size %d", size);
1099
1100   len = codec_decode_audio (marudec->context,
1101       (int16_t *) GST_BUFFER_DATA (*outbuf), &have_data,
1102       data, size, marudec->dev);
1103
1104   GST_DEBUG_OBJECT (marudec,
1105     "Decode audio: len=%d, have_data=%d", len, have_data);
1106
1107   if (len >= 0 && have_data > 0) {
1108     GST_DEBUG_OBJECT (marudec, "Creating output buffer");
1109     if (!gst_marudec_negotiate (marudec, FALSE)) {
1110       gst_buffer_unref (*outbuf);
1111       *outbuf = NULL;
1112       len = -1;
1113       GST_DEBUG_OBJECT (marudec, "return flow %d, out %p, len %d",
1114         *ret, *outbuf, len);
1115       return len;
1116     }
1117
1118     // GST_BUFFER_SIZE (*outbuf) = have_data;
1119     GST_BUFFER_SIZE (*outbuf) = len;
1120
1121     if (GST_CLOCK_TIME_IS_VALID (dec_info->timestamp)) {
1122       out_timestamp = dec_info->timestamp;
1123     } else {
1124       out_timestamp = marudec->next_out;
1125     }
1126
1127     /* calculate based on number of samples */
1128     out_duration = gst_util_uint64_scale (have_data, GST_SECOND,
1129         marudec->format.audio.depth * marudec->format.audio.channels *
1130         marudec->format.audio.samplerate);
1131
1132     out_offset = dec_info->offset;
1133
1134     GST_DEBUG_OBJECT (marudec,
1135         "Buffer created. Size: %d, timestamp: %" GST_TIME_FORMAT
1136         ", duration: %" GST_TIME_FORMAT, have_data,
1137         GST_TIME_ARGS (out_timestamp), GST_TIME_ARGS (out_duration));
1138
1139     GST_BUFFER_TIMESTAMP (*outbuf) = out_timestamp;
1140     GST_BUFFER_DURATION (*outbuf) = out_duration;
1141     GST_BUFFER_OFFSET (*outbuf) = out_offset;
1142     gst_buffer_set_caps (*outbuf, GST_PAD_CAPS (marudec->srcpad));
1143
1144     if (GST_CLOCK_TIME_IS_VALID (out_timestamp)) {
1145       marudec->next_out = out_timestamp + out_duration;
1146     }
1147
1148     if (G_UNLIKELY (!clip_audio_buffer (marudec, *outbuf,
1149         out_timestamp, out_duration))) {
1150       GST_DEBUG_OBJECT (marudec, "buffer_clipped");
1151       gst_buffer_unref (*outbuf);
1152       *outbuf = NULL;
1153       GST_DEBUG_OBJECT (marudec, "return flow %d, out %p, len %d", *ret, *outbuf, len);
1154       return len;
1155     }
1156   } else {
1157     gst_buffer_unref (*outbuf);
1158     *outbuf = NULL;
1159   }
1160
1161   if (len == -1 && !strcmp(codec->name, "aac")) {
1162     GST_ELEMENT_ERROR (marudec, STREAM, DECODE, (NULL),
1163         ("Decoding of AAC stream by FFMPEG failed."));
1164     *ret = GST_FLOW_ERROR;
1165   }
1166
1167   GST_DEBUG_OBJECT (marudec, "return flow %d, out %p, len %d",
1168     *ret, *outbuf, len);
1169   return len;
1170 }
1171
1172 static gint
1173 gst_marudec_frame (GstMaruDec *marudec, guint8 *data, guint size,
1174     gint *got_data, const GstTSInfo *dec_info, gint64 in_offset, GstFlowReturn *ret)
1175 {
1176   GstMaruDecClass *oclass;
1177   GstBuffer *outbuf = NULL;
1178   gint have_data = 0, len = 0;
1179
1180   if (G_UNLIKELY (marudec->context->codec == NULL)) {
1181     GST_ERROR_OBJECT (marudec, "no codec context");
1182     return -1;
1183   }
1184
1185   *ret = GST_FLOW_OK;
1186   oclass = (GstMaruDecClass *) (G_OBJECT_GET_CLASS (marudec));
1187
1188   switch (oclass->codec->media_type) {
1189   case AVMEDIA_TYPE_VIDEO:
1190     len = gst_marudec_video_frame (marudec, data, size,
1191         dec_info, in_offset, &outbuf, ret);
1192     break;
1193   case AVMEDIA_TYPE_AUDIO:
1194     len = gst_marudec_audio_frame (marudec, oclass->codec, data, size,
1195         dec_info, &outbuf, ret);
1196     if (outbuf == NULL && marudec->discont) {
1197       GST_DEBUG_OBJECT (marudec, "no buffer but keeping timestamp");
1198 //      marudec->clear_ts = FALSE;
1199     }
1200     break;
1201   default:
1202     GST_ERROR_OBJECT (marudec, "Asked to decode non-audio/video frame!");
1203     g_assert_not_reached ();
1204     break;
1205   }
1206
1207   if (outbuf) {
1208     have_data = 1;
1209   }
1210
1211   if (len < 0 || have_data < 0) {
1212     GST_WARNING_OBJECT (marudec,
1213         "maru_%sdec: decoding error (len: %d, have_data: %d)",
1214         oclass->codec->name, len, have_data);
1215     *got_data = 0;
1216     return len;
1217   } else if (len == 0 && have_data == 0) {
1218     *got_data = 0;
1219     return len;
1220   } else {
1221     *got_data = 1;
1222   }
1223
1224   if (outbuf) {
1225     GST_LOG_OBJECT (marudec,
1226         "Decoded data, now pushing buffer %p with offset %" G_GINT64_FORMAT
1227         ", timestamp %" GST_TIME_FORMAT " and duration %" GST_TIME_FORMAT,
1228         outbuf, GST_BUFFER_OFFSET (outbuf),
1229         GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)),
1230         GST_TIME_ARGS (GST_BUFFER_DURATION (outbuf)));
1231
1232     if (marudec->discont) {
1233       /* GST_BUFFER_FLAG_DISCONT :
1234        * the buffer marks a data discontinuity in the stream. This typically
1235        * occurs after a seek or a dropped buffer from a live or network source.
1236        */
1237       GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
1238       marudec->discont = FALSE;
1239     }
1240
1241     if (marudec->segment.rate > 0.0) {
1242       // push forward
1243       *ret = gst_pad_push (marudec->srcpad, outbuf);
1244     } else {
1245       // push reverse
1246       GST_DEBUG_OBJECT (marudec, "queued frame");
1247       marudec->queued = g_list_prepend (marudec->queued, outbuf);
1248       *ret = GST_FLOW_OK;
1249     }
1250   } else {
1251     GST_DEBUG_OBJECT (marudec, "Didn't get a decoded buffer");
1252   }
1253
1254   return len;
1255 }
1256
1257 static GstFlowReturn
1258 gst_marudec_chain (GstPad *pad, GstBuffer *buffer)
1259 {
1260   GstMaruDec *marudec;
1261   GstMaruDecClass *oclass;
1262   guint8 *in_buf;
1263   gint in_size, have_data;
1264   GstFlowReturn ret = GST_FLOW_OK;
1265   GstClockTime in_timestamp;
1266   GstClockTime in_duration;
1267   gboolean discont;
1268   gint64 in_offset;
1269   const GstTSInfo *in_info;
1270   const GstTSInfo *dec_info;
1271
1272   marudec = (GstMaruDec *) (GST_PAD_PARENT (pad));
1273
1274   if (G_UNLIKELY (!marudec->opened)) {
1275     // not_negotiated
1276     oclass = (GstMaruDecClass *) (G_OBJECT_GET_CLASS (marudec));
1277     GST_ELEMENT_ERROR (marudec, CORE, NEGOTIATION, (NULL),
1278       ("maru_%sdec: input format was not set before data start",
1279         oclass->codec->name));
1280     gst_buffer_unref (buffer);
1281     return GST_FLOW_NOT_NEGOTIATED;
1282   }
1283
1284   discont = GST_BUFFER_IS_DISCONT (buffer);
1285
1286   // FIXME
1287   if (G_UNLIKELY (discont)) {
1288     GST_DEBUG_OBJECT (marudec, "received DISCONT");
1289     gst_marudec_drain (marudec);
1290 //    gst_marudec_flush_pcache (marudec);
1291     codec_flush_buffers (marudec->context, marudec->dev);
1292     marudec->discont = TRUE;
1293     gst_marudec_reset_ts (marudec);
1294   }
1295 //  marudec->clear_ts = TRUE;
1296
1297   oclass = (GstMaruDecClass *) (G_OBJECT_GET_CLASS (marudec));
1298 #if 0
1299   if (G_UNLIKELY (marudec->waiting_for_key)) {
1300     if (GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DELTA_UNIT) &&
1301       oclass->codec->media_type != AVMEDIA_TYPE_AUDIO) {
1302       // skip_keyframe
1303     }
1304     marudec->waiting_for_key = FALSE;
1305   }
1306
1307   if (marudec->pcache) {
1308     GST_LOG_OBJECT (marudec, "join parse cache");
1309     buffer = gst_buffer_join (marudec->pcache, buffer);
1310     marudec->pcache = NULL;
1311   }
1312 #endif
1313
1314   in_timestamp = GST_BUFFER_TIMESTAMP (buffer);
1315   in_duration = GST_BUFFER_DURATION (buffer);
1316   in_offset = GST_BUFFER_OFFSET (buffer);
1317
1318   in_info = gst_ts_info_store (marudec, in_timestamp, in_duration, in_offset);
1319
1320 #if 0
1321   if (in_timestamp != -1) {
1322     if (!marudec->reordered_in && marudec->last_in != -1) {
1323       if (in_timestamp < marudec->last_in) {
1324         GST_LOG_OBJECT (marudec, "detected reordered input timestamps");
1325         marudec->reordered_in = TRUE;
1326         marudec->last_diff = GST_CLOCK_TIME_NONE;
1327       } else if (in_timestamp > marudec->last_in) {
1328         GstClockTime diff;
1329         diff = in_timestamp - marudec->last_in;
1330         if (marudec->last_frames) {
1331           diff /= marudec->last_frames;
1332         }
1333
1334         GST_LOG_OBJECT (marudec, "estimated duration %" GST_TIME_FORMAT " %u",
1335           GST_TIME_ARGS (diff), marudec->last_frames);
1336
1337         marudec->last_diff = diff;
1338       }
1339     }
1340     marudec->last_in = in_timestamp;
1341     marudec->last_frames;
1342   }
1343 #endif
1344
1345   GST_LOG_OBJECT (marudec,
1346     "Received new data of size %u, offset: %" G_GUINT64_FORMAT ", ts:%"
1347     GST_TIME_FORMAT ", dur: %" GST_TIME_FORMAT ", info %d",
1348     GST_BUFFER_SIZE (buffer), GST_BUFFER_OFFSET (buffer),
1349     GST_TIME_ARGS (in_timestamp), GST_TIME_ARGS (in_duration), in_info->idx);
1350
1351   in_buf = GST_BUFFER_DATA (buffer);
1352   in_size = GST_BUFFER_SIZE (buffer);
1353
1354   dec_info = in_info;
1355
1356   gst_marudec_frame (marudec, in_buf, in_size, &have_data, dec_info, in_offset, &ret);
1357
1358 #if 0
1359   if (marudec->clear_ts) {
1360     in_timestamp = GST_CLOCK_TIME_NONE;
1361     in_duration = GST_CLOCK_TIME_NONE;
1362     in_offset = GST_BUFFER_OFFSET_NONE;
1363     in_info = GST_TS_INFO_NONE;
1364   } else {
1365     marudec->clear_ts = TRUE;
1366   }
1367 #endif
1368
1369   gst_buffer_unref (buffer);
1370
1371   return ret;
1372 }
1373
1374 static GstStateChangeReturn
1375 gst_marudec_change_state (GstElement *element, GstStateChange transition)
1376 {
1377   GstMaruDec *marudec = (GstMaruDec *) element;
1378   GstStateChangeReturn ret;
1379
1380   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
1381
1382   switch (transition) {
1383   case GST_STATE_CHANGE_PAUSED_TO_READY:
1384     GST_OBJECT_LOCK (marudec);
1385     gst_marudec_close (marudec);
1386     GST_OBJECT_UNLOCK (marudec);
1387
1388     /* clear queue */
1389     clear_queued (marudec);
1390     break;
1391   default:
1392     break;
1393   }
1394
1395   return ret;
1396 }
1397
1398 gboolean
1399 gst_marudec_register (GstPlugin *plugin, GList *element)
1400 {
1401   GTypeInfo typeinfo = {
1402       sizeof (GstMaruDecClass),
1403       (GBaseInitFunc) gst_marudec_base_init,
1404       NULL,
1405       (GClassInitFunc) gst_marudec_class_init,
1406       NULL,
1407       NULL,
1408       sizeof (GstMaruDec),
1409       0,
1410       (GInstanceInitFunc) gst_marudec_init,
1411   };
1412
1413   GType type;
1414   gchar *type_name;
1415   gint rank = GST_RANK_PRIMARY;
1416   GList *elem = element;
1417   CodecElement *codec = NULL;
1418
1419   if (!elem) {
1420     return FALSE;
1421   }
1422
1423   /* register element */
1424   do {
1425     codec = (CodecElement *)(elem->data);
1426     if (!codec) {
1427       return FALSE;
1428     }
1429
1430     if (codec->codec_type != CODEC_TYPE_DECODE) {
1431       continue;
1432     }
1433
1434     type_name = g_strdup_printf ("maru_%sdec", codec->name);
1435     type = g_type_from_name (type_name);
1436     if (!type) {
1437       type = g_type_register_static (GST_TYPE_ELEMENT, type_name, &typeinfo, 0);
1438       g_type_set_qdata (type, GST_MARUDEC_PARAMS_QDATA, (gpointer) codec);
1439     }
1440
1441     if (!gst_element_register (plugin, type_name, rank, type)) {
1442       g_free (type_name);
1443       return FALSE;
1444     }
1445     g_free (type_name);
1446   } while ((elem = elem->next));
1447
1448   return TRUE;
1449 }