2
* The contents of this file are subject to the Mozilla Public License
3
* Version 1.1 (the "License"); you may not use this file except in
4
* compliance with the License. You may obtain a copy of the License at
5
* http://www.mozilla.org/MPL/.
7
* Software distributed under the License is distributed on an "AS IS"
8
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
9
* License for the specific language governing rights and limitations
12
* The Original Code is Fluendo MPEG Demuxer plugin.
14
* The Initial Developer of the Original Code is Fluendo, S.L.
15
* Portions created by Fluendo, S.L. are Copyright (C) 2005
16
* Fluendo, S.L. All Rights Reserved.
18
* Contributor(s): Wim Taymans <wim@fluendo.com>
19
* Jan Schmidt <thaytan@noraisin.net>
26
#include "gstmpegdefs.h"
27
#include "gstpesfilter.h"
29
GST_DEBUG_CATEGORY (gstflupesfilter_debug);
30
#define GST_CAT_DEFAULT (gstflupesfilter_debug)
32
static GstFlowReturn gst_pes_filter_data_push (GstPESFilter * filter,
33
gboolean first, GstBuffer * buffer);
35
#define ADAPTER_OFFSET_FLUSH(_bytes_) if (filter->adapter_offset) *filter->adapter_offset = *filter->adapter_offset + (_bytes_)
37
/* May pass null for adapter to have the filter create one */
39
gst_pes_filter_init (GstPESFilter * filter, GstAdapter * adapter,
40
guint64 * adapter_offset)
42
g_return_if_fail (filter != NULL);
45
g_object_ref (adapter);
47
adapter = gst_adapter_new ();
49
filter->adapter = adapter;
50
filter->adapter_offset = adapter_offset;
51
filter->state = STATE_HEADER_PARSE;
52
filter->gather_pes = FALSE;
53
filter->allow_unbounded = FALSE;
57
gst_pes_filter_uninit (GstPESFilter * filter)
59
g_return_if_fail (filter != NULL);
62
g_object_unref (filter->adapter);
63
filter->adapter = NULL;
64
filter->adapter_offset = NULL;
68
gst_pes_filter_set_callbacks (GstPESFilter * filter,
69
GstPESFilterData data_cb, GstPESFilterResync resync_cb, gpointer user_data)
71
g_return_if_fail (filter != NULL);
73
filter->data_cb = data_cb;
74
filter->resync_cb = resync_cb;
75
filter->user_data = user_data;
78
/* sync:4 == 00xx ! pts:3 ! 1 ! pts:15 ! 1 | pts:15 ! 1 */
79
#define READ_TS(data, target, lost_sync_label) \
80
if ((*data & 0x01) != 0x01) goto lost_sync_label; \
81
target = ((guint64) (*data++ & 0x0E)) << 29; \
82
target |= ((guint64) (*data++ )) << 22; \
83
if ((*data & 0x01) != 0x01) goto lost_sync_label; \
84
target |= ((guint64) (*data++ & 0xFE)) << 14; \
85
target |= ((guint64) (*data++ )) << 7; \
86
if ((*data & 0x01) != 0x01) goto lost_sync_label; \
87
target |= ((guint64) (*data++ & 0xFE)) >> 1;
90
gst_pes_filter_is_sync (guint32 sync)
92
return ((sync & 0xfffffffc) == 0x000001bc) ||
93
((sync & 0xffffffe0) == 0x000001c0) ||
94
((sync & 0xfffffff0) == 0x000001f0) ||
95
((sync & 0xfffffff0) == 0x000001e0);
99
gst_pes_filter_parse (GstPESFilter * filter)
104
gboolean STD_buffer_bound_scale;
105
guint16 STD_buffer_size_bound;
108
gboolean have_size = FALSE;
110
/* read start code and length */
111
if (!(data = gst_adapter_peek (filter->adapter, 6)))
115
start_code = GST_READ_UINT32_BE (data);
116
if (!gst_pes_filter_is_sync (start_code))
119
filter->start_code = start_code;
120
filter->id = data[3];
122
/* skip start code */
125
/* start parsing length */
126
filter->length = GST_READ_UINT16_BE (data);
128
/* see how much is available */
129
avail = gst_adapter_available (filter->adapter);
131
GST_DEBUG ("id 0x%02x length %d, avail %d start code 0x%02x", filter->id,
132
filter->length, avail, filter->start_code);
134
/* A data length of 0 indicates an unbounded packet in transport
135
* streams, but actually a 0 sized packet in program streams or
136
* for anything except video packets */
138
/* FIXME: Remove this hack that is checking start_code. Instead, we need
139
* a callback that a start_code has been collected, giving the caller a chance
140
* to set the allow_unbounded flag if they want */
141
if (filter->length == 0 &&
142
((filter->start_code & 0xFFFFFFF0) == PACKET_VIDEO_START_CODE ||
143
filter->allow_unbounded)) {
144
GST_DEBUG ("id 0x%02x, unbounded length", filter->id);
145
filter->unbounded_packet = TRUE;
147
filter->unbounded_packet = FALSE;
149
if (filter->gather_pes && avail < filter->length + 6) {
150
GST_DEBUG ("id 0x%02x, bounded length %d, only have %d",
151
filter->id, filter->length + 6, avail);
155
/* if we need more data from now on, we lost sync */
156
avail = MIN (avail, filter->length + 6);
159
/* read more data, either the whole packet if there is a length
160
* or whatever we have available if this in an unbounded packet. */
161
if (!(data = gst_adapter_peek (filter->adapter, avail)))
164
/* This will make us flag LOST_SYNC if we run out of data from here onward */
167
/* skip start code and length */
171
GST_DEBUG ("datalen %d", datalen);
173
switch (filter->start_code) {
174
case ID_PS_PROGRAM_STREAM_MAP:
175
case ID_PRIVATE_STREAM_2:
178
case ID_PROGRAM_STREAM_DIRECTORY:
179
case ID_DSMCC_STREAM:
180
case ID_ITU_TREC_H222_TYPE_E_STREAM:
182
case ID_PADDING_STREAM:
183
GST_DEBUG ("skipping padding stream");
192
filter->pts = filter->dts = -1;
194
/* stuffing bits, first two bits are '10' for mpeg2 pes so this code is
203
GST_DEBUG ("got stuffing bit");
209
/* STD buffer size, never for mpeg2 */
210
if ((*data & 0xc0) == 0x40) {
211
GST_DEBUG ("have STD");
216
STD_buffer_bound_scale = *data & 0x20;
217
STD_buffer_size_bound = ((guint16) (*data++ & 0x1F)) << 8;
218
STD_buffer_size_bound |= *data++;
223
/* PTS but no DTS, never for mpeg2 */
224
if ((*data & 0xf0) == 0x20) {
225
GST_DEBUG ("PTS without DTS");
229
READ_TS (data, filter->pts, lost_sync);
230
GST_DEBUG ("PTS found %" G_GUINT64_FORMAT, filter->pts);
233
/* PTS and DTS, never for mpeg2 */
234
else if ((*data & 0xf0) == 0x30) {
235
GST_DEBUG ("PTS and DTS");
239
READ_TS (data, filter->pts, lost_sync);
240
READ_TS (data, filter->dts, lost_sync);
241
GST_DEBUG ("PTS found %" G_GUINT64_FORMAT, filter->pts);
242
GST_DEBUG ("DTS found %" G_GUINT64_FORMAT, filter->dts);
244
} else if ((*data & 0xc0) == 0x80) {
247
guint8 header_data_length = 0;
249
GST_DEBUG ("MPEG2 PES packet");
254
* 2: PES_scrambling_control
256
* 1: data_alignment_indicator
258
* 1: original_or_copy
262
GST_DEBUG ("flags: 0x%02x", flags);
263
if ((flags & 0xc0) != 0x80)
266
/* check PES scrambling control */
267
if ((flags & 0x30) != 0)
273
* 1: DSM_trick_mode_flag
274
* 1: additional_copy_info_flag
276
* 1: PES_extension_flag
280
/* 8: PES_header_data_length */
281
header_data_length = *data++;
284
GST_DEBUG ("header_data_length: %d, flags 0x%02x",
285
header_data_length, flags);
287
if (header_data_length > datalen)
290
/* only DTS: this is invalid */
291
if ((flags & 0xc0) == 0x40)
295
if ((flags & 0x80)) {
299
READ_TS (data, filter->pts, lost_sync);
300
GST_DEBUG ("PTS found %" G_GUINT64_FORMAT, filter->pts);
301
header_data_length -= 5;
305
if ((flags & 0x40)) {
306
READ_TS (data, filter->dts, lost_sync);
309
GST_DEBUG ("DTS found %" G_GUINT64_FORMAT, filter->dts);
310
header_data_length -= 5;
314
if ((flags & 0x20)) {
315
GST_DEBUG ("%x ESCR found", filter->id);
319
header_data_length -= 6;
323
if ((flags & 0x10)) {
329
es_rate = ((guint32) (*data++ & 0x07)) << 14;
330
es_rate |= ((guint32) (*data++)) << 7;
331
es_rate |= ((guint32) (*data++ & 0xFE)) >> 1;
332
GST_DEBUG ("%x ES Rate found %u", filter->id, es_rate);
333
header_data_length -= 3;
336
/* DSM_trick_mode_flag */
337
if ((flags & 0x08)) {
338
guint8 trick_mode_flags;
343
/* 3: trick_mode_control */
344
trick_mode_flags = *data++;
345
GST_DEBUG ("%x DSM trick mode found, flags 0x%02x", filter->id,
349
if ((trick_mode_flags & 0xe0) == 0x00) {
352
else if ((trick_mode_flags & 0xe0) == 0x20) {
355
else if ((trick_mode_flags & 0xe0) == 0x40) {
358
else if ((trick_mode_flags & 0xe0) == 0x60) {
361
else if ((trick_mode_flags & 0xe0) == 0x80) {
367
header_data_length -= 1;
370
/* additional_copy_info_flag */
371
if ((flags & 0x04)) {
372
GST_DEBUG ("%x additional copy info, flags 0x%02x", filter->id, *data);
375
if ((flags & 0x02)) {
376
GST_DEBUG ("%x PES_CRC", filter->id);
378
/* PES_extension_flag */
379
if ((flags & 0x01)) {
380
GST_DEBUG ("%x PES_extension", filter->id);
383
/* calculate the amount of real data in this PES packet */
384
data += header_data_length;
385
datalen -= header_data_length;
386
} else if (*data == 0x0f) {
387
/* Not sure what this clause is for */
391
/* Data byte wasn't recognised as a flags byte */
392
GST_DEBUG ("Unrecognised flags byte 0x%02x\n", *data);
400
consumed = avail - 6 - datalen;
402
if (filter->unbounded_packet == FALSE) {
403
filter->length -= avail - 6;
404
GST_DEBUG ("pushing %d, need %d more, consumed %d",
405
datalen, filter->length, consumed);
407
GST_DEBUG ("pushing %d, unbounded packet, consumed %d",
412
out = gst_buffer_new ();
413
GST_BUFFER_DATA (out) = g_memdup (data, datalen);
414
GST_BUFFER_SIZE (out) = datalen;
415
GST_BUFFER_MALLOCDATA (out) = GST_BUFFER_DATA (out);
417
ret = gst_pes_filter_data_push (filter, TRUE, out);
418
filter->first = FALSE;
420
GST_LOG ("first being set to TRUE");
421
filter->first = TRUE;
425
if (filter->length > 0 || filter->unbounded_packet)
426
filter->state = STATE_DATA_PUSH;
429
gst_adapter_flush (filter->adapter, avail);
430
ADAPTER_OFFSET_FLUSH (avail);
436
if (filter->unbounded_packet == FALSE) {
437
if (have_size == TRUE) {
438
GST_DEBUG ("bounded need more data %d, lost sync",
439
gst_adapter_available (filter->adapter));
440
ret = GST_FLOW_LOST_SYNC;
442
GST_DEBUG ("bounded need more data %d, breaking for more",
443
gst_adapter_available (filter->adapter));
444
ret = GST_FLOW_NEED_MORE_DATA;
447
GST_DEBUG ("unbounded need more data %d",
448
gst_adapter_available (filter->adapter));
449
ret = GST_FLOW_NEED_MORE_DATA;
456
GST_DEBUG ("skipping 0x%02x", filter->id);
457
gst_adapter_flush (filter->adapter, avail);
458
ADAPTER_OFFSET_FLUSH (avail);
460
filter->length -= avail - 6;
461
if (filter->length > 0 || filter->unbounded_packet)
462
filter->state = STATE_DATA_SKIP;
467
GST_DEBUG ("skipping encrypted 0x%02x", filter->id);
468
gst_adapter_flush (filter->adapter, avail);
469
ADAPTER_OFFSET_FLUSH (avail);
471
filter->length -= avail - 6;
472
if (filter->length > 0 || filter->unbounded_packet)
473
filter->state = STATE_DATA_SKIP;
478
GST_DEBUG ("lost sync");
479
gst_adapter_flush (filter->adapter, 4);
480
ADAPTER_OFFSET_FLUSH (4);
482
return GST_FLOW_LOST_SYNC;
487
gst_pes_filter_data_push (GstPESFilter * filter, gboolean first,
492
GST_LOG ("pushing, first: %d", first);
494
if (filter->data_cb) {
495
ret = filter->data_cb (filter, first, buffer, filter->user_data);
497
gst_buffer_unref (buffer);
504
gst_pes_filter_push (GstPESFilter * filter, GstBuffer * buffer)
508
g_return_val_if_fail (filter != NULL, GST_FLOW_ERROR);
509
g_return_val_if_fail (buffer != NULL, GST_FLOW_ERROR);
511
switch (filter->state) {
512
case STATE_HEADER_PARSE:
513
gst_adapter_push (filter->adapter, buffer);
514
ret = gst_pes_filter_parse (filter);
516
case STATE_DATA_PUSH:
517
ret = gst_pes_filter_data_push (filter, filter->first, buffer);
518
filter->first = FALSE;
520
case STATE_DATA_SKIP:
521
gst_buffer_unref (buffer);
532
GST_DEBUG ("wrong internal state %d", filter->state);
533
return GST_FLOW_ERROR;
538
gst_pes_filter_process (GstPESFilter * filter)
541
gboolean skip = FALSE;
543
g_return_val_if_fail (filter != NULL, GST_FLOW_ERROR);
545
switch (filter->state) {
546
case STATE_HEADER_PARSE:
547
ret = gst_pes_filter_parse (filter);
549
case STATE_DATA_SKIP:
552
case STATE_DATA_PUSH:
553
if (filter->length > 0 || filter->unbounded_packet) {
556
avail = gst_adapter_available (filter->adapter);
557
if (filter->unbounded_packet == FALSE)
558
avail = MIN (avail, filter->length);
561
gst_adapter_flush (filter->adapter, avail);
562
ADAPTER_OFFSET_FLUSH (avail);
568
data = gst_adapter_take (filter->adapter, avail);
570
out = gst_buffer_new ();
571
GST_BUFFER_DATA (out) = data;
572
GST_BUFFER_SIZE (out) = avail;
573
GST_BUFFER_MALLOCDATA (out) = data;
575
ret = gst_pes_filter_data_push (filter, filter->first, out);
576
filter->first = FALSE;
579
if (filter->unbounded_packet == FALSE) {
580
filter->length -= avail;
581
if (filter->length == 0)
582
filter->state = STATE_HEADER_PARSE;
585
filter->state = STATE_HEADER_PARSE;
597
GST_DEBUG ("wrong internal state %d", filter->state);
598
return GST_FLOW_ERROR;
603
gst_pes_filter_flush (GstPESFilter * filter)
605
g_return_if_fail (filter != NULL);
607
if (filter->adapter) {
608
gst_adapter_clear (filter->adapter);
609
if (filter->adapter_offset)
610
*filter->adapter_offset = G_MAXUINT64;
612
filter->state = STATE_HEADER_PARSE;
616
gst_pes_filter_drain (GstPESFilter * filter)
618
g_return_val_if_fail (filter != NULL, GST_FLOW_ERROR);
620
gst_pes_filter_flush (filter);