Tizen 2.0 Release
[framework/multimedia/gst-plugins-bad0.10.git] / ext / resindvd / gstpesfilter.c
1 /* 
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/.
6  *
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
10  * under the License.
11  *
12  * The Original Code is Fluendo MPEG Demuxer plugin.
13  *
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.
17  *
18  * Contributor(s): Wim Taymans <wim@fluendo.com>
19  *                 Jan Schmidt <thaytan@noraisin.net>
20  */
21
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25
26 #include "gstmpegdefs.h"
27 #include "gstpesfilter.h"
28
29 GST_DEBUG_CATEGORY (gstflupesfilter_debug);
30 #define GST_CAT_DEFAULT (gstflupesfilter_debug)
31
32 static GstFlowReturn gst_pes_filter_data_push (GstPESFilter * filter,
33     gboolean first, GstBuffer * buffer);
34
35 #define ADAPTER_OFFSET_FLUSH(_bytes_)  if (filter->adapter_offset) *filter->adapter_offset = *filter->adapter_offset + (_bytes_)
36
37 /* May pass null for adapter to have the filter create one */
38 void
39 gst_pes_filter_init (GstPESFilter * filter, GstAdapter * adapter,
40     guint64 * adapter_offset)
41 {
42   g_return_if_fail (filter != NULL);
43
44   if (adapter != NULL)
45     g_object_ref (adapter);
46   else
47     adapter = gst_adapter_new ();
48
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;
54 }
55
56 void
57 gst_pes_filter_uninit (GstPESFilter * filter)
58 {
59   g_return_if_fail (filter != NULL);
60
61   if (filter->adapter)
62     g_object_unref (filter->adapter);
63   filter->adapter = NULL;
64   filter->adapter_offset = NULL;
65 }
66
67 void
68 gst_pes_filter_set_callbacks (GstPESFilter * filter,
69     GstPESFilterData data_cb, GstPESFilterResync resync_cb, gpointer user_data)
70 {
71   g_return_if_fail (filter != NULL);
72
73   filter->data_cb = data_cb;
74   filter->resync_cb = resync_cb;
75   filter->user_data = user_data;
76 }
77
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;
88
89 static gboolean
90 gst_pes_filter_is_sync (guint32 sync)
91 {
92   return ((sync & 0xfffffffc) == 0x000001bc) ||
93       ((sync & 0xffffffe0) == 0x000001c0) ||
94       ((sync & 0xfffffff0) == 0x000001f0) ||
95       ((sync & 0xfffffff0) == 0x000001e0);
96 }
97
98 static GstFlowReturn
99 gst_pes_filter_parse (GstPESFilter * filter)
100 {
101   GstFlowReturn ret;
102   guint32 start_code;
103
104   guint16 STD_buffer_size_bound;
105   const guint8 *data;
106   gint avail, datalen;
107   gboolean have_size = FALSE;
108
109   /* read start code and length */
110   if (!(data = gst_adapter_peek (filter->adapter, 6)))
111     goto need_more_data;
112
113   /* get start code */
114   start_code = GST_READ_UINT32_BE (data);
115   if (!gst_pes_filter_is_sync (start_code))
116     goto lost_sync;
117
118   filter->start_code = start_code;
119   filter->id = data[3];
120
121   /* skip start code */
122   data += 4;
123
124   /* start parsing length */
125   filter->length = GST_READ_UINT16_BE (data);
126
127   /* see how much is available */
128   avail = gst_adapter_available (filter->adapter);
129
130   GST_DEBUG ("id 0x%02x length %d, avail %d start code 0x%02x", filter->id,
131       filter->length, avail, filter->start_code);
132
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 */
136
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;
145   } else {
146     filter->unbounded_packet = FALSE;
147
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);
151       goto need_more_data;
152     }
153
154     /* if we need more data from now on, we lost sync */
155     avail = MIN (avail, filter->length + 6);
156   }
157
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)))
161     goto need_more_data;
162
163   /* This will make us flag LOST_SYNC if we run out of data from here onward */
164   have_size = TRUE;
165
166   /* skip start code and length */
167   data += 6;
168   datalen = avail - 6;
169
170   GST_DEBUG ("datalen %d", datalen);
171
172   switch (filter->start_code) {
173     case ID_PS_PROGRAM_STREAM_MAP:
174     case ID_PRIVATE_STREAM_2:
175     case ID_ECM_STREAM:
176     case ID_EMM_STREAM:
177     case ID_PROGRAM_STREAM_DIRECTORY:
178     case ID_DSMCC_STREAM:
179     case ID_ITU_TREC_H222_TYPE_E_STREAM:
180       goto skip;
181     case ID_PADDING_STREAM:
182       GST_DEBUG ("skipping padding stream");
183       goto skip;
184     default:
185       break;
186   }
187
188   if (datalen < 1)
189     goto need_more_data;
190
191   filter->pts = filter->dts = -1;
192
193   /* stuffing bits, first two bits are '10' for mpeg2 pes so this code is
194    * not triggered. */
195   while (TRUE) {
196     if (*data != 0xff)
197       break;
198
199     data++;
200     datalen--;
201
202     GST_DEBUG ("got stuffing bit");
203
204     if (datalen < 1)
205       goto need_more_data;
206   }
207
208   /* STD buffer size, never for mpeg2 */
209   if ((*data & 0xc0) == 0x40) {
210     GST_DEBUG ("have STD");
211
212     if (datalen < 3)
213       goto need_more_data;
214
215     /* STD_buffer_bound_scale = *data & 0x20; */
216     STD_buffer_size_bound = ((guint16) (*data++ & 0x1F)) << 8;
217     STD_buffer_size_bound |= *data++;
218
219     datalen -= 2;
220   }
221
222   /* PTS but no DTS, never for mpeg2 */
223   if ((*data & 0xf0) == 0x20) {
224     GST_DEBUG ("PTS without DTS");
225
226     if (datalen < 5)
227       goto need_more_data;
228     READ_TS (data, filter->pts, lost_sync);
229     GST_DEBUG ("PTS found %" G_GUINT64_FORMAT, filter->pts);
230     datalen -= 5;
231   }
232   /* PTS and DTS, never for mpeg2 */
233   else if ((*data & 0xf0) == 0x30) {
234     GST_DEBUG ("PTS and DTS");
235
236     if (datalen < 10)
237       goto need_more_data;
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);
242     datalen -= 10;
243   } else if ((*data & 0xc0) == 0x80) {
244     /* mpeg2 case */
245     guchar flags;
246     guint8 header_data_length = 0;
247
248     GST_DEBUG ("MPEG2 PES packet");
249
250     if (datalen < 3)
251       goto need_more_data;
252     /* 2: '10'
253      * 2: PES_scrambling_control
254      * 1: PES_priority
255      * 1: data_alignment_indicator
256      * 1: copyright
257      * 1: original_or_copy
258      */
259     flags = *data++;
260
261     GST_DEBUG ("flags: 0x%02x", flags);
262     if ((flags & 0xc0) != 0x80)
263       goto lost_sync;
264
265     /* check PES scrambling control */
266     if ((flags & 0x30) != 0)
267       goto encrypted;
268
269     /* 2: PTS_DTS_flags
270      * 1: ESCR_flag
271      * 1: ES_rate_flag
272      * 1: DSM_trick_mode_flag
273      * 1: additional_copy_info_flag
274      * 1: PES_CRC_flag
275      * 1: PES_extension_flag
276      */
277     flags = *data++;
278
279     /* 8: PES_header_data_length */
280     header_data_length = *data++;
281     datalen -= 3;
282
283     GST_DEBUG ("header_data_length: %d, flags 0x%02x",
284         header_data_length, flags);
285
286     if (header_data_length > datalen)
287       goto need_more_data;
288
289     /* only DTS: this is invalid */
290     if ((flags & 0xc0) == 0x40)
291       goto lost_sync;
292
293     /* check for PTS */
294     if ((flags & 0x80)) {
295       if (datalen < 5)
296         goto need_more_data;
297
298       READ_TS (data, filter->pts, lost_sync);
299       GST_DEBUG ("PTS found %" G_GUINT64_FORMAT, filter->pts);
300       header_data_length -= 5;
301       datalen -= 5;
302     }
303     /* check for DTS */
304     if ((flags & 0x40)) {
305       READ_TS (data, filter->dts, lost_sync);
306       if (datalen < 5)
307         goto need_more_data;
308       GST_DEBUG ("DTS found %" G_GUINT64_FORMAT, filter->dts);
309       header_data_length -= 5;
310       datalen -= 5;
311     }
312     /* ESCR_flag */
313     if ((flags & 0x20)) {
314       GST_DEBUG ("%x ESCR found", filter->id);
315       if (datalen < 6)
316         goto need_more_data;
317       data += 6;
318       header_data_length -= 6;
319       datalen -= 6;
320     }
321     /* ES_rate_flag */
322     if ((flags & 0x10)) {
323       guint32 es_rate;
324
325       if (datalen < 3)
326         goto need_more_data;
327
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;
333       datalen -= 3;
334     }
335     /* DSM_trick_mode_flag */
336     if ((flags & 0x08)) {
337       guint8 trick_mode_flags;
338
339       if (datalen < 1)
340         goto need_more_data;
341
342       /* 3: trick_mode_control */
343       trick_mode_flags = *data++;
344       GST_DEBUG ("%x DSM trick mode found, flags 0x%02x", filter->id,
345           trick_mode_flags);
346
347       /* fast_forward */
348       if ((trick_mode_flags & 0xe0) == 0x00) {
349       }
350       /* slow motion */
351       else if ((trick_mode_flags & 0xe0) == 0x20) {
352       }
353       /* freeze frame */
354       else if ((trick_mode_flags & 0xe0) == 0x40) {
355       }
356       /* fast reverse */
357       else if ((trick_mode_flags & 0xe0) == 0x60) {
358       }
359       /* slow reverse */
360       else if ((trick_mode_flags & 0xe0) == 0x80) {
361       }
362       /* reserved */
363       else {
364       }
365
366       header_data_length -= 1;
367       datalen -= 1;
368     }
369     /* additional_copy_info_flag  */
370     if ((flags & 0x04)) {
371       GST_DEBUG ("%x additional copy info, flags 0x%02x", filter->id, *data);
372     }
373     /* PES_CRC_flag  */
374     if ((flags & 0x02)) {
375       GST_DEBUG ("%x PES_CRC", filter->id);
376     }
377     /* PES_extension_flag  */
378     if ((flags & 0x01)) {
379       GST_DEBUG ("%x PES_extension", filter->id);
380     }
381
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 */
387     data++;
388     datalen--;
389   } else {
390     /* Data byte wasn't recognised as a flags byte */
391     GST_DEBUG ("Unrecognised flags byte 0x%02x\n", *data);
392     goto lost_sync;
393   }
394
395   {
396     GstBuffer *out;
397     guint16 consumed;
398
399     consumed = avail - 6 - datalen;
400
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);
405     } else {
406       GST_DEBUG ("pushing %d, unbounded packet, consumed %d",
407           datalen, consumed);
408     }
409
410     if (datalen > 0) {
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);
415
416       ret = gst_pes_filter_data_push (filter, TRUE, out);
417       filter->first = FALSE;
418     } else {
419       GST_LOG ("first being set to TRUE");
420       filter->first = TRUE;
421       ret = GST_FLOW_OK;
422     }
423
424     if (filter->length > 0 || filter->unbounded_packet)
425       filter->state = STATE_DATA_PUSH;
426   }
427
428   gst_adapter_flush (filter->adapter, avail);
429   ADAPTER_OFFSET_FLUSH (avail);
430
431   return ret;
432
433 need_more_data:
434   {
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;
440       } else {
441         GST_DEBUG ("bounded need more data %d, breaking for more",
442             gst_adapter_available (filter->adapter));
443         ret = GST_FLOW_NEED_MORE_DATA;
444       }
445     } else {
446       GST_DEBUG ("unbounded need more data %d",
447           gst_adapter_available (filter->adapter));
448       ret = GST_FLOW_NEED_MORE_DATA;
449     }
450
451     return ret;
452   }
453 skip:
454   {
455     GST_DEBUG ("skipping 0x%02x", filter->id);
456     gst_adapter_flush (filter->adapter, avail);
457     ADAPTER_OFFSET_FLUSH (avail);
458
459     filter->length -= avail - 6;
460     if (filter->length > 0 || filter->unbounded_packet)
461       filter->state = STATE_DATA_SKIP;
462     return GST_FLOW_OK;
463   }
464 encrypted:
465   {
466     GST_DEBUG ("skipping encrypted 0x%02x", filter->id);
467     gst_adapter_flush (filter->adapter, avail);
468     ADAPTER_OFFSET_FLUSH (avail);
469
470     filter->length -= avail - 6;
471     if (filter->length > 0 || filter->unbounded_packet)
472       filter->state = STATE_DATA_SKIP;
473     return GST_FLOW_OK;
474   }
475 lost_sync:
476   {
477     GST_DEBUG ("lost sync");
478     gst_adapter_flush (filter->adapter, 4);
479     ADAPTER_OFFSET_FLUSH (4);
480
481     return GST_FLOW_LOST_SYNC;
482   }
483 }
484
485 static GstFlowReturn
486 gst_pes_filter_data_push (GstPESFilter * filter, gboolean first,
487     GstBuffer * buffer)
488 {
489   GstFlowReturn ret;
490
491   GST_LOG ("pushing, first: %d", first);
492
493   if (filter->data_cb) {
494     ret = filter->data_cb (filter, first, buffer, filter->user_data);
495   } else {
496     gst_buffer_unref (buffer);
497     ret = GST_FLOW_OK;
498   }
499   return ret;
500 }
501
502 GstFlowReturn
503 gst_pes_filter_push (GstPESFilter * filter, GstBuffer * buffer)
504 {
505   GstFlowReturn ret;
506
507   g_return_val_if_fail (filter != NULL, GST_FLOW_ERROR);
508   g_return_val_if_fail (buffer != NULL, GST_FLOW_ERROR);
509
510   switch (filter->state) {
511     case STATE_HEADER_PARSE:
512       gst_adapter_push (filter->adapter, buffer);
513       ret = gst_pes_filter_parse (filter);
514       break;
515     case STATE_DATA_PUSH:
516       ret = gst_pes_filter_data_push (filter, filter->first, buffer);
517       filter->first = FALSE;
518       break;
519     case STATE_DATA_SKIP:
520       gst_buffer_unref (buffer);
521       ret = GST_FLOW_OK;
522       break;
523     default:
524       goto wrong_state;
525   }
526   return ret;
527
528   /* ERROR */
529 wrong_state:
530   {
531     GST_DEBUG ("wrong internal state %d", filter->state);
532     return GST_FLOW_ERROR;
533   }
534 }
535
536 GstFlowReturn
537 gst_pes_filter_process (GstPESFilter * filter)
538 {
539   GstFlowReturn ret;
540   gboolean skip = FALSE;
541
542   g_return_val_if_fail (filter != NULL, GST_FLOW_ERROR);
543
544   switch (filter->state) {
545     case STATE_HEADER_PARSE:
546       ret = gst_pes_filter_parse (filter);
547       break;
548     case STATE_DATA_SKIP:
549       skip = TRUE;
550       /* fallthrough */
551     case STATE_DATA_PUSH:
552       if (filter->length > 0 || filter->unbounded_packet) {
553         gint avail;
554
555         avail = gst_adapter_available (filter->adapter);
556         if (filter->unbounded_packet == FALSE)
557           avail = MIN (avail, filter->length);
558
559         if (skip) {
560           gst_adapter_flush (filter->adapter, avail);
561           ADAPTER_OFFSET_FLUSH (avail);
562           ret = GST_FLOW_OK;
563         } else {
564           GstBuffer *out;
565           guint8 *data;
566
567           data = gst_adapter_take (filter->adapter, avail);
568
569           out = gst_buffer_new ();
570           GST_BUFFER_DATA (out) = data;
571           GST_BUFFER_SIZE (out) = avail;
572           GST_BUFFER_MALLOCDATA (out) = data;
573
574           ret = gst_pes_filter_data_push (filter, filter->first, out);
575           filter->first = FALSE;
576         }
577
578         if (filter->unbounded_packet == FALSE) {
579           filter->length -= avail;
580           if (filter->length == 0)
581             filter->state = STATE_HEADER_PARSE;
582         }
583       } else {
584         filter->state = STATE_HEADER_PARSE;
585         ret = GST_FLOW_OK;
586       }
587       break;
588     default:
589       goto wrong_state;
590   }
591   return ret;
592
593   /* ERROR */
594 wrong_state:
595   {
596     GST_DEBUG ("wrong internal state %d", filter->state);
597     return GST_FLOW_ERROR;
598   }
599 }
600
601 void
602 gst_pes_filter_flush (GstPESFilter * filter)
603 {
604   g_return_if_fail (filter != NULL);
605
606   if (filter->adapter) {
607     gst_adapter_clear (filter->adapter);
608     if (filter->adapter_offset)
609       *filter->adapter_offset = G_MAXUINT64;
610   }
611   filter->state = STATE_HEADER_PARSE;
612 }
613
614 GstFlowReturn
615 gst_pes_filter_drain (GstPESFilter * filter)
616 {
617   g_return_val_if_fail (filter != NULL, GST_FLOW_ERROR);
618
619   gst_pes_filter_flush (filter);
620
621   return GST_FLOW_OK;
622 }