1  /*
2   * This library is licensed under 2 different licenses and you
3   * can choose to use it under the terms of either one of them. The
4   * two licenses are the MPL 1.1 and the LGPL.
5   *
6   * MPL:
7   *
8   * The contents of this file are subject to the Mozilla Public License
9   * Version 1.1 (the "License"); you may not use this file except in
10   * compliance with the License. You may obtain a copy of the License at
11   * http://www.mozilla.org/MPL/.
12   *
13   * Software distributed under the License is distributed on an "AS IS"
14   * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
15   * License for the specific language governing rights and limitations
16   * under the License.
17   *
18   * LGPL:
19   *
20   * This library is free software; you can redistribute it and/or
21   * modify it under the terms of the GNU Library General Public
22   * License as published by the Free Software Foundation; either
23   * version 2 of the License, or (at your option) any later version.
24   *
25   * This library is distributed in the hope that it will be useful,
26   * but WITHOUT ANY WARRANTY; without even the implied warranty of
27   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
28   * Library General Public License for more details.
29   *
30   * You should have received a copy of the GNU Library General Public
31   * License along with this library; if not, write to the
32   * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
33   * Boston, MA 02110-1301, USA.
34   *
35   * The Original Code is Fluendo MPEG Demuxer plugin.
36   *
37   * The Initial Developer of the Original Code is Fluendo, S.L.
38   * Portions created by Fluendo, S.L. are Copyright (C) 2005
39   * Fluendo, S.L. All Rights Reserved.
40   *
41   * Contributor(s): Wim Taymans <wim@fluendo.com>
42   */
43 
44 #ifdef HAVE_CONFIG_H
45 #include "config.h"
46 #endif
47 
48 #include "gstmpegdefs.h"
49 #include "gstpesfilter.h"
50 
51 GST_DEBUG_CATEGORY (mpegpspesfilter_debug);
52 #define GST_CAT_DEFAULT (mpegpspesfilter_debug)
53 
54 static GstFlowReturn gst_pes_filter_data_push (GstPESFilter * filter,
55     gboolean first, GstBuffer * buffer);
56 
57 #define ADAPTER_OFFSET_FLUSH(_bytes_)  if (filter->adapter_offset) *filter->adapter_offset = *filter->adapter_offset + (_bytes_)
58 
59 /* May pass null for adapter to have the filter create one */
60 void
gst_pes_filter_init(GstPESFilter * filter,GstAdapter * adapter,guint64 * adapter_offset)61 gst_pes_filter_init (GstPESFilter * filter, GstAdapter * adapter,
62     guint64 * adapter_offset)
63 {
64   g_return_if_fail (filter != NULL);
65 
66   if (adapter != NULL)
67     g_object_ref (adapter);
68   else
69     adapter = gst_adapter_new ();
70 
71   filter->adapter = adapter;
72   filter->adapter_offset = adapter_offset;
73   filter->state = STATE_HEADER_PARSE;
74   filter->gather_pes = FALSE;
75   filter->allow_unbounded = FALSE;
76 }
77 
78 void
gst_pes_filter_uninit(GstPESFilter * filter)79 gst_pes_filter_uninit (GstPESFilter * filter)
80 {
81   g_return_if_fail (filter != NULL);
82 
83   if (filter->adapter)
84     g_object_unref (filter->adapter);
85   filter->adapter = NULL;
86   filter->adapter_offset = NULL;
87 }
88 
89 void
gst_pes_filter_set_callbacks(GstPESFilter * filter,GstPESFilterData data_cb,GstPESFilterResync resync_cb,gpointer user_data)90 gst_pes_filter_set_callbacks (GstPESFilter * filter,
91     GstPESFilterData data_cb, GstPESFilterResync resync_cb, gpointer user_data)
92 {
93   g_return_if_fail (filter != NULL);
94 
95   filter->data_cb = data_cb;
96   filter->resync_cb = resync_cb;
97   filter->user_data = user_data;
98 }
99 
100 static gboolean
gst_pes_filter_is_sync(guint32 sync)101 gst_pes_filter_is_sync (guint32 sync)
102 {
103   return ((sync & 0xfffffffc) == 0x000001bc) ||
104       ((sync & 0xfffffffd) == 0x000001bd) ||
105       ((sync & 0xffffffe0) == 0x000001c0) ||
106       ((sync & 0xfffffff0) == 0x000001f0) ||
107       ((sync & 0xfffffff0) == 0x000001e0);
108 }
109 
110 static GstFlowReturn
gst_pes_filter_parse(GstPESFilter * filter)111 gst_pes_filter_parse (GstPESFilter * filter)
112 {
113   GstFlowReturn ret;
114   guint32 start_code;
115 
116   gboolean STD_buffer_bound_scale G_GNUC_UNUSED;
117   guint16 STD_buffer_size_bound;
118   const guint8 *data;
119   gint avail, datalen;
120   gboolean have_size = FALSE;
121 
122   avail = gst_adapter_available (filter->adapter);
123 
124   if (avail < 6)
125     goto need_more_data;
126 
127   data = gst_adapter_map (filter->adapter, 6);
128 
129   /* read start code and length */
130 
131   /* get start code */
132   start_code = GST_READ_UINT32_BE (data);
133   if (!gst_pes_filter_is_sync (start_code))
134     goto lost_sync;
135 
136   filter->start_code = start_code;
137   filter->id = data[3];
138 
139   /* skip start code */
140   data += 4;
141 
142   /* start parsing length */
143   filter->length = GST_READ_UINT16_BE (data);
144 
145   GST_DEBUG ("id 0x%02x length %d, avail %d start code 0x%02x", filter->id,
146       filter->length, avail, filter->start_code);
147 
148   /* A data length of 0 indicates an unbounded packet in transport
149    * streams, but actually a 0 sized packet in program streams or
150    * for anything except video packets */
151 
152   /* FIXME: Remove this hack that is checking start_code. Instead, we need
153    * a callback that a start_code has been collected, giving the caller a chance
154    * to set the allow_unbounded flag if they want */
155   if (filter->length == 0 &&
156       ((filter->start_code & 0xFFFFFFF0) == PACKET_VIDEO_START_CODE ||
157           filter->start_code == ID_EXTENDED_STREAM_ID ||
158           filter->allow_unbounded)) {
159     GST_DEBUG ("id 0x%02x, unbounded length", filter->id);
160     filter->unbounded_packet = TRUE;
161   } else {
162     filter->unbounded_packet = FALSE;
163 
164     if (filter->gather_pes && avail < filter->length + 6) {
165       GST_DEBUG ("id 0x%02x, bounded length %d, only have %d",
166           filter->id, filter->length + 6, avail);
167       goto need_more_data;
168     }
169 
170     /* if we need more data from now on, we lost sync */
171     avail = MIN (avail, filter->length + 6);
172   }
173 
174   if (avail < 6)
175     goto need_more_data;
176 
177   gst_adapter_unmap (filter->adapter);
178 
179   /* read more data, either the whole packet if there is a length
180    * or whatever we have available if this in an unbounded packet. */
181   data = gst_adapter_map (filter->adapter, avail);
182 
183   /* This will make us flag LOST_SYNC if we run out of data from here onward */
184   have_size = TRUE;
185 
186   /* skip start code and length */
187   data += 6;
188   datalen = avail - 6;
189 
190   GST_DEBUG ("datalen %d", datalen);
191 
192   switch (filter->start_code) {
193     case ID_PS_PROGRAM_STREAM_MAP:
194     case ID_PRIVATE_STREAM_2:
195     case ID_ECM_STREAM:
196     case ID_EMM_STREAM:
197     case ID_PROGRAM_STREAM_DIRECTORY:
198     case ID_DSMCC_STREAM:
199     case ID_ITU_TREC_H222_TYPE_E_STREAM:
200       /* Push directly out */
201       goto push_out;
202     case ID_PADDING_STREAM:
203       GST_DEBUG ("skipping padding stream");
204       goto skip;
205     default:
206       break;
207   }
208 
209   if (datalen == 0)
210     goto need_more_data;
211   filter->pts = filter->dts = -1;
212 
213   /* stuffing bits, first two bits are '10' for mpeg2 pes so this code is
214    * not triggered. */
215   while (TRUE) {
216     if (*data != 0xff)
217       break;
218 
219     data++;
220     datalen--;
221 
222     GST_DEBUG ("got stuffing bit");
223 
224     if (datalen < 1)
225       goto need_more_data;
226   }
227 
228   /* STD buffer size, never for mpeg2 */
229   if ((*data & 0xc0) == 0x40) {
230     GST_DEBUG ("have STD");
231 
232     if (datalen < 3)
233       goto need_more_data;
234 
235     STD_buffer_bound_scale = *data & 0x20;
236     STD_buffer_size_bound = ((guint16) (*data++ & 0x1F)) << 8;
237     STD_buffer_size_bound |= *data++;
238 
239     datalen -= 2;
240   }
241 
242   /* PTS but no DTS, never for mpeg2 */
243   if ((*data & 0xf0) == 0x20) {
244     GST_DEBUG ("PTS without DTS");
245 
246     if (datalen < 5)
247       goto need_more_data;
248     READ_TS (data, filter->pts, lost_sync);
249     GST_DEBUG ("PTS found %" G_GUINT64_FORMAT, filter->pts);
250     datalen -= 5;
251   }
252   /* PTS and DTS, never for mpeg2 */
253   else if ((*data & 0xf0) == 0x30) {
254     GST_DEBUG ("PTS and DTS");
255 
256     if (datalen < 10)
257       goto need_more_data;
258     READ_TS (data, filter->pts, lost_sync);
259     READ_TS (data, filter->dts, lost_sync);
260     GST_DEBUG ("PTS found %" G_GUINT64_FORMAT, filter->pts);
261     GST_DEBUG ("DTS found %" G_GUINT64_FORMAT, filter->dts);
262     datalen -= 10;
263   } else if ((*data & 0xc0) == 0x80) {
264     /* mpeg2 case */
265     guchar flags;
266     guint8 header_data_length = 0;
267 
268     GST_DEBUG ("MPEG2 PES packet");
269 
270     if (datalen < 3)
271       goto need_more_data;
272     /* 2: '10'
273      * 2: PES_scrambling_control
274      * 1: PES_priority
275      * 1: data_alignment_indicator
276      * 1: copyright
277      * 1: original_or_copy
278      */
279     flags = *data++;
280 
281     GST_DEBUG ("flags: 0x%02x", flags);
282     if ((flags & 0xc0) != 0x80)
283       goto lost_sync;
284 
285     /* check PES scrambling control */
286     if ((flags & 0x30) != 0)
287       GST_DEBUG ("PES scrambling control: %x", (flags >> 4) & 0x3);
288 
289     /* 2: PTS_DTS_flags
290      * 1: ESCR_flag
291      * 1: ES_rate_flag
292      * 1: DSM_trick_mode_flag
293      * 1: additional_copy_info_flag
294      * 1: PES_CRC_flag
295      * 1: PES_extension_flag
296      */
297     flags = *data++;
298 
299     /* 8: PES_header_data_length */
300     header_data_length = *data++;
301     datalen -= 3;
302 
303     GST_DEBUG ("header_data_length: %d, flags 0x%02x",
304         header_data_length, flags);
305 
306     if (header_data_length > datalen)
307       goto need_more_data;
308 
309     /* only DTS: this is invalid */
310     if ((flags & 0xc0) == 0x40)
311       goto lost_sync;
312 
313     /* check for PTS */
314     if ((flags & 0x80)) {
315       if (datalen < 5)
316         goto need_more_data;
317 
318       READ_TS (data, filter->pts, lost_sync);
319       GST_DEBUG ("PTS found %" G_GUINT64_FORMAT, filter->pts);
320       header_data_length -= 5;
321       datalen -= 5;
322     }
323     /* check for DTS */
324     if ((flags & 0x40)) {
325       READ_TS (data, filter->dts, lost_sync);
326       if (datalen < 5)
327         goto need_more_data;
328       GST_DEBUG ("DTS found %" G_GUINT64_FORMAT, filter->dts);
329       header_data_length -= 5;
330       datalen -= 5;
331     }
332     /* ESCR_flag */
333     if ((flags & 0x20)) {
334       GST_DEBUG ("%x ESCR found", filter->id);
335       if (datalen < 6)
336         goto need_more_data;
337       data += 6;
338       header_data_length -= 6;
339       datalen -= 6;
340     }
341     /* ES_rate_flag */
342     if ((flags & 0x10)) {
343       guint32 es_rate;
344 
345       if (datalen < 3)
346         goto need_more_data;
347 
348       es_rate = ((guint32) (*data++ & 0x07)) << 14;
349       es_rate |= ((guint32) (*data++)) << 7;
350       es_rate |= ((guint32) (*data++ & 0xFE)) >> 1;
351       GST_DEBUG ("%x ES Rate found %u", filter->id, es_rate);
352       header_data_length -= 3;
353       datalen -= 3;
354     }
355     /* DSM_trick_mode_flag */
356     if ((flags & 0x08)) {
357       guint8 trick_mode_flags;
358 
359       if (datalen < 1)
360         goto need_more_data;
361 
362       /* 3: trick_mode_control */
363       trick_mode_flags = *data++;
364       GST_DEBUG ("%x DSM trick mode found, flags 0x%02x", filter->id,
365           trick_mode_flags);
366 
367       /* fast_forward */
368       if ((trick_mode_flags & 0xe0) == 0x00) {
369       }
370       /* slow motion */
371       else if ((trick_mode_flags & 0xe0) == 0x20) {
372       }
373       /* freeze frame */
374       else if ((trick_mode_flags & 0xe0) == 0x40) {
375       }
376       /* fast reverse */
377       else if ((trick_mode_flags & 0xe0) == 0x60) {
378       }
379       /* slow reverse */
380       else if ((trick_mode_flags & 0xe0) == 0x80) {
381       }
382       /* reserved */
383       else {
384       }
385 
386       header_data_length -= 1;
387       datalen -= 1;
388     }
389     /* additional_copy_info_flag  */
390     if ((flags & 0x04)) {
391       GST_DEBUG ("%x additional copy info, flags 0x%02x", filter->id, *data);
392     }
393     /* PES_CRC_flag  */
394     if ((flags & 0x02)) {
395       GST_DEBUG ("%x PES_CRC", filter->id);
396     }
397     /* PES_extension_flag  */
398     if ((flags & 0x01)) {
399       flags = *data++;
400       header_data_length -= 1;
401       datalen -= 1;
402       GST_DEBUG ("%x PES_extension, flags 0x%02x", filter->id, flags);
403       /* PES_private_data_flag */
404       if ((flags & 0x80)) {
405         GST_DEBUG ("%x PES_private_data_flag", filter->id);
406         data += 16;
407         header_data_length -= 16;
408         datalen -= 16;
409       }
410       /* pack_header_field_flag */
411       if ((flags & 0x40)) {
412         guint8 pack_field_length = *data;
413         GST_DEBUG ("%x pack_header_field_flag, pack_field_length %d",
414             filter->id, pack_field_length);
415         data += pack_field_length + 1;
416         header_data_length -= pack_field_length + 1;
417         datalen -= pack_field_length + 1;
418       }
419       /* program_packet_sequence_counter_flag */
420       if ((flags & 0x20)) {
421         GST_DEBUG ("%x program_packet_sequence_counter_flag", filter->id);
422         data += 2;
423         header_data_length -= 2;
424         datalen -= 2;
425       }
426       /* P-STD_buffer_flag */
427       if ((flags & 0x10)) {
428         GST_DEBUG ("%x P-STD_buffer_flag", filter->id);
429         data += 2;
430         header_data_length -= 2;
431         datalen -= 2;
432       }
433       /* PES_extension_flag_2 */
434       if ((flags & 0x01)) {
435         guint8 PES_extension_field_length = *data++;
436         GST_DEBUG ("%x PES_extension_flag_2, len %d",
437             filter->id, PES_extension_field_length & 0x7f);
438         if (PES_extension_field_length == 0x81) {
439           GST_DEBUG ("%x substream id 0x%02x", filter->id, *data);
440         }
441         data += PES_extension_field_length & 0x7f;
442         header_data_length -= (PES_extension_field_length & 0x7f) + 1;
443         datalen -= (PES_extension_field_length & 0x7f) + 1;
444       }
445     }
446     /* calculate the amount of real data in this PES packet */
447     data += header_data_length;
448     datalen -= header_data_length;
449   } else if (*data == 0x0f) {
450     /* Not sure what this clause is for */
451     data++;
452     datalen--;
453   } else {
454     /* Data byte wasn't recognised as a flags byte */
455     GST_DEBUG ("Unrecognised flags byte 0x%02x\n", *data);
456     goto lost_sync;
457   }
458 
459 push_out:
460   {
461     GstBuffer *out;
462 #ifndef GST_DISABLE_GST_DEBUG
463     guint16 consumed;
464 
465     consumed = avail - 6 - datalen;
466 #endif
467 
468     if (filter->unbounded_packet == FALSE) {
469       filter->length -= avail - 6;
470       GST_DEBUG ("pushing %d, need %d more, consumed %d",
471           datalen, filter->length, consumed);
472     } else {
473       GST_DEBUG ("pushing %d, unbounded packet, consumed %d",
474           datalen, consumed);
475     }
476 
477     if (datalen > 0) {
478       out = gst_buffer_new_allocate (NULL, datalen, NULL);
479       gst_buffer_fill (out, 0, data, datalen);
480       ret = gst_pes_filter_data_push (filter, TRUE, out);
481       filter->first = FALSE;
482     } else {
483       GST_LOG ("first being set to TRUE");
484       filter->first = TRUE;
485       ret = GST_FLOW_OK;
486     }
487 
488     if (filter->length > 0 || filter->unbounded_packet)
489       filter->state = STATE_DATA_PUSH;
490   }
491 
492   gst_adapter_unmap (filter->adapter);
493   gst_adapter_flush (filter->adapter, avail);
494   ADAPTER_OFFSET_FLUSH (avail);
495 
496   return ret;
497 
498 need_more_data:
499   {
500     if (filter->unbounded_packet == FALSE) {
501       if (have_size == TRUE) {
502         GST_DEBUG ("bounded need more data %" G_GSIZE_FORMAT " , lost sync",
503             gst_adapter_available (filter->adapter));
504         ret = GST_FLOW_LOST_SYNC;
505       } else {
506         GST_DEBUG ("bounded need more data %" G_GSIZE_FORMAT
507             ", breaking for more", gst_adapter_available (filter->adapter));
508         ret = GST_FLOW_NEED_MORE_DATA;
509       }
510     } else {
511       GST_DEBUG ("unbounded need more data %" G_GSIZE_FORMAT,
512           gst_adapter_available (filter->adapter));
513       ret = GST_FLOW_NEED_MORE_DATA;
514     }
515     gst_adapter_unmap (filter->adapter);
516     return ret;
517   }
518 skip:
519   {
520     gst_adapter_unmap (filter->adapter);
521 
522     GST_DEBUG ("skipping 0x%02x", filter->id);
523     gst_adapter_flush (filter->adapter, avail);
524     ADAPTER_OFFSET_FLUSH (avail);
525 
526     filter->length -= avail - 6;
527     if (filter->length > 0 || filter->unbounded_packet)
528       filter->state = STATE_DATA_SKIP;
529     return GST_FLOW_OK;
530   }
531 lost_sync:
532   {
533     gst_adapter_unmap (filter->adapter);
534     GST_DEBUG ("lost sync");
535     gst_adapter_flush (filter->adapter, 4);
536     ADAPTER_OFFSET_FLUSH (4);
537 
538     return GST_FLOW_LOST_SYNC;
539   }
540 }
541 
542 static GstFlowReturn
gst_pes_filter_data_push(GstPESFilter * filter,gboolean first,GstBuffer * buffer)543 gst_pes_filter_data_push (GstPESFilter * filter, gboolean first,
544     GstBuffer * buffer)
545 {
546   GstFlowReturn ret;
547 
548   GST_LOG ("pushing, first: %d", first);
549 
550   if (filter->data_cb) {
551     ret = filter->data_cb (filter, first, buffer, filter->user_data);
552   } else {
553     gst_buffer_unref (buffer);
554     ret = GST_FLOW_OK;
555   }
556   return ret;
557 }
558 
559 GstFlowReturn
gst_pes_filter_push(GstPESFilter * filter,GstBuffer * buffer)560 gst_pes_filter_push (GstPESFilter * filter, GstBuffer * buffer)
561 {
562   GstFlowReturn ret;
563 
564   g_return_val_if_fail (filter != NULL, GST_FLOW_ERROR);
565   g_return_val_if_fail (buffer != NULL, GST_FLOW_ERROR);
566 
567   switch (filter->state) {
568     case STATE_HEADER_PARSE:
569       gst_adapter_push (filter->adapter, buffer);
570       ret = gst_pes_filter_parse (filter);
571       break;
572     case STATE_DATA_PUSH:
573       ret = gst_pes_filter_data_push (filter, filter->first, buffer);
574       filter->first = FALSE;
575       break;
576     case STATE_DATA_SKIP:
577       gst_buffer_unref (buffer);
578       ret = GST_FLOW_OK;
579       break;
580     default:
581       goto wrong_state;
582   }
583   return ret;
584 
585   /* ERROR */
586 wrong_state:
587   {
588     GST_DEBUG ("wrong internal state %d", filter->state);
589     return GST_FLOW_ERROR;
590   }
591 }
592 
593 GstFlowReturn
gst_pes_filter_process(GstPESFilter * filter)594 gst_pes_filter_process (GstPESFilter * filter)
595 {
596   GstFlowReturn ret;
597   gboolean skip = FALSE;
598 
599   g_return_val_if_fail (filter != NULL, GST_FLOW_ERROR);
600 
601   switch (filter->state) {
602     case STATE_HEADER_PARSE:
603       ret = gst_pes_filter_parse (filter);
604       break;
605     case STATE_DATA_SKIP:
606       skip = TRUE;
607       /* fallthrough */
608     case STATE_DATA_PUSH:
609       if (filter->length > 0 || filter->unbounded_packet) {
610         gint avail;
611 
612         avail = gst_adapter_available (filter->adapter);
613         if (filter->unbounded_packet == FALSE)
614           avail = MIN (avail, filter->length);
615 
616         if (skip) {
617           gst_adapter_flush (filter->adapter, avail);
618           ADAPTER_OFFSET_FLUSH (avail);
619           ret = GST_FLOW_OK;
620         } else {
621           GstBuffer *out;
622 
623           out = gst_adapter_take_buffer (filter->adapter, avail);
624 
625           ret = gst_pes_filter_data_push (filter, filter->first, out);
626           filter->first = FALSE;
627         }
628 
629         if (filter->unbounded_packet == FALSE) {
630           filter->length -= avail;
631           if (filter->length == 0)
632             filter->state = STATE_HEADER_PARSE;
633         }
634       } else {
635         filter->state = STATE_HEADER_PARSE;
636         ret = GST_FLOW_OK;
637       }
638       break;
639     default:
640       goto wrong_state;
641   }
642   return ret;
643 
644   /* ERROR */
645 wrong_state:
646   {
647     GST_DEBUG ("wrong internal state %d", filter->state);
648     return GST_FLOW_ERROR;
649   }
650 }
651 
652 void
gst_pes_filter_flush(GstPESFilter * filter)653 gst_pes_filter_flush (GstPESFilter * filter)
654 {
655   g_return_if_fail (filter != NULL);
656 
657   if (filter->adapter) {
658     gst_adapter_clear (filter->adapter);
659     if (filter->adapter_offset)
660       *filter->adapter_offset = G_MAXUINT64;
661   }
662   filter->state = STATE_HEADER_PARSE;
663 }
664 
665 GstFlowReturn
gst_pes_filter_drain(GstPESFilter * filter)666 gst_pes_filter_drain (GstPESFilter * filter)
667 {
668   g_return_val_if_fail (filter != NULL, GST_FLOW_ERROR);
669 
670   gst_pes_filter_flush (filter);
671 
672   return GST_FLOW_OK;
673 }
674