~oah-dev/oah/gst-plugins-bad

« back to all changes in this revision

Viewing changes to gst/mpegvideoparse/mpegvideoparse.c

  • Committer: Haakon Sporsheim
  • Date: 2009-03-12 13:52:03 UTC
  • Revision ID: haakon.sporsheim@tandberg.com-20090312135203-i5k294hgkushb0mt
Initial import of git repository: git://anongit.freedesktop.org/gstreamer/gst-plugins-bad (tag: RELEASE-0_10_10)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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_STATIC (mpv_parse_debug);
 
45
#define GST_CAT_DEFAULT mpv_parse_debug
 
46
 
 
47
/* elementfactory information */
 
48
static GstElementDetails mpegvideoparse_details =
 
49
GST_ELEMENT_DETAILS ("MPEG video elementary stream parser",
 
50
    "Codec/Parser/Video",
 
51
    "Parses and frames MPEG-1 and MPEG-2 elementary video streams",
 
52
    "Wim Taymans <wim.taymans@chello.be>\n"
 
53
    "Jan Schmidt <thaytan@mad.scientist.com>");
 
54
 
 
55
static GstStaticPadTemplate src_template =
 
56
GST_STATIC_PAD_TEMPLATE ("src", GST_PAD_SRC,
 
57
    GST_PAD_ALWAYS,
 
58
    GST_STATIC_CAPS ("video/mpeg, "
 
59
        "mpegversion = (int) [ 1, 2 ], "
 
60
        "parsed = (boolean) true, "
 
61
        "systemstream = (boolean) false, "
 
62
        "width = (int) [ 16, 4096 ], "
 
63
        "height = (int) [ 16, 4096 ], "
 
64
        "pixel-aspect-ratio = (fraction) [ 0/1, MAX ], "
 
65
        "framerate = (fraction) [ 0/1, MAX ]")
 
66
    );
 
67
 
 
68
static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
 
69
    GST_PAD_SINK,
 
70
    GST_PAD_ALWAYS,
 
71
    GST_STATIC_CAPS ("video/mpeg, "
 
72
        "mpegversion = (int) [ 1, 2 ], "
 
73
        "parsed = (boolean) false, " "systemstream = (boolean) false")
 
74
    );
 
75
 
 
76
/* MpegVideoParse signals and args */
 
77
enum
 
78
{
 
79
  /* FILL ME */
 
80
  LAST_SIGNAL
 
81
};
 
82
 
 
83
enum
 
84
{
 
85
  ARG_0
 
86
      /* FILL ME */
 
87
};
 
88
 
 
89
static void gst_mpegvideoparse_class_init (MpegVideoParseClass * klass);
 
90
static void gst_mpegvideoparse_base_init (MpegVideoParseClass * klass);
 
91
static void gst_mpegvideoparse_init (MpegVideoParse * mpegvideoparse);
 
92
static void gst_mpegvideoparse_dispose (GObject * object);
 
93
 
 
94
static GstFlowReturn gst_mpegvideoparse_chain (GstPad * pad, GstBuffer * buf);
 
95
static gboolean mpv_parse_sink_event (GstPad * pad, GstEvent * event);
 
96
static void gst_mpegvideoparse_flush (MpegVideoParse * mpegvideoparse);
 
97
static GstStateChangeReturn
 
98
gst_mpegvideoparse_change_state (GstElement * element,
 
99
    GstStateChange transition);
 
100
 
 
101
static void mpv_send_pending_segs (MpegVideoParse * mpegvideoparse);
 
102
static void mpv_clear_pending_segs (MpegVideoParse * mpegvideoparse);
 
103
 
 
104
static GstElementClass *parent_class = NULL;
 
105
 
 
106
/*static guint gst_mpegvideoparse_signals[LAST_SIGNAL] = { 0 }; */
 
107
 
 
108
GType
 
109
mpegvideoparse_get_type (void)
 
110
{
 
111
  static GType mpegvideoparse_type = 0;
 
112
 
 
113
  if (!mpegvideoparse_type) {
 
114
    static const GTypeInfo mpegvideoparse_info = {
 
115
      sizeof (MpegVideoParseClass),
 
116
      (GBaseInitFunc) gst_mpegvideoparse_base_init,
 
117
      NULL,
 
118
      (GClassInitFunc) gst_mpegvideoparse_class_init,
 
119
      NULL,
 
120
      NULL,
 
121
      sizeof (MpegVideoParse),
 
122
      0,
 
123
      (GInstanceInitFunc) gst_mpegvideoparse_init,
 
124
    };
 
125
 
 
126
    mpegvideoparse_type =
 
127
        g_type_register_static (GST_TYPE_ELEMENT, "MpegVideoParse",
 
128
        &mpegvideoparse_info, 0);
 
129
  }
 
130
  return mpegvideoparse_type;
 
131
}
 
132
 
 
133
static void
 
134
gst_mpegvideoparse_base_init (MpegVideoParseClass * klass)
 
135
{
 
136
  GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
 
137
 
 
138
  gst_element_class_add_pad_template (element_class,
 
139
      gst_static_pad_template_get (&src_template));
 
140
  gst_element_class_add_pad_template (element_class,
 
141
      gst_static_pad_template_get (&sink_template));
 
142
 
 
143
  gst_element_class_set_details (element_class, &mpegvideoparse_details);
 
144
}
 
145
 
 
146
static void
 
147
gst_mpegvideoparse_class_init (MpegVideoParseClass * klass)
 
148
{
 
149
  GObjectClass *gobject_class;
 
150
  GstElementClass *gstelement_class;
 
151
 
 
152
  gstelement_class = (GstElementClass *) klass;
 
153
  gobject_class = G_OBJECT_CLASS (klass);
 
154
 
 
155
  parent_class = g_type_class_peek_parent (klass);
 
156
 
 
157
  gobject_class->dispose = (GObjectFinalizeFunc) (gst_mpegvideoparse_dispose);
 
158
  gstelement_class->change_state = gst_mpegvideoparse_change_state;
 
159
}
 
160
 
 
161
static void
 
162
mpv_parse_reset (MpegVideoParse * mpegvideoparse)
 
163
{
 
164
  mpegvideoparse->seq_hdr.mpeg_version = 0;
 
165
  mpegvideoparse->seq_hdr.width = mpegvideoparse->seq_hdr.height = -1;
 
166
  mpegvideoparse->seq_hdr.fps_n = mpegvideoparse->seq_hdr.par_w = 0;
 
167
  mpegvideoparse->seq_hdr.fps_d = mpegvideoparse->seq_hdr.par_h = 1;
 
168
 
 
169
  mpv_clear_pending_segs (mpegvideoparse);
 
170
}
 
171
 
 
172
static void
 
173
mpv_send_pending_segs (MpegVideoParse * mpegvideoparse)
 
174
{
 
175
  while (mpegvideoparse->pending_segs) {
 
176
    GstEvent *ev = mpegvideoparse->pending_segs->data;
 
177
 
 
178
    gst_pad_push_event (mpegvideoparse->srcpad, ev);
 
179
 
 
180
    mpegvideoparse->pending_segs =
 
181
        g_list_delete_link (mpegvideoparse->pending_segs,
 
182
        mpegvideoparse->pending_segs);
 
183
  }
 
184
  mpegvideoparse->pending_segs = NULL;
 
185
}
 
186
 
 
187
static void
 
188
mpv_clear_pending_segs (MpegVideoParse * mpegvideoparse)
 
189
{
 
190
  while (mpegvideoparse->pending_segs) {
 
191
    GstEvent *ev = mpegvideoparse->pending_segs->data;
 
192
    gst_event_unref (ev);
 
193
 
 
194
    mpegvideoparse->pending_segs =
 
195
        g_list_delete_link (mpegvideoparse->pending_segs,
 
196
        mpegvideoparse->pending_segs);
 
197
  }
 
198
}
 
199
 
 
200
static void
 
201
gst_mpegvideoparse_init (MpegVideoParse * mpegvideoparse)
 
202
{
 
203
  mpegvideoparse->sinkpad =
 
204
      gst_pad_new_from_static_template (&sink_template, "sink");
 
205
  gst_pad_set_chain_function (mpegvideoparse->sinkpad,
 
206
      gst_mpegvideoparse_chain);
 
207
  gst_pad_set_event_function (mpegvideoparse->sinkpad, mpv_parse_sink_event);
 
208
  gst_element_add_pad (GST_ELEMENT (mpegvideoparse), mpegvideoparse->sinkpad);
 
209
 
 
210
  mpegvideoparse->srcpad =
 
211
      gst_pad_new_from_static_template (&src_template, "src");
 
212
  gst_pad_use_fixed_caps (mpegvideoparse->srcpad);
 
213
  gst_element_add_pad (GST_ELEMENT (mpegvideoparse), mpegvideoparse->srcpad);
 
214
 
 
215
  mpeg_packetiser_init (&mpegvideoparse->packer);
 
216
 
 
217
  mpv_parse_reset (mpegvideoparse);
 
218
}
 
219
 
 
220
void
 
221
gst_mpegvideoparse_dispose (GObject * object)
 
222
{
 
223
  MpegVideoParse *mpegvideoparse = GST_MPEGVIDEOPARSE (object);
 
224
 
 
225
  mpeg_packetiser_free (&mpegvideoparse->packer);
 
226
  gst_buffer_replace (&mpegvideoparse->seq_hdr_buf, NULL);
 
227
 
 
228
  G_OBJECT_CLASS (parent_class)->dispose (object);
 
229
}
 
230
 
 
231
static gboolean
 
232
mpegvideoparse_handle_sequence (MpegVideoParse * mpegvideoparse,
 
233
    GstBuffer * buf)
 
234
{
 
235
  MPEGSeqHdr new_hdr;
 
236
  guint8 *cur, *end;
 
237
 
 
238
  cur = GST_BUFFER_DATA (buf);
 
239
  end = GST_BUFFER_DATA (buf) + GST_BUFFER_SIZE (buf);
 
240
 
 
241
  memset (&new_hdr, 0, sizeof (MPEGSeqHdr));
 
242
 
 
243
  if (G_UNLIKELY (!mpeg_util_parse_sequence_hdr (&new_hdr, cur, end)))
 
244
    return FALSE;
 
245
 
 
246
  if (memcmp (&mpegvideoparse->seq_hdr, &new_hdr, sizeof (MPEGSeqHdr)) != 0) {
 
247
    GstCaps *caps;
 
248
    GstBuffer *seq_buf;
 
249
 
 
250
    /* Store the entire sequence header + sequence header extension
 
251
       for output as codec_data */
 
252
    seq_buf = gst_buffer_copy (buf);
 
253
    gst_buffer_replace (&mpegvideoparse->seq_hdr_buf, seq_buf);
 
254
    gst_buffer_unref (seq_buf);
 
255
 
 
256
    caps = gst_caps_new_simple ("video/mpeg",
 
257
        "systemstream", G_TYPE_BOOLEAN, FALSE,
 
258
        "parsed", G_TYPE_BOOLEAN, TRUE,
 
259
        "mpegversion", G_TYPE_INT, new_hdr.mpeg_version,
 
260
        "width", G_TYPE_INT, new_hdr.width,
 
261
        "height", G_TYPE_INT, new_hdr.height,
 
262
        "framerate", GST_TYPE_FRACTION, new_hdr.fps_n, new_hdr.fps_d,
 
263
        "pixel-aspect-ratio", GST_TYPE_FRACTION, new_hdr.par_w, new_hdr.par_h,
 
264
        "codec_data", GST_TYPE_BUFFER, seq_buf, NULL);
 
265
 
 
266
    GST_DEBUG ("New mpegvideoparse caps: %" GST_PTR_FORMAT, caps);
 
267
    if (!gst_pad_set_caps (mpegvideoparse->srcpad, caps)) {
 
268
      gst_caps_unref (caps);
 
269
      return FALSE;
 
270
    }
 
271
    gst_caps_unref (caps);
 
272
 
 
273
    /* And update the new_hdr into our stored version */
 
274
    mpegvideoparse->seq_hdr = new_hdr;
 
275
  }
 
276
 
 
277
  return TRUE;
 
278
}
 
279
 
 
280
static gboolean
 
281
mpegvideoparse_handle_picture (MpegVideoParse * mpegvideoparse, GstBuffer * buf)
 
282
{
 
283
  guint8 *cur, *end;
 
284
  guint32 sync_word = 0xffffffff;
 
285
 
 
286
  cur = GST_BUFFER_DATA (buf);
 
287
  end = GST_BUFFER_DATA (buf) + GST_BUFFER_SIZE (buf);
 
288
 
 
289
  cur = mpeg_util_find_start_code (&sync_word, cur, end);
 
290
  while (cur != NULL) {
 
291
    /* Cur points at the last byte of the start code */
 
292
    if (cur[0] == MPEG_PACKET_PICTURE) {
 
293
      guint8 *pic_data = cur - 3;
 
294
      MPEGPictureHdr hdr;
 
295
 
 
296
      /* pic_data points to the first byte of the sync word now */
 
297
      if (!mpeg_util_parse_picture_hdr (&hdr, pic_data, end))
 
298
        return FALSE;
 
299
 
 
300
      if (hdr.pic_type != MPEG_PICTURE_TYPE_I)
 
301
        GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
 
302
 
 
303
      GST_LOG_OBJECT (mpegvideoparse, "Picture type is %u", hdr.pic_type);
 
304
      /* FIXME: Can use the picture type and number of fields to track a
 
305
       * timestamp */
 
306
    }
 
307
    cur = mpeg_util_find_start_code (&sync_word, cur, end);
 
308
  }
 
309
 
 
310
  return TRUE;
 
311
}
 
312
 
 
313
#if 0
 
314
static guint64
 
315
gst_mpegvideoparse_time_code (guchar * gop, MPEGSeqHdr * seq_hdr)
 
316
{
 
317
  guint32 data = GST_READ_UINT32_BE (gop);
 
318
  guint64 seconds;
 
319
  guint8 frames;
 
320
 
 
321
  seconds = ((data & 0xfc000000) >> 26) * 3600; /* hours */
 
322
  seconds += ((data & 0x03f00000) >> 20) * 60;  /* minutes */
 
323
  seconds += (data & 0x0007e000) >> 13; /* seconds */
 
324
 
 
325
  frames = (data & 0x00001f80) >> 7;
 
326
 
 
327
  return seconds * GST_SECOND + gst_util_uint64_scale_int (frames * GST_SECOND,
 
328
      seq_hdr->fps_d, seq_hdr->fps_n);
 
329
}
 
330
#endif
 
331
 
 
332
static void
 
333
gst_mpegvideoparse_flush (MpegVideoParse * mpegvideoparse)
 
334
{
 
335
  GST_DEBUG_OBJECT (mpegvideoparse, "mpegvideoparse: flushing");
 
336
 
 
337
  mpegvideoparse->next_offset = GST_BUFFER_OFFSET_NONE;
 
338
 
 
339
  g_list_foreach (mpegvideoparse->gather, (GFunc) gst_mini_object_unref, NULL);
 
340
  g_list_free (mpegvideoparse->gather);
 
341
  mpegvideoparse->gather = NULL;
 
342
  g_list_foreach (mpegvideoparse->decode, (GFunc) gst_mini_object_unref, NULL);
 
343
  g_list_free (mpegvideoparse->decode);
 
344
  mpegvideoparse->decode = NULL;
 
345
  mpeg_packetiser_flush (&mpegvideoparse->packer);
 
346
 
 
347
  mpv_clear_pending_segs (mpegvideoparse);
 
348
}
 
349
 
 
350
static GstFlowReturn
 
351
mpegvideoparse_drain_avail (MpegVideoParse * mpegvideoparse)
 
352
{
 
353
  MPEGBlockInfo *cur;
 
354
  GstBuffer *buf = NULL;
 
355
  GstFlowReturn res = GST_FLOW_OK;
 
356
 
 
357
  cur = mpeg_packetiser_get_block (&mpegvideoparse->packer, &buf);
 
358
  while ((cur != NULL) && (res == GST_FLOW_OK)) {
 
359
    /* Handle the block */
 
360
    GST_LOG_OBJECT (mpegvideoparse,
 
361
        "Have block of size %u with pack_type 0x%02x and flags 0x%02x",
 
362
        cur->length, cur->first_pack_type, cur->flags);
 
363
 
 
364
    /* Don't start pushing out buffers until we've seen a sequence header */
 
365
    if (mpegvideoparse->seq_hdr.mpeg_version == 0) {
 
366
      if (cur->flags & MPEG_BLOCK_FLAG_SEQUENCE) {
 
367
        /* Found a sequence header */
 
368
        if (!mpegvideoparse_handle_sequence (mpegvideoparse, buf)) {
 
369
          GST_DEBUG_OBJECT (mpegvideoparse,
 
370
              "Invalid sequence header. Dropping buffer.");
 
371
          gst_buffer_unref (buf);
 
372
          buf = NULL;
 
373
        }
 
374
      } else {
 
375
        if (buf) {
 
376
          GST_DEBUG_OBJECT (mpegvideoparse,
 
377
              "No sequence header yet. Dropping buffer of %u bytes",
 
378
              GST_BUFFER_SIZE (buf));
 
379
          gst_buffer_unref (buf);
 
380
          buf = NULL;
 
381
        }
 
382
      }
 
383
    }
 
384
 
 
385
    if (buf != NULL) {
 
386
      /* If outputting a PICTURE packet, we can calculate the duration
 
387
         and possibly the timestamp */
 
388
      if (cur->flags & MPEG_BLOCK_FLAG_PICTURE) {
 
389
        if (!mpegvideoparse_handle_picture (mpegvideoparse, buf)) {
 
390
          /* Corrupted picture. Drop it. */
 
391
          GST_DEBUG_OBJECT (mpegvideoparse,
 
392
              "Corrupted picture header. Dropping buffer of %u bytes",
 
393
              GST_BUFFER_SIZE (buf));
 
394
          mpegvideoparse->need_discont = TRUE;
 
395
          gst_buffer_unref (buf);
 
396
          buf = NULL;
 
397
        }
 
398
      }
 
399
    }
 
400
 
 
401
    if (buf != NULL) {
 
402
      GST_DEBUG_OBJECT (mpegvideoparse,
 
403
          "mpegvideoparse: pushing buffer of %u bytes with ts %"
 
404
          GST_TIME_FORMAT, GST_BUFFER_SIZE (buf),
 
405
          GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)));
 
406
 
 
407
      gst_buffer_set_caps (buf, GST_PAD_CAPS (mpegvideoparse->srcpad));
 
408
 
 
409
      if (mpegvideoparse->need_discont) {
 
410
        GST_DEBUG_OBJECT (mpegvideoparse,
 
411
            "setting discont flag on outgoing buffer");
 
412
        GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
 
413
        mpegvideoparse->need_discont = FALSE;
 
414
      }
 
415
 
 
416
      mpv_send_pending_segs (mpegvideoparse);
 
417
 
 
418
      res = gst_pad_push (mpegvideoparse->srcpad, buf);
 
419
      buf = NULL;
 
420
    }
 
421
 
 
422
    /* Advance to the next data block */
 
423
    mpeg_packetiser_next_block (&mpegvideoparse->packer);
 
424
    cur = mpeg_packetiser_get_block (&mpegvideoparse->packer, &buf);
 
425
  }
 
426
  if (buf != NULL)
 
427
    gst_buffer_unref (buf);
 
428
 
 
429
  return res;
 
430
}
 
431
 
 
432
static GstFlowReturn
 
433
gst_mpegvideoparse_chain_forward (MpegVideoParse * mpegvideoparse,
 
434
    gboolean discont, GstBuffer * buf)
 
435
{
 
436
  GstFlowReturn res;
 
437
  guint64 next_offset = GST_BUFFER_OFFSET_NONE;
 
438
 
 
439
  GST_DEBUG_OBJECT (mpegvideoparse,
 
440
      "mpegvideoparse: received buffer of %u bytes with ts %"
 
441
      GST_TIME_FORMAT " and offset %" G_GINT64_FORMAT, GST_BUFFER_SIZE (buf),
 
442
      GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)), GST_BUFFER_OFFSET (buf));
 
443
 
 
444
  /* If we have an offset, and the incoming offset doesn't match, 
 
445
     or we have a discont, handle it first by flushing out data
 
446
     we have collected. */
 
447
  if (mpegvideoparse->next_offset != GST_BUFFER_OFFSET_NONE) {
 
448
    if (GST_BUFFER_OFFSET_IS_VALID (buf)) {
 
449
      if (mpegvideoparse->next_offset != GST_BUFFER_OFFSET (buf))
 
450
        discont = TRUE;
 
451
      next_offset = GST_BUFFER_OFFSET (buf) + GST_BUFFER_SIZE (buf);
 
452
    } else {
 
453
      next_offset = mpegvideoparse->next_offset + GST_BUFFER_SIZE (buf);
 
454
    }
 
455
  }
 
456
 
 
457
  /* Clear out any existing stuff if the new buffer is discontinuous */
 
458
  if (discont) {
 
459
    GST_DEBUG_OBJECT (mpegvideoparse, "Have discont packet, draining data");
 
460
    mpegvideoparse->need_discont = TRUE;
 
461
 
 
462
    mpeg_packetiser_handle_eos (&mpegvideoparse->packer);
 
463
    res = mpegvideoparse_drain_avail (mpegvideoparse);
 
464
    mpeg_packetiser_flush (&mpegvideoparse->packer);
 
465
    if (res != GST_FLOW_OK) {
 
466
      gst_buffer_unref (buf);
 
467
      goto done;
 
468
    }
 
469
  }
 
470
 
 
471
  /* Takes ownership of the data */
 
472
  mpeg_packetiser_add_buf (&mpegvideoparse->packer, buf);
 
473
 
 
474
  /* And push out what we can */
 
475
  res = mpegvideoparse_drain_avail (mpegvideoparse);
 
476
 
 
477
done:
 
478
  /* Update our offset */
 
479
  mpegvideoparse->next_offset = next_offset;
 
480
 
 
481
  return res;
 
482
}
 
483
 
 
484
/* scan the decode queue for a picture header with an I frame and return the
 
485
 * index in the first buffer. We only scan the first buffer and possibly a
 
486
 * couple of bytes of the next buffers to find the I frame. Scanning is done
 
487
 * backwards because the first buffer could contain many picture start codes
 
488
 * with I frames. */
 
489
static guint
 
490
scan_keyframe (MpegVideoParse * mpegvideoparse)
 
491
{
 
492
  guint64 scanword;
 
493
  guint count;
 
494
  GList *walk;
 
495
  GstBuffer *head;
 
496
  guint8 *data;
 
497
  guint size;
 
498
 
 
499
  /* we use an 8 byte buffer, this is enough to hold the picture start code and
 
500
   * the picture header bits we are interested in. We init to 0xff so that when
 
501
   * we have a valid picture start without the header bits, we will be able to
 
502
   * detect this because it will generate an invalid picture type. */
 
503
  scanword = ~G_GUINT64_CONSTANT (0);
 
504
 
 
505
  GST_LOG_OBJECT (mpegvideoparse, "scan keyframe");
 
506
 
 
507
  /* move to the second buffer if we can, we should have at least one buffer */
 
508
  walk = mpegvideoparse->decode;
 
509
  g_return_val_if_fail (walk != NULL, -1);
 
510
 
 
511
  head = GST_BUFFER_CAST (walk->data);
 
512
 
 
513
  count = 0;
 
514
  walk = g_list_next (walk);
 
515
  while (walk) {
 
516
    GstBuffer *buf = GST_BUFFER_CAST (walk->data);
 
517
 
 
518
    data = GST_BUFFER_DATA (buf);
 
519
    size = GST_BUFFER_SIZE (buf);
 
520
 
 
521
    GST_LOG_OBJECT (mpegvideoparse, "collect remaining %d bytes from %p",
 
522
        6 - count, buf);
 
523
 
 
524
    while (size > 0 && count < 6) {
 
525
      scanword = (scanword << 8) | *data++;
 
526
      size--;
 
527
      count++;
 
528
    }
 
529
    if (count == 6)
 
530
      break;
 
531
 
 
532
    walk = g_list_next (walk);
 
533
  }
 
534
  /* move bits to the beginning of the word now */
 
535
  if (count)
 
536
    scanword = (scanword << (8 * (8 - count)));
 
537
 
 
538
  GST_LOG_OBJECT (mpegvideoparse, "scanword 0x%016llx", scanword);
 
539
 
 
540
  data = GST_BUFFER_DATA (head);
 
541
  size = GST_BUFFER_SIZE (head);
 
542
 
 
543
  while (size > 0) {
 
544
    scanword = (((guint64) data[size - 1]) << 56) | (scanword >> 8);
 
545
 
 
546
    GST_LOG_OBJECT (mpegvideoparse, "scanword at %d 0x%016llx", size - 1,
 
547
        scanword);
 
548
 
 
549
    /* check picture start and picture type */
 
550
    if ((scanword & G_GUINT64_CONSTANT (0xffffffff00380000)) ==
 
551
        G_GUINT64_CONSTANT (0x0000010000080000))
 
552
      break;
 
553
 
 
554
    size--;
 
555
  }
 
556
  return size - 1;
 
557
}
 
558
 
 
559
/* For reverse playback we use a technique that can be used for
 
560
 * any keyframe based video codec.
 
561
 *
 
562
 * Input:
 
563
 *  Buffer decoding order:  7  8  9  4  5  6  1  2  3  EOS
 
564
 *  Keyframe flag:                      K        K
 
565
 *  Discont flag:           D        D        D
 
566
 *
 
567
 * - Each Discont marks a discont in the decoding order.
 
568
 * - The keyframes mark where we can start decoding. For mpeg they are either
 
569
 *   set by the demuxer or we have to scan the buffers for a syncword and
 
570
 *   picture header with an I frame.
 
571
 *
 
572
 * First we prepend incomming buffers to the gather queue, whenever we receive
 
573
 * a discont, we flush out the gather queue.
 
574
 *
 
575
 * The above data will be accumulated in the gather queue like this:
 
576
 *
 
577
 *   gather queue:  9  8  7
 
578
 *                        D
 
579
 *
 
580
 * Whe buffer 4 is received (with a DISCONT), we flush the gather queue like
 
581
 * this:
 
582
 *
 
583
 *   while (gather)
 
584
 *     take head of queue and prepend to decode queue.
 
585
 *     if we copied a keyframe, decode the decode queue.
 
586
 *
 
587
 * After we flushed the gather queue, we add 4 to the (now empty) gather queue.
 
588
 * We get the following situation:
 
589
 *
 
590
 *  gather queue:    4
 
591
 *  decode queue:    7  8  9
 
592
 *
 
593
 * After we received 5 (Keyframe) and 6:
 
594
 *
 
595
 *  gather queue:    6  5  4
 
596
 *  decode queue:    7  8  9
 
597
 *
 
598
 * When we receive 1 (DISCONT) which triggers a flush of the gather queue:
 
599
 *
 
600
 *   Copy head of the gather queue (6) to decode queue:
 
601
 *
 
602
 *    gather queue:    5  4
 
603
 *    decode queue:    6  7  8  9
 
604
 *
 
605
 *   Copy head of the gather queue (5) to decode queue. This is a keyframe so we
 
606
 *   can start decoding.
 
607
 *
 
608
 *    gather queue:    4
 
609
 *    decode queue:    5  6  7  8  9
 
610
 *
 
611
 *   Decode frames in decode queue, we don't actually do the decoding but we
 
612
 *   will send the decode queue to the downstream element. This will empty the
 
613
 *   decoding queue again.
 
614
 *
 
615
 *   Copy head of the gather queue (4) to decode queue, we flushed the gather
 
616
 *   queue and can now store input buffer in the gather queue:
 
617
 *
 
618
 *    gather queue:    1
 
619
 *    decode queue:    4
 
620
 *
 
621
 *  When we receive EOS, the queue looks like:
 
622
 *
 
623
 *    gather queue:    3  2  1
 
624
 *    decode queue:    4
 
625
 *
 
626
 *  Fill decode queue, first keyframe we copy is 2:
 
627
 *
 
628
 *    gather queue:    1
 
629
 *    decode queue:    2  3  4
 
630
 *
 
631
 *  After pushing the decode queue:
 
632
 *
 
633
 *    gather queue:    1
 
634
 *    decode queue:    
 
635
 *
 
636
 *  Leftover buffer 1 cannot be decoded and must be discarded.
 
637
 */
 
638
static GstFlowReturn
 
639
gst_mpegvideoparse_flush_decode (MpegVideoParse * mpegvideoparse, guint idx)
 
640
{
 
641
  GstFlowReturn res = GST_FLOW_OK;
 
642
  GstBuffer *head = NULL;
 
643
 
 
644
  while (mpegvideoparse->decode) {
 
645
    GstBuffer *buf;
 
646
 
 
647
    buf = GST_BUFFER_CAST (mpegvideoparse->decode->data);
 
648
 
 
649
    if (idx != -1) {
 
650
      GstBuffer *temp;
 
651
 
 
652
      if (idx > 0) {
 
653
        /* first buffer, split at the point where the picture start was
 
654
         * detected and store as the new head of the decoding list. */
 
655
        head = gst_buffer_create_sub (buf, 0, idx);
 
656
        /* push the remainder after the picture sync point downstream, this is the
 
657
         * first DISCONT buffer we push. */
 
658
        temp = gst_buffer_create_sub (buf, idx, GST_BUFFER_SIZE (buf) - idx);
 
659
        /* don't need old buffer anymore and swap new buffer */
 
660
        gst_buffer_unref (buf);
 
661
        buf = temp;
 
662
      }
 
663
      GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
 
664
      idx = -1;
 
665
    } else {
 
666
      /* next buffers are not discont */
 
667
      GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
 
668
    }
 
669
 
 
670
    GST_DEBUG_OBJECT (mpegvideoparse, "pushing buffer %p, ts %" GST_TIME_FORMAT,
 
671
        buf, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)));
 
672
 
 
673
    res = gst_pad_push (mpegvideoparse->srcpad, buf);
 
674
 
 
675
    mpegvideoparse->decode =
 
676
        g_list_delete_link (mpegvideoparse->decode, mpegvideoparse->decode);
 
677
  }
 
678
  if (head) {
 
679
    /* store remainder of the buffer */
 
680
    mpegvideoparse->decode = g_list_prepend (mpegvideoparse->decode, head);
 
681
  }
 
682
  return res;
 
683
}
 
684
 
 
685
static GstFlowReturn
 
686
gst_mpegvideoparse_chain_reverse (MpegVideoParse * mpegvideoparse,
 
687
    gboolean discont, GstBuffer * buf)
 
688
{
 
689
  GstFlowReturn res = GST_FLOW_OK;
 
690
 
 
691
  /* if we have a discont, move buffers to the decode list */
 
692
  if (G_UNLIKELY (discont)) {
 
693
    GST_DEBUG_OBJECT (mpegvideoparse, "received discont,gathering buffers");
 
694
 
 
695
    while (mpegvideoparse->gather) {
 
696
      GstBuffer *gbuf;
 
697
      guint keyframeidx;
 
698
 
 
699
      gbuf = GST_BUFFER_CAST (mpegvideoparse->gather->data);
 
700
      /* remove from the gather list */
 
701
      mpegvideoparse->gather =
 
702
          g_list_delete_link (mpegvideoparse->gather, mpegvideoparse->gather);
 
703
      /* copy to decode queue */
 
704
      mpegvideoparse->decode = g_list_prepend (mpegvideoparse->decode, gbuf);
 
705
 
 
706
      GST_DEBUG_OBJECT (mpegvideoparse, "copied decoding buffer %p, len %d",
 
707
          gbuf, g_list_length (mpegvideoparse->decode));
 
708
 
 
709
      /* check if we copied a keyframe, we scan the buffers on the decode queue.
 
710
       * We only need to scan the first buffer and at most 3 bytes of the second
 
711
       * buffer. We return the index of the keyframe (or -1 when nothing was
 
712
       * found) */
 
713
      while ((keyframeidx = scan_keyframe (mpegvideoparse)) != -1) {
 
714
        GST_DEBUG_OBJECT (mpegvideoparse, "copied keyframe at %u", keyframeidx);
 
715
        res = gst_mpegvideoparse_flush_decode (mpegvideoparse, keyframeidx);
 
716
      }
 
717
    }
 
718
  }
 
719
 
 
720
  if (buf) {
 
721
    /* add buffer to gather queue */
 
722
    GST_DEBUG_OBJECT (mpegvideoparse, "gathering buffer %p, size %u", buf,
 
723
        GST_BUFFER_SIZE (buf));
 
724
    mpegvideoparse->gather = g_list_prepend (mpegvideoparse->gather, buf);
 
725
  }
 
726
 
 
727
  return res;
 
728
}
 
729
 
 
730
static GstFlowReturn
 
731
gst_mpegvideoparse_chain (GstPad * pad, GstBuffer * buf)
 
732
{
 
733
  MpegVideoParse *mpegvideoparse;
 
734
  GstFlowReturn res;
 
735
  gboolean discont;
 
736
 
 
737
  mpegvideoparse =
 
738
      GST_MPEGVIDEOPARSE (gst_object_get_parent (GST_OBJECT (pad)));
 
739
 
 
740
  discont = GST_BUFFER_IS_DISCONT (buf);
 
741
 
 
742
  if (mpegvideoparse->segment.rate > 0.0)
 
743
    res = gst_mpegvideoparse_chain_forward (mpegvideoparse, discont, buf);
 
744
  else
 
745
    res = gst_mpegvideoparse_chain_reverse (mpegvideoparse, discont, buf);
 
746
 
 
747
  gst_object_unref (mpegvideoparse);
 
748
 
 
749
  return res;
 
750
}
 
751
 
 
752
static gboolean
 
753
mpv_parse_sink_event (GstPad * pad, GstEvent * event)
 
754
{
 
755
  gboolean res = TRUE;
 
756
  MpegVideoParse *mpegvideoparse =
 
757
      GST_MPEGVIDEOPARSE (gst_pad_get_parent (pad));
 
758
 
 
759
  switch (GST_EVENT_TYPE (event)) {
 
760
    case GST_EVENT_NEWSEGMENT:
 
761
    {
 
762
      gdouble rate, applied_rate;
 
763
      GstFormat format;
 
764
      gint64 start, stop, pos;
 
765
      gboolean update;
 
766
 
 
767
      gst_event_parse_new_segment_full (event, &update, &rate, &applied_rate,
 
768
          &format, &start, &stop, &pos);
 
769
 
 
770
      if (format == GST_FORMAT_BYTES) {
 
771
        /* FIXME: Later, we might use a seek table to seek on elementary stream
 
772
           files, and that would allow byte-to-time conversions. It's not a high
 
773
           priority - most mpeg video is muxed and then the demuxer handles 
 
774
           seeking. In the meantime, here's some commented out logic copied
 
775
           from mp3parse */
 
776
#if 0
 
777
        GstClockTime seg_start, seg_stop, seg_pos;
 
778
 
 
779
        /* stop time is allowed to be open-ended, but not start & pos */
 
780
        if (!mp3parse_bytepos_to_time (mp3parse, stop, &seg_stop))
 
781
          seg_stop = GST_CLOCK_TIME_NONE;
 
782
        if (mp3parse_bytepos_to_time (mp3parse, start, &seg_start) &&
 
783
            mp3parse_bytepos_to_time (mp3parse, pos, &seg_pos)) {
 
784
          gst_event_unref (event);
 
785
          event = gst_event_new_new_segment_full (update, rate, applied_rate,
 
786
              GST_FORMAT_TIME, seg_start, seg_stop, seg_pos);
 
787
          format = GST_FORMAT_TIME;
 
788
          GST_DEBUG_OBJECT (mp3parse, "Converted incoming segment to TIME. "
 
789
              "start = %" G_GINT64_FORMAT ", stop = %" G_GINT64_FORMAT
 
790
              "pos = %" G_GINT64_FORMAT, seg_start, seg_stop, seg_pos);
 
791
        }
 
792
#endif
 
793
      }
 
794
 
 
795
      if (format != GST_FORMAT_TIME) {
 
796
        /* Unknown incoming segment format. Output a default open-ended 
 
797
         * TIME segment */
 
798
        gst_event_unref (event);
 
799
 
 
800
        /* set new values */
 
801
        format = GST_FORMAT_TIME;
 
802
        start = 0;
 
803
        stop = GST_CLOCK_TIME_NONE;
 
804
        pos = 0;
 
805
        /* create a new segment with these values */
 
806
        event = gst_event_new_new_segment_full (update, rate, applied_rate,
 
807
            format, start, stop, pos);
 
808
      }
 
809
 
 
810
      /* now configure the values */
 
811
      gst_segment_set_newsegment_full (&mpegvideoparse->segment, update,
 
812
          rate, applied_rate, format, start, stop, pos);
 
813
 
 
814
      GST_DEBUG_OBJECT (mpegvideoparse,
 
815
          "Pushing newseg rate %g, applied rate %g, format %d, start %"
 
816
          G_GINT64_FORMAT ", stop %" G_GINT64_FORMAT ", pos %" G_GINT64_FORMAT,
 
817
          rate, applied_rate, format, start, stop, pos);
 
818
 
 
819
      /* Forward the event if we've seen a sequence header
 
820
       * and therefore set output caps, otherwise queue it for later */
 
821
      if (mpegvideoparse->seq_hdr.mpeg_version != 0)
 
822
        res = gst_pad_push_event (mpegvideoparse->srcpad, event);
 
823
      else {
 
824
        res = TRUE;
 
825
        mpegvideoparse->pending_segs =
 
826
            g_list_append (mpegvideoparse->pending_segs, event);
 
827
      }
 
828
      break;
 
829
    }
 
830
    case GST_EVENT_FLUSH_STOP:
 
831
      GST_DEBUG_OBJECT (mpegvideoparse, "flush stop");
 
832
      gst_mpegvideoparse_flush (mpegvideoparse);
 
833
      res = gst_pad_push_event (mpegvideoparse->srcpad, event);
 
834
      break;
 
835
    case GST_EVENT_EOS:
 
836
      /* Push any remaining buffers out, then flush. */
 
837
      GST_DEBUG_OBJECT (mpegvideoparse, "received EOS");
 
838
      if (mpegvideoparse->segment.rate >= 0.0) {
 
839
        mpeg_packetiser_handle_eos (&mpegvideoparse->packer);
 
840
        mpegvideoparse_drain_avail (mpegvideoparse);
 
841
        gst_mpegvideoparse_flush (mpegvideoparse);
 
842
      } else {
 
843
        gst_mpegvideoparse_chain_reverse (mpegvideoparse, TRUE, NULL);
 
844
        gst_mpegvideoparse_flush_decode (mpegvideoparse, 0);
 
845
      }
 
846
      res = gst_pad_push_event (mpegvideoparse->srcpad, event);
 
847
      break;
 
848
    default:
 
849
      res = gst_pad_push_event (mpegvideoparse->srcpad, event);
 
850
      break;
 
851
  }
 
852
 
 
853
  gst_object_unref (mpegvideoparse);
 
854
  return res;
 
855
}
 
856
 
 
857
static GstStateChangeReturn
 
858
gst_mpegvideoparse_change_state (GstElement * element,
 
859
    GstStateChange transition)
 
860
{
 
861
  MpegVideoParse *mpegvideoparse;
 
862
  GstStateChangeReturn ret;
 
863
 
 
864
  g_return_val_if_fail (GST_IS_MPEGVIDEOPARSE (element),
 
865
      GST_STATE_CHANGE_FAILURE);
 
866
 
 
867
  mpegvideoparse = GST_MPEGVIDEOPARSE (element);
 
868
 
 
869
  switch (transition) {
 
870
    case GST_STATE_CHANGE_READY_TO_PAUSED:
 
871
      gst_segment_init (&mpegvideoparse->segment, GST_FORMAT_UNDEFINED);
 
872
      break;
 
873
    default:
 
874
      break;
 
875
  }
 
876
 
 
877
  ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
 
878
 
 
879
  switch (transition) {
 
880
    case GST_STATE_CHANGE_PAUSED_TO_READY:
 
881
      mpv_parse_reset (mpegvideoparse);
 
882
      gst_mpegvideoparse_flush (mpegvideoparse);
 
883
      break;
 
884
    default:
 
885
      break;
 
886
  }
 
887
 
 
888
  return ret;
 
889
}
 
890
 
 
891
static gboolean
 
892
plugin_init (GstPlugin * plugin)
 
893
{
 
894
  GST_DEBUG_CATEGORY_INIT (mpv_parse_debug, "mpegvideoparse", 0,
 
895
      "MPEG Video Parser");
 
896
 
 
897
  return gst_element_register (plugin, "mpegvideoparse",
 
898
      GST_RANK_SECONDARY - 1, GST_TYPE_MPEGVIDEOPARSE);
 
899
}
 
900
 
 
901
GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
 
902
    GST_VERSION_MINOR,
 
903
    "mpegvideoparse",
 
904
    "MPEG-1 and MPEG-2 video parser",
 
905
    plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)