Tizen 2.0 Release
[framework/multimedia/gst-plugins-bad0.10.git] / gst / mpegvideoparse / mpegvideoparse.c
1 /* GStreamer
2  * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
3  * Copyright (C) <2007> Jan Schmidt <thaytan@mad.scientist.com>
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Library General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Library General Public License for more details.
14  *
15  * You should have received a copy of the GNU Library General Public
16  * License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18  * Boston, MA 02111-1307, USA.
19  */
20
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24
25 #include <string.h>
26 #include "mpegvideoparse.h"
27
28 /* FIXME: there are still some things to do in this element.
29  * + Handle Sequence Display Extension to output the display size
30  *   rather than the encoded size.
31  * + Do all the other stuff (documentation, tests) to get it into
32  *   ugly or good.
33  * + low priority:
34  *   - handle seeking in raw elementary streams
35  *   - calculate timestamps for all un-timestamped frames, taking into
36  *     account frame re-ordering. Doing this probably requires introducing
37  *     an extra end-to-end delay however, so might not be really desirable.
38  *   - Collect a list of regions and the sequence headers that apply
39  *     to each region so that we properly handle SEQUENCE_END followed
40  *     by a new sequence. At the moment, the caps will change if the
41  *     sequence changes, but if we then seek to a different spot it might
42  *     be wrong. Fortunately almost every stream only has 1 sequence.
43  */
44 GST_DEBUG_CATEGORY (mpv_parse_debug);
45 #define GST_CAT_DEFAULT mpv_parse_debug
46
47 static GstStaticPadTemplate src_template =
48 GST_STATIC_PAD_TEMPLATE ("src", GST_PAD_SRC,
49     GST_PAD_ALWAYS,
50     GST_STATIC_CAPS ("video/mpeg, "
51         "mpegversion = (int) [ 1, 2 ], "
52         "parsed = (boolean) true, "
53         "systemstream = (boolean) false, "
54         "width = (int) [ 16, 4096 ], "
55         "height = (int) [ 16, 4096 ], "
56         "pixel-aspect-ratio = (fraction) [ 0/1, MAX ], "
57         "framerate = (fraction) [ 0/1, MAX ]")
58     );
59
60 static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
61     GST_PAD_SINK,
62     GST_PAD_ALWAYS,
63     GST_STATIC_CAPS ("video/mpeg, "
64         "mpegversion = (int) [ 1, 2 ], "
65         "parsed = (boolean) false, " "systemstream = (boolean) false")
66     );
67
68 /* MpegVideoParse signals and args */
69 enum
70 {
71   /* FILL ME */
72   LAST_SIGNAL
73 };
74
75 enum
76 {
77   ARG_0
78       /* FILL ME */
79 };
80
81 static void gst_mpegvideoparse_class_init (MpegVideoParseClass * klass);
82 static void gst_mpegvideoparse_base_init (MpegVideoParseClass * klass);
83 static void gst_mpegvideoparse_init (MpegVideoParse * mpegvideoparse);
84 static void gst_mpegvideoparse_dispose (GObject * object);
85
86 static GstFlowReturn gst_mpegvideoparse_chain (GstPad * pad, GstBuffer * buf);
87 static gboolean mpv_parse_sink_event (GstPad * pad, GstEvent * event);
88 static void gst_mpegvideoparse_flush (MpegVideoParse * mpegvideoparse);
89 static GstStateChangeReturn
90 gst_mpegvideoparse_change_state (GstElement * element,
91     GstStateChange transition);
92
93 static void mpv_send_pending_segs (MpegVideoParse * mpegvideoparse);
94 static void mpv_clear_pending_segs (MpegVideoParse * mpegvideoparse);
95
96 static GstElementClass *parent_class = NULL;
97
98 /*static guint gst_mpegvideoparse_signals[LAST_SIGNAL] = { 0 }; */
99
100 GType
101 mpegvideoparse_get_type (void)
102 {
103   static GType mpegvideoparse_type = 0;
104
105   if (!mpegvideoparse_type) {
106     static const GTypeInfo mpegvideoparse_info = {
107       sizeof (MpegVideoParseClass),
108       (GBaseInitFunc) gst_mpegvideoparse_base_init,
109       NULL,
110       (GClassInitFunc) gst_mpegvideoparse_class_init,
111       NULL,
112       NULL,
113       sizeof (MpegVideoParse),
114       0,
115       (GInstanceInitFunc) gst_mpegvideoparse_init,
116     };
117
118     mpegvideoparse_type =
119         g_type_register_static (GST_TYPE_ELEMENT, "MpegVideoParse",
120         &mpegvideoparse_info, 0);
121   }
122   return mpegvideoparse_type;
123 }
124
125 static void
126 gst_mpegvideoparse_base_init (MpegVideoParseClass * klass)
127 {
128   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
129
130   gst_element_class_add_static_pad_template (element_class, &src_template);
131   gst_element_class_add_static_pad_template (element_class,
132       &sink_template);
133
134   gst_element_class_set_details_simple (element_class,
135       "MPEG video elementary stream parser",
136       "Codec/Parser/Video",
137       "Parses and frames MPEG-1 and MPEG-2 elementary video streams",
138       "Wim Taymans <wim.taymans@chello.be>, "
139       "Jan Schmidt <thaytan@mad.scientist.com>");
140 }
141
142 static void
143 gst_mpegvideoparse_class_init (MpegVideoParseClass * klass)
144 {
145   GObjectClass *gobject_class;
146   GstElementClass *gstelement_class;
147
148   gstelement_class = (GstElementClass *) klass;
149   gobject_class = G_OBJECT_CLASS (klass);
150
151   parent_class = g_type_class_peek_parent (klass);
152
153   gobject_class->dispose = (GObjectFinalizeFunc) (gst_mpegvideoparse_dispose);
154   gstelement_class->change_state = gst_mpegvideoparse_change_state;
155 }
156
157 static void
158 mpv_parse_reset (MpegVideoParse * mpegvideoparse)
159 {
160   mpegvideoparse->seq_hdr.mpeg_version = 0;
161   mpegvideoparse->seq_hdr.width = mpegvideoparse->seq_hdr.height = -1;
162   mpegvideoparse->seq_hdr.fps_n = mpegvideoparse->seq_hdr.par_w = 0;
163   mpegvideoparse->seq_hdr.fps_d = mpegvideoparse->seq_hdr.par_h = 1;
164
165   mpv_clear_pending_segs (mpegvideoparse);
166 }
167
168 static void
169 mpv_send_pending_segs (MpegVideoParse * mpegvideoparse)
170 {
171   while (mpegvideoparse->pending_segs) {
172     GstEvent *ev = mpegvideoparse->pending_segs->data;
173
174     gst_pad_push_event (mpegvideoparse->srcpad, ev);
175
176     mpegvideoparse->pending_segs =
177         g_list_delete_link (mpegvideoparse->pending_segs,
178         mpegvideoparse->pending_segs);
179   }
180   mpegvideoparse->pending_segs = NULL;
181 }
182
183 static void
184 mpv_clear_pending_segs (MpegVideoParse * mpegvideoparse)
185 {
186   while (mpegvideoparse->pending_segs) {
187     GstEvent *ev = mpegvideoparse->pending_segs->data;
188     gst_event_unref (ev);
189
190     mpegvideoparse->pending_segs =
191         g_list_delete_link (mpegvideoparse->pending_segs,
192         mpegvideoparse->pending_segs);
193   }
194 }
195
196 static void
197 gst_mpegvideoparse_init (MpegVideoParse * mpegvideoparse)
198 {
199   mpegvideoparse->sinkpad =
200       gst_pad_new_from_static_template (&sink_template, "sink");
201   gst_pad_set_chain_function (mpegvideoparse->sinkpad,
202       gst_mpegvideoparse_chain);
203   gst_pad_set_event_function (mpegvideoparse->sinkpad, mpv_parse_sink_event);
204   gst_element_add_pad (GST_ELEMENT (mpegvideoparse), mpegvideoparse->sinkpad);
205
206   mpegvideoparse->srcpad =
207       gst_pad_new_from_static_template (&src_template, "src");
208   gst_pad_use_fixed_caps (mpegvideoparse->srcpad);
209   gst_element_add_pad (GST_ELEMENT (mpegvideoparse), mpegvideoparse->srcpad);
210
211   mpeg_packetiser_init (&mpegvideoparse->packer);
212
213   mpv_parse_reset (mpegvideoparse);
214 }
215
216 void
217 gst_mpegvideoparse_dispose (GObject * object)
218 {
219   MpegVideoParse *mpegvideoparse = GST_MPEGVIDEOPARSE (object);
220
221   mpeg_packetiser_free (&mpegvideoparse->packer);
222   gst_buffer_replace (&mpegvideoparse->seq_hdr_buf, NULL);
223
224   G_OBJECT_CLASS (parent_class)->dispose (object);
225 }
226
227 static gboolean
228 mpegvideoparse_handle_sequence (MpegVideoParse * mpegvideoparse,
229     GstBuffer * buf)
230 {
231   MPEGSeqHdr new_hdr;
232   guint8 *cur, *end;
233
234   cur = GST_BUFFER_DATA (buf);
235   end = GST_BUFFER_DATA (buf) + GST_BUFFER_SIZE (buf);
236
237   memset (&new_hdr, 0, sizeof (MPEGSeqHdr));
238
239   if (G_UNLIKELY (!mpeg_util_parse_sequence_hdr (&new_hdr, cur, end)))
240     return FALSE;
241
242   if (new_hdr.width < 16 || new_hdr.width > 4096 ||
243       new_hdr.height < 16 || new_hdr.height > 4096) {
244     GST_WARNING_OBJECT (mpegvideoparse, "Width/height out of valid range "
245         "[16, 4096]");
246     return FALSE;
247   }
248
249   if (memcmp (&mpegvideoparse->seq_hdr, &new_hdr, sizeof (MPEGSeqHdr)) != 0) {
250     GstCaps *caps;
251     GstBuffer *seq_buf;
252     /*
253      * Profile indication - 1 => High, 2 => Spatially Scalable,
254      *                      3 => SNR Scalable, 4 => Main, 5 => Simple
255      * 4:2:2 and Multi-view have profile = 0, with the escape bit set to 1
256      */
257     const gchar *profiles[] = { "high", "spatial", "snr", "main", "simple" };
258     /*
259      * Level indication - 4 => High, 6 => High-1440, 8 => Main, 10 => Low,
260      *                    except in the case of profile = 0
261      */
262     const gchar *levels[] = { "high", "high-1440", "main", "low" };
263
264     /* Store the entire sequence header + sequence header extension
265        for output as codec_data */
266     seq_buf = gst_buffer_copy (buf);
267     gst_buffer_replace (&mpegvideoparse->seq_hdr_buf, seq_buf);
268     gst_buffer_unref (seq_buf);
269
270     caps = gst_caps_new_simple ("video/mpeg",
271         "systemstream", G_TYPE_BOOLEAN, FALSE,
272         "parsed", G_TYPE_BOOLEAN, TRUE,
273         "mpegversion", G_TYPE_INT, new_hdr.mpeg_version,
274         "width", G_TYPE_INT, new_hdr.width,
275         "height", G_TYPE_INT, new_hdr.height,
276         "framerate", GST_TYPE_FRACTION, new_hdr.fps_n, new_hdr.fps_d,
277         "pixel-aspect-ratio", GST_TYPE_FRACTION, new_hdr.par_w, new_hdr.par_h,
278         "interlaced", G_TYPE_BOOLEAN, !new_hdr.progressive,
279         "codec_data", GST_TYPE_BUFFER, seq_buf, NULL);
280
281     if (new_hdr.mpeg_version == 2) {
282       const gchar *profile = NULL, *level = NULL;
283
284       if (new_hdr.profile > 0 && new_hdr.profile < 6)
285         profile = profiles[new_hdr.profile - 1];
286
287       if ((new_hdr.level > 3) && (new_hdr.level < 11) &&
288           (new_hdr.level % 2 == 0))
289         level = levels[(new_hdr.level >> 1) - 1];
290
291       if (new_hdr.profile == 8) {
292         /* Non-hierarchical profile */
293         switch (new_hdr.level) {
294           case 2:
295             level = levels[0];
296             break;
297           case 5:
298             level = levels[2];
299             profile = "4:2:2";
300             break;
301           case 10:
302             level = levels[0];
303             break;
304           case 11:
305             level = levels[1];
306             break;
307           case 13:
308             level = levels[2];
309             break;
310           case 14:
311             level = levels[3];
312             profile = "multiview";
313             break;
314           default:
315             break;
316         }
317       }
318
319       if (profile)
320         gst_caps_set_simple (caps, "profile", G_TYPE_STRING, profile, NULL);
321       else
322         GST_DEBUG ("Invalid profile - %u", new_hdr.profile);
323
324       if (level)
325         gst_caps_set_simple (caps, "level", G_TYPE_STRING, level, NULL);
326       else
327         GST_DEBUG ("Invalid level - %u", new_hdr.level);
328     }
329
330     GST_DEBUG ("New mpegvideoparse caps: %" GST_PTR_FORMAT, caps);
331     if (!gst_pad_set_caps (mpegvideoparse->srcpad, caps)) {
332       gst_caps_unref (caps);
333       return FALSE;
334     }
335     gst_caps_unref (caps);
336
337     if (new_hdr.bitrate > 0) {
338       GstTagList *taglist;
339
340       taglist = gst_tag_list_new_full (GST_TAG_BITRATE, new_hdr.bitrate, NULL);
341       gst_element_found_tags_for_pad (GST_ELEMENT_CAST (mpegvideoparse),
342           mpegvideoparse->srcpad, taglist);
343     }
344
345     /* And update the new_hdr into our stored version */
346     mpegvideoparse->seq_hdr = new_hdr;
347   }
348
349   return TRUE;
350 }
351
352 #ifndef GST_DISABLE_GST_DEBUG
353 static const gchar *
354 picture_start_code_name (guint8 psc)
355 {
356   guint i;
357   const struct
358   {
359     guint8 psc;
360     const gchar *name;
361   } psc_names[] = {
362     {
363     0x00, "Picture Start"}, {
364     0xb0, "Reserved"}, {
365     0xb1, "Reserved"}, {
366     0xb2, "User Data Start"}, {
367     0xb3, "Sequence Header Start"}, {
368     0xb4, "Sequence Error"}, {
369     0xb5, "Extnsion Start"}, {
370     0xb6, "Reserved"}, {
371     0xb7, "Sequence End"}, {
372     0xb8, "Group Start"}, {
373     0xb9, "Program End"}
374   };
375   if (psc < 0xB0 && psc > 0)
376     return "Slice Start";
377
378   for (i = 0; i < G_N_ELEMENTS (psc_names); i++)
379     if (psc_names[i].psc == psc)
380       return psc_names[i].name;
381
382   return "UNKNOWN";
383 };
384
385 static const gchar *
386 picture_type_name (guint8 pct)
387 {
388   guint i;
389   const struct
390   {
391     guint8 pct;
392     const gchar *name;
393   } pct_names[] = {
394     {
395     0, "Forbidden"}, {
396     1, "I Frame"}, {
397     2, "P Frame"}, {
398     3, "B Frame"}, {
399     4, "DC Intra Coded (Shall Not Be Used!)"}
400   };
401
402   for (i = 0; i < G_N_ELEMENTS (pct_names); i++)
403     if (pct_names[i].pct == pct)
404       return pct_names[i].name;
405
406   return "Reserved/Unknown";
407 }
408 #endif /* GST_DISABLE_GST_DEBUG */
409
410 static gboolean
411 mpegvideoparse_handle_picture (MpegVideoParse * mpegvideoparse, GstBuffer * buf)
412 {
413   guint8 *cur, *end;
414   guint32 sync_word = 0xffffffff;
415
416   cur = GST_BUFFER_DATA (buf);
417   end = GST_BUFFER_DATA (buf) + GST_BUFFER_SIZE (buf);
418
419   cur = mpeg_util_find_start_code (&sync_word, cur, end);
420   while (cur != NULL) {
421     if (cur[0] == 0 || cur[0] > 0xaf)
422       GST_LOG_OBJECT (mpegvideoparse, "Picture Start Code : %s",
423           picture_start_code_name (cur[0]));
424     /* Cur points at the last byte of the start code */
425     if (cur[0] == MPEG_PACKET_PICTURE) {
426       guint8 *pic_data = cur - 3;
427       MPEGPictureHdr hdr;
428
429       /* pic_data points to the first byte of the sync word now */
430       if (!mpeg_util_parse_picture_hdr (&hdr, pic_data, end))
431         return FALSE;
432
433       if (hdr.pic_type != MPEG_PICTURE_TYPE_I)
434         GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
435
436       GST_LOG_OBJECT (mpegvideoparse, "Picture type is %s",
437           picture_type_name (hdr.pic_type));
438       /* FIXME: Can use the picture type and number of fields to track a
439        * timestamp */
440       break;
441     }
442     cur = mpeg_util_find_start_code (&sync_word, cur, end);
443   }
444
445   return TRUE;
446 }
447
448 #if 0
449 static guint64
450 gst_mpegvideoparse_time_code (guchar * gop, MPEGSeqHdr * seq_hdr)
451 {
452   guint32 data = GST_READ_UINT32_BE (gop);
453   guint64 seconds;
454   guint8 frames;
455
456   seconds = ((data & 0xfc000000) >> 26) * 3600; /* hours */
457   seconds += ((data & 0x03f00000) >> 20) * 60;  /* minutes */
458   seconds += (data & 0x0007e000) >> 13; /* seconds */
459
460   frames = (data & 0x00001f80) >> 7;
461
462   return seconds * GST_SECOND + gst_util_uint64_scale_int (frames * GST_SECOND,
463       seq_hdr->fps_d, seq_hdr->fps_n);
464 }
465 #endif
466
467 static void
468 gst_mpegvideoparse_flush (MpegVideoParse * mpegvideoparse)
469 {
470   GST_DEBUG_OBJECT (mpegvideoparse, "mpegvideoparse: flushing");
471
472   mpegvideoparse->next_offset = GST_BUFFER_OFFSET_NONE;
473
474   g_list_foreach (mpegvideoparse->gather, (GFunc) gst_mini_object_unref, NULL);
475   g_list_free (mpegvideoparse->gather);
476   mpegvideoparse->gather = NULL;
477   g_list_foreach (mpegvideoparse->decode, (GFunc) gst_mini_object_unref, NULL);
478   g_list_free (mpegvideoparse->decode);
479   mpegvideoparse->decode = NULL;
480   mpeg_packetiser_flush (&mpegvideoparse->packer);
481
482   mpv_clear_pending_segs (mpegvideoparse);
483 }
484
485 static GstFlowReturn
486 mpegvideoparse_drain_avail (MpegVideoParse * mpegvideoparse)
487 {
488   MPEGBlockInfo *cur;
489   GstBuffer *buf = NULL;
490   GstFlowReturn res = GST_FLOW_OK;
491
492   cur = mpeg_packetiser_get_block (&mpegvideoparse->packer, &buf);
493   while ((cur != NULL) && (res == GST_FLOW_OK)) {
494     /* Handle the block */
495     GST_LOG_OBJECT (mpegvideoparse,
496         "Have block of size %u with pack_type %s and flags 0x%02x",
497         cur->length, picture_start_code_name (cur->first_pack_type),
498         cur->flags);
499
500     if ((cur->flags & MPEG_BLOCK_FLAG_SEQUENCE) && buf != NULL) {
501       /* Found a sequence header */
502       if (!mpegvideoparse_handle_sequence (mpegvideoparse, buf)) {
503         GST_DEBUG_OBJECT (mpegvideoparse,
504             "Invalid sequence header. Dropping buffer.");
505         gst_buffer_unref (buf);
506         buf = NULL;
507       }
508     } else if (mpegvideoparse->seq_hdr.mpeg_version == 0 && buf) {
509       /* Don't start pushing out buffers until we've seen a sequence header */
510       GST_DEBUG_OBJECT (mpegvideoparse,
511           "No sequence header yet. Dropping buffer of %u bytes",
512           GST_BUFFER_SIZE (buf));
513       gst_buffer_unref (buf);
514       buf = NULL;
515     }
516
517     if (buf != NULL) {
518       /* If outputting a PICTURE packet, we can calculate the duration
519          and possibly the timestamp */
520       if (cur->flags & MPEG_BLOCK_FLAG_PICTURE) {
521         if (!mpegvideoparse_handle_picture (mpegvideoparse, buf)) {
522           /* Corrupted picture. Drop it. */
523           GST_DEBUG_OBJECT (mpegvideoparse,
524               "Corrupted picture header. Dropping buffer of %u bytes",
525               GST_BUFFER_SIZE (buf));
526           mpegvideoparse->need_discont = TRUE;
527           gst_buffer_unref (buf);
528           buf = NULL;
529         }
530       }
531     }
532
533     if (buf != NULL) {
534       GST_DEBUG_OBJECT (mpegvideoparse,
535           "mpegvideoparse: pushing buffer of %u bytes with ts %"
536           GST_TIME_FORMAT, GST_BUFFER_SIZE (buf),
537           GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)));
538
539       gst_buffer_set_caps (buf, GST_PAD_CAPS (mpegvideoparse->srcpad));
540
541       if (mpegvideoparse->need_discont) {
542         GST_DEBUG_OBJECT (mpegvideoparse,
543             "setting discont flag on outgoing buffer");
544         GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
545         mpegvideoparse->need_discont = FALSE;
546       }
547
548       mpv_send_pending_segs (mpegvideoparse);
549
550       res = gst_pad_push (mpegvideoparse->srcpad, buf);
551       buf = NULL;
552     }
553
554     /* Advance to the next data block */
555     mpeg_packetiser_next_block (&mpegvideoparse->packer);
556     cur = mpeg_packetiser_get_block (&mpegvideoparse->packer, &buf);
557   }
558   if (buf != NULL)
559     gst_buffer_unref (buf);
560
561   return res;
562 }
563
564 static GstFlowReturn
565 gst_mpegvideoparse_chain_forward (MpegVideoParse * mpegvideoparse,
566     gboolean discont, GstBuffer * buf)
567 {
568   GstFlowReturn res;
569   guint64 next_offset = GST_BUFFER_OFFSET_NONE;
570
571   GST_DEBUG_OBJECT (mpegvideoparse,
572       "mpegvideoparse: received buffer of %u bytes with ts %"
573       GST_TIME_FORMAT " and offset %" G_GINT64_FORMAT, GST_BUFFER_SIZE (buf),
574       GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)), GST_BUFFER_OFFSET (buf));
575
576   /* If we have an offset, and the incoming offset doesn't match, 
577      or we have a discont, handle it first by flushing out data
578      we have collected. */
579   if (mpegvideoparse->next_offset != GST_BUFFER_OFFSET_NONE) {
580     if (GST_BUFFER_OFFSET_IS_VALID (buf)) {
581       if (mpegvideoparse->next_offset != GST_BUFFER_OFFSET (buf))
582         discont = TRUE;
583       next_offset = GST_BUFFER_OFFSET (buf) + GST_BUFFER_SIZE (buf);
584     } else {
585       next_offset = mpegvideoparse->next_offset + GST_BUFFER_SIZE (buf);
586     }
587   }
588
589   /* Clear out any existing stuff if the new buffer is discontinuous */
590   if (discont) {
591     GST_DEBUG_OBJECT (mpegvideoparse, "Have discont packet, draining data");
592     mpegvideoparse->need_discont = TRUE;
593
594     mpeg_packetiser_handle_eos (&mpegvideoparse->packer);
595     res = mpegvideoparse_drain_avail (mpegvideoparse);
596     mpeg_packetiser_flush (&mpegvideoparse->packer);
597     if (res != GST_FLOW_OK) {
598       gst_buffer_unref (buf);
599       goto done;
600     }
601   }
602
603   /* Takes ownership of the data */
604   mpeg_packetiser_add_buf (&mpegvideoparse->packer, buf);
605
606   /* And push out what we can */
607   res = mpegvideoparse_drain_avail (mpegvideoparse);
608
609 done:
610   /* Update our offset */
611   mpegvideoparse->next_offset = next_offset;
612
613   return res;
614 }
615
616 /* scan the decode queue for a picture header with an I frame and return the
617  * index in the first buffer. We only scan the first buffer and possibly a
618  * couple of bytes of the next buffers to find the I frame. Scanning is done
619  * backwards because the first buffer could contain many picture start codes
620  * with I frames. */
621 static guint
622 scan_keyframe (MpegVideoParse * mpegvideoparse)
623 {
624   guint64 scanword;
625   guint count;
626   GList *walk;
627   GstBuffer *head;
628   guint8 *data;
629   guint size;
630
631   /* we use an 8 byte buffer, this is enough to hold the picture start code and
632    * the picture header bits we are interested in. We init to 0xff so that when
633    * we have a valid picture start without the header bits, we will be able to
634    * detect this because it will generate an invalid picture type. */
635   scanword = ~G_GUINT64_CONSTANT (0);
636
637   GST_LOG_OBJECT (mpegvideoparse, "scan keyframe");
638
639   /* move to the second buffer if we can, we should have at least one buffer */
640   walk = mpegvideoparse->decode;
641   g_return_val_if_fail (walk != NULL, -1);
642
643   head = GST_BUFFER_CAST (walk->data);
644
645   count = 0;
646   walk = g_list_next (walk);
647   while (walk) {
648     GstBuffer *buf = GST_BUFFER_CAST (walk->data);
649
650     data = GST_BUFFER_DATA (buf);
651     size = GST_BUFFER_SIZE (buf);
652
653     GST_LOG_OBJECT (mpegvideoparse, "collect remaining %d bytes from %p",
654         6 - count, buf);
655
656     while (size > 0 && count < 6) {
657       scanword = (scanword << 8) | *data++;
658       size--;
659       count++;
660     }
661     if (count == 6)
662       break;
663
664     walk = g_list_next (walk);
665   }
666   /* move bits to the beginning of the word now */
667   if (count)
668     scanword = (scanword << (8 * (8 - count)));
669
670   GST_LOG_OBJECT (mpegvideoparse, "scanword 0x%016" G_GINT64_MODIFIER "x",
671       scanword);
672
673   data = GST_BUFFER_DATA (head);
674   size = GST_BUFFER_SIZE (head);
675
676   while (size > 0) {
677     scanword = (((guint64) data[size - 1]) << 56) | (scanword >> 8);
678
679     GST_LOG_OBJECT (mpegvideoparse,
680         "scanword at %d 0x%016" G_GINT64_MODIFIER "x", size - 1, scanword);
681
682     /* check picture start and picture type */
683     if ((scanword & G_GUINT64_CONSTANT (0xffffffff00380000)) ==
684         G_GUINT64_CONSTANT (0x0000010000080000))
685       break;
686
687     size--;
688   }
689   return size - 1;
690 }
691
692 /* For reverse playback we use a technique that can be used for
693  * any keyframe based video codec.
694  *
695  * Input:
696  *  Buffer decoding order:  7  8  9  4  5  6  1  2  3  EOS
697  *  Keyframe flag:                      K        K
698  *  Discont flag:           D        D        D
699  *
700  * - Each Discont marks a discont in the decoding order.
701  * - The keyframes mark where we can start decoding. For mpeg they are either
702  *   set by the demuxer or we have to scan the buffers for a syncword and
703  *   picture header with an I frame.
704  *
705  * First we prepend incomming buffers to the gather queue, whenever we receive
706  * a discont, we flush out the gather queue.
707  *
708  * The above data will be accumulated in the gather queue like this:
709  *
710  *   gather queue:  9  8  7
711  *                        D
712  *
713  * Whe buffer 4 is received (with a DISCONT), we flush the gather queue like
714  * this:
715  *
716  *   while (gather)
717  *     take head of queue and prepend to decode queue.
718  *     if we copied a keyframe, decode the decode queue.
719  *
720  * After we flushed the gather queue, we add 4 to the (now empty) gather queue.
721  * We get the following situation:
722  *
723  *  gather queue:    4
724  *  decode queue:    7  8  9
725  *
726  * After we received 5 (Keyframe) and 6:
727  *
728  *  gather queue:    6  5  4
729  *  decode queue:    7  8  9
730  *
731  * When we receive 1 (DISCONT) which triggers a flush of the gather queue:
732  *
733  *   Copy head of the gather queue (6) to decode queue:
734  *
735  *    gather queue:    5  4
736  *    decode queue:    6  7  8  9
737  *
738  *   Copy head of the gather queue (5) to decode queue. This is a keyframe so we
739  *   can start decoding.
740  *
741  *    gather queue:    4
742  *    decode queue:    5  6  7  8  9
743  *
744  *   Decode frames in decode queue, we don't actually do the decoding but we
745  *   will send the decode queue to the downstream element. This will empty the
746  *   decoding queue again.
747  *
748  *   Copy head of the gather queue (4) to decode queue, we flushed the gather
749  *   queue and can now store input buffer in the gather queue:
750  *
751  *    gather queue:    1
752  *    decode queue:    4
753  *
754  *  When we receive EOS, the queue looks like:
755  *
756  *    gather queue:    3  2  1
757  *    decode queue:    4
758  *
759  *  Fill decode queue, first keyframe we copy is 2:
760  *
761  *    gather queue:    1
762  *    decode queue:    2  3  4
763  *
764  *  After pushing the decode queue:
765  *
766  *    gather queue:    1
767  *    decode queue:    
768  *
769  *  Leftover buffer 1 cannot be decoded and must be discarded.
770  */
771 static GstFlowReturn
772 gst_mpegvideoparse_flush_decode (MpegVideoParse * mpegvideoparse, guint idx)
773 {
774   GstFlowReturn res = GST_FLOW_OK;
775   GstBuffer *head = NULL;
776
777   while (mpegvideoparse->decode) {
778     GstBuffer *buf;
779
780     buf = GST_BUFFER_CAST (mpegvideoparse->decode->data);
781
782     if (idx != -1) {
783       GstBuffer *temp;
784
785       if (idx > 0) {
786         /* first buffer, split at the point where the picture start was
787          * detected and store as the new head of the decoding list. */
788         head = gst_buffer_create_sub (buf, 0, idx);
789         /* push the remainder after the picture sync point downstream, this is the
790          * first DISCONT buffer we push. */
791         temp = gst_buffer_create_sub (buf, idx, GST_BUFFER_SIZE (buf) - idx);
792         /* don't need old buffer anymore and swap new buffer */
793         gst_buffer_unref (buf);
794         buf = temp;
795       }
796       GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
797       idx = -1;
798     } else {
799       /* next buffers are not discont */
800       GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
801     }
802
803     GST_DEBUG_OBJECT (mpegvideoparse, "pushing buffer %p, ts %" GST_TIME_FORMAT,
804         buf, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)));
805
806     res = gst_pad_push (mpegvideoparse->srcpad, buf);
807
808     mpegvideoparse->decode =
809         g_list_delete_link (mpegvideoparse->decode, mpegvideoparse->decode);
810   }
811   if (head) {
812     /* store remainder of the buffer */
813     mpegvideoparse->decode = g_list_prepend (mpegvideoparse->decode, head);
814   }
815   return res;
816 }
817
818 static GstFlowReturn
819 gst_mpegvideoparse_chain_reverse (MpegVideoParse * mpegvideoparse,
820     gboolean discont, GstBuffer * buf)
821 {
822   GstFlowReturn res = GST_FLOW_OK;
823
824   /* if we have a discont, move buffers to the decode list */
825   if (G_UNLIKELY (discont)) {
826     GST_DEBUG_OBJECT (mpegvideoparse, "received discont,gathering buffers");
827
828     while (mpegvideoparse->gather) {
829       GstBuffer *gbuf;
830       guint keyframeidx;
831
832       gbuf = GST_BUFFER_CAST (mpegvideoparse->gather->data);
833       /* remove from the gather list */
834       mpegvideoparse->gather =
835           g_list_delete_link (mpegvideoparse->gather, mpegvideoparse->gather);
836       /* copy to decode queue */
837       mpegvideoparse->decode = g_list_prepend (mpegvideoparse->decode, gbuf);
838
839       GST_DEBUG_OBJECT (mpegvideoparse, "copied decoding buffer %p, len %d",
840           gbuf, g_list_length (mpegvideoparse->decode));
841
842       /* check if we copied a keyframe, we scan the buffers on the decode queue.
843        * We only need to scan the first buffer and at most 3 bytes of the second
844        * buffer. We return the index of the keyframe (or -1 when nothing was
845        * found) */
846       while ((keyframeidx = scan_keyframe (mpegvideoparse)) != -1) {
847         GST_DEBUG_OBJECT (mpegvideoparse, "copied keyframe at %u", keyframeidx);
848         res = gst_mpegvideoparse_flush_decode (mpegvideoparse, keyframeidx);
849       }
850     }
851   }
852
853   if (buf) {
854     /* add buffer to gather queue */
855     GST_DEBUG_OBJECT (mpegvideoparse, "gathering buffer %p, size %u", buf,
856         GST_BUFFER_SIZE (buf));
857     mpegvideoparse->gather = g_list_prepend (mpegvideoparse->gather, buf);
858   }
859
860   return res;
861 }
862
863 static GstFlowReturn
864 gst_mpegvideoparse_chain (GstPad * pad, GstBuffer * buf)
865 {
866   MpegVideoParse *mpegvideoparse;
867   GstFlowReturn res;
868   gboolean discont;
869
870   mpegvideoparse =
871       GST_MPEGVIDEOPARSE (gst_object_get_parent (GST_OBJECT (pad)));
872
873   discont = GST_BUFFER_IS_DISCONT (buf);
874
875   if (mpegvideoparse->segment.rate > 0.0)
876     res = gst_mpegvideoparse_chain_forward (mpegvideoparse, discont, buf);
877   else
878     res = gst_mpegvideoparse_chain_reverse (mpegvideoparse, discont, buf);
879
880   gst_object_unref (mpegvideoparse);
881
882   return res;
883 }
884
885 static gboolean
886 mpv_parse_sink_event (GstPad * pad, GstEvent * event)
887 {
888   gboolean res = TRUE;
889   MpegVideoParse *mpegvideoparse =
890       GST_MPEGVIDEOPARSE (gst_pad_get_parent (pad));
891
892   switch (GST_EVENT_TYPE (event)) {
893     case GST_EVENT_NEWSEGMENT:
894     {
895       gdouble rate, applied_rate;
896       GstFormat format;
897       gint64 start, stop, pos;
898       gboolean update;
899
900       gst_event_parse_new_segment_full (event, &update, &rate, &applied_rate,
901           &format, &start, &stop, &pos);
902
903       if (format == GST_FORMAT_BYTES) {
904         /* FIXME: Later, we might use a seek table to seek on elementary stream
905            files, and that would allow byte-to-time conversions. It's not a high
906            priority - most mpeg video is muxed and then the demuxer handles 
907            seeking. In the meantime, here's some commented out logic copied
908            from mp3parse */
909 #if 0
910         GstClockTime seg_start, seg_stop, seg_pos;
911
912         /* stop time is allowed to be open-ended, but not start & pos */
913         if (!mp3parse_bytepos_to_time (mp3parse, stop, &seg_stop))
914           seg_stop = GST_CLOCK_TIME_NONE;
915         if (mp3parse_bytepos_to_time (mp3parse, start, &seg_start) &&
916             mp3parse_bytepos_to_time (mp3parse, pos, &seg_pos)) {
917           gst_event_unref (event);
918           event = gst_event_new_new_segment_full (update, rate, applied_rate,
919               GST_FORMAT_TIME, seg_start, seg_stop, seg_pos);
920           format = GST_FORMAT_TIME;
921           GST_DEBUG_OBJECT (mp3parse, "Converted incoming segment to TIME. "
922               "start = %" G_GINT64_FORMAT ", stop = %" G_GINT64_FORMAT
923               "pos = %" G_GINT64_FORMAT, seg_start, seg_stop, seg_pos);
924         }
925 #endif
926       }
927
928       if (format != GST_FORMAT_TIME) {
929         /* Unknown incoming segment format. Output a default open-ended 
930          * TIME segment */
931         gst_event_unref (event);
932
933         /* set new values */
934         format = GST_FORMAT_TIME;
935         start = 0;
936         stop = GST_CLOCK_TIME_NONE;
937         pos = 0;
938         /* create a new segment with these values */
939         event = gst_event_new_new_segment_full (update, rate, applied_rate,
940             format, start, stop, pos);
941       }
942
943       gst_mpegvideoparse_flush (mpegvideoparse);
944
945       /* now configure the values */
946       gst_segment_set_newsegment_full (&mpegvideoparse->segment, update,
947           rate, applied_rate, format, start, stop, pos);
948
949       GST_DEBUG_OBJECT (mpegvideoparse,
950           "Pushing newseg rate %g, applied rate %g, format %d, start %"
951           G_GINT64_FORMAT ", stop %" G_GINT64_FORMAT ", pos %" G_GINT64_FORMAT,
952           rate, applied_rate, format, start, stop, pos);
953
954       /* Forward the event if we've seen a sequence header
955        * and therefore set output caps, otherwise queue it for later */
956       if (mpegvideoparse->seq_hdr.mpeg_version != 0)
957         res = gst_pad_push_event (mpegvideoparse->srcpad, event);
958       else {
959         res = TRUE;
960         mpegvideoparse->pending_segs =
961             g_list_append (mpegvideoparse->pending_segs, event);
962       }
963       break;
964     }
965     case GST_EVENT_FLUSH_STOP:
966       GST_DEBUG_OBJECT (mpegvideoparse, "flush stop");
967       gst_mpegvideoparse_flush (mpegvideoparse);
968       res = gst_pad_push_event (mpegvideoparse->srcpad, event);
969       break;
970     case GST_EVENT_EOS:
971       /* Push any remaining buffers out, then flush. */
972       GST_DEBUG_OBJECT (mpegvideoparse, "received EOS");
973       if (mpegvideoparse->segment.rate >= 0.0) {
974         mpeg_packetiser_handle_eos (&mpegvideoparse->packer);
975         mpegvideoparse_drain_avail (mpegvideoparse);
976         gst_mpegvideoparse_flush (mpegvideoparse);
977       } else {
978         gst_mpegvideoparse_chain_reverse (mpegvideoparse, TRUE, NULL);
979         gst_mpegvideoparse_flush_decode (mpegvideoparse, 0);
980       }
981       res = gst_pad_push_event (mpegvideoparse->srcpad, event);
982       break;
983     default:
984       res = gst_pad_push_event (mpegvideoparse->srcpad, event);
985       break;
986   }
987
988   gst_object_unref (mpegvideoparse);
989   return res;
990 }
991
992 static GstStateChangeReturn
993 gst_mpegvideoparse_change_state (GstElement * element,
994     GstStateChange transition)
995 {
996   MpegVideoParse *mpegvideoparse;
997   GstStateChangeReturn ret;
998
999   g_return_val_if_fail (GST_IS_MPEGVIDEOPARSE (element),
1000       GST_STATE_CHANGE_FAILURE);
1001
1002   mpegvideoparse = GST_MPEGVIDEOPARSE (element);
1003
1004   switch (transition) {
1005     case GST_STATE_CHANGE_READY_TO_PAUSED:
1006       gst_segment_init (&mpegvideoparse->segment, GST_FORMAT_UNDEFINED);
1007       break;
1008     default:
1009       break;
1010   }
1011
1012   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
1013
1014   switch (transition) {
1015     case GST_STATE_CHANGE_PAUSED_TO_READY:
1016       mpv_parse_reset (mpegvideoparse);
1017       gst_mpegvideoparse_flush (mpegvideoparse);
1018       break;
1019     default:
1020       break;
1021   }
1022
1023   return ret;
1024 }
1025
1026 static gboolean
1027 plugin_init (GstPlugin * plugin)
1028 {
1029   GST_DEBUG_CATEGORY_INIT (mpv_parse_debug, "legacympegvideoparse", 0,
1030       "MPEG Video Parser");
1031
1032   return gst_element_register (plugin, "legacympegvideoparse",
1033       GST_RANK_NONE, GST_TYPE_MPEGVIDEOPARSE);
1034 }
1035
1036 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
1037     GST_VERSION_MINOR,
1038     "mpegvideoparse",
1039     "MPEG-1 and MPEG-2 video parser",
1040     plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)