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 guint16 STD_buffer_size_bound;
107 gboolean have_size = FALSE;
109 /* read start code and length */
110 if (!(data = gst_adapter_peek (filter->adapter, 6)))
114 start_code = GST_READ_UINT32_BE (data);
115 if (!gst_pes_filter_is_sync (start_code))
118 filter->start_code = start_code;
119 filter->id = data[3];
121 /* skip start code */
124 /* start parsing length */
125 filter->length = GST_READ_UINT16_BE (data);
127 /* see how much is available */
128 avail = gst_adapter_available (filter->adapter);
130 GST_DEBUG ("id 0x%02x length %d, avail %d start code 0x%02x", filter->id,
131 filter->length, avail, filter->start_code);
133 /* A data length of 0 indicates an unbounded packet in transport
134 * streams, but actually a 0 sized packet in program streams or
135 * for anything except video packets */
137 /* FIXME: Remove this hack that is checking start_code. Instead, we need
138 * a callback that a start_code has been collected, giving the caller a chance
139 * to set the allow_unbounded flag if they want */
140 if (filter->length == 0 &&
141 ((filter->start_code & 0xFFFFFFF0) == PACKET_VIDEO_START_CODE ||
142 filter->allow_unbounded)) {
143 GST_DEBUG ("id 0x%02x, unbounded length", filter->id);
144 filter->unbounded_packet = TRUE;
146 filter->unbounded_packet = FALSE;
148 if (filter->gather_pes && avail < filter->length + 6) {
149 GST_DEBUG ("id 0x%02x, bounded length %d, only have %d",
150 filter->id, filter->length + 6, avail);
154 /* if we need more data from now on, we lost sync */
155 avail = MIN (avail, filter->length + 6);
158 /* read more data, either the whole packet if there is a length
159 * or whatever we have available if this in an unbounded packet. */
160 if (!(data = gst_adapter_peek (filter->adapter, avail)))
163 /* This will make us flag LOST_SYNC if we run out of data from here onward */
166 /* skip start code and length */
170 GST_DEBUG ("datalen %d", datalen);
172 switch (filter->start_code) {
173 case ID_PS_PROGRAM_STREAM_MAP:
174 case ID_PRIVATE_STREAM_2:
177 case ID_PROGRAM_STREAM_DIRECTORY:
178 case ID_DSMCC_STREAM:
179 case ID_ITU_TREC_H222_TYPE_E_STREAM:
181 case ID_PADDING_STREAM:
182 GST_DEBUG ("skipping padding stream");
191 filter->pts = filter->dts = -1;
193 /* stuffing bits, first two bits are '10' for mpeg2 pes so this code is
202 GST_DEBUG ("got stuffing bit");
208 /* STD buffer size, never for mpeg2 */
209 if ((*data & 0xc0) == 0x40) {
210 GST_DEBUG ("have STD");
215 /* STD_buffer_bound_scale = *data & 0x20; */
216 STD_buffer_size_bound = ((guint16) (*data++ & 0x1F)) << 8;
217 STD_buffer_size_bound |= *data++;
222 /* PTS but no DTS, never for mpeg2 */
223 if ((*data & 0xf0) == 0x20) {
224 GST_DEBUG ("PTS without DTS");
228 READ_TS (data, filter->pts, lost_sync);
229 GST_DEBUG ("PTS found %" G_GUINT64_FORMAT, filter->pts);
232 /* PTS and DTS, never for mpeg2 */
233 else if ((*data & 0xf0) == 0x30) {
234 GST_DEBUG ("PTS and DTS");
238 READ_TS (data, filter->pts, lost_sync);
239 READ_TS (data, filter->dts, lost_sync);
240 GST_DEBUG ("PTS found %" G_GUINT64_FORMAT, filter->pts);
241 GST_DEBUG ("DTS found %" G_GUINT64_FORMAT, filter->dts);
243 } else if ((*data & 0xc0) == 0x80) {
246 guint8 header_data_length = 0;
248 GST_DEBUG ("MPEG2 PES packet");
253 * 2: PES_scrambling_control
255 * 1: data_alignment_indicator
257 * 1: original_or_copy
261 GST_DEBUG ("flags: 0x%02x", flags);
262 if ((flags & 0xc0) != 0x80)
265 /* check PES scrambling control */
266 if ((flags & 0x30) != 0)
272 * 1: DSM_trick_mode_flag
273 * 1: additional_copy_info_flag
275 * 1: PES_extension_flag
279 /* 8: PES_header_data_length */
280 header_data_length = *data++;
283 GST_DEBUG ("header_data_length: %d, flags 0x%02x",
284 header_data_length, flags);
286 if (header_data_length > datalen)
289 /* only DTS: this is invalid */
290 if ((flags & 0xc0) == 0x40)
294 if ((flags & 0x80)) {
298 READ_TS (data, filter->pts, lost_sync);
299 GST_DEBUG ("PTS found %" G_GUINT64_FORMAT, filter->pts);
300 header_data_length -= 5;
304 if ((flags & 0x40)) {
305 READ_TS (data, filter->dts, lost_sync);
308 GST_DEBUG ("DTS found %" G_GUINT64_FORMAT, filter->dts);
309 header_data_length -= 5;
313 if ((flags & 0x20)) {
314 GST_DEBUG ("%x ESCR found", filter->id);
318 header_data_length -= 6;
322 if ((flags & 0x10)) {
328 es_rate = ((guint32) (*data++ & 0x07)) << 14;
329 es_rate |= ((guint32) (*data++)) << 7;
330 es_rate |= ((guint32) (*data++ & 0xFE)) >> 1;
331 GST_DEBUG ("%x ES Rate found %u", filter->id, es_rate);
332 header_data_length -= 3;
335 /* DSM_trick_mode_flag */
336 if ((flags & 0x08)) {
337 guint8 trick_mode_flags;
342 /* 3: trick_mode_control */
343 trick_mode_flags = *data++;
344 GST_DEBUG ("%x DSM trick mode found, flags 0x%02x", filter->id,
348 if ((trick_mode_flags & 0xe0) == 0x00) {
351 else if ((trick_mode_flags & 0xe0) == 0x20) {
354 else if ((trick_mode_flags & 0xe0) == 0x40) {
357 else if ((trick_mode_flags & 0xe0) == 0x60) {
360 else if ((trick_mode_flags & 0xe0) == 0x80) {
366 header_data_length -= 1;
369 /* additional_copy_info_flag */
370 if ((flags & 0x04)) {
371 GST_DEBUG ("%x additional copy info, flags 0x%02x", filter->id, *data);
374 if ((flags & 0x02)) {
375 GST_DEBUG ("%x PES_CRC", filter->id);
377 /* PES_extension_flag */
378 if ((flags & 0x01)) {
379 GST_DEBUG ("%x PES_extension", filter->id);
382 /* calculate the amount of real data in this PES packet */
383 data += header_data_length;
384 datalen -= header_data_length;
385 } else if (*data == 0x0f) {
386 /* Not sure what this clause is for */
390 /* Data byte wasn't recognised as a flags byte */
391 GST_DEBUG ("Unrecognised flags byte 0x%02x\n", *data);
399 consumed = avail - 6 - datalen;
401 if (filter->unbounded_packet == FALSE) {
402 filter->length -= avail - 6;
403 GST_DEBUG ("pushing %d, need %d more, consumed %d",
404 datalen, filter->length, consumed);
406 GST_DEBUG ("pushing %d, unbounded packet, consumed %d",
411 out = gst_buffer_new ();
412 GST_BUFFER_DATA (out) = g_memdup (data, datalen);
413 GST_BUFFER_SIZE (out) = datalen;
414 GST_BUFFER_MALLOCDATA (out) = GST_BUFFER_DATA (out);
416 ret = gst_pes_filter_data_push (filter, TRUE, out);
417 filter->first = FALSE;
419 GST_LOG ("first being set to TRUE");
420 filter->first = TRUE;
424 if (filter->length > 0 || filter->unbounded_packet)
425 filter->state = STATE_DATA_PUSH;
428 gst_adapter_flush (filter->adapter, avail);
429 ADAPTER_OFFSET_FLUSH (avail);
435 if (filter->unbounded_packet == FALSE) {
436 if (have_size == TRUE) {
437 GST_DEBUG ("bounded need more data %d, lost sync",
438 gst_adapter_available (filter->adapter));
439 ret = GST_FLOW_LOST_SYNC;
441 GST_DEBUG ("bounded need more data %d, breaking for more",
442 gst_adapter_available (filter->adapter));
443 ret = GST_FLOW_NEED_MORE_DATA;
446 GST_DEBUG ("unbounded need more data %d",
447 gst_adapter_available (filter->adapter));
448 ret = GST_FLOW_NEED_MORE_DATA;
455 GST_DEBUG ("skipping 0x%02x", filter->id);
456 gst_adapter_flush (filter->adapter, avail);
457 ADAPTER_OFFSET_FLUSH (avail);
459 filter->length -= avail - 6;
460 if (filter->length > 0 || filter->unbounded_packet)
461 filter->state = STATE_DATA_SKIP;
466 GST_DEBUG ("skipping encrypted 0x%02x", filter->id);
467 gst_adapter_flush (filter->adapter, avail);
468 ADAPTER_OFFSET_FLUSH (avail);
470 filter->length -= avail - 6;
471 if (filter->length > 0 || filter->unbounded_packet)
472 filter->state = STATE_DATA_SKIP;
477 GST_DEBUG ("lost sync");
478 gst_adapter_flush (filter->adapter, 4);
479 ADAPTER_OFFSET_FLUSH (4);
481 return GST_FLOW_LOST_SYNC;
486 gst_pes_filter_data_push (GstPESFilter * filter, gboolean first,
491 GST_LOG ("pushing, first: %d", first);
493 if (filter->data_cb) {
494 ret = filter->data_cb (filter, first, buffer, filter->user_data);
496 gst_buffer_unref (buffer);
503 gst_pes_filter_push (GstPESFilter * filter, GstBuffer * buffer)
507 g_return_val_if_fail (filter != NULL, GST_FLOW_ERROR);
508 g_return_val_if_fail (buffer != NULL, GST_FLOW_ERROR);
510 switch (filter->state) {
511 case STATE_HEADER_PARSE:
512 gst_adapter_push (filter->adapter, buffer);
513 ret = gst_pes_filter_parse (filter);
515 case STATE_DATA_PUSH:
516 ret = gst_pes_filter_data_push (filter, filter->first, buffer);
517 filter->first = FALSE;
519 case STATE_DATA_SKIP:
520 gst_buffer_unref (buffer);
531 GST_DEBUG ("wrong internal state %d", filter->state);
532 return GST_FLOW_ERROR;
537 gst_pes_filter_process (GstPESFilter * filter)
540 gboolean skip = FALSE;
542 g_return_val_if_fail (filter != NULL, GST_FLOW_ERROR);
544 switch (filter->state) {
545 case STATE_HEADER_PARSE:
546 ret = gst_pes_filter_parse (filter);
548 case STATE_DATA_SKIP:
551 case STATE_DATA_PUSH:
552 if (filter->length > 0 || filter->unbounded_packet) {
555 avail = gst_adapter_available (filter->adapter);
556 if (filter->unbounded_packet == FALSE)
557 avail = MIN (avail, filter->length);
560 gst_adapter_flush (filter->adapter, avail);
561 ADAPTER_OFFSET_FLUSH (avail);
567 data = gst_adapter_take (filter->adapter, avail);
569 out = gst_buffer_new ();
570 GST_BUFFER_DATA (out) = data;
571 GST_BUFFER_SIZE (out) = avail;
572 GST_BUFFER_MALLOCDATA (out) = data;
574 ret = gst_pes_filter_data_push (filter, filter->first, out);
575 filter->first = FALSE;
578 if (filter->unbounded_packet == FALSE) {
579 filter->length -= avail;
580 if (filter->length == 0)
581 filter->state = STATE_HEADER_PARSE;
584 filter->state = STATE_HEADER_PARSE;
596 GST_DEBUG ("wrong internal state %d", filter->state);
597 return GST_FLOW_ERROR;
602 gst_pes_filter_flush (GstPESFilter * filter)
604 g_return_if_fail (filter != NULL);
606 if (filter->adapter) {
607 gst_adapter_clear (filter->adapter);
608 if (filter->adapter_offset)
609 *filter->adapter_offset = G_MAXUINT64;
611 filter->state = STATE_HEADER_PARSE;
615 gst_pes_filter_drain (GstPESFilter * filter)
617 g_return_val_if_fail (filter != NULL, GST_FLOW_ERROR);
619 gst_pes_filter_flush (filter);