tizen 2.3.1 release
[framework/multimedia/gst-plugins-ext0.10.git] / piffdemux / src / piffdemux.c
1
2
3 #ifdef HAVE_CONFIG_H
4 #include "config.h"
5 #endif
6
7 #include "piffdemux.h"
8 #include <glib/gprintf.h>
9 #include <gst/tag/tag.h>
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include <piffatomparser.h>
14 #include <piffdemux_fourcc.h>
15 #include <piffpalette.h>
16 #include <piffdemux_types.h>
17 #include <piffdemux_dump.h>
18
19 #define PIFF_DEFAULT_TRACKID   -1
20 #define PIFF_DEFAULT_FOURCC   0
21 #define PIFF_DEFAULT_TIMESCALE 10000000
22 #define PIFF_DEFAULT_DURATION -1
23 #define PIFF_DEFAULT_START_TS 0
24 #define PIFF_DEFAULT_START_TS 0
25
26 #define PIFF_DEFAULT_WIDTH 16
27 #define PIFF_DEFAULT_HEIGHT 16
28 #define PIFF_DEFAULT_BPS 16
29
30 #undef DEC_OUT_FRAME_DUMP
31
32 #ifdef DEC_OUT_FRAME_DUMP
33 #include <stdio.h>
34 FILE *piffdump = NULL;
35 #endif
36
37 #define PIFFDEMUX_RB16(x)       ((((const unsigned char*)(x))[0] << 8) | ((const unsigned char*)(x))[1])
38 /* max. size considered 'sane' for non-mdat atoms */
39 #define PIFFDEMUX_MAX_ATOM_SIZE (25*1024*1024)
40
41 /* if the sample index is larger than this, something is likely wrong */
42 #define PIFFDEMUX_MAX_SAMPLE_INDEX_SIZE (50*1024*1024)
43
44 GST_DEBUG_CATEGORY (piffdemux_debug);
45
46 typedef struct _PiffDemuxSegment PiffDemuxSegment;
47 typedef struct _PiffDemuxSample PiffDemuxSample;
48 typedef struct _PiffDemuxSubSampleEncryption PiffDemuxSubSampleEncryption;
49 typedef struct _PiffDemuxSubSampleEntryInfo PiffDemuxSubSampleEntryInfo;
50
51 enum
52 {
53   PROR_PIFF_0,
54   PROP_PIFF_MEDIA_CAPS,
55   PROP_PIFF_MEDIA_TIMESCALE,
56   PROP_PIFF_MEDIA_DURATION,
57   PROP_PIFF_MEDIA_START_TIMESTAMP,
58   PROP_PIFF_IS_LIVE,
59   PROP_PIFF_LOOKAHEAD_COUNT,
60   PROP_PIFF_AVG_FRAME_DUR,
61 #ifdef DRM_ENABLE
62   PROP_PROTECTION_HEADER_BUFFER,
63 #endif
64 };
65
66 enum
67 {
68   SIGNAL_LIVE_PARAM,
69   LAST_SIGNAL
70 };
71
72 static guint gst_piffdemux_signals[LAST_SIGNAL] = { 0 };
73
74 struct _PiffDemuxSubSampleEntryInfo
75 {
76   guint16 LenofClearData;
77   guint32 LenofEncryptData;
78 };
79
80 struct _PiffDemuxSubSampleEncryption
81 {
82   guint16 n_entries;
83   PiffDemuxSubSampleEntryInfo *sub_entry;
84 };
85
86 struct _PiffDemuxSample
87 {
88   guint32 size;
89   gint32 pts_offset;            /* Add this value to timestamp to get the pts */
90   guint64 offset;
91   guint64 timestamp;            /* DTS In mov time */
92   guint32 duration;             /* In mov time */
93   gboolean keyframe;            /* TRUE when this packet is a keyframe */
94   guint8 *iv;                           /* initialization vector for decryption*/
95   PiffDemuxSubSampleEncryption *sub_encry;
96 };
97
98 /* timestamp is the DTS */
99 #define PIFFSAMPLE_DTS(stream,sample) gst_util_uint64_scale ((sample)->timestamp,\
100     GST_SECOND, (stream)->timescale)
101 /* timestamp + offset is the PTS */
102 #define PIFFSAMPLE_PTS(stream,sample) gst_util_uint64_scale ((sample)->timestamp + \
103     (sample)->pts_offset, GST_SECOND, (stream)->timescale)
104 /* timestamp + duration - dts is the duration */
105 #define PIFFSAMPLE_DUR_DTS(stream,sample,dts) (gst_util_uint64_scale ((sample)->timestamp + \
106     (sample)->duration, GST_SECOND, (stream)->timescale) - (dts));
107 /* timestamp + offset + duration - pts is the duration */
108 #define PIFFSAMPLE_DUR_PTS(stream,sample,pts) (gst_util_uint64_scale ((sample)->timestamp + \
109     (sample)->pts_offset + (sample)->duration, GST_SECOND, (stream)->timescale) - (pts));
110
111 #define PIFFSAMPLE_KEYFRAME(stream,sample) ((sample)->keyframe);
112
113 typedef char uuid_t[16];
114
115 static const uuid_t tfxd_uuid = { 0x6d, 0x1d, 0x9b, 0x05,
116                                                0x42, 0xd5, 0x44, 0xe6,
117                                                0x80, 0xe2, 0x14, 0x1d,
118                                                0xaf, 0xf7, 0x57, 0xb2 };
119
120 static const uuid_t tfrf_uuid = { 0xd4, 0x80, 0x7e, 0xf2,
121                                               0xca, 0x39, 0x46, 0x95,
122                                               0x8e, 0x54, 0x26, 0xcb,
123                                               0x9e, 0x46, 0xa7, 0x9f };
124
125 static const uuid_t encrypt_uuid = {  0xa2, 0x39, 0x4f, 0x52,
126                                                         0x5a, 0x9b, 0x4f, 0x14,
127                                                         0xa2, 0x44, 0x6c, 0x42,
128                                                         0x7c, 0x64, 0x8d, 0xf4 };
129
130 #define SE_OVERRIDE_TE_FLAGS 0x000001
131 #define SE_USE_SUBSAMPLE_ENCRYPTION 0x000002
132
133 typedef enum
134 {
135   UUID_UNKNOWN = -1,
136   UUID_TFXD,
137   UUID_TFRF,
138   UUID_SAMPLE_ENCRYPT,
139 }uuid_type_t;
140
141 struct _PiffDemuxSegment
142 {
143   /* global time and duration, all gst time */
144   guint64 time;
145   guint64 stop_time;
146   guint64 duration;
147   /* media time of trak, all gst time */
148   guint64 media_start;
149   guint64 media_stop;
150   gdouble rate;
151 };
152
153
154 struct _PiffDemuxStream
155 {
156   /* stream type */
157   guint32 subtype;
158   GstCaps *caps;
159   guint32 fourcc;
160
161   /* duration/scale */
162   guint64 duration;             /* in timescale */
163   guint32 timescale;
164
165   /* our samples */
166   guint32 n_samples;
167   PiffDemuxSample *samples;
168   guint32 min_duration;         /* duration in timescale of first sample, used for figuring out
169                                    the framerate, in timescale units */
170
171   /* if we use chunks or samples */
172   gboolean sampled;
173   guint padding;
174
175   /* when a discontinuity is pending */
176   gboolean discont;
177
178   /* list of buffers to push first */
179   GSList *buffers;
180
181   /* buffer needs some custom processing, e.g. subtitles */
182   gboolean need_process;
183
184     /* current position */
185   guint32 segment_index;
186   guint32 sample_index;
187   guint64 time_position;        /* in gst time */
188
189   /* the Gst segment we are processing out, used for clipping */
190   GstSegment segment;
191
192   /* last GstFlowReturn */
193   GstFlowReturn last_ret;
194
195
196   /* quicktime segments */
197   guint32 n_segments;
198   PiffDemuxSegment *segments;
199   guint32 from_sample;
200   guint32 to_sample;
201
202   gboolean sent_eos;
203   GstTagList *pending_tags;
204   gboolean send_global_tags;
205
206   GstEvent *pending_event;
207
208   gboolean sent_nsevent;
209
210   guint64 start_ts;
211
212   guint64 avg_dur; /* average frame duration */
213 };
214
215
216 enum PiffDemuxState
217 {
218   PIFFDEMUX_STATE_INITIAL,        /* Initial state (haven't got the header yet) */
219   PIFFDEMUX_STATE_HEADER,         /* Parsing the header */
220   PIFFDEMUX_STATE_MOVIE,          /* Parsing/Playing the media data */
221   PIFFDEMUX_STATE_BUFFER_MDAT     /* Buffering the mdat atom */
222 };
223
224
225 static GNode *piffdemux_tree_get_child_by_type (GNode * node, guint32 fourcc);
226 static GNode *piffdemux_tree_get_child_by_type_full (GNode * node,
227     guint32 fourcc, GstByteReader * parser);
228 static GNode *piffdemux_tree_get_sibling_by_type (GNode * node, guint32 fourcc);
229 static GNode *piffdemux_tree_get_sibling_by_type_full (GNode * node,
230     guint32 fourcc, GstByteReader * parser);
231
232 static GstStaticPadTemplate gst_piffdemux_sink_template =
233     GST_STATIC_PAD_TEMPLATE ("sink",
234     GST_PAD_SINK,
235     GST_PAD_ALWAYS,
236     GST_STATIC_CAPS ("application/x-piff")
237     );
238
239 static GstStaticPadTemplate gst_piffdemux_src_template =
240 GST_STATIC_PAD_TEMPLATE ("src",
241     GST_PAD_SRC,
242     GST_PAD_ALWAYS,
243     GST_STATIC_CAPS_ANY);
244
245
246 GST_BOILERPLATE (GstPiffDemux, gst_piffdemux, GstPiffDemux, GST_TYPE_ELEMENT);
247
248 static void gst_piffdemux_dispose (GObject * object);
249
250 static GstStateChangeReturn gst_piffdemux_change_state (GstElement * element,
251     GstStateChange transition);
252 static void
253 gst_piffdemux_set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec);
254 static void
255 gst_piffdemux_get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec);
256 static GstFlowReturn gst_piffdemux_chain (GstPad * sinkpad, GstBuffer * inbuf);
257 static gboolean gst_piffdemux_handle_sink_event (GstPad * pad, GstEvent * event);
258 static gboolean piffdemux_parse_node (GstPiffDemux * piffdemux, GNode * node, const guint8 * buffer, guint length);
259 static gboolean piffdemux_parse_sample_encryption(GstPiffDemux * piffdemux, GstByteReader *sample_encrypt, PiffDemuxStream * stream);
260 static gboolean piffdemux_parse_mfhd (GstPiffDemux * piffdemux, GstByteReader * mfhd);
261 static gboolean gst_piffdemux_handle_src_event (GstPad * pad, GstEvent * event);
262 static const GstQueryType *gst_piffdemux_get_src_query_types (GstPad * pad);
263 static gboolean gst_piffdemux_handle_src_query (GstPad * pad, GstQuery * query);
264
265 #ifdef DRM_ENABLE
266 static void piffdemux_get_playready_licence (GstPiffDemux *demux);
267 void test_drm_trusted_operation_cb(drm_trusted_user_operation_info_s *operation_info, void *output_data);
268 #endif
269
270 static gboolean
271 ConvertH264_MetaDCI_to_3GPPDCI(unsigned char *dci_meta_buf, unsigned int dci_meta_size, unsigned char **dci_3gpp_buf, unsigned int *dci_3gpp_size);
272 void
273 __gst_piffdemux_marshal_BOOLEAN__OBJECT (GClosure *closure,
274                                    GValue       *return_value G_GNUC_UNUSED,
275                                    guint         n_param_values,
276                                    const GValue *param_values,
277                                    gpointer      invocation_hint G_GNUC_UNUSED,
278                                    gpointer      marshal_data);
279
280 static void
281 gst_piffdemux_base_init (gpointer klass)
282 {
283   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
284
285   gst_element_class_add_pad_template (element_class,
286       gst_static_pad_template_get (&gst_piffdemux_sink_template));
287   gst_element_class_add_pad_template (element_class,
288       gst_static_pad_template_get (&gst_piffdemux_src_template));
289   gst_element_class_set_details_simple (element_class, "PIFF demuxer",
290       "Codec/Parser",
291       "Parser for PIFF file format",
292       "naveen ch <naveen.ch@samsung.com>");
293
294   GST_DEBUG_CATEGORY_INIT (piffdemux_debug, "piffdemux", 0, "piffdemux plugin");
295 }
296
297 static void
298 gst_piffdemux_class_init (GstPiffDemuxClass * klass)
299 {
300   GObjectClass *gobject_class;
301   GstElementClass *gstelement_class;
302
303   gobject_class = (GObjectClass *) klass;
304   gstelement_class = (GstElementClass *) klass;
305
306   parent_class = g_type_class_peek_parent (klass);
307
308   gobject_class->dispose = gst_piffdemux_dispose;
309   gobject_class->set_property = gst_piffdemux_set_property;
310   gobject_class->get_property = gst_piffdemux_get_property;
311
312   gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_piffdemux_change_state);
313
314   g_object_class_install_property (gobject_class, PROP_PIFF_MEDIA_CAPS,
315                                    g_param_spec_boxed ("caps", "Caps",
316                                    "The allowed caps for the src pad", GST_TYPE_CAPS,
317                                    G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
318
319   /* timescale of media to be set by application */
320   g_object_class_install_property (gobject_class, PROP_PIFF_MEDIA_TIMESCALE,
321                                    g_param_spec_uint64 ("timescale", "media timescale",
322                                    "media timescale in PIFF Manifest", 0, G_MAXUINT64,
323                                    PIFF_DEFAULT_TIMESCALE,
324                                    G_PARAM_READWRITE));
325 #ifdef DRM_ENABLE
326   g_object_class_install_property (gobject_class, PROP_PROTECTION_HEADER_BUFFER,
327                                    gst_param_spec_mini_object ("protection-header", "protection header buffer",
328                                    "protection header used for playready", GST_TYPE_BUFFER,
329                                    G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
330 #endif
331   g_object_class_install_property (gobject_class, PROP_PIFF_MEDIA_DURATION,
332                                    g_param_spec_int64 ("duration", "Duration of media",
333                                    "Total duration of the content", -1, G_MAXINT64,
334                                    PIFF_DEFAULT_DURATION,
335                                    G_PARAM_READWRITE));
336
337   g_object_class_install_property (gobject_class, PROP_PIFF_MEDIA_START_TIMESTAMP,
338                                    g_param_spec_uint64 ("start-ts", "expected start timestamp",
339                                    "expected start timestamp to avoid reset", 0, G_MAXUINT64,
340                                    PIFF_DEFAULT_START_TS,
341                                    G_PARAM_READWRITE));
342
343   g_object_class_install_property (gobject_class, PROP_PIFF_IS_LIVE,
344                                    g_param_spec_boolean ("is-live", "Is presentation is Live or VOD",
345                                    "If Presentation is Live (true) else VOD (false)",
346                                    FALSE, G_PARAM_READWRITE));
347
348   g_object_class_install_property (gobject_class, PROP_PIFF_LOOKAHEAD_COUNT,
349                                    g_param_spec_uint ("lookahead-count", "Lookahead count value",
350                                    "Look ahead count used in case of Live presentation", 0, G_MAXUINT,
351                                    0, G_PARAM_READWRITE));
352
353   g_object_class_install_property (gobject_class, PROP_PIFF_AVG_FRAME_DUR,
354                                    g_param_spec_uint64 ("frame-dur", "Average frame duration",
355                                    "Average frame duration", 0, G_MAXUINT64,
356                                    G_MAXUINT64,
357                                    G_PARAM_READABLE));
358
359   gst_piffdemux_signals[SIGNAL_LIVE_PARAM] = g_signal_new ("live-param",
360                                                            G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
361                                                            G_STRUCT_OFFSET (GstPiffDemuxClass, live_param), NULL, NULL,
362                                                            g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1, G_TYPE_POINTER);
363
364 }
365
366
367 static void
368 gst_piffdemux_init (GstPiffDemux * piffdemux, GstPiffDemuxClass * klass)
369 {
370   /* sink pad */
371   piffdemux->sinkpad = gst_pad_new_from_static_template (&gst_piffdemux_sink_template, "sink");
372   gst_pad_set_chain_function (piffdemux->sinkpad, gst_piffdemux_chain);
373   gst_pad_set_event_function (piffdemux->sinkpad, gst_piffdemux_handle_sink_event);
374   gst_element_add_pad (GST_ELEMENT_CAST (piffdemux), piffdemux->sinkpad);
375
376   /* source pad */
377   piffdemux->srcpad = gst_pad_new_from_static_template (&gst_piffdemux_src_template, "src");
378   gst_pad_set_event_function (piffdemux->srcpad, gst_piffdemux_handle_src_event);
379   gst_pad_use_fixed_caps (piffdemux->srcpad);
380   gst_pad_set_query_type_function (piffdemux->srcpad, gst_piffdemux_get_src_query_types);
381   gst_pad_set_query_function (piffdemux->srcpad, gst_piffdemux_handle_src_query);
382   gst_element_add_pad (GST_ELEMENT_CAST (piffdemux), piffdemux->srcpad);
383
384   piffdemux->stream = g_new0 (PiffDemuxStream, 1);
385   piffdemux->stream->fourcc = PIFF_DEFAULT_FOURCC;
386   piffdemux->stream->timescale = PIFF_DEFAULT_TIMESCALE;
387   piffdemux->stream->duration = PIFF_DEFAULT_DURATION;
388   piffdemux->stream->caps = NULL;
389   piffdemux->stream->discont = TRUE;
390   piffdemux->stream->need_process = FALSE;
391   piffdemux->stream->segment_index = -1;
392   piffdemux->stream->time_position = 0;
393   piffdemux->stream->sample_index = -1;
394   piffdemux->stream->last_ret = GST_FLOW_OK;
395   piffdemux->stream->sent_nsevent = FALSE;
396   piffdemux->stream->start_ts = PIFF_DEFAULT_START_TS;
397   piffdemux->stream->avg_dur = -1;
398
399   piffdemux->state = PIFFDEMUX_STATE_INITIAL;
400   piffdemux->neededbytes = 16;
401   piffdemux->todrop = 0;
402   piffdemux->adapter = gst_adapter_new ();
403   piffdemux->offset = 0;
404   piffdemux->first_mdat = -1;
405   piffdemux->mdatoffset = GST_CLOCK_TIME_NONE;
406   piffdemux->mdatbuffer = NULL;
407   piffdemux->moof_rcvd = FALSE;
408   piffdemux->is_live = FALSE;
409   piffdemux->lookahead_cnt = 0;
410 #ifdef DRM_ENABLE
411   piffdemux->pr_handle = NULL;
412 #endif
413   piffdemux->decrypt_init = FALSE;
414   piffdemux->encrypt_content = FALSE;
415
416 #ifdef DEC_OUT_FRAME_DUMP
417     piffdump = fopen ("/opt/media/piff_out_dump.dmp", "w+");
418     if (piffdump == NULL)
419     {
420         g_print ("\nNot able to create frame dump file\n");
421     }
422 #endif
423
424   gst_segment_init (&piffdemux->segment, GST_FORMAT_TIME);
425 }
426
427 static void
428 gst_piffdemux_dispose (GObject * object)
429 {
430   GstPiffDemux *piffdemux = GST_PIFFDEMUX (object);
431
432   if (piffdemux->adapter) {
433     g_object_unref (G_OBJECT (piffdemux->adapter));
434     piffdemux->adapter = NULL;
435   }
436
437 #ifdef DEC_OUT_FRAME_DUMP
438     {
439         fclose (piffdump);
440         piffdump = NULL;
441     }
442 #endif
443   G_OBJECT_CLASS (parent_class)->dispose (object);
444 }
445
446
447 static void
448 gst_piffdemux_set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
449 {
450   GstPiffDemux *piffdemux = GST_PIFFDEMUX (object);
451
452   switch (prop_id) {
453     case PROP_PIFF_MEDIA_CAPS: {
454       if (piffdemux->stream->caps)
455         gst_caps_unref(piffdemux->stream->caps);
456       piffdemux->stream->caps = gst_caps_copy (gst_value_get_caps (value));
457       gchar *caps_string = gst_caps_to_string(piffdemux->stream->caps);
458       GST_DEBUG_OBJECT (piffdemux, "stream caps = %s", caps_string);
459       g_free(caps_string);
460       caps_string = NULL;
461       if (!gst_pad_set_caps(piffdemux->srcpad, piffdemux->stream->caps)) {
462         GST_ERROR_OBJECT (piffdemux, "not able to set caps...");
463       }
464       break;
465     }
466     case PROP_PIFF_MEDIA_TIMESCALE:
467       piffdemux->stream->timescale = g_value_get_uint64(value);
468       break;
469     case PROP_PIFF_MEDIA_DURATION:
470       piffdemux->stream->duration = g_value_get_int64(value);
471       break;
472     case PROP_PIFF_MEDIA_START_TIMESTAMP:
473       piffdemux->stream->start_ts = g_value_get_uint64(value);
474       GST_INFO_OBJECT (piffdemux, "start_ts = %"GST_TIME_FORMAT, GST_TIME_ARGS(piffdemux->stream->start_ts));
475       break;
476     case PROP_PIFF_IS_LIVE:
477       piffdemux->is_live = g_value_get_boolean(value);
478       break;
479     case PROP_PIFF_LOOKAHEAD_COUNT:
480       piffdemux->lookahead_cnt = g_value_get_uint(value);
481       GST_DEBUG_OBJECT (piffdemux, "Look ahead count = %d", piffdemux->lookahead_cnt);
482       break;
483 #ifdef DRM_ENABLE
484     case PROP_PROTECTION_HEADER_BUFFER:
485       piffdemux->protection_header = gst_value_get_buffer(value);
486       piffdemux_get_playready_licence (piffdemux);
487       break;
488 #endif
489     default:
490       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
491       break;
492     }
493 }
494
495
496 static void
497 gst_piffdemux_get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
498 {
499   GstPiffDemux *piffdemux = GST_PIFFDEMUX (object);
500
501   switch (prop_id) {
502      case PROP_PIFF_MEDIA_CAPS:
503       gst_value_set_caps (value, piffdemux->stream->caps);
504       break;
505     case PROP_PIFF_MEDIA_TIMESCALE:
506       g_value_set_uint64 (value, piffdemux->stream->timescale);
507       break;
508     case PROP_PIFF_MEDIA_DURATION:
509       g_value_set_int64 (value, piffdemux->stream->duration);
510       break;
511     case PROP_PIFF_MEDIA_START_TIMESTAMP:
512       g_value_set_uint64 (value, piffdemux->stream->start_ts);
513       break;
514     case PROP_PIFF_IS_LIVE:
515       g_value_set_boolean(value, piffdemux->is_live);
516       break;
517     case PROP_PIFF_LOOKAHEAD_COUNT:
518       g_value_set_uint (value, piffdemux->lookahead_cnt);
519       break;
520     case PROP_PIFF_AVG_FRAME_DUR:
521       g_value_set_uint64 (value, piffdemux->stream->avg_dur);
522       break;
523 #ifdef DRM_ENABLE
524     case PROP_PROTECTION_HEADER_BUFFER:
525       gst_value_take_buffer (value, piffdemux->protection_header);
526       break;
527 #endif
528     default:
529       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
530       break;
531     }
532 }
533
534
535 static void
536 gst_piffdemux_post_no_playable_stream_error (GstPiffDemux * piffdemux)
537 {
538   if (piffdemux->posted_redirect) {
539     GST_ELEMENT_ERROR (piffdemux, STREAM, DEMUX,
540         ("This file contains no playable streams."),
541         ("no known streams found, a redirect message has been posted"));
542   } else {
543     GST_ELEMENT_ERROR (piffdemux, STREAM, DEMUX,
544         ("This file contains no playable streams."),
545         ("no known streams found"));
546   }
547
548 }
549
550 static gboolean
551 gst_piffdemux_src_convert (GstPad * pad, GstFormat src_format, gint64 src_value,
552     GstFormat dest_format, gint64 * dest_value)
553 {
554   gboolean res = TRUE;
555   PiffDemuxStream *stream = gst_pad_get_element_private (pad);
556   GstPiffDemux *piffdemux = GST_PIFFDEMUX (gst_pad_get_parent (pad));
557
558   if (stream->subtype != FOURCC_vide) {
559     res = FALSE;
560     goto done;
561   }
562
563   switch (src_format) {
564     case GST_FORMAT_TIME:
565       switch (dest_format) {
566         case GST_FORMAT_BYTES:{
567
568           break;
569         }
570         default:
571           res = FALSE;
572           break;
573       }
574       break;
575     case GST_FORMAT_BYTES:
576       switch (dest_format) {
577         case GST_FORMAT_TIME:{
578
579           break;
580         }
581         default:
582           res = FALSE;
583           break;
584       }
585       break;
586     default:
587       res = FALSE;
588   }
589
590 done:
591   gst_object_unref (piffdemux);
592
593   return res;
594 }
595
596 static const GstQueryType *
597 gst_piffdemux_get_src_query_types (GstPad * pad)
598 {
599   static const GstQueryType src_types[] = {
600     GST_QUERY_POSITION,
601     GST_QUERY_DURATION,
602     GST_QUERY_CONVERT,
603     GST_QUERY_FORMATS,
604     GST_QUERY_SEEKING,
605     0
606   };
607
608   return src_types;
609 }
610
611 static gboolean
612 gst_piffdemux_get_duration (GstPiffDemux * piffdemux, gint64 * duration)
613 {
614   gboolean res = TRUE;
615
616   *duration = GST_CLOCK_TIME_NONE;
617
618   if (piffdemux->stream->duration != 0) {
619     if (piffdemux->stream->duration != G_MAXINT64 && piffdemux->stream->timescale != 0) {
620       *duration = gst_util_uint64_scale (piffdemux->stream->duration,
621           GST_SECOND, piffdemux->stream->timescale);
622     }
623   }
624   return res;
625 }
626
627 static gboolean
628 gst_piffdemux_handle_src_query (GstPad * pad, GstQuery * query)
629 {
630   gboolean res = FALSE;
631   GstPiffDemux *piffdemux = GST_PIFFDEMUX (gst_pad_get_parent (pad));
632
633   GST_LOG_OBJECT (pad, "%s query", GST_QUERY_TYPE_NAME (query));
634
635   switch (GST_QUERY_TYPE (query)) {
636     case GST_QUERY_POSITION:
637       GST_ERROR ("Querying POSITION from piffdemux....");
638       if (GST_CLOCK_TIME_IS_VALID (piffdemux->segment.last_stop)) {
639         gst_query_set_position (query, GST_FORMAT_TIME,
640             piffdemux->segment.last_stop);
641         res = TRUE;
642       }
643       break;
644     case GST_QUERY_DURATION:{
645       GstFormat fmt;
646       GST_ERROR ("Querying DURATION from piffdemux....");
647
648       gst_query_parse_duration (query, &fmt, NULL);
649       if (fmt == GST_FORMAT_TIME) {
650         gint64 duration = -1;
651
652         gst_piffdemux_get_duration (piffdemux, &duration);
653         if (duration > 0) {
654           gst_query_set_duration (query, GST_FORMAT_TIME, duration);
655           res = TRUE;
656         }
657       }
658       break;
659     }
660     case GST_QUERY_CONVERT:{
661       GstFormat src_fmt, dest_fmt;
662       gint64 src_value, dest_value = 0;
663
664       gst_query_parse_convert (query, &src_fmt, &src_value, &dest_fmt, NULL);
665
666       res = gst_piffdemux_src_convert (pad,
667           src_fmt, src_value, dest_fmt, &dest_value);
668       if (res) {
669         gst_query_set_convert (query, src_fmt, src_value, dest_fmt, dest_value);
670         res = TRUE;
671       }
672       break;
673     }
674     case GST_QUERY_FORMATS:
675       gst_query_set_formats (query, 2, GST_FORMAT_TIME, GST_FORMAT_BYTES);
676       res = TRUE;
677       break;
678     case GST_QUERY_SEEKING:{
679
680       break;
681     }
682     default:
683       res = gst_pad_query_default (pad, query);
684       break;
685   }
686
687   gst_object_unref (piffdemux);
688
689   return res;
690 }
691
692
693 static void
694 gst_piffdemux_push_tags (GstPiffDemux * piffdemux, PiffDemuxStream * stream)
695 {
696   if (G_UNLIKELY (stream->pending_tags)) {
697     GST_DEBUG_OBJECT (piffdemux, "Sending tags %" GST_PTR_FORMAT,
698         stream->pending_tags);
699     gst_pad_push_event (piffdemux->srcpad,
700         gst_event_new_tag (stream->pending_tags));
701     stream->pending_tags = NULL;
702   }
703
704   if (G_UNLIKELY (stream->send_global_tags && piffdemux->tag_list)) {
705     GST_DEBUG_OBJECT (piffdemux, "Sending global tags %" GST_PTR_FORMAT,
706         piffdemux->tag_list);
707     gst_pad_push_event (piffdemux->srcpad,
708         gst_event_new_tag (gst_tag_list_copy (piffdemux->tag_list)));
709     stream->send_global_tags = FALSE;
710   }
711 }
712
713
714 static void
715 gst_piffdemux_push_event (GstPiffDemux * piffdemux, GstEvent * event)
716 {
717   GstEventType etype = GST_EVENT_TYPE (event);
718
719   GST_DEBUG_OBJECT (piffdemux, "pushing %s event on source pad",
720       GST_EVENT_TYPE_NAME (event));
721
722   if (piffdemux->stream->sent_eos) {
723     GST_INFO_OBJECT (piffdemux, "already sent eos");
724     return;
725   }
726
727   if (!gst_pad_push_event (piffdemux->srcpad, event)) {
728     GST_ERROR_OBJECT (piffdemux, "error in sending event to srcpad...");
729   }
730
731   if (etype == GST_EVENT_EOS)
732     piffdemux->stream->sent_eos = TRUE;
733 }
734
735
736 /* find the segment for @time_position for @stream
737  *
738  * Returns -1 if the segment cannot be found.
739  */
740 static guint32
741 gst_piffdemux_find_segment (GstPiffDemux * piffdemux, PiffDemuxStream * stream,
742     guint64 time_position)
743 {
744   gint i;
745   guint32 seg_idx;
746
747   GST_LOG_OBJECT (piffdemux, "finding segment for %" GST_TIME_FORMAT,
748       GST_TIME_ARGS (time_position));
749
750   /* find segment corresponding to time_position if we are looking
751    * for a segment. */
752   seg_idx = -1;
753   for (i = 0; i < stream->n_segments; i++) {
754     PiffDemuxSegment *segment = &stream->segments[i];
755
756     GST_LOG_OBJECT (piffdemux,
757         "looking at segment %" GST_TIME_FORMAT "-%" GST_TIME_FORMAT,
758         GST_TIME_ARGS (segment->time), GST_TIME_ARGS (segment->stop_time));
759
760     /* For the last segment we include stop_time in the last segment */
761     if (i < stream->n_segments - 1) {
762       if (segment->time <= time_position && time_position < segment->stop_time) {
763         GST_LOG_OBJECT (piffdemux, "segment %d matches", i);
764         seg_idx = i;
765         break;
766       }
767     } else {
768       if (segment->time <= time_position && time_position <= segment->stop_time) {
769         GST_LOG_OBJECT (piffdemux, "segment %d matches", i);
770         seg_idx = i;
771         break;
772       }
773     }
774   }
775   return seg_idx;
776 }
777
778
779 static gboolean
780 gst_piffdemux_handle_src_event (GstPad * pad, GstEvent * event)
781 {
782   gboolean res = TRUE;
783   GstPiffDemux *piffdemux = GST_PIFFDEMUX (gst_pad_get_parent (pad));
784
785   switch (GST_EVENT_TYPE (event)) {
786     case GST_EVENT_QOS:
787     case GST_EVENT_NAVIGATION:
788       res = FALSE;
789       gst_event_unref (event);
790       break;
791     case GST_EVENT_SEEK:
792     default:
793       res = gst_pad_event_default (pad, event);
794       break;
795   }
796
797   gst_object_unref (piffdemux);
798
799   return res;
800 }
801
802
803 static void
804 gst_piffdemux_move_stream (GstPiffDemux * piffdemux, PiffDemuxStream * str,
805     guint32 index)
806 {
807   /* no change needed */
808   if (index == str->sample_index)
809     return;
810
811   GST_DEBUG_OBJECT (piffdemux, "moving to sample %u of %u", index,
812       str->n_samples);
813
814   /* position changed, we have a discont */
815   str->sample_index = index;
816   /* Each time we move in the stream we store the position where we are
817    * starting from */
818   str->from_sample = index;
819   str->discont = TRUE;
820 }
821
822 // TODO: need to check more on this below function
823 /* stream/index return sample that is min/max w.r.t. byte position,
824  * time is min/max w.r.t. time of samples,
825  * the latter need not be time of the former sample */
826 static void
827 gst_piffdemux_find_sample (GstPiffDemux * piffdemux, gint64 byte_pos, gboolean fw,
828     gboolean set, PiffDemuxStream ** _stream, gint * _index, gint64 * _time)
829 {
830   gint i, index;
831   gint64 time, min_time;
832   PiffDemuxStream *stream;
833   PiffDemuxStream *str = piffdemux->stream;
834   gint inc;
835   gboolean set_sample;
836
837   min_time = -1;
838   stream = NULL;
839   index = -1;
840
841   set_sample = !set;
842   if (fw) {
843     i = 0;
844     inc = 1;
845   } else {
846     i = str->n_samples - 1;
847     inc = -1;
848   }
849
850   for (; (i >= 0) && (i < str->n_samples); i += inc) {
851     if (str->samples[i].size &&
852     ((fw && (str->samples[i].offset >= byte_pos)) ||
853     (!fw &&
854     (str->samples[i].offset + str->samples[i].size <=
855     byte_pos)))) {
856       /* move stream to first available sample */
857       if (set) {
858         gst_piffdemux_move_stream (piffdemux, str, i);
859         set_sample = TRUE;
860       }
861       /* determine min/max time */
862       time = str->samples[i].timestamp + str->samples[i].pts_offset;
863       time = gst_util_uint64_scale (time, GST_SECOND, str->timescale);
864       /*if (min_time == -1 || (!fw && time > min_time) ||
865       (fw && time < min_time)) : Dead code*/ {
866         min_time = time;
867       }
868       index = i;
869       break;
870     }
871   }
872   /* no sample for this stream, mark eos */
873   if (!set_sample)
874     gst_piffdemux_move_stream (piffdemux, str, str->n_samples);
875
876   if (_time)
877     *_time = min_time;
878   if (_stream)
879     *_stream = str;
880   if (_index)
881     *_index = index;
882 }
883
884
885 static gboolean
886 gst_piffdemux_handle_sink_event (GstPad * sinkpad, GstEvent * event)
887 {
888   GstPiffDemux *demux = GST_PIFFDEMUX (GST_PAD_PARENT (sinkpad));
889   gboolean res;
890
891   GST_LOG_OBJECT (demux, "handling %s event", GST_EVENT_TYPE_NAME (event));
892
893   switch (GST_EVENT_TYPE (event)) {
894     case GST_EVENT_NEWSEGMENT:
895     {
896       GstFormat format;
897       gdouble rate, arate;
898       gint64 start, stop, time, offset = 0;
899       PiffDemuxStream *stream;
900       gint idx;
901       gboolean update;
902       GstSegment segment;
903
904       /* some debug output */
905       gst_segment_init (&segment, GST_FORMAT_UNDEFINED);
906       gst_event_parse_new_segment_full (event, &update, &rate, &arate, &format,
907           &start, &stop, &time);
908       gst_segment_set_newsegment_full (&segment, update, rate, arate, format,
909           start, stop, time);
910       GST_ERROR_OBJECT (demux,
911           "received format %d newsegment %" GST_SEGMENT_FORMAT, format,
912           &segment);
913
914       /* chain will send initial newsegment after pads have been added */
915       if (demux->state != PIFFDEMUX_STATE_MOVIE ) {
916         GST_DEBUG_OBJECT (demux, "still starting, eating event");
917         goto exit;
918       }
919
920       /* we only expect a BYTE segment, e.g. following a seek */
921       if (format == GST_FORMAT_BYTES) {
922         if (start > 0) {
923           gint64 requested_seek_time;
924           guint64 seek_offset;
925
926           offset = start;
927
928           GST_OBJECT_LOCK (demux);
929           requested_seek_time = demux->requested_seek_time;
930           seek_offset = demux->seek_offset;
931           demux->requested_seek_time = -1;
932           demux->seek_offset = -1;
933           GST_OBJECT_UNLOCK (demux);
934
935           if (offset == seek_offset) {
936             start = requested_seek_time;
937           } else {
938             gst_piffdemux_find_sample (demux, start, TRUE, FALSE, NULL, NULL,
939                 &start);
940             start = MAX (start, 0);
941           }
942         }
943         if (stop > 0) {
944           gst_piffdemux_find_sample (demux, stop, FALSE, FALSE, NULL, NULL,
945               &stop);
946           /* keyframe seeking should already arrange for start >= stop,
947            * but make sure in other rare cases */
948           stop = MAX (stop, start);
949         }
950       }
951 #if 0
952       else if (format == GST_FORMAT_TIME) {
953           // Supporting TIME_FORMAT for new_segment
954           //gst_piffdemux_push_event (demux,event);
955         PiffDemuxStream *stream = NULL;
956         int i = -1;
957
958           demux->neededbytes = 16;
959           demux->state = PIFFDEMUX_STATE_INITIAL;
960           demux->offset = 0;
961
962         /* Figure out which stream this is packet belongs to */
963         for (i = 0; i < demux->n_streams; i++) {
964           stream = demux->streams[i];
965            stream->last_ts = start;
966            stream->discont = TRUE;
967            stream->sample_index = stream->n_samples;
968         }
969
970            /* accept upstream's notion of segment and distribute along */
971           gst_segment_set_newsegment_full (&demux->segment, update, rate, arate,
972               GST_FORMAT_TIME, start, stop, start);
973           GST_ERROR_OBJECT (demux, "Pushing newseg update %d, rate %g, "
974               "applied rate %g, format %d, start %" GST_TIME_FORMAT ", "
975               "stop %" GST_TIME_FORMAT, update, rate, arate, GST_FORMAT_TIME,
976               GST_TIME_ARGS (start), GST_TIME_ARGS (stop));
977
978           gst_piffdemux_push_event (demux,
979               gst_event_new_new_segment_full (update, rate, arate, GST_FORMAT_TIME, start, stop, start));
980
981            /* clear leftover in current segment, if any */
982           gst_adapter_clear (demux->adapter);
983
984           goto exit;
985       }
986 #endif
987       else {
988         GST_DEBUG_OBJECT (demux, "unsupported segment format, ignoring");
989         goto exit;
990       }
991
992       /* accept upstream's notion of segment and distribute along */
993       gst_segment_set_newsegment_full (&demux->segment, update, rate, arate,
994           GST_FORMAT_TIME, start, stop, start);
995       GST_ERROR_OBJECT (demux, "Pushing newseg update %d, rate %g, "
996           "applied rate %g, format %d, start %" GST_TIME_FORMAT ", "
997           "stop %" GST_TIME_FORMAT, update, rate, arate, GST_FORMAT_TIME,
998           GST_TIME_ARGS (start), GST_TIME_ARGS (stop));
999
1000       gst_piffdemux_push_event (demux,
1001           gst_event_new_new_segment_full (update, rate, arate, GST_FORMAT_TIME,
1002               start, stop, start));
1003
1004       /* clear leftover in current segment, if any */
1005       gst_adapter_clear (demux->adapter);
1006       /* set up streaming thread */
1007       gst_piffdemux_find_sample (demux, offset, TRUE, TRUE, &stream, &idx, NULL);
1008       demux->offset = offset;
1009       if (stream) {
1010         demux->todrop = stream->samples[idx].offset - offset;
1011         demux->neededbytes = demux->todrop + stream->samples[idx].size;
1012       } else {
1013         /* set up for EOS */
1014         demux->neededbytes = -1;
1015         demux->todrop = 0;
1016       }
1017     exit:
1018       gst_event_unref (event);
1019       res = TRUE;
1020       goto drop;
1021       break;
1022     }
1023     case GST_EVENT_FLUSH_STOP:
1024     {
1025       /* clean up, force EOS if no more info follows */
1026       gst_adapter_clear (demux->adapter);
1027       demux->offset = 0;
1028       demux->neededbytes = -1;
1029       /* reset flow return, e.g. following seek */
1030       demux->stream->last_ret = GST_FLOW_OK;
1031       demux->stream->sent_eos = FALSE;
1032       break;
1033     }
1034     case GST_EVENT_EOS:
1035       break;
1036     default:
1037       break;
1038   }
1039
1040   res = gst_pad_event_default (demux->sinkpad, event);
1041
1042 drop:
1043   return res;
1044 }
1045
1046
1047 static void
1048 gst_piffdemux_stream_free (GstPiffDemux * piffdemux, PiffDemuxStream * stream)
1049 {
1050   int i = 0;
1051
1052   g_return_if_fail (stream != NULL);
1053
1054   while (stream->buffers) {
1055     gst_buffer_unref (GST_BUFFER_CAST (stream->buffers->data));
1056     stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
1057   }
1058
1059   for (i = 0; i < stream->n_samples; i++) {
1060     if (stream->samples[i].iv) {
1061       free (stream->samples[i].iv);
1062       stream->samples[i].iv = NULL;
1063     }
1064     if (stream->samples[i].sub_encry) {
1065       if (stream->samples[i].sub_encry->sub_entry) {
1066         g_free (stream->samples[i].sub_encry->sub_entry);
1067         stream->samples[i].sub_encry->sub_entry = NULL;
1068       }
1069
1070       free (stream->samples[i].sub_encry);
1071       stream->samples[i].sub_encry = NULL;
1072     }
1073   }
1074
1075   if (stream->samples) {
1076     g_free (stream->samples);
1077     stream->samples = NULL;
1078   }
1079   if (stream->caps) {
1080     gst_caps_unref (stream->caps);
1081     stream->caps = NULL;
1082   }
1083   if (stream->segments) {
1084     g_free (stream->segments);
1085     stream->segments = NULL;
1086   }
1087   if (stream->pending_tags) {
1088     gst_tag_list_free (stream->pending_tags);
1089     stream->pending_tags = NULL;
1090   }
1091   g_free (stream);
1092 }
1093
1094
1095 static GstStateChangeReturn
1096 gst_piffdemux_change_state (GstElement * element, GstStateChange transition)
1097 {
1098   GstPiffDemux *piffdemux = GST_PIFFDEMUX (element);
1099   GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE;
1100
1101   switch (transition) {
1102     case GST_STATE_CHANGE_PAUSED_TO_READY:
1103       break;
1104     default:
1105       break;
1106   }
1107
1108   result = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
1109
1110   switch (transition) {
1111     case GST_STATE_CHANGE_PAUSED_TO_READY:{
1112       piffdemux->state = PIFFDEMUX_STATE_INITIAL;
1113       piffdemux->neededbytes = 16;
1114       piffdemux->todrop = 0;
1115       piffdemux->posted_redirect = FALSE;
1116       piffdemux->offset = 0;
1117       piffdemux->first_mdat = -1;
1118       piffdemux->mdatoffset = GST_CLOCK_TIME_NONE;
1119       if (piffdemux->mdatbuffer)
1120         gst_buffer_unref (piffdemux->mdatbuffer);
1121       piffdemux->mdatbuffer = NULL;
1122       if (piffdemux->tag_list)
1123         gst_tag_list_free (piffdemux->tag_list);
1124       piffdemux->tag_list = NULL;
1125       gst_adapter_clear (piffdemux->adapter);
1126       gst_piffdemux_stream_free (piffdemux, piffdemux->stream);
1127       gst_segment_init (&piffdemux->segment, GST_FORMAT_TIME);
1128       break;
1129     }
1130     default:
1131       break;
1132   }
1133
1134   return result;
1135 }
1136
1137 static void
1138 piffdemux_post_global_tags (GstPiffDemux * piffdemux)
1139 {
1140   if (piffdemux->tag_list) {
1141     /* all header tags ready and parsed, push them */
1142     GST_INFO_OBJECT (piffdemux, "posting global tags: %" GST_PTR_FORMAT,
1143         piffdemux->tag_list);
1144     /* post now, send event on pads later */
1145     gst_element_post_message (GST_ELEMENT (piffdemux),
1146         gst_message_new_tag (GST_OBJECT (piffdemux),
1147             gst_tag_list_copy (piffdemux->tag_list)));
1148   }
1149 }
1150
1151
1152 /* caller verifies at least 8 bytes in buf */
1153 static void
1154 extract_initial_length_and_fourcc (const guint8 * data, guint size,
1155     guint64 * plength, guint32 * pfourcc)
1156 {
1157   guint64 length;
1158   guint32 fourcc;
1159
1160   length = PIFF_UINT32 (data);
1161   GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
1162   fourcc = PIFF_FOURCC (data + 4);
1163   GST_DEBUG ("atom type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
1164
1165   if (length == 0) {
1166     length = G_MAXUINT32;
1167   } else if (length == 1 && size >= 16) {
1168     /* this means we have an extended size, which is the 64 bit value of
1169      * the next 8 bytes */
1170     length = PIFF_UINT64 (data + 8);
1171     GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
1172   }
1173
1174   if (plength)
1175     *plength = length;
1176   if (pfourcc)
1177     *pfourcc = fourcc;
1178 }
1179
1180 static gboolean
1181 piffdemux_update_sample_offset (GstPiffDemux * piffdemu, PiffDemuxStream * stream, gint64 uuid_offset)
1182 {
1183   PiffDemuxSample *sample;
1184   gint i;
1185
1186   sample = stream->samples ;
1187   for (i = 0; i < stream->n_samples; i++)
1188   {
1189     sample->offset = sample->offset + uuid_offset;
1190     sample++;
1191   }
1192   return TRUE;
1193 }
1194
1195 static uuid_type_t
1196 piffdemux_get_uuid_type(GstPiffDemux * piffdemux, GstByteReader *uuid_data, gint64 *uuid_offset)
1197 {
1198   uuid_type_t uuid_type = UUID_UNKNOWN;
1199   guint32 box_len = 0;
1200   guint64 box_long_len = 0;
1201   gchar uuid[16] = {0,};
1202   int i = 0;
1203
1204   if (!gst_byte_reader_get_uint32_be (uuid_data, &box_len))
1205     goto invalid_uuid;
1206
1207   /* Skipping fourcc */
1208   if (!gst_byte_reader_skip (uuid_data, 4))
1209     goto invalid_uuid;
1210
1211   if (box_len == 1)
1212   {
1213     GST_WARNING ("TfxdBoxLongLength field is present...");
1214     if (!gst_byte_reader_get_uint64_be (uuid_data, &box_long_len))
1215       goto invalid_uuid;
1216     GST_DEBUG ("tfxd long length = %llu", box_long_len);
1217
1218     *uuid_offset = box_long_len;
1219   }
1220   else
1221   {
1222     GST_DEBUG ("Box Len = %d", box_len);
1223     *uuid_offset = box_len;
1224   }
1225
1226   //g_print ("\n\n\n 0x");
1227   for (i = 0; i < sizeof (uuid); i++)
1228   {
1229     if (!gst_byte_reader_get_uint8 (uuid_data, &(uuid[i])))
1230       goto invalid_uuid;
1231     //g_print ("%02x", uuid[i]);
1232   }
1233   //g_print ("\n\n\n");
1234
1235   if (!memcmp(uuid, tfxd_uuid, sizeof (uuid_t)))
1236   {
1237     GST_INFO ("Found TFXD box");
1238     return UUID_TFXD;
1239   }
1240   else if (!memcmp(uuid, tfrf_uuid, sizeof (uuid_t)))
1241   {
1242     GST_INFO ("Found TFRF box");
1243     return UUID_TFRF;
1244   }
1245   else if (!memcmp(uuid, encrypt_uuid, sizeof (uuid_t)))
1246   {
1247     GST_INFO ("Found sample encryption box");
1248     return UUID_SAMPLE_ENCRYPT;
1249   }
1250   else
1251   {
1252     GST_WARNING ("Not an valid UUID box..");
1253     goto invalid_uuid;
1254   }
1255   return uuid_type;
1256
1257 invalid_uuid:
1258   GST_ERROR ("Error in parsing UUID atom...");
1259   return UUID_UNKNOWN;
1260 }
1261
1262 static gboolean
1263 piffdemux_parse_sample_encryption(GstPiffDemux * piffdemux, GstByteReader *sample_encrypt, PiffDemuxStream * stream)
1264 {
1265   guint32 flags = 0;
1266   guint32 sample_count = 0;
1267   guint32 i = 0;
1268   guint32 algo_id;
1269   guint8 iv_size = 0;
1270
1271   if (!gst_byte_reader_skip (sample_encrypt, 1) ||
1272       !gst_byte_reader_get_uint24_be (sample_encrypt, &flags))
1273     goto invalid_encryption;
1274
1275   if (flags & SE_OVERRIDE_TE_FLAGS) {
1276     /* get algorithm id */
1277     if (!gst_byte_reader_get_uint32_be (sample_encrypt, &algo_id))
1278       goto invalid_encryption;
1279
1280     /* get IV size */
1281     if (!gst_byte_reader_get_uint8 (sample_encrypt, &iv_size))
1282       goto invalid_encryption;
1283
1284     // TODO: need to add reading of KID
1285   } else {
1286     GST_INFO_OBJECT (piffdemux, "Override flags are not present... taking default IV_Size = 8");
1287     iv_size = 8;
1288   }
1289
1290   /* Get sample count*/
1291   if (!gst_byte_reader_get_uint32_be (sample_encrypt, &sample_count))
1292     goto invalid_encryption;
1293
1294   GST_INFO_OBJECT (piffdemux, "Sample count = %d", sample_count);
1295
1296   if (sample_count != stream->n_samples) {
1297     GST_ERROR_OBJECT (piffdemux, "Not all samples has IV vectors... Don't know how to handle. sample_cnt = %d and stream->n_samples = %d",
1298       sample_count, stream->n_samples);
1299     goto invalid_encryption;
1300   }
1301
1302   for (i = 0; i < stream->n_samples; i++) {
1303     guint8 iv_idx = iv_size;
1304
1305     /* resetting entire IV array */
1306     stream->samples[i].iv = (guint8 *)malloc (iv_size);
1307     if (NULL == stream->samples[i].iv) {
1308       GST_ERROR ("Failed to allocate memory...\n");
1309       goto invalid_encryption;
1310     }
1311
1312     memset (stream->samples[i].iv, 0x00, iv_size);
1313
1314     iv_idx = 0;
1315     while (iv_idx < iv_size) {
1316       /* get IV byte */
1317       if (!gst_byte_reader_get_uint8 (sample_encrypt, &(stream->samples[i].iv[iv_idx])))
1318         goto invalid_encryption;
1319
1320       iv_idx++;
1321     }
1322
1323 #ifdef DEBUG_IV
1324   {
1325     guint8 tmp_idx = 0;
1326     g_print ("sample[%d] : 0x ", i);
1327
1328     while (tmp_idx < iv_size ) {
1329       g_print ("%02x ", stream->samples[i].iv[tmp_idx]);
1330       tmp_idx++;
1331     }
1332     g_print ("\n");
1333   }
1334 #endif
1335
1336     if (flags & SE_USE_SUBSAMPLE_ENCRYPTION) {
1337       guint16 n_entries;
1338       guint16 n_idx;
1339
1340       /* NumberofEntries in SubSampleEncryption */
1341       if (!gst_byte_reader_get_uint16_be (sample_encrypt, &n_entries))
1342         goto invalid_encryption;
1343
1344       stream->samples[i].sub_encry = (PiffDemuxSubSampleEncryption *)malloc (sizeof (PiffDemuxSubSampleEncryption));
1345       if (NULL == stream->samples[i].sub_encry) {
1346         GST_ERROR ("Failed to allocate memory...\n");
1347         goto invalid_encryption;
1348       }
1349
1350       stream->samples[i].sub_encry->sub_entry = g_try_new0 (PiffDemuxSubSampleEntryInfo, n_entries);
1351       if (NULL == stream->samples[i].sub_encry->sub_entry) {
1352         GST_ERROR_OBJECT (piffdemux, "Failed to allocate memory...");
1353         goto invalid_encryption;
1354       }
1355
1356       stream->samples[i].sub_encry->n_entries = n_entries;
1357
1358       GST_DEBUG_OBJECT (piffdemux,"No. of subsample entries = %d", stream->samples[i].sub_encry->n_entries);
1359
1360       for (n_idx = 0; n_idx < n_entries; n_idx++) {
1361         if (!gst_byte_reader_get_uint16_be (sample_encrypt, &(stream->samples[i].sub_encry->sub_entry[n_idx].LenofClearData)))
1362           goto invalid_encryption;
1363
1364         GST_DEBUG_OBJECT (piffdemux,"entry[%d] and lengthofClearData = %d", n_idx, stream->samples[i].sub_encry->sub_entry[n_idx].LenofClearData);
1365
1366         if (!gst_byte_reader_get_uint32_be (sample_encrypt, &(stream->samples[i].sub_encry->sub_entry[n_idx].LenofEncryptData)))
1367           goto invalid_encryption;
1368
1369         GST_DEBUG_OBJECT (piffdemux,"entry[%d] and lengthofEncryptData = %d", n_idx, stream->samples[i].sub_encry->sub_entry[n_idx].LenofEncryptData);
1370       }
1371     }
1372   }
1373
1374   return TRUE;
1375
1376 invalid_encryption:
1377   {
1378     GST_WARNING_OBJECT (piffdemux, "invalid sample encryption header");
1379     return FALSE;
1380   }
1381 }
1382
1383
1384 static gboolean
1385 piffdemux_parse_trun (GstPiffDemux * piffdemux, GstByteReader * trun,
1386     PiffDemuxStream * stream, guint32 d_sample_duration, guint32 d_sample_size,
1387     guint32 d_sample_flags, gint64 moof_offset, gint64 moof_length,
1388     gint64 * base_offset, gint64 * running_offset)
1389 {
1390   guint64 timestamp;
1391   gint32 data_offset = 0;
1392   guint32 flags = 0, first_flags = 0, samples_count = 0;
1393   gint i;
1394   guint8 *data;
1395   guint entry_size, dur_offset, size_offset, flags_offset = 0, ct_offset = 0;
1396   PiffDemuxSample *sample;
1397   gboolean ismv = FALSE;
1398   guint64 total_duration = 0;
1399
1400   GST_LOG_OBJECT (piffdemux, "parsing trun stream ; "
1401       "default dur %d, size %d, flags 0x%x, base offset %" G_GINT64_FORMAT,
1402        d_sample_duration, d_sample_size, d_sample_flags,
1403       *base_offset);
1404
1405   //Resetting the samples
1406   stream->n_samples = 0;
1407
1408   if (!gst_byte_reader_skip (trun, 1) ||
1409       !gst_byte_reader_get_uint24_be (trun, &flags))
1410     goto fail;
1411
1412   if (!gst_byte_reader_get_uint32_be (trun, &samples_count))
1413     goto fail;
1414
1415   if (flags & TR_DATA_OFFSET) {
1416     /* note this is really signed */
1417     if (!gst_byte_reader_get_int32_be (trun, &data_offset))
1418       goto fail;
1419     GST_LOG_OBJECT (piffdemux, "trun data offset %d", data_offset);
1420     /* default base offset = first byte of moof */
1421     if (*base_offset == -1) {
1422       GST_LOG_OBJECT (piffdemux, "base_offset at moof and moof_offset = %"G_GINT64_FORMAT, moof_offset);
1423       *base_offset = moof_offset;
1424     }
1425     *running_offset = *base_offset + data_offset;
1426   } else {
1427     /* if no offset at all, that would mean data starts at moof start,
1428      * which is a bit wrong and is ismv crappy way, so compensate
1429      * assuming data is in mdat following moof */
1430     if (*base_offset == -1) {
1431       *base_offset = moof_offset + moof_length + 8;
1432       GST_LOG_OBJECT (piffdemux, "base_offset assumed in mdat after moof");
1433       ismv = TRUE;
1434     }
1435     if (*running_offset == -1)
1436       *running_offset = *base_offset;
1437   }
1438
1439   GST_LOG_OBJECT (piffdemux, "running offset now %" G_GINT64_FORMAT,
1440       *running_offset);
1441   GST_LOG_OBJECT (piffdemux, "trun offset %d, flags 0x%x, entries %d",
1442       data_offset, flags, samples_count);
1443
1444   if (flags & TR_FIRST_SAMPLE_FLAGS) {
1445     if (G_UNLIKELY (flags & TR_SAMPLE_FLAGS)) {
1446       GST_DEBUG_OBJECT (piffdemux,
1447           "invalid flags; SAMPLE and FIRST_SAMPLE present, discarding latter");
1448       flags ^= TR_FIRST_SAMPLE_FLAGS;
1449     } else {
1450       if (!gst_byte_reader_get_uint32_be (trun, &first_flags))
1451         goto fail;
1452       GST_LOG_OBJECT (piffdemux, "first flags: 0x%x", first_flags);
1453     }
1454   }
1455
1456   /* FIXME ? spec says other bits should also be checked to determine
1457    * entry size (and prefix size for that matter) */
1458   entry_size = 0;
1459   dur_offset = size_offset = 0;
1460   if (flags & TR_SAMPLE_DURATION) {
1461     GST_LOG_OBJECT (piffdemux, "entry duration present");
1462     dur_offset = entry_size;
1463     entry_size += 4;
1464   }
1465   if (flags & TR_SAMPLE_SIZE) {
1466     GST_LOG_OBJECT (piffdemux, "entry size present");
1467     size_offset = entry_size;
1468     entry_size += 4;
1469   }
1470   if (flags & TR_SAMPLE_FLAGS) {
1471     GST_LOG_OBJECT (piffdemux, "entry flags present");
1472     flags_offset = entry_size;
1473     entry_size += 4;
1474   }
1475   if (flags & TR_COMPOSITION_TIME_OFFSETS) {
1476     GST_LOG_OBJECT (piffdemux, "entry ct offset present");
1477     ct_offset = entry_size;
1478     entry_size += 4;
1479   }
1480
1481   if (!piff_atom_parser_has_chunks (trun, samples_count, entry_size))
1482     goto fail;
1483   data = (guint8 *) gst_byte_reader_peek_data_unchecked (trun);
1484
1485   if (stream->n_samples >=
1486       PIFFDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (PiffDemuxSample))
1487     goto index_too_big;
1488
1489   GST_DEBUG_OBJECT (piffdemux, "allocating n_samples %u * %u (%.2f MB)",
1490       stream->n_samples, (guint) sizeof (PiffDemuxSample),
1491       stream->n_samples * sizeof (PiffDemuxSample) / (1024.0 * 1024.0));
1492
1493   /* create a new array of samples if it's the first sample parsed */
1494   if (stream->n_samples == 0)
1495     stream->samples = g_try_new0 (PiffDemuxSample, samples_count);
1496   /* or try to reallocate it with space enough to insert the new samples */
1497   else
1498     stream->samples = g_try_renew (PiffDemuxSample, stream->samples,
1499         stream->n_samples + samples_count);
1500   if (stream->samples == NULL)
1501     goto out_of_memory;
1502
1503   if (G_UNLIKELY (stream->n_samples == 0)) {
1504     /* the timestamp of the first sample is also provided by the tfra entry
1505      * but we shouldn't rely on it as it is at the end of files */
1506     timestamp = 0;
1507   } else {
1508     /* subsequent fragments extend stream */
1509     timestamp =
1510         stream->samples[stream->n_samples - 1].timestamp +
1511         stream->samples[stream->n_samples - 1].duration;
1512   }
1513   sample = stream->samples + stream->n_samples;
1514   for (i = 0; i < samples_count; i++) {
1515     guint32 dur, size, sflags, ct;
1516
1517     /* first read sample data */
1518     if (flags & TR_SAMPLE_DURATION) {
1519       dur = PIFF_UINT32 (data + dur_offset);
1520     } else {
1521       dur = d_sample_duration;
1522     }
1523     if (flags & TR_SAMPLE_SIZE) {
1524       size = PIFF_UINT32 (data + size_offset);
1525     } else {
1526       size = d_sample_size;
1527     }
1528
1529     GST_DEBUG_OBJECT(piffdemux,"Size of sample %d is %d", i, size);
1530
1531     if (flags & TR_FIRST_SAMPLE_FLAGS) {
1532       if (i == 0) {
1533         sflags = first_flags;
1534       } else {
1535         sflags = d_sample_flags;
1536       }
1537     } else if (flags & TR_SAMPLE_FLAGS) {
1538       sflags = PIFF_UINT32 (data + flags_offset);
1539     } else {
1540       sflags = d_sample_flags;
1541     }
1542     if (flags & TR_COMPOSITION_TIME_OFFSETS) {
1543       ct = PIFF_UINT32 (data + ct_offset);
1544     } else {
1545       ct = 0;
1546     }
1547     data += entry_size;
1548
1549     /* fill the sample information */
1550     sample->offset = *running_offset;
1551     sample->pts_offset = ct;
1552     sample->size = size;
1553     sample->timestamp = timestamp;
1554     sample->duration = dur;
1555     /* sample-is-difference-sample */
1556     /* ismv seems to use 0x40 for keyframe, 0xc0 for non-keyframe,
1557      * now idea how it relates to bitfield other than massive LE/BE confusion */
1558     sample->keyframe = ismv ? ((sflags & 0xff) == 0x40) : !(sflags & 0x10000);
1559     sample->iv = NULL;
1560     sample->sub_encry = NULL;
1561
1562     stream->samples[i] = *sample;
1563
1564     *running_offset += size;
1565     timestamp += dur;
1566     sample++;
1567
1568     /* calculate total duration of the present fragment */
1569     total_duration += gst_util_uint64_scale (dur, GST_SECOND, stream->timescale);
1570   }
1571
1572   stream->sample_index = 0;
1573
1574   stream->n_samples += samples_count;
1575
1576   /* calculate avg fps based on avg frame duration */
1577   stream->avg_dur = total_duration/samples_count;
1578   g_print ("total dur = %"GST_TIME_FORMAT", avg_dur = %"GST_TIME_FORMAT"count = %d\n",
1579         GST_TIME_ARGS(total_duration), GST_TIME_ARGS(stream->avg_dur), samples_count);
1580
1581   return TRUE;
1582
1583 fail:
1584   {
1585     GST_WARNING_OBJECT (piffdemux, "failed to parse trun");
1586     return FALSE;
1587   }
1588 out_of_memory:
1589   {
1590     GST_WARNING_OBJECT (piffdemux, "failed to allocate %d samples",
1591         stream->n_samples);
1592     return FALSE;
1593   }
1594 index_too_big:
1595   {
1596     GST_WARNING_OBJECT (piffdemux, "not allocating index of %d samples, would "
1597         "be larger than %uMB (broken file?)", stream->n_samples,
1598         PIFFDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
1599     return FALSE;
1600   }
1601 }
1602
1603 static gboolean
1604 piffdemux_parse_mfhd (GstPiffDemux * piffdemux, GstByteReader * mfhd)
1605 {
1606   guint32 seq_num = 0;
1607
1608   if (!gst_byte_reader_skip (mfhd, 4))
1609     goto invalid_mfhd;
1610
1611   if (!gst_byte_reader_get_uint32_be (mfhd, &seq_num))
1612     goto invalid_mfhd;
1613
1614   GST_DEBUG_OBJECT (piffdemux, "sequence number present in mfhd = %d", seq_num);
1615
1616   return TRUE;
1617
1618 invalid_mfhd:
1619   {
1620     GST_WARNING_OBJECT (piffdemux, "invalid movie fragment header");
1621     return FALSE;
1622   }
1623 }
1624
1625
1626 static gboolean
1627 piffdemux_parse_tfhd (GstPiffDemux * piffdemux, GstByteReader * tfhd,
1628     guint32 * default_sample_duration,
1629     guint32 * default_sample_size, guint32 * default_sample_flags,
1630     gint64 * base_offset)
1631 {
1632   guint32 flags = 0;
1633   guint32 track_id = 0;
1634
1635   if (!gst_byte_reader_skip (tfhd, 1) ||
1636       !gst_byte_reader_get_uint24_be (tfhd, &flags))
1637     goto invalid_track;
1638
1639   if (!gst_byte_reader_get_uint32_be (tfhd, &track_id))
1640     goto invalid_track;
1641
1642   GST_DEBUG_OBJECT (piffdemux, "trackID = %d", track_id);
1643
1644   if (flags & TF_BASE_DATA_OFFSET) {
1645     if (!gst_byte_reader_get_uint64_be (tfhd, (guint64 *) base_offset))
1646       goto invalid_track;
1647     GST_DEBUG ("BaseData Offset = %"G_GUINT64_FORMAT, base_offset);
1648   }
1649
1650   /* FIXME: Handle TF_SAMPLE_DESCRIPTION_INDEX properly */
1651   if (flags & TF_SAMPLE_DESCRIPTION_INDEX)
1652     if (!gst_byte_reader_skip (tfhd, 4))
1653       goto invalid_track;
1654
1655   if (flags & TF_DEFAULT_SAMPLE_DURATION)
1656     if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_duration))
1657       goto invalid_track;
1658
1659   if (flags & TF_DEFAULT_SAMPLE_SIZE)
1660     if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_size))
1661       goto invalid_track;
1662
1663   if (flags & TF_DEFAULT_SAMPLE_FLAGS)
1664     if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_flags))
1665       goto invalid_track;
1666
1667   return TRUE;
1668
1669 invalid_track:
1670   {
1671     GST_WARNING_OBJECT (piffdemux, "invalid track fragment header");
1672     return FALSE;
1673   }
1674 }
1675
1676 static gboolean
1677 piffdemux_parse_tfxd (GstPiffDemux * piffdemux, PiffDemuxStream *stream,GstByteReader * tfxd)
1678 {
1679   guint8 version = 0;
1680
1681   // TODO: In my opinion, tfxd will be mainly useful when lookahead count = 0. In this case, based on this duration, next fragment timstamp can be calculted.. Need to test this using our server
1682
1683   if (!gst_byte_reader_get_uint8 (tfxd, &version))
1684     goto invalid_tfxd;
1685
1686   if (!gst_byte_reader_skip (tfxd, 3))
1687     goto invalid_tfxd;
1688
1689   if (!piffdemux->lookahead_cnt) {
1690     piffdemux->param = (piff_live_param_t *)malloc (sizeof (piff_live_param_t));
1691     if (NULL == piffdemux->param) {
1692       GST_ERROR_OBJECT (piffdemux, "Memory not available...\n");
1693       return FALSE;
1694     }
1695     piffdemux->param->count = 1;
1696     piffdemux->param->long_info = NULL;
1697     piffdemux->param->info = NULL;
1698     piffdemux->param->is_eos = FALSE;
1699
1700     // TODO: presentation will be ended based on timeout in souphttpsrc in lookaheadcnt = 0 case
1701   }
1702
1703   if (version == 1) {
1704     guint64 duration = 0;
1705     guint64 timestamp = 0;
1706
1707     GST_LOG_OBJECT (piffdemux, "Time and Duration are in 64-bit format...");
1708     if (!gst_byte_reader_get_uint64_be (tfxd, &timestamp))
1709       goto invalid_tfxd;
1710     if (!gst_byte_reader_get_uint64_be (tfxd, &duration))
1711       goto invalid_tfxd;
1712
1713     GST_DEBUG_OBJECT (piffdemux, "tfxd : absolute timestamp = %"G_GUINT64_FORMAT" and duration of fragment = %"G_GUINT64_FORMAT,
1714         timestamp, duration);
1715
1716     if (!piffdemux->lookahead_cnt) {
1717       piffdemux->param->long_info = (piff_fragment_longtime_info *)malloc (piffdemux->param->count * sizeof (piff_fragment_longtime_info));
1718       if (NULL == piffdemux->param->long_info) {
1719         GST_ERROR_OBJECT (piffdemux, "Memory not available...\n");
1720         return FALSE;
1721       }
1722
1723       /* Calculate next fragment's timestamp using current fragment's timestamp + duration */
1724       piffdemux->param->long_info->duration = GST_CLOCK_TIME_NONE;
1725       piffdemux->param->long_info->ts = timestamp +duration;
1726     }
1727   } else if (version == 0) {
1728     guint32 duration = 0;
1729     guint32 timestamp = 0;
1730     GST_LOG_OBJECT (piffdemux, "Time and Duration are in 32-bit format...");
1731
1732     if (!gst_byte_reader_get_uint32_be (tfxd, &timestamp))
1733       goto invalid_tfxd;
1734
1735     if (!gst_byte_reader_get_uint32_be (tfxd, &duration))
1736       goto invalid_tfxd;
1737
1738     GST_DEBUG_OBJECT (piffdemux, "tfxd : absolute timestamp = %"G_GUINT32_FORMAT" and duration of fragment = %"G_GUINT32_FORMAT,
1739         timestamp, duration);
1740
1741     if (!piffdemux->lookahead_cnt) {
1742       piffdemux->param->info = (piff_fragment_time_info *)malloc (piffdemux->param->count * sizeof (piff_fragment_time_info));
1743       if (NULL == piffdemux->param->info) {
1744         GST_ERROR_OBJECT (piffdemux, "Memory not available...\n");
1745         return FALSE;
1746       }
1747       /* Calculate next fragment's timestamp using current fragment's timestamp + duration */
1748       piffdemux->param->info->duration = GST_CLOCK_TIME_NONE;
1749       piffdemux->param->info->ts = timestamp +duration;
1750     }
1751   } else {
1752     GST_ERROR_OBJECT (piffdemux, "Invalid Version in tfxd...");
1753     return FALSE;
1754   }
1755
1756   if (!piffdemux->lookahead_cnt) {
1757     GST_DEBUG_OBJECT (piffdemux, "Emitting live-param signal...");
1758     g_signal_emit (piffdemux, gst_piffdemux_signals[SIGNAL_LIVE_PARAM], 0, piffdemux->param);
1759   }
1760
1761   return TRUE;
1762
1763 invalid_tfxd:
1764   GST_ERROR ("Invalid TFXD atom...");
1765   return FALSE;
1766 }
1767
1768
1769 static gboolean
1770 piffdemux_parse_tfrf (GstPiffDemux * piffdemux, PiffDemuxStream *stream,GstByteReader * tfrf)
1771 {
1772   guint8 version = 0;
1773   guint8 frag_cnt = 0;
1774   guint8 i = 0;
1775
1776   /* Getting version info */
1777   if (!gst_byte_reader_get_uint8 (tfrf, &version))
1778     goto invalid_tfrf;
1779
1780   /* skipping reserved flags */
1781   if (!gst_byte_reader_skip (tfrf, 3))
1782     goto invalid_tfrf;
1783
1784   if (!gst_byte_reader_get_uint8 (tfrf, &frag_cnt))
1785     goto invalid_tfrf;
1786
1787   GST_INFO_OBJECT (piffdemux, "Subsequent fragments info count = %d", frag_cnt);
1788
1789   piffdemux->param = (piff_live_param_t *)malloc(sizeof (piff_live_param_t));
1790   if (NULL == piffdemux->param) {
1791     GST_ERROR_OBJECT (piffdemux, "Memory not available...\n");
1792     return FALSE;
1793   }
1794
1795   piffdemux->param->count = frag_cnt;
1796   piffdemux->param->long_info = NULL;
1797   piffdemux->param->info = NULL;
1798   piffdemux->param->is_eos = FALSE;
1799
1800   // TODO: Duration and timestamp values need to be posted to msl using g_signal_emit
1801
1802   if (version == 1) {
1803     guint64 duration = 0;
1804     guint64 timestamp = 0;
1805     GST_LOG_OBJECT (piffdemux, "Time and Duration are in 64-bit format...");
1806
1807     piffdemux->param->long_info = (piff_fragment_longtime_info *)malloc (piffdemux->param->count * sizeof (piff_fragment_longtime_info));
1808     if (NULL == piffdemux->param->long_info) {
1809       GST_ERROR_OBJECT (piffdemux, "Memory not available...\n");
1810       return FALSE;
1811     }
1812
1813     for (i = 0; i < frag_cnt; i++) {
1814       if (!gst_byte_reader_get_uint64_be (tfrf, &timestamp))
1815         goto invalid_tfrf;
1816       if (!gst_byte_reader_get_uint64_be (tfrf, &duration))
1817         goto invalid_tfrf;
1818       GST_DEBUG_OBJECT (piffdemux, "tfrf long: absolute timestamp = %"G_GUINT64_FORMAT" and duration of fragment = %"G_GUINT64_FORMAT"\n",
1819           timestamp, duration);
1820       (piffdemux->param->long_info[i]).ts = timestamp;
1821       (piffdemux->param->long_info[i]).duration = duration;
1822     }
1823   } else if (version == 0) {
1824     guint32 duration = 0;
1825     guint32 timestamp = 0;
1826     GST_LOG_OBJECT (piffdemux, "Time and Duration are in 32-bit format...");
1827
1828     piffdemux->param->info = (piff_fragment_time_info *)malloc (piffdemux->param->count * sizeof (piff_fragment_time_info));
1829     if (NULL == piffdemux->param->info) {
1830       GST_ERROR ("Memory not available...\n");
1831       return FALSE;
1832     }
1833
1834     for (i = 0; i < frag_cnt; i++) {
1835       if (!gst_byte_reader_get_uint32_be (tfrf, &timestamp))
1836         goto invalid_tfrf;
1837       if (!gst_byte_reader_get_uint32_be (tfrf, &duration))
1838         goto invalid_tfrf;
1839
1840       GST_DEBUG_OBJECT (piffdemux, "tfrf int: absolute timestamp = %"G_GUINT32_FORMAT" and duration of fragment = %"G_GUINT32_FORMAT,
1841           timestamp, duration);
1842       (piffdemux->param->info[i]).ts = timestamp;
1843       (piffdemux->param->info[i]).duration = duration;
1844     }
1845   } else {
1846     GST_ERROR_OBJECT (piffdemux, "Invalid Version in tfrf...");
1847     return FALSE;
1848   }
1849
1850   g_print ("Signalling from TFRF box..\n");
1851   g_signal_emit (piffdemux, gst_piffdemux_signals[SIGNAL_LIVE_PARAM], 0, piffdemux->param);
1852
1853   return TRUE;
1854
1855 invalid_tfrf:
1856   GST_ERROR_OBJECT (piffdemux, "Invalid TFRF atom...");
1857   return FALSE;
1858 }
1859
1860
1861 static gboolean
1862 piffdemux_parse_moof (GstPiffDemux * piffdemux, const guint8 * buffer, guint length,
1863     guint64 moof_offset, PiffDemuxStream * stream)
1864 {
1865   GNode *moof_node, *mfhd_node, *traf_node, *tfhd_node, *trun_node, *uuid_node;
1866   GstByteReader mfhd_data, trun_data, tfhd_data, uuid_data;
1867   guint32 ds_size = 0, ds_duration = 0, ds_flags = 0;
1868   gint64 base_offset, running_offset;
1869   gint64 uuid_offset = 0;
1870   gboolean found_tfxd = FALSE;
1871   gboolean found_tfrf = FALSE;
1872
1873   /* NOTE @stream ignored */
1874
1875   moof_node = g_node_new ((guint8 *) buffer);
1876   piffdemux_parse_node (piffdemux, moof_node, buffer, length);
1877   //piffdemux_node_dump (piffdemux, moof_node);
1878
1879   /* unknown base_offset to start with */
1880   base_offset = running_offset = -1;
1881
1882   mfhd_node = piffdemux_tree_get_child_by_type_full (moof_node, FOURCC_mfhd, &mfhd_data);
1883   if (!mfhd_node)
1884     goto missing_mfhd;
1885
1886   if (!piffdemux_parse_mfhd (piffdemux, &mfhd_data))
1887     goto missing_mfhd;
1888
1889   traf_node = piffdemux_tree_get_child_by_type (moof_node, FOURCC_traf);
1890   while (traf_node) {
1891     /* Fragment Header node */
1892     tfhd_node =
1893         piffdemux_tree_get_child_by_type_full (traf_node, FOURCC_tfhd,
1894         &tfhd_data);
1895     if (!tfhd_node)
1896       goto missing_tfhd;
1897     if (!piffdemux_parse_tfhd (piffdemux, &tfhd_data, &ds_duration,
1898             &ds_size, &ds_flags, &base_offset))
1899       goto missing_tfhd;
1900
1901     if (G_UNLIKELY (base_offset < -1))
1902       goto lost_offset;
1903
1904     /* Track Run node */
1905     trun_node =
1906         piffdemux_tree_get_child_by_type_full (traf_node, FOURCC_trun,
1907         &trun_data);
1908     while (trun_node) {
1909       piffdemux_parse_trun (piffdemux, &trun_data, stream,
1910           ds_duration, ds_size, ds_flags, moof_offset, length, &base_offset,
1911           &running_offset);
1912       /* iterate all siblings */
1913       trun_node = piffdemux_tree_get_sibling_by_type_full (trun_node, FOURCC_trun,
1914           &trun_data);
1915     }
1916
1917     uuid_node =  piffdemux_tree_get_child_by_type (traf_node, FOURCC_uuid);
1918     while (uuid_node) {
1919       uuid_type_t uuid_type;
1920       guint8 *lbuffer = (guint8 *) uuid_node->data;
1921
1922       gst_byte_reader_init (&uuid_data, lbuffer, PIFF_UINT32 (lbuffer));
1923
1924       uuid_type = piffdemux_get_uuid_type (piffdemux, &uuid_data, &uuid_offset);
1925
1926       if ((UUID_TFXD == uuid_type) && piffdemux->is_live) {
1927         // TODO: Dont know, why we should not consider tfxd offset...if we use tfxd offset also, not working.. PIFF doc does not say anything :(
1928         found_tfxd = TRUE;
1929         if (!piffdemux_parse_tfxd (piffdemux, stream, &uuid_data))
1930           goto fail;
1931       } else if ((UUID_TFRF == uuid_type) && piffdemux->is_live && piffdemux->lookahead_cnt) {
1932         found_tfrf = TRUE;
1933         if (!piffdemux_parse_tfrf (piffdemux, stream, &uuid_data))
1934           goto fail;
1935          piffdemux_update_sample_offset (piffdemux, stream, uuid_offset);
1936         running_offset += uuid_offset;
1937       } else if (UUID_SAMPLE_ENCRYPT == uuid_type) {
1938         if (!piffdemux_parse_sample_encryption (piffdemux, &uuid_data, stream))
1939           goto fail;
1940       } else {
1941         GST_WARNING_OBJECT (piffdemux, "Ignoring Wrong UUID...");
1942       }
1943
1944       /* iterate all siblings */
1945       uuid_node = piffdemux_tree_get_sibling_by_type (uuid_node, FOURCC_uuid);
1946     }
1947
1948     if (piffdemux->is_live) {
1949       if (!found_tfxd) {
1950         GST_ERROR_OBJECT (piffdemux, "TFXD box is not present for live stream");
1951         goto fail;
1952       }
1953
1954       if (!found_tfrf && piffdemux->lookahead_cnt) {
1955         /* when lookahead count is non-zero in manifest & if tfrf box is not present., means EOS */
1956         GST_INFO_OBJECT (piffdemux, "Reached Endof Live presentation..");
1957
1958         piffdemux->param = (piff_live_param_t *)malloc (sizeof (piff_live_param_t));
1959         if (NULL == piffdemux->param) {
1960           GST_ERROR_OBJECT (piffdemux, "Memory not available...\n");
1961           goto fail;
1962         }
1963         piffdemux->param->count = 0;
1964         piffdemux->param->long_info = NULL;
1965         piffdemux->param->info = NULL;
1966         piffdemux->param->is_eos = TRUE; /* marking EOS */
1967         g_signal_emit (piffdemux, gst_piffdemux_signals[SIGNAL_LIVE_PARAM], 0, piffdemux->param);
1968       }
1969     }
1970
1971     /* if no new base_offset provided for next traf,
1972      * base is end of current traf */
1973     base_offset = running_offset;
1974     running_offset = -1;
1975
1976     /* iterate all siblings */
1977     traf_node = piffdemux_tree_get_sibling_by_type (traf_node, FOURCC_traf);
1978   }
1979   g_node_destroy (moof_node);
1980   return TRUE;
1981
1982 missing_mfhd:
1983   {
1984     GST_DEBUG_OBJECT (piffdemux, "missing mfhd box");
1985     goto fail;
1986   }
1987
1988 missing_tfhd:
1989   {
1990     GST_DEBUG_OBJECT (piffdemux, "missing tfhd box");
1991     goto fail;
1992   }
1993 lost_offset:
1994   {
1995     GST_DEBUG_OBJECT (piffdemux, "lost offset");
1996     goto fail;
1997   }
1998 fail:
1999   {
2000     g_node_destroy (moof_node);
2001
2002     GST_ELEMENT_ERROR (piffdemux, STREAM, DEMUX,
2003         ("This file is corrupt and cannot be played."), (NULL));
2004
2005     return FALSE;
2006   }
2007 }
2008
2009
2010 /* activate the given segment number @seg_idx of @stream at time @offset.
2011  * @offset is an absolute global position over all the segments.
2012  *
2013  * This will push out a NEWSEGMENT event with the right values and
2014  * position the stream index to the first decodable sample before
2015  * @offset.
2016  */
2017 static gboolean
2018 gst_piffdemux_activate_segment (GstPiffDemux * piffdemux, PiffDemuxStream * stream,
2019     guint32 seg_idx, guint64 offset)
2020 {
2021   GstEvent *event;
2022   PiffDemuxSegment *segment;
2023   guint64 seg_time;
2024   guint64 start, stop, time;
2025   gdouble rate;
2026
2027   GST_LOG_OBJECT (piffdemux, "activate segment %d, offset %" G_GUINT64_FORMAT,
2028       seg_idx, offset);
2029
2030   /* update the current segment */
2031   stream->segment_index = seg_idx;
2032
2033   /* get the segment */
2034   segment = &stream->segments[seg_idx];
2035
2036   if (G_UNLIKELY (offset < segment->time)) {
2037     GST_WARNING_OBJECT (piffdemux, "offset < segment->time %" G_GUINT64_FORMAT,
2038         segment->time);
2039     return FALSE;
2040   }
2041
2042   /* segment lies beyond total indicated duration */
2043   if (G_UNLIKELY (piffdemux->segment.duration != -1 &&
2044           segment->time > piffdemux->segment.duration)) {
2045     GST_WARNING_OBJECT (piffdemux, "file duration %" G_GINT64_FORMAT
2046         " < segment->time %" G_GUINT64_FORMAT, piffdemux->segment.duration,
2047         segment->time);
2048     return FALSE;
2049   }
2050
2051   /* get time in this segment */
2052   seg_time = offset - segment->time;
2053
2054   GST_LOG_OBJECT (piffdemux, "seg_time %" GST_TIME_FORMAT,
2055       GST_TIME_ARGS (seg_time));
2056
2057   if (G_UNLIKELY (seg_time > segment->duration)) {
2058     GST_LOG_OBJECT (piffdemux, "seg_time > segment->duration %" GST_TIME_FORMAT,
2059         GST_TIME_ARGS (segment->duration));
2060     return FALSE;
2061   }
2062
2063   /* piffdemux->segment.stop is in outside-time-realm, whereas
2064    * segment->media_stop is in track-time-realm.
2065    *
2066    * In order to compare the two, we need to bring segment.stop
2067    * into the track-time-realm */
2068
2069   stop = piffdemux->segment.stop;
2070   if (stop == -1)
2071     stop = piffdemux->segment.duration;
2072   if (stop == -1)
2073     stop = segment->media_stop;
2074   else
2075     stop =
2076         MIN (segment->media_stop, stop - segment->time + segment->media_start);
2077
2078   if (piffdemux->segment.rate >= 0) {
2079     start = MIN (segment->media_start + seg_time, stop);
2080     time = offset;
2081   } else {
2082     if (segment->media_start >= piffdemux->segment.start) {
2083       start = segment->media_start;
2084       time = segment->time;
2085     } else {
2086       start = piffdemux->segment.start;
2087       time = segment->time + (piffdemux->segment.start - segment->media_start);
2088     }
2089
2090     start = MAX (segment->media_start, piffdemux->segment.start);
2091     stop = MIN (segment->media_start + seg_time, stop);
2092   }
2093
2094   GST_DEBUG_OBJECT (piffdemux, "newsegment %d from %" GST_TIME_FORMAT
2095       " to %" GST_TIME_FORMAT ", time %" GST_TIME_FORMAT, seg_idx,
2096       GST_TIME_ARGS (start), GST_TIME_ARGS (stop), GST_TIME_ARGS (time));
2097
2098   /* combine global rate with that of the segment */
2099   rate = segment->rate * piffdemux->segment.rate;
2100
2101   /* update the segment values used for clipping */
2102   gst_segment_init (&stream->segment, GST_FORMAT_TIME);
2103   gst_segment_set_newsegment (&stream->segment, FALSE, rate, GST_FORMAT_TIME,
2104       start, stop, time);
2105
2106   /* now prepare and send the segment */
2107   event = gst_event_new_new_segment (FALSE, rate, GST_FORMAT_TIME,
2108       start, stop, time);
2109   gst_pad_push_event (piffdemux->srcpad, event);
2110   /* assume we can send more data now */
2111   stream->last_ret = GST_FLOW_OK;
2112   /* clear to send tags on this pad now */
2113   gst_piffdemux_push_tags (piffdemux, stream);
2114
2115   return TRUE;
2116 }
2117
2118
2119 /* prepare to get the current sample of @stream, getting essential values.
2120  *
2121  * This function will also prepare and send the segment when needed.
2122  *
2123  * Return FALSE if the stream is EOS.
2124  */
2125 static gboolean
2126 gst_piffdemux_prepare_current_sample (GstPiffDemux * piffdemux,
2127     PiffDemuxStream * stream, guint64 * offset, guint * size, guint64 * timestamp,
2128     guint64 * duration, gboolean * keyframe)
2129 {
2130   PiffDemuxSample *sample;
2131   guint64 time_position;
2132   guint32 seg_idx;
2133
2134   g_return_val_if_fail (stream != NULL, FALSE);
2135
2136   time_position = stream->time_position;
2137   if (G_UNLIKELY (time_position == -1))
2138     goto eos;
2139
2140   seg_idx = stream->segment_index;
2141   if (G_UNLIKELY (seg_idx == -1)) {
2142     /* find segment corresponding to time_position if we are looking
2143      * for a segment. */
2144     seg_idx = gst_piffdemux_find_segment (piffdemux, stream, time_position);
2145
2146     /* nothing found, we're really eos */
2147     if (seg_idx == -1)
2148       goto eos;
2149   }
2150
2151   /* different segment, activate it, sample_index will be set. */
2152   if (G_UNLIKELY (stream->segment_index != seg_idx))
2153     gst_piffdemux_activate_segment (piffdemux, stream, seg_idx, time_position);
2154
2155   GST_LOG_OBJECT (piffdemux, "segment active, index = %u of %u",
2156       stream->sample_index, stream->n_samples);
2157
2158   if (G_UNLIKELY (stream->sample_index >= stream->n_samples))
2159     goto eos;
2160
2161
2162   /* now get the info for the sample we're at */
2163   sample = &stream->samples[stream->sample_index];
2164
2165   *timestamp = PIFFSAMPLE_PTS (stream, sample);
2166   *offset = sample->offset;
2167   *size = sample->size;
2168   *duration = PIFFSAMPLE_DUR_PTS (stream, sample, *timestamp);
2169   *keyframe = PIFFSAMPLE_KEYFRAME (stream, sample);
2170
2171   return TRUE;
2172
2173   /* special cases */
2174 eos:
2175   {
2176     stream->time_position = -1;
2177     return FALSE;
2178   }
2179 }
2180
2181 /* the input buffer metadata must be writable,
2182  * but time/duration etc not yet set and need not be preserved */
2183 static GstBuffer *
2184 gst_piffdemux_process_buffer (GstPiffDemux * piffdemux, PiffDemuxStream * stream,
2185     GstBuffer * buf)
2186 {
2187   guint8 *data;
2188   guint size, nsize = 0;
2189   gchar *str;
2190
2191   data = GST_BUFFER_DATA (buf);
2192   size = GST_BUFFER_SIZE (buf);
2193
2194   if (G_UNLIKELY (stream->subtype != FOURCC_text)) {
2195     return buf;
2196   }
2197
2198   if (G_LIKELY (size >= 2)) {
2199     nsize = GST_READ_UINT16_BE (data);
2200     nsize = MIN (nsize, size - 2);
2201   }
2202
2203   GST_LOG_OBJECT (piffdemux, "3GPP timed text subtitle: %d/%d", nsize, size);
2204
2205   /* takes care of UTF-8 validation or UTF-16 recognition,
2206    * no other encoding expected */
2207   str = gst_tag_freeform_string_to_utf8 ((gchar *) data + 2, nsize, NULL);
2208   if (str) {
2209     gst_buffer_unref (buf);
2210     buf = gst_buffer_new ();
2211     GST_BUFFER_DATA (buf) = GST_BUFFER_MALLOCDATA (buf) = (guint8 *) str;
2212     GST_BUFFER_SIZE (buf) = strlen (str);
2213   } else {
2214     /* may be 0-size subtitle, which is also sent to keep pipeline going */
2215     GST_BUFFER_DATA (buf) = data + 2;
2216     GST_BUFFER_SIZE (buf) = nsize;
2217   }
2218
2219   /* FIXME ? convert optional subsequent style info to markup */
2220
2221   return buf;
2222 }
2223
2224 /* Sets a buffer's attributes properly and pushes it downstream.
2225  * Also checks for additional actions and custom processing that may
2226  * need to be done first.
2227  */
2228 static gboolean
2229 gst_piffdemux_decorate_and_push_buffer (GstPiffDemux * piffdemux,
2230     PiffDemuxStream * stream, GstBuffer * buf,
2231     guint64 timestamp, guint64 duration, gboolean keyframe, guint64 position,
2232     guint64 byte_position)
2233 {
2234   GstFlowReturn ret = GST_FLOW_OK;
2235
2236   if (!stream->caps) {
2237     GST_WARNING_OBJECT (piffdemux, "caps are empty...creat any caps");
2238     stream->caps = gst_caps_new_any();
2239     if (!stream->caps) {
2240       GST_ERROR_OBJECT (piffdemux, "failed to create caps...");
2241       ret = GST_FLOW_ERROR;
2242       goto exit;
2243     }
2244   }
2245
2246   /* position reporting */
2247   if (piffdemux->segment.rate >= 0) {
2248    // TODO: Segment fault is coming here for Audio stream.. need to check
2249
2250     gst_segment_set_last_stop (&piffdemux->segment, GST_FORMAT_TIME, position);
2251     //gst_piffdemux_sync_streams (piffdemux);
2252   }
2253
2254   /* send out pending buffers */
2255   while (stream->buffers) {
2256     GstBuffer *buffer = (GstBuffer *) stream->buffers->data;
2257
2258     if (G_UNLIKELY (stream->discont)) {
2259       GST_LOG_OBJECT (piffdemux, "marking discont buffer");
2260       GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT);
2261       stream->discont = FALSE;
2262     }
2263     gst_buffer_set_caps (buffer, stream->caps);
2264
2265     gst_pad_push (piffdemux->srcpad, buffer);
2266
2267     stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
2268   }
2269
2270   /* we're going to modify the metadata */
2271   buf = gst_buffer_make_metadata_writable (buf);
2272
2273   /* for subtitle processing */
2274   if (G_UNLIKELY (stream->need_process))
2275     buf = gst_piffdemux_process_buffer (piffdemux, stream, buf);
2276
2277   GST_BUFFER_TIMESTAMP (buf) = timestamp;
2278   GST_BUFFER_DURATION (buf) = duration;
2279   GST_BUFFER_OFFSET (buf) = -1;
2280   GST_BUFFER_OFFSET_END (buf) = -1;
2281
2282   if (G_UNLIKELY (stream->padding)) {
2283     GST_BUFFER_DATA (buf) += stream->padding;
2284     GST_BUFFER_SIZE (buf) -= stream->padding;
2285   }
2286
2287   if (G_UNLIKELY (buf == NULL))
2288     goto exit;
2289
2290   if (G_UNLIKELY (stream->discont)) {
2291     GST_LOG_OBJECT (piffdemux, "marking discont buffer");
2292     GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
2293     stream->discont = FALSE;
2294   }
2295
2296   if (!keyframe)
2297     GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
2298
2299  //g_print ("\n\npad caps : %s\n\n", gst_caps_to_string (gst_pad_get_caps (stream->pad)));
2300
2301   //gst_buffer_set_caps (buf, stream->caps); // commenting to avoid caps by setting properties
2302
2303   // TODO: need to see how resolution switch will work
2304   gst_buffer_set_caps (buf, stream->caps);
2305
2306 #ifdef DRM_ENABLE
2307   if (piffdemux->encrypt_content) {
2308     drm_trusted_payload_info_s read_input_data = {0, };
2309     drm_trusted_read_decrypt_resp_data_s read_output_data = {0, };
2310     gint offset = 0;
2311     PiffDemuxSample *sample = &stream->samples[stream->sample_index];
2312
2313     if (sample->sub_encry) {
2314       offset = sample->sub_encry->sub_entry[0].LenofClearData;
2315     }
2316
2317     read_input_data.media_offset = 0;
2318     read_input_data.payload_data =  GST_BUFFER_DATA(buf) + offset;
2319     read_input_data.payload_data_len = GST_BUFFER_SIZE(buf) - offset;
2320     read_input_data.payload_iv_len = 8;
2321     read_input_data.payload_iv = (unsigned char *) malloc (8);
2322     read_input_data.payload_data_output =  GST_BUFFER_DATA(buf) + offset;
2323     if (NULL == read_input_data.payload_iv) {
2324       GST_ERROR ("Failed to allocate memory...");
2325       ret = GST_FLOW_ERROR;
2326       goto exit;
2327     }
2328     memcpy (read_input_data.payload_iv, sample->iv, 8);
2329
2330     ret = drm_trusted_read_decrypt_session(piffdemux->pr_handle , &read_input_data, &read_output_data);
2331     if (DRM_TRUSTED_RETURN_SUCCESS != ret) {
2332       GST_ERROR_OBJECT (piffdemux, "failed to decrypt buffer...");
2333       free (read_input_data.payload_iv);
2334       ret = GST_FLOW_ERROR;
2335       goto exit;
2336     }
2337
2338     if (read_output_data.read_size != read_input_data.payload_data_len) {
2339       g_print ("Decrypter did not consume data fully...\n\n\n");
2340     }
2341
2342     free (read_input_data.payload_iv);
2343     read_input_data.payload_iv = NULL;
2344
2345   }
2346 #endif
2347
2348   GST_LOG_OBJECT (piffdemux,
2349       "Pushing buffer of size = %d with time %" GST_TIME_FORMAT ", duration %"
2350       GST_TIME_FORMAT, GST_BUFFER_SIZE(buf), GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)),
2351       GST_TIME_ARGS (GST_BUFFER_DURATION (buf)));
2352
2353 #ifdef DEC_OUT_FRAME_DUMP
2354     {
2355         int written = 0;
2356         written = fwrite (GST_BUFFER_DATA (buf), sizeof (unsigned char), GST_BUFFER_SIZE (buf), piffdump);
2357         g_print ("PIFFDEMUX: written = %d\n", written);
2358         fflush (piffdump);
2359     }
2360 #endif
2361
2362   ret = gst_pad_push (piffdemux->srcpad, buf);
2363
2364 exit:
2365   return ret;
2366 }
2367
2368
2369 /*
2370  * next_entry_size
2371  *
2372  * Returns the size of the first entry at the current offset.
2373  * If -1, there are none (which means EOS or empty file).
2374  */
2375 static guint64
2376 next_entry_size (GstPiffDemux * demux)
2377 {
2378   PiffDemuxStream *stream = demux->stream;
2379   PiffDemuxSample *sample;
2380
2381   GST_LOG_OBJECT (demux, "Finding entry at offset %" G_GUINT64_FORMAT,
2382       demux->offset);
2383
2384   GST_DEBUG_OBJECT (demux, "demux->sample_index = %d", stream->sample_index);
2385
2386   if (stream->sample_index == -1)
2387     stream->sample_index = 0;
2388
2389   if (stream->sample_index >= stream->n_samples) {
2390     GST_LOG_OBJECT (demux, "stream %d samples exhausted n_samples = %d",
2391                 stream->sample_index, stream->n_samples);
2392     return -1;
2393   }
2394
2395   sample = &stream->samples[stream->sample_index];
2396
2397   GST_LOG_OBJECT (demux,
2398       "Checking Stream %d (sample_index:%d / offset:%" G_GUINT64_FORMAT
2399       " / size:%" G_GUINT32_FORMAT ")", stream->sample_index, stream->sample_index,
2400       sample->offset, sample->size);
2401
2402   GST_LOG_OBJECT (demux, "stream : demux->offset :%"G_GUINT64_FORMAT, demux->offset);
2403
2404   stream = demux->stream;
2405   sample = &stream->samples[stream->sample_index];
2406
2407   if (sample->offset >= demux->offset) {
2408     demux->todrop = sample->offset - demux->offset;
2409     return sample->size + demux->todrop;
2410   }
2411
2412   GST_DEBUG_OBJECT (demux,
2413       "There wasn't any entry at offset %" G_GUINT64_FORMAT, demux->offset);
2414   return -1;
2415 }
2416
2417 static void
2418 gst_piffdemux_post_progress (GstPiffDemux * demux, gint num, gint denom)
2419 {
2420   gint perc = (gint) ((gdouble) num * 100.0 / (gdouble) denom);
2421
2422   gst_element_post_message (GST_ELEMENT_CAST (demux),
2423       gst_message_new_element (GST_OBJECT_CAST (demux),
2424           gst_structure_new ("progress", "percent", G_TYPE_INT, perc, NULL)));
2425 }
2426
2427 static gboolean
2428 piffdemux_seek_offset (GstPiffDemux * demux, guint64 offset)
2429 {
2430   GstEvent *event;
2431   gboolean res = 0;
2432
2433   GST_DEBUG_OBJECT (demux, "Seeking to %" G_GUINT64_FORMAT, offset);
2434
2435   event =
2436       gst_event_new_seek (1.0, GST_FORMAT_BYTES,
2437       GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET, offset,
2438       GST_SEEK_TYPE_NONE, -1);
2439
2440   res = gst_pad_push_event (demux->sinkpad, event);
2441
2442   return res;
2443 }
2444
2445 static GstFlowReturn
2446 gst_piffdemux_chain (GstPad * sinkpad, GstBuffer * inbuf)
2447 {
2448   GstPiffDemux *demux;
2449   GstFlowReturn ret = GST_FLOW_OK;
2450   demux = GST_PIFFDEMUX (gst_pad_get_parent (sinkpad));
2451 #ifdef DRM_ENABLE
2452   if (demux->encrypt_content && !demux->decrypt_init) {
2453     int ret = -1;
2454     drm_trusted_permission_type_e perm_type = DRM_TRUSTED_PERMISSION_TYPE_PLAY;
2455     drm_trusted_open_decrypt_info_s open_input_data = {0, };
2456     drm_trusted_open_decrypt_resp_data_s open_output_data = {0, };
2457     drm_trusted_set_consumption_state_info_s state_input_data = {0, };
2458
2459     open_input_data.file_type = DRM_TRUSTED_TYPE_PIFF;
2460     open_input_data.permission = perm_type;
2461     open_input_data.operation_callback.callback = test_drm_trusted_operation_cb;
2462     open_input_data.lic_header.header = GST_BUFFER_DATA(demux->protection_header);
2463     open_input_data.lic_header.header_len = GST_BUFFER_SIZE (demux->protection_header);
2464
2465     /* Open Decrypt Session*/
2466     ret = drm_trusted_open_decrypt_session(&open_input_data, &open_output_data, &(demux->pr_handle));
2467     if (DRM_TRUSTED_RETURN_SUCCESS != ret) {
2468       GST_ERROR_OBJECT (demux, "failed to open decrypt session");
2469       goto unknown_stream;
2470     }
2471
2472     /* Before Read, Appropriate state MUST be SET */
2473     state_input_data.state = DRM_CONSUMPTION_STARTED;
2474     ret = drm_trusted_set_decrypt_state(demux->pr_handle, &state_input_data);
2475     if (DRM_TRUSTED_RETURN_SUCCESS != ret) {
2476       GST_ERROR_OBJECT (demux, "failed to set decrypt state...");
2477       goto unknown_stream;
2478     }
2479
2480     demux->decrypt_init = TRUE;
2481   }
2482 #endif
2483   gst_adapter_push (demux->adapter, inbuf);
2484
2485   /* we never really mean to buffer that much */
2486   if (demux->neededbytes == -1)
2487     goto eos;
2488
2489   GST_DEBUG_OBJECT (demux, "pushing in inbuf %p, neededbytes:%u, available:%u",
2490       inbuf, demux->neededbytes, gst_adapter_available (demux->adapter));
2491
2492   while (((gst_adapter_available (demux->adapter)) >= demux->neededbytes) &&
2493       (ret == GST_FLOW_OK)) {
2494
2495     GST_DEBUG_OBJECT (demux,
2496         "state:%d , demux->neededbytes:%d, demux->offset:%" G_GUINT64_FORMAT,
2497         demux->state, demux->neededbytes, demux->offset);
2498
2499     switch (demux->state) {
2500       case PIFFDEMUX_STATE_INITIAL:{
2501         const guint8 *data;
2502         guint32 fourcc;
2503         guint64 size;
2504
2505         data = gst_adapter_peek (demux->adapter, demux->neededbytes);
2506
2507         if (!data) {
2508           GST_ERROR_OBJECT (demux, "peeked adapter buffer is NULL");
2509           ret = GST_FLOW_ERROR;
2510           break;
2511         }
2512
2513         /* get fourcc/length, set neededbytes */
2514         extract_initial_length_and_fourcc ((guint8 *) data, demux->neededbytes,
2515             &size, &fourcc);
2516         GST_DEBUG_OBJECT (demux, "Peeking found [%" GST_FOURCC_FORMAT "] "
2517             "size: %" G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), size);
2518         if (size == 0) {
2519           GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
2520               ("This file is invalid and cannot be played."),
2521               ("initial atom '%" GST_FOURCC_FORMAT "' has empty length",
2522                   GST_FOURCC_ARGS (fourcc)));
2523
2524           ret = GST_FLOW_ERROR;
2525           break;
2526         }
2527
2528         if (fourcc == FOURCC_mdat) {
2529           if (demux->moof_rcvd) {
2530             /* we have the headers, start playback */
2531             demux->state = PIFFDEMUX_STATE_MOVIE;
2532             demux->neededbytes = next_entry_size (demux);
2533             demux->mdatleft = size;
2534
2535             /* Only post, event on pads is done after newsegment */
2536             piffdemux_post_global_tags (demux);
2537           } else {
2538              GST_ERROR_OBJECT (demux, "mdata received before moof.. not handled");
2539              goto unknown_stream;
2540           }
2541         } else if (G_UNLIKELY (size > PIFFDEMUX_MAX_ATOM_SIZE)) {
2542           GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
2543               ("This file is invalid and cannot be played."),
2544               ("atom %" GST_FOURCC_FORMAT " has bogus size %" G_GUINT64_FORMAT,
2545                   GST_FOURCC_ARGS (fourcc), size));
2546           ret = GST_FLOW_ERROR;
2547           break;
2548         } else {
2549           demux->neededbytes = size;
2550           demux->state = PIFFDEMUX_STATE_HEADER;
2551         }
2552         break;
2553       }
2554       case PIFFDEMUX_STATE_HEADER:{
2555         const guint8 *data;
2556         guint32 fourcc;
2557
2558         GST_DEBUG_OBJECT (demux, "In header");
2559
2560         data = gst_adapter_peek (demux->adapter, demux->neededbytes);
2561
2562         if (!data) {
2563           GST_ERROR_OBJECT (demux, "peeked adapter buffer is NULL");
2564           ret = GST_FLOW_ERROR;
2565           break;
2566         }
2567
2568         /* parse the header */
2569         extract_initial_length_and_fourcc (data, demux->neededbytes, NULL,
2570             &fourcc);
2571         if (fourcc == FOURCC_moof) {
2572             GST_DEBUG_OBJECT (demux, "Parsing [moof]");
2573             if (!piffdemux_parse_moof (demux, data, demux->neededbytes,
2574                     demux->offset, demux->stream)) {
2575               ret = GST_FLOW_ERROR;
2576               goto done;
2577             }
2578             demux->moof_rcvd = TRUE;
2579         }  else {
2580           GST_WARNING_OBJECT (demux,
2581               "Unknown fourcc while parsing header : %" GST_FOURCC_FORMAT,
2582               GST_FOURCC_ARGS (fourcc));
2583           /* Let's jump that one and go back to initial state */
2584         }
2585
2586         if (demux->mdatbuffer) {
2587           /* the mdat was before the header */
2588           GST_DEBUG_OBJECT (demux, "We have mdatbuffer:%p",
2589              demux->mdatbuffer);
2590           gst_adapter_clear (demux->adapter);
2591           demux->mdatbuffer = NULL;
2592           demux->offset = demux->mdatoffset;
2593           demux->neededbytes = next_entry_size (demux);
2594           demux->state = PIFFDEMUX_STATE_MOVIE;
2595           demux->mdatleft = gst_adapter_available (demux->adapter);
2596
2597           /* Only post, event on pads is done after newsegment */
2598           piffdemux_post_global_tags (demux);
2599         } else {
2600           GST_DEBUG_OBJECT (demux, "Carrying on normally");
2601           gst_adapter_flush (demux->adapter, demux->neededbytes);
2602             demux->offset += demux->neededbytes;
2603           demux->neededbytes = 16;
2604           demux->state = PIFFDEMUX_STATE_INITIAL;
2605         }
2606
2607         break;
2608       }
2609       case PIFFDEMUX_STATE_BUFFER_MDAT:{
2610         GstBuffer *buf;
2611
2612         GST_DEBUG_OBJECT (demux, "Got our buffer at offset %" G_GUINT64_FORMAT,
2613             demux->offset);
2614         buf = gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
2615         GST_DEBUG_OBJECT (demux, "mdatbuffer starts with %" GST_FOURCC_FORMAT,
2616             GST_FOURCC_ARGS (PIFF_FOURCC (GST_BUFFER_DATA (buf) + 4)));
2617         if (demux->mdatbuffer)
2618           demux->mdatbuffer = gst_buffer_join (demux->mdatbuffer, buf);
2619         else
2620           demux->mdatbuffer = buf;
2621         demux->offset += demux->neededbytes;
2622         demux->neededbytes = 16;
2623         demux->state = PIFFDEMUX_STATE_INITIAL;
2624         gst_piffdemux_post_progress (demux, 1, 1);
2625
2626         break;
2627       }
2628       case PIFFDEMUX_STATE_MOVIE:{
2629         GstBuffer *outbuf;
2630         PiffDemuxStream *stream = demux->stream;
2631         PiffDemuxSample *sample;
2632         guint64 timestamp, duration, position;
2633         gboolean keyframe;
2634
2635         GST_DEBUG_OBJECT (demux,
2636             "BEGIN // in MOVIE for offset %" G_GUINT64_FORMAT, demux->offset);
2637
2638         if (demux->fragmented) {
2639           GST_DEBUG_OBJECT (demux, "mdat remaining %" G_GUINT64_FORMAT,
2640               demux->mdatleft);
2641           if (G_LIKELY (demux->todrop < demux->mdatleft)) {
2642             /* if needed data starts within this atom,
2643              * then it should not exceed this atom */
2644             if (G_UNLIKELY (demux->neededbytes > demux->mdatleft)) {
2645
2646               GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
2647                   ("This file is invalid and cannot be played."),
2648                   ("sample data crosses atom boundary"));
2649
2650               ret = GST_FLOW_ERROR;
2651               break;
2652             }
2653             demux->mdatleft -= demux->neededbytes;
2654           } else {
2655             GST_DEBUG_OBJECT (demux, "data atom emptied; resuming atom scan");
2656             /* so we are dropping more than left in this atom */
2657             demux->todrop -= demux->mdatleft;
2658             demux->neededbytes -= demux->mdatleft;
2659             demux->mdatleft = 0;
2660             /* need to resume atom parsing so we do not miss any other pieces */
2661             demux->state = PIFFDEMUX_STATE_INITIAL;
2662             demux->neededbytes = 16;
2663             break;
2664           }
2665         }
2666
2667         if (demux->todrop) {
2668           GST_LOG_OBJECT (demux, "Dropping %d bytes", demux->todrop);
2669           gst_adapter_flush (demux->adapter, demux->todrop);
2670           demux->neededbytes -= demux->todrop;
2671           demux->offset += demux->todrop;
2672         }
2673
2674         if ( !stream->sent_nsevent) {
2675           //TODO: better to parse sink event function and send that new_segment
2676 #if 1
2677           demux->pending_newsegment = gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_TIME,
2678                                         demux->stream->start_ts, -1, demux->stream->start_ts);
2679 #else
2680           demux->pending_newsegment = gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_TIME,
2681                                         0, gst_util_uint64_scale (stream->duration, GST_SECOND, stream->timescale), 0);
2682 #endif
2683
2684           GST_INFO_OBJECT (demux, "New segment event : start = %"GST_TIME_FORMAT", stop = %" GST_TIME_FORMAT,
2685                             GST_TIME_ARGS (demux->stream->start_ts), GST_TIME_ARGS(gst_util_uint64_scale (stream->duration, GST_SECOND, stream->timescale)));
2686
2687           if (!gst_pad_push_event (demux->srcpad, demux->pending_newsegment)) {
2688             GST_ERROR_OBJECT (demux, "failding to send new segment...");
2689             goto newsegment_error;
2690           }
2691           stream->sent_nsevent = TRUE;
2692         }
2693
2694         /* Put data in a buffer, set timestamps, caps, ... */
2695         outbuf = gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
2696
2697         GST_DEBUG_OBJECT (demux, "Taken %d size buffer from adapter...", outbuf ? GST_BUFFER_SIZE (outbuf) : 0);
2698
2699         GST_DEBUG_OBJECT (demux, "stream : %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (stream->fourcc));
2700
2701         g_return_val_if_fail (outbuf != NULL, GST_FLOW_ERROR);
2702
2703         sample = &stream->samples[stream->sample_index];
2704
2705         GST_DEBUG_OBJECT (demux, "start_ts = %"GST_TIME_FORMAT" ts : %"GST_TIME_FORMAT" ts = %llu, pts_offset = %u, scale = %d\n",
2706                         GST_TIME_ARGS(stream->start_ts),GST_TIME_ARGS(sample->timestamp), sample->timestamp,
2707                         sample->pts_offset,stream->timescale);
2708
2709         position = PIFFSAMPLE_DTS (stream, sample);
2710         timestamp = PIFFSAMPLE_PTS (stream, sample) + stream->start_ts; // Adding to avoid resetting of timestamp
2711         duration = PIFFSAMPLE_DUR_DTS (stream, sample, position);
2712         keyframe = PIFFSAMPLE_KEYFRAME (stream, sample);
2713
2714         ret = gst_piffdemux_decorate_and_push_buffer (demux, stream, outbuf,
2715             timestamp, duration, keyframe, position, demux->offset);
2716
2717         stream->sample_index++;
2718
2719         /* update current offset and figure out size of next buffer */
2720         GST_LOG_OBJECT (demux, "increasing offset %" G_GUINT64_FORMAT " by %u",
2721             demux->offset, demux->neededbytes);
2722         demux->offset += demux->neededbytes;
2723         GST_LOG_OBJECT (demux, "offset is now %" G_GUINT64_FORMAT,
2724             demux->offset);
2725
2726         if ((demux->neededbytes = next_entry_size (demux)) == -1) {
2727           GST_DEBUG_OBJECT (demux, "finished parsing mdat, need to search next moof atom");
2728           demux->neededbytes = 16;
2729           demux->state = PIFFDEMUX_STATE_INITIAL;
2730           GST_DEBUG ("\n\n Storing %s last_ts %"GST_TIME_FORMAT"\n\n", stream->subtype == FOURCC_vide ? "video" : "audio", GST_TIME_ARGS(timestamp));
2731           stream->start_ts = timestamp + duration;
2732           //goto eos;
2733         }
2734         break;
2735       }
2736       default:
2737         goto invalid_state;
2738     }
2739   }
2740
2741   /* when buffering movie data, at least show user something is happening */
2742   if (ret == GST_FLOW_OK && demux->state == PIFFDEMUX_STATE_BUFFER_MDAT &&
2743       gst_adapter_available (demux->adapter) <= demux->neededbytes) {
2744     gst_piffdemux_post_progress (demux, gst_adapter_available (demux->adapter),
2745         demux->neededbytes);
2746   }
2747 done:
2748   gst_object_unref (demux);
2749
2750   return ret;
2751
2752   /* ERRORS */
2753 unknown_stream:
2754   {
2755     GST_ELEMENT_ERROR (demux, STREAM, FAILED, (NULL), ("unknown stream found"));
2756     ret = GST_FLOW_ERROR;
2757     goto done;
2758   }
2759 eos:
2760   {
2761     GST_DEBUG_OBJECT (demux, "no next entry, EOS");
2762     ret = GST_FLOW_UNEXPECTED;
2763     goto done;
2764   }
2765 invalid_state:
2766   {
2767     GST_ELEMENT_ERROR (demux, STREAM, FAILED,
2768         (NULL), ("piffdemuxer invalid state %d", demux->state));
2769     ret = GST_FLOW_ERROR;
2770     goto done;
2771   }
2772 newsegment_error:
2773   {
2774     GST_ELEMENT_ERROR (demux, STREAM, FAILED,
2775         (NULL), ("could not send newsegment event"));
2776     ret = GST_FLOW_ERROR;
2777     goto done;
2778   }
2779 }
2780
2781 static gboolean
2782 piffdemux_parse_container (GstPiffDemux * piffdemux, GNode * node, const guint8 * buf,
2783     const guint8 * end)
2784 {
2785   while (G_UNLIKELY (buf < end)) {
2786     GNode *child;
2787     guint32 len;
2788
2789     if (G_UNLIKELY (buf + 4 > end)) {
2790       GST_LOG_OBJECT (piffdemux, "buffer overrun");
2791       break;
2792     }
2793     len = PIFF_UINT32 (buf);
2794     if (G_UNLIKELY (len == 0)) {
2795       GST_LOG_OBJECT (piffdemux, "empty container");
2796       break;
2797     }
2798     if (G_UNLIKELY (len < 8)) {
2799       GST_WARNING_OBJECT (piffdemux, "length too short (%d < 8)", len);
2800       break;
2801     }
2802     if (G_UNLIKELY (len > (end - buf))) {
2803       GST_WARNING_OBJECT (piffdemux, "length too long (%d > %d)", len,
2804           (gint) (end - buf));
2805       break;
2806     }
2807
2808     child = g_node_new ((guint8 *) buf);
2809     g_node_append (node, child);
2810     GST_LOG_OBJECT (piffdemux, "adding new node of len %d", len);
2811     piffdemux_parse_node (piffdemux, child, buf, len);
2812
2813     buf += len;
2814   }
2815   return TRUE;
2816 }
2817
2818
2819 static gboolean
2820 piffdemux_parse_node (GstPiffDemux * piffdemux, GNode * node, const guint8 * buffer,
2821     guint length)
2822 {
2823   guint32 fourcc = 0;
2824   guint32 node_length = 0;
2825   const PiffNodeType *type;
2826   const guint8 *end;
2827
2828   GST_LOG_OBJECT (piffdemux, "piffdemux_parse buffer %p length %u", buffer, length);
2829
2830   if (G_UNLIKELY (length < 8))
2831     goto not_enough_data;
2832
2833   node_length = PIFF_UINT32 (buffer);
2834   fourcc = PIFF_FOURCC (buffer + 4);
2835
2836   /* ignore empty nodes */
2837   if (G_UNLIKELY (fourcc == 0 || node_length == 8))
2838     return TRUE;
2839
2840   type = piffdemux_type_get (fourcc);
2841
2842   end = buffer + length;
2843
2844   GST_LOG_OBJECT (piffdemux,
2845       "parsing '%" GST_FOURCC_FORMAT "', length=%u, name '%s'",
2846       GST_FOURCC_ARGS (fourcc), node_length, type->name);
2847
2848   if (node_length > length)
2849     goto broken_atom_size;
2850
2851   if (type->flags & PIFF_FLAG_CONTAINER) {
2852     piffdemux_parse_container (piffdemux, node, buffer + 8, end);
2853   }
2854   GST_LOG_OBJECT (piffdemux, "parsed '%" GST_FOURCC_FORMAT "'",
2855       GST_FOURCC_ARGS (fourcc));
2856   return TRUE;
2857
2858 /* ERRORS */
2859 not_enough_data:
2860   {
2861
2862     GST_ELEMENT_ERROR (piffdemux, STREAM, DEMUX,
2863         ("This file is corrupt and cannot be played."),
2864         ("Not enough data for an atom header, got only %u bytes", length));
2865
2866     return FALSE;
2867   }
2868 broken_atom_size:
2869   {
2870     GST_ELEMENT_ERROR (piffdemux, STREAM, DEMUX,
2871         ("This file is corrupt and cannot be played."),
2872         ("Atom '%" GST_FOURCC_FORMAT "' has size of %u bytes, but we have only "
2873             "%u bytes available.", GST_FOURCC_ARGS (fourcc), node_length,
2874             length));
2875
2876     return FALSE;
2877   }
2878 }
2879
2880
2881 static GNode *
2882 piffdemux_tree_get_child_by_type (GNode * node, guint32 fourcc)
2883 {
2884   GNode *child;
2885   guint8 *buffer;
2886   guint32 child_fourcc;
2887
2888   for (child = g_node_first_child (node); child;
2889       child = g_node_next_sibling (child)) {
2890     buffer = (guint8 *) child->data;
2891
2892     child_fourcc = PIFF_FOURCC (buffer + 4);
2893
2894     if (G_UNLIKELY (child_fourcc == fourcc)) {
2895       return child;
2896     }
2897   }
2898   return NULL;
2899 }
2900
2901 static GNode *
2902 piffdemux_tree_get_child_by_type_full (GNode * node, guint32 fourcc,
2903     GstByteReader * parser)
2904 {
2905   GNode *child;
2906   guint8 *buffer;
2907   guint32 child_fourcc, child_len;
2908
2909   for (child = g_node_first_child (node); child;
2910       child = g_node_next_sibling (child)) {
2911     buffer = (guint8 *) child->data;
2912
2913     child_len = PIFF_UINT32 (buffer);
2914     child_fourcc = PIFF_FOURCC (buffer + 4);
2915
2916     if (G_UNLIKELY (child_fourcc == fourcc)) {
2917       if (G_UNLIKELY (child_len < (4 + 4)))
2918         return NULL;
2919       /* FIXME: must verify if atom length < parent atom length */
2920       gst_byte_reader_init (parser, buffer + (4 + 4), child_len - (4 + 4));
2921       return child;
2922     }
2923   }
2924   return NULL;
2925 }
2926
2927 static GNode *
2928 piffdemux_tree_get_sibling_by_type_full (GNode * node, guint32 fourcc,
2929     GstByteReader * parser)
2930 {
2931   GNode *child;
2932   guint8 *buffer;
2933   guint32 child_fourcc, child_len;
2934
2935   for (child = g_node_next_sibling (node); child;
2936       child = g_node_next_sibling (child)) {
2937     buffer = (guint8 *) child->data;
2938
2939     child_fourcc = PIFF_FOURCC (buffer + 4);
2940
2941     if (child_fourcc == fourcc) {
2942       if (parser) {
2943         child_len = PIFF_UINT32 (buffer);
2944         if (G_UNLIKELY (child_len < (4 + 4)))
2945           return NULL;
2946         /* FIXME: must verify if atom length < parent atom length */
2947         gst_byte_reader_init (parser, buffer + (4 + 4), child_len - (4 + 4));
2948       }
2949       return child;
2950     }
2951   }
2952   return NULL;
2953 }
2954
2955 static GNode *
2956 piffdemux_tree_get_sibling_by_type (GNode * node, guint32 fourcc)
2957 {
2958   return piffdemux_tree_get_sibling_by_type_full (node, fourcc, NULL);
2959 }
2960
2961 #define _codec(name) \
2962   do { \
2963     if (codec_name) { \
2964       *codec_name = g_strdup (name); \
2965     } \
2966   } while (0)
2967
2968 void
2969 gst_piffdemux_set_video_params (GstPiffDemux * piffdemux, guint fourcc,
2970                                         guint width, guint height,
2971                                         guint fps_n, guint fps_d, unsigned char *codec_data, unsigned int codec_data_len)
2972 {
2973   GstCaps *caps = NULL;
2974   GstBuffer *dci = NULL;
2975
2976   if (codec_data && codec_data_len) {
2977     dci = gst_buffer_new_and_alloc (codec_data_len);
2978     if (!dci) {
2979       GST_ERROR_OBJECT (piffdemux, "failed to create codec data buffer...");
2980     } else {
2981       memcpy (GST_BUFFER_DATA(dci), codec_data, codec_data_len);
2982     }
2983   }
2984
2985   switch (fourcc) {
2986
2987     case GST_MAKE_FOURCC ('a', 'v', 'c', '1'):
2988       caps = gst_caps_new_simple ("video/x-h264",
2989                                   "width", G_TYPE_INT, width,
2990                                   "height", G_TYPE_INT, height,
2991                                   "framerate", GST_TYPE_FRACTION, fps_n, fps_d,
2992                                   "stream-format", G_TYPE_STRING, "avc",
2993                                   "alignment", G_TYPE_STRING, "au",
2994                                   "codec_data", GST_TYPE_BUFFER, dci,
2995                                   NULL);
2996       break;
2997
2998     case FOURCC_ovc1:
2999       caps = gst_caps_new_simple ("video/x-wmv",
3000                                   "width", G_TYPE_INT, width,
3001                                   "height", G_TYPE_INT, height,
3002                                   "framerate", GST_TYPE_FRACTION, fps_n, fps_d,
3003                                   "wmvversion", G_TYPE_INT, 3,
3004                                   "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC ('W', 'V', 'C', '1'),
3005                                   "codec_data", GST_TYPE_BUFFER, dci,
3006                                   NULL);
3007       break;
3008
3009     default: {
3010       char *s;
3011       s = g_strdup_printf ("video/x-gst-fourcc-%" GST_FOURCC_FORMAT,
3012           GST_FOURCC_ARGS (fourcc));
3013       caps = gst_caps_new_simple (s,
3014                                   "width", G_TYPE_INT, width,
3015                                   "height", G_TYPE_INT, height,
3016                                   "framerate", GST_TYPE_FRACTION, fps_n, fps_d,
3017                                   "codec_data", GST_TYPE_BUFFER, dci,
3018                                   NULL);
3019       break;
3020     }
3021   }
3022
3023   piffdemux->stream->caps = caps;
3024   gchar *caps_string = gst_caps_to_string(caps);
3025   GST_INFO_OBJECT (piffdemux, "prepared video caps : %s", caps_string);
3026   g_free(caps_string);
3027   caps_string = NULL;
3028 }
3029
3030 void
3031 gst_piffdemux_set_audio_params (GstPiffDemux * piffdemux, guint fourcc,
3032                                         guint sampling_rate, guint bps, guint channels, unsigned char *codec_data, unsigned int codec_data_len)
3033 {
3034   GstCaps *caps = NULL;
3035   GstBuffer *dci = NULL;
3036
3037   if (codec_data && codec_data_len) {
3038     dci = gst_buffer_new_and_alloc (codec_data_len);
3039     if (!dci) {
3040       GST_ERROR_OBJECT (piffdemux, "failed to create codec data buffer...");
3041     } else {
3042       memcpy (GST_BUFFER_DATA(dci), codec_data, codec_data_len);
3043     }
3044   }
3045
3046   switch (fourcc) {
3047
3048     case GST_MAKE_FOURCC ('m', 'p', '4', 'a'):
3049       caps = gst_caps_new_simple ("audio/mpeg",
3050                                   "mpegversion", G_TYPE_INT, 4,
3051                                   "framed", G_TYPE_BOOLEAN, TRUE,
3052                                   "stream-format", G_TYPE_STRING, "raw",
3053                                   "rate", G_TYPE_INT, (int) sampling_rate,
3054                                   "channels", G_TYPE_INT, channels,
3055                                   NULL);
3056       break;
3057
3058     case FOURCC_owma:
3059       caps = gst_caps_new_simple ("audio/x-wma",
3060                                   "rate", G_TYPE_INT, (int) sampling_rate,
3061                                   "channels", G_TYPE_INT, channels,
3062                                   NULL);
3063       break;
3064
3065     default: {
3066       char *s;
3067       s = g_strdup_printf ("audio/x-gst-fourcc-%" GST_FOURCC_FORMAT,
3068           GST_FOURCC_ARGS (fourcc));
3069       caps = gst_caps_new_simple (s,
3070                                   "rate", G_TYPE_INT, (int) sampling_rate,
3071                                   "channels", G_TYPE_INT, channels,
3072                                   NULL);
3073       break;
3074     }
3075   }
3076
3077   piffdemux->stream->caps = caps;
3078   char *tmp_caps_name = gst_caps_to_string(caps);
3079   GST_INFO_OBJECT (piffdemux, "prepared audio caps : %s", tmp_caps_name);
3080   g_free(tmp_caps_name);
3081
3082 }
3083
3084 #define g_marshal_value_peek_object(v)   g_value_get_object (v)
3085
3086 void
3087 __gst_piffdemux_marshal_BOOLEAN__OBJECT (GClosure *closure,
3088                                    GValue       *return_value G_GNUC_UNUSED,
3089                                    guint         n_param_values,
3090                                    const GValue *param_values,
3091                                    gpointer      invocation_hint G_GNUC_UNUSED,
3092                                    gpointer      marshal_data)
3093 {
3094   typedef gboolean (*GMarshalFunc_BOOLEAN__OBJECT) (gpointer  data1,
3095                                                     gpointer      arg_1,
3096                                                     gpointer     data2);
3097   register GMarshalFunc_BOOLEAN__OBJECT callback;
3098   register GCClosure *cc = (GCClosure*) closure;
3099   register gpointer data1, data2;
3100   gboolean v_return;
3101
3102   g_return_if_fail (return_value != NULL);
3103   g_return_if_fail (n_param_values == 2);
3104
3105   if (G_CCLOSURE_SWAP_DATA (closure))
3106   {
3107     data1 = closure->data;
3108     data2 = g_value_peek_pointer (param_values + 0);
3109   }
3110   else
3111   {
3112     data1 = g_value_peek_pointer (param_values + 0);
3113     data2 = closure->data;
3114   }
3115   callback = (GMarshalFunc_BOOLEAN__OBJECT) (marshal_data ? marshal_data : cc->callback);
3116
3117   v_return = callback (data1,
3118                        g_marshal_value_peek_object (param_values + 1),
3119                        data2);
3120
3121   g_value_set_boolean (return_value, v_return);
3122 }
3123
3124 #define PIFFDEMUX_SPSPPS_LENGTH_SIZE     2
3125
3126 static gboolean
3127 ConvertH264_MetaDCI_to_3GPPDCI(unsigned char *dci_meta_buf, unsigned int dci_meta_size, unsigned char **dci_3gpp_buf, unsigned int *dci_3gpp_size)
3128 {
3129   unsigned short unit_size = 0;
3130   unsigned int total_size = 0;
3131   unsigned char unit_nb = 0;
3132   unsigned char sps_done = 0;
3133   const unsigned char *extradata = NULL;
3134   unsigned int h264_nal_length_size = 0;
3135   unsigned char *out = NULL;
3136   //g_print ("\n\nConvertH264_MetaDCI_to_3GPPDCI Entering.............\n");
3137
3138   /* nothing to filter */
3139   if ((dci_meta_buf == NULL) || (dci_meta_size < 6))
3140   {
3141     GST_ERROR ("Insufficient codec data...\n");
3142     return FALSE;
3143   }
3144
3145   /* Removing unnecessary info in meta data */
3146   extradata = (unsigned char *)dci_meta_buf + 4;
3147
3148   /* retrieve Length of Length*/
3149   h264_nal_length_size = (*extradata++ & 0x03) + 1;
3150
3151   GST_LOG ("Length Of Length is %d\n", h264_nal_length_size);
3152   if (h264_nal_length_size == 3)
3153   {
3154     GST_ERROR ("LengthOfLength is WRONG...\n");
3155     return FALSE;
3156   }
3157
3158   /* retrieve sps and pps unit(s) */
3159   unit_nb = *extradata++ & 0x1f; /* number of sps unit(s) */
3160   GST_LOG ("No. of SPS units = %u\n", unit_nb);
3161
3162   if (!unit_nb)
3163   {
3164     GST_ERROR ("SPS is not present....\n");
3165     return FALSE;
3166   }
3167
3168   while (unit_nb--)
3169   {
3170     /* get SPS/PPS data Length*/
3171     unit_size = PIFFDEMUX_RB16(extradata);
3172
3173     GST_LOG ("SPS size = %d", unit_size);
3174
3175     /* Extra 4 bytes for adding size of the packet */
3176     total_size += unit_size + h264_nal_length_size;
3177
3178     /* Check if SPS/PPS Data Length crossed buffer Length */
3179     if ((extradata + 2 + unit_size) > (dci_meta_buf + dci_meta_size))
3180     {
3181       GST_ERROR ("SPS Length is wrong in DCI...\n");
3182       if (out)
3183       {
3184         free (out);
3185       }
3186       return FALSE;
3187     }
3188     out = realloc(out, total_size);
3189     if (!out)
3190     {
3191       GST_ERROR ("realloc FAILED...\n");
3192       return FALSE;
3193     }
3194     /* Copy length of SPS header */
3195    // tmp = (unsigned int *)(out + total_size - unit_size - h264_nal_length_size);
3196    // *tmp = unit_size;
3197    (out + total_size - unit_size - h264_nal_length_size)[0] = 0;
3198    (out + total_size - unit_size - h264_nal_length_size)[1] = 0;
3199    (out + total_size - unit_size - h264_nal_length_size)[2] = 0;
3200    (out + total_size - unit_size - h264_nal_length_size)[3] = (unsigned char)unit_size;
3201
3202    // memcpy(out + total_size - unit_size - h264_nal_length_size, &unit_size, h264_nal_length_size);
3203    //g_print ("out[0] = %02x, out[1] = %02x, out[2] = %02x = out[3] = %02x\n",
3204    //out[total_size - unit_size - h264_nal_length_size],  out[total_size - unit_size - h264_nal_length_size+1],
3205    //out[total_size - unit_size - h264_nal_length_size + 2],  out[total_size - unit_size - h264_nal_length_size + 3]);
3206
3207     /* Copy SPS/PPS Length and data */
3208     memcpy(out + total_size - unit_size,  extradata + PIFFDEMUX_SPSPPS_LENGTH_SIZE, unit_size);
3209
3210     extradata += (PIFFDEMUX_SPSPPS_LENGTH_SIZE + unit_size);
3211
3212     if (!unit_nb && !sps_done++)
3213     {
3214       /* Completed reading SPS data, now read PPS data */
3215       unit_nb = *extradata++; /* number of pps unit(s) */
3216       GST_DEBUG ("No. of PPS units = %d\n", unit_nb);
3217     }
3218   }
3219
3220   *dci_3gpp_buf = malloc (total_size);
3221   if (NULL == *dci_3gpp_buf)
3222   {
3223     GST_ERROR ("Memory Allocation FAILED...\n");
3224     free (out);
3225     return FALSE;
3226   }
3227
3228   memcpy(*dci_3gpp_buf, out, total_size);
3229   *dci_3gpp_size = total_size;
3230
3231   GST_DEBUG ("SPS_PPS size = %d\n", total_size);
3232
3233   free(out);
3234
3235   return TRUE;
3236  }
3237
3238 #ifdef DRM_ENABLE
3239 static void
3240 piffdemux_get_playready_licence (GstPiffDemux *demux)
3241 {
3242   int ret = -1;
3243   drm_trusted_piff_get_license_info_s license_info;
3244   drm_trusted_request_type_e request_type = DRM_TRUSTED_REQ_TYPE_PIFF_GET_LICENSE;
3245
3246   memset(&license_info, 0x00, sizeof(drm_trusted_piff_get_license_info_s));
3247
3248   license_info.lic_header.header = (unsigned char*) GST_BUFFER_DATA (demux->protection_header);
3249   license_info.lic_header.header_len = GST_BUFFER_SIZE (demux->protection_header);
3250
3251   ret = drm_trusted_handle_request(request_type, (void *) &license_info, NULL);
3252   if (DRM_TRUSTED_RETURN_SUCCESS != ret) {
3253     GST_ERROR_OBJECT (demux,"failed to get license...");
3254     GST_ELEMENT_ERROR (demux, RESOURCE, FAILED, ("failed to get license"), (NULL));
3255     return;
3256   }
3257
3258   GST_INFO_OBJECT (demux, "Got license....\n");
3259
3260   demux->encrypt_content = TRUE;
3261
3262   return;
3263 }
3264
3265 void
3266 test_drm_trusted_operation_cb(drm_trusted_user_operation_info_s *operation_info, void *output_data)
3267 {
3268         g_print ("Callback Hit:test_drm_trusted_operation_cb\n");
3269         g_print ("operation_status=%d\n",operation_info->operation_status);
3270         g_print ("operation_type=%d\n",operation_info->operation_type);
3271 }
3272 #endif
3273