8 #include <glib/gprintf.h>
9 #include <gst/tag/tag.h>
13 #include <piffatomparser.h>
14 #include <piffdemux_fourcc.h>
15 #include <piffpalette.h>
16 #include <piffdemux_types.h>
17 #include <piffdemux_dump.h>
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
26 #define PIFF_DEFAULT_WIDTH 16
27 #define PIFF_DEFAULT_HEIGHT 16
28 #define PIFF_DEFAULT_BPS 16
30 #undef DEC_OUT_FRAME_DUMP
32 #ifdef DEC_OUT_FRAME_DUMP
34 FILE *piffdump = NULL;
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)
41 /* if the sample index is larger than this, something is likely wrong */
42 #define PIFFDEMUX_MAX_SAMPLE_INDEX_SIZE (50*1024*1024)
44 GST_DEBUG_CATEGORY (piffdemux_debug);
46 typedef struct _PiffDemuxSegment PiffDemuxSegment;
47 typedef struct _PiffDemuxSample PiffDemuxSample;
48 typedef struct _PiffDemuxSubSampleEncryption PiffDemuxSubSampleEncryption;
49 typedef struct _PiffDemuxSubSampleEntryInfo PiffDemuxSubSampleEntryInfo;
55 PROP_PIFF_MEDIA_TIMESCALE,
56 PROP_PIFF_MEDIA_DURATION,
57 PROP_PIFF_MEDIA_START_TIMESTAMP,
59 PROP_PIFF_LOOKAHEAD_COUNT,
60 PROP_PIFF_AVG_FRAME_DUR,
62 PROP_PROTECTION_HEADER_BUFFER,
72 static guint gst_piffdemux_signals[LAST_SIGNAL] = { 0 };
74 struct _PiffDemuxSubSampleEntryInfo
76 guint16 LenofClearData;
77 guint32 LenofEncryptData;
80 struct _PiffDemuxSubSampleEncryption
83 PiffDemuxSubSampleEntryInfo *sub_entry;
86 struct _PiffDemuxSample
89 gint32 pts_offset; /* Add this value to timestamp to get the pts */
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;
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));
111 #define PIFFSAMPLE_KEYFRAME(stream,sample) ((sample)->keyframe);
113 typedef char uuid_t[16];
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 };
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 };
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 };
130 #define SE_OVERRIDE_TE_FLAGS 0x000001
131 #define SE_USE_SUBSAMPLE_ENCRYPTION 0x000002
141 struct _PiffDemuxSegment
143 /* global time and duration, all gst time */
147 /* media time of trak, all gst time */
154 struct _PiffDemuxStream
162 guint64 duration; /* in timescale */
167 PiffDemuxSample *samples;
168 guint32 min_duration; /* duration in timescale of first sample, used for figuring out
169 the framerate, in timescale units */
171 /* if we use chunks or samples */
175 /* when a discontinuity is pending */
178 /* list of buffers to push first */
181 /* buffer needs some custom processing, e.g. subtitles */
182 gboolean need_process;
184 /* current position */
185 guint32 segment_index;
186 guint32 sample_index;
187 guint64 time_position; /* in gst time */
189 /* the Gst segment we are processing out, used for clipping */
192 /* last GstFlowReturn */
193 GstFlowReturn last_ret;
196 /* quicktime segments */
198 PiffDemuxSegment *segments;
203 GstTagList *pending_tags;
204 gboolean send_global_tags;
206 GstEvent *pending_event;
208 gboolean sent_nsevent;
212 guint64 avg_dur; /* average frame duration */
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 */
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);
232 static GstStaticPadTemplate gst_piffdemux_sink_template =
233 GST_STATIC_PAD_TEMPLATE ("sink",
236 GST_STATIC_CAPS ("application/x-piff")
239 static GstStaticPadTemplate gst_piffdemux_src_template =
240 GST_STATIC_PAD_TEMPLATE ("src",
243 GST_STATIC_CAPS_ANY);
246 GST_BOILERPLATE (GstPiffDemux, gst_piffdemux, GstPiffDemux, GST_TYPE_ELEMENT);
248 static void gst_piffdemux_dispose (GObject * object);
250 static GstStateChangeReturn gst_piffdemux_change_state (GstElement * element,
251 GstStateChange transition);
253 gst_piffdemux_set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec);
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);
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);
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);
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);
281 gst_piffdemux_base_init (gpointer klass)
283 GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
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",
291 "Parser for PIFF file format",
292 "naveen ch <naveen.ch@samsung.com>");
294 GST_DEBUG_CATEGORY_INIT (piffdemux_debug, "piffdemux", 0, "piffdemux plugin");
298 gst_piffdemux_class_init (GstPiffDemuxClass * klass)
300 GObjectClass *gobject_class;
301 GstElementClass *gstelement_class;
303 gobject_class = (GObjectClass *) klass;
304 gstelement_class = (GstElementClass *) klass;
306 parent_class = g_type_class_peek_parent (klass);
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;
312 gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_piffdemux_change_state);
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));
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,
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));
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,
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,
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));
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));
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,
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);
368 gst_piffdemux_init (GstPiffDemux * piffdemux, GstPiffDemuxClass * klass)
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);
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);
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;
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;
411 piffdemux->pr_handle = NULL;
413 piffdemux->decrypt_init = FALSE;
414 piffdemux->encrypt_content = FALSE;
416 #ifdef DEC_OUT_FRAME_DUMP
417 piffdump = fopen ("/opt/media/piff_out_dump.dmp", "w+");
418 if (piffdump == NULL)
420 g_print ("\nNot able to create frame dump file\n");
424 gst_segment_init (&piffdemux->segment, GST_FORMAT_TIME);
428 gst_piffdemux_dispose (GObject * object)
430 GstPiffDemux *piffdemux = GST_PIFFDEMUX (object);
432 if (piffdemux->adapter) {
433 g_object_unref (G_OBJECT (piffdemux->adapter));
434 piffdemux->adapter = NULL;
437 #ifdef DEC_OUT_FRAME_DUMP
443 G_OBJECT_CLASS (parent_class)->dispose (object);
448 gst_piffdemux_set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
450 GstPiffDemux *piffdemux = GST_PIFFDEMUX (object);
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);
461 if (!gst_pad_set_caps(piffdemux->srcpad, piffdemux->stream->caps)) {
462 GST_ERROR_OBJECT (piffdemux, "not able to set caps...");
466 case PROP_PIFF_MEDIA_TIMESCALE:
467 piffdemux->stream->timescale = g_value_get_uint64(value);
469 case PROP_PIFF_MEDIA_DURATION:
470 piffdemux->stream->duration = g_value_get_int64(value);
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));
476 case PROP_PIFF_IS_LIVE:
477 piffdemux->is_live = g_value_get_boolean(value);
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);
484 case PROP_PROTECTION_HEADER_BUFFER:
485 piffdemux->protection_header = gst_value_get_buffer(value);
486 piffdemux_get_playready_licence (piffdemux);
490 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
497 gst_piffdemux_get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
499 GstPiffDemux *piffdemux = GST_PIFFDEMUX (object);
502 case PROP_PIFF_MEDIA_CAPS:
503 gst_value_set_caps (value, piffdemux->stream->caps);
505 case PROP_PIFF_MEDIA_TIMESCALE:
506 g_value_set_uint64 (value, piffdemux->stream->timescale);
508 case PROP_PIFF_MEDIA_DURATION:
509 g_value_set_int64 (value, piffdemux->stream->duration);
511 case PROP_PIFF_MEDIA_START_TIMESTAMP:
512 g_value_set_uint64 (value, piffdemux->stream->start_ts);
514 case PROP_PIFF_IS_LIVE:
515 g_value_set_boolean(value, piffdemux->is_live);
517 case PROP_PIFF_LOOKAHEAD_COUNT:
518 g_value_set_uint (value, piffdemux->lookahead_cnt);
520 case PROP_PIFF_AVG_FRAME_DUR:
521 g_value_set_uint64 (value, piffdemux->stream->avg_dur);
524 case PROP_PROTECTION_HEADER_BUFFER:
525 gst_value_take_buffer (value, piffdemux->protection_header);
529 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
536 gst_piffdemux_post_no_playable_stream_error (GstPiffDemux * piffdemux)
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"));
543 GST_ELEMENT_ERROR (piffdemux, STREAM, DEMUX,
544 ("This file contains no playable streams."),
545 ("no known streams found"));
551 gst_piffdemux_src_convert (GstPad * pad, GstFormat src_format, gint64 src_value,
552 GstFormat dest_format, gint64 * dest_value)
555 PiffDemuxStream *stream = gst_pad_get_element_private (pad);
556 GstPiffDemux *piffdemux = GST_PIFFDEMUX (gst_pad_get_parent (pad));
558 if (stream->subtype != FOURCC_vide) {
563 switch (src_format) {
564 case GST_FORMAT_TIME:
565 switch (dest_format) {
566 case GST_FORMAT_BYTES:{
575 case GST_FORMAT_BYTES:
576 switch (dest_format) {
577 case GST_FORMAT_TIME:{
591 gst_object_unref (piffdemux);
596 static const GstQueryType *
597 gst_piffdemux_get_src_query_types (GstPad * pad)
599 static const GstQueryType src_types[] = {
612 gst_piffdemux_get_duration (GstPiffDemux * piffdemux, gint64 * duration)
616 *duration = GST_CLOCK_TIME_NONE;
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);
628 gst_piffdemux_handle_src_query (GstPad * pad, GstQuery * query)
630 gboolean res = FALSE;
631 GstPiffDemux *piffdemux = GST_PIFFDEMUX (gst_pad_get_parent (pad));
633 GST_LOG_OBJECT (pad, "%s query", GST_QUERY_TYPE_NAME (query));
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);
644 case GST_QUERY_DURATION:{
646 GST_ERROR ("Querying DURATION from piffdemux....");
648 gst_query_parse_duration (query, &fmt, NULL);
649 if (fmt == GST_FORMAT_TIME) {
650 gint64 duration = -1;
652 gst_piffdemux_get_duration (piffdemux, &duration);
654 gst_query_set_duration (query, GST_FORMAT_TIME, duration);
660 case GST_QUERY_CONVERT:{
661 GstFormat src_fmt, dest_fmt;
662 gint64 src_value, dest_value = 0;
664 gst_query_parse_convert (query, &src_fmt, &src_value, &dest_fmt, NULL);
666 res = gst_piffdemux_src_convert (pad,
667 src_fmt, src_value, dest_fmt, &dest_value);
669 gst_query_set_convert (query, src_fmt, src_value, dest_fmt, dest_value);
674 case GST_QUERY_FORMATS:
675 gst_query_set_formats (query, 2, GST_FORMAT_TIME, GST_FORMAT_BYTES);
678 case GST_QUERY_SEEKING:{
683 res = gst_pad_query_default (pad, query);
687 gst_object_unref (piffdemux);
694 gst_piffdemux_push_tags (GstPiffDemux * piffdemux, PiffDemuxStream * stream)
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;
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;
715 gst_piffdemux_push_event (GstPiffDemux * piffdemux, GstEvent * event)
717 GstEventType etype = GST_EVENT_TYPE (event);
719 GST_DEBUG_OBJECT (piffdemux, "pushing %s event on source pad",
720 GST_EVENT_TYPE_NAME (event));
722 if (piffdemux->stream->sent_eos) {
723 GST_INFO_OBJECT (piffdemux, "already sent eos");
727 if (!gst_pad_push_event (piffdemux->srcpad, event)) {
728 GST_ERROR_OBJECT (piffdemux, "error in sending event to srcpad...");
731 if (etype == GST_EVENT_EOS)
732 piffdemux->stream->sent_eos = TRUE;
736 /* find the segment for @time_position for @stream
738 * Returns -1 if the segment cannot be found.
741 gst_piffdemux_find_segment (GstPiffDemux * piffdemux, PiffDemuxStream * stream,
742 guint64 time_position)
747 GST_LOG_OBJECT (piffdemux, "finding segment for %" GST_TIME_FORMAT,
748 GST_TIME_ARGS (time_position));
750 /* find segment corresponding to time_position if we are looking
753 for (i = 0; i < stream->n_segments; i++) {
754 PiffDemuxSegment *segment = &stream->segments[i];
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));
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);
768 if (segment->time <= time_position && time_position <= segment->stop_time) {
769 GST_LOG_OBJECT (piffdemux, "segment %d matches", i);
780 gst_piffdemux_handle_src_event (GstPad * pad, GstEvent * event)
783 GstPiffDemux *piffdemux = GST_PIFFDEMUX (gst_pad_get_parent (pad));
785 switch (GST_EVENT_TYPE (event)) {
787 case GST_EVENT_NAVIGATION:
789 gst_event_unref (event);
793 res = gst_pad_event_default (pad, event);
797 gst_object_unref (piffdemux);
804 gst_piffdemux_move_stream (GstPiffDemux * piffdemux, PiffDemuxStream * str,
807 /* no change needed */
808 if (index == str->sample_index)
811 GST_DEBUG_OBJECT (piffdemux, "moving to sample %u of %u", index,
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
818 str->from_sample = index;
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 */
827 gst_piffdemux_find_sample (GstPiffDemux * piffdemux, gint64 byte_pos, gboolean fw,
828 gboolean set, PiffDemuxStream ** _stream, gint * _index, gint64 * _time)
831 gint64 time, min_time;
832 PiffDemuxStream *stream;
833 PiffDemuxStream *str = piffdemux->stream;
846 i = str->n_samples - 1;
850 for (; (i >= 0) && (i < str->n_samples); i += inc) {
851 if (str->samples[i].size &&
852 ((fw && (str->samples[i].offset >= byte_pos)) ||
854 (str->samples[i].offset + str->samples[i].size <=
856 /* move stream to first available sample */
858 gst_piffdemux_move_stream (piffdemux, str, i);
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*/ {
872 /* no sample for this stream, mark eos */
874 gst_piffdemux_move_stream (piffdemux, str, str->n_samples);
886 gst_piffdemux_handle_sink_event (GstPad * sinkpad, GstEvent * event)
888 GstPiffDemux *demux = GST_PIFFDEMUX (GST_PAD_PARENT (sinkpad));
891 GST_LOG_OBJECT (demux, "handling %s event", GST_EVENT_TYPE_NAME (event));
893 switch (GST_EVENT_TYPE (event)) {
894 case GST_EVENT_NEWSEGMENT:
898 gint64 start, stop, time, offset = 0;
899 PiffDemuxStream *stream;
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,
910 GST_ERROR_OBJECT (demux,
911 "received format %d newsegment %" GST_SEGMENT_FORMAT, format,
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");
920 /* we only expect a BYTE segment, e.g. following a seek */
921 if (format == GST_FORMAT_BYTES) {
923 gint64 requested_seek_time;
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);
935 if (offset == seek_offset) {
936 start = requested_seek_time;
938 gst_piffdemux_find_sample (demux, start, TRUE, FALSE, NULL, NULL,
940 start = MAX (start, 0);
944 gst_piffdemux_find_sample (demux, stop, FALSE, FALSE, NULL, NULL,
946 /* keyframe seeking should already arrange for start >= stop,
947 * but make sure in other rare cases */
948 stop = MAX (stop, start);
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;
958 demux->neededbytes = 16;
959 demux->state = PIFFDEMUX_STATE_INITIAL;
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;
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));
978 gst_piffdemux_push_event (demux,
979 gst_event_new_new_segment_full (update, rate, arate, GST_FORMAT_TIME, start, stop, start));
981 /* clear leftover in current segment, if any */
982 gst_adapter_clear (demux->adapter);
988 GST_DEBUG_OBJECT (demux, "unsupported segment format, ignoring");
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));
1000 gst_piffdemux_push_event (demux,
1001 gst_event_new_new_segment_full (update, rate, arate, GST_FORMAT_TIME,
1002 start, stop, start));
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;
1010 demux->todrop = stream->samples[idx].offset - offset;
1011 demux->neededbytes = demux->todrop + stream->samples[idx].size;
1013 /* set up for EOS */
1014 demux->neededbytes = -1;
1018 gst_event_unref (event);
1023 case GST_EVENT_FLUSH_STOP:
1025 /* clean up, force EOS if no more info follows */
1026 gst_adapter_clear (demux->adapter);
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;
1040 res = gst_pad_event_default (demux->sinkpad, event);
1048 gst_piffdemux_stream_free (GstPiffDemux * piffdemux, PiffDemuxStream * stream)
1052 g_return_if_fail (stream != NULL);
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);
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;
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;
1070 free (stream->samples[i].sub_encry);
1071 stream->samples[i].sub_encry = NULL;
1075 if (stream->samples) {
1076 g_free (stream->samples);
1077 stream->samples = NULL;
1080 gst_caps_unref (stream->caps);
1081 stream->caps = NULL;
1083 if (stream->segments) {
1084 g_free (stream->segments);
1085 stream->segments = NULL;
1087 if (stream->pending_tags) {
1088 gst_tag_list_free (stream->pending_tags);
1089 stream->pending_tags = NULL;
1095 static GstStateChangeReturn
1096 gst_piffdemux_change_state (GstElement * element, GstStateChange transition)
1098 GstPiffDemux *piffdemux = GST_PIFFDEMUX (element);
1099 GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE;
1101 switch (transition) {
1102 case GST_STATE_CHANGE_PAUSED_TO_READY:
1108 result = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
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);
1138 piffdemux_post_global_tags (GstPiffDemux * piffdemux)
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)));
1152 /* caller verifies at least 8 bytes in buf */
1154 extract_initial_length_and_fourcc (const guint8 * data, guint size,
1155 guint64 * plength, guint32 * pfourcc)
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));
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);
1181 piffdemux_update_sample_offset (GstPiffDemux * piffdemu, PiffDemuxStream * stream, gint64 uuid_offset)
1183 PiffDemuxSample *sample;
1186 sample = stream->samples ;
1187 for (i = 0; i < stream->n_samples; i++)
1189 sample->offset = sample->offset + uuid_offset;
1196 piffdemux_get_uuid_type(GstPiffDemux * piffdemux, GstByteReader *uuid_data, gint64 *uuid_offset)
1198 uuid_type_t uuid_type = UUID_UNKNOWN;
1199 guint32 box_len = 0;
1200 guint64 box_long_len = 0;
1201 gchar uuid[16] = {0,};
1204 if (!gst_byte_reader_get_uint32_be (uuid_data, &box_len))
1207 /* Skipping fourcc */
1208 if (!gst_byte_reader_skip (uuid_data, 4))
1213 GST_WARNING ("TfxdBoxLongLength field is present...");
1214 if (!gst_byte_reader_get_uint64_be (uuid_data, &box_long_len))
1216 GST_DEBUG ("tfxd long length = %llu", box_long_len);
1218 *uuid_offset = box_long_len;
1222 GST_DEBUG ("Box Len = %d", box_len);
1223 *uuid_offset = box_len;
1226 //g_print ("\n\n\n 0x");
1227 for (i = 0; i < sizeof (uuid); i++)
1229 if (!gst_byte_reader_get_uint8 (uuid_data, &(uuid[i])))
1231 //g_print ("%02x", uuid[i]);
1233 //g_print ("\n\n\n");
1235 if (!memcmp(uuid, tfxd_uuid, sizeof (uuid_t)))
1237 GST_INFO ("Found TFXD box");
1240 else if (!memcmp(uuid, tfrf_uuid, sizeof (uuid_t)))
1242 GST_INFO ("Found TFRF box");
1245 else if (!memcmp(uuid, encrypt_uuid, sizeof (uuid_t)))
1247 GST_INFO ("Found sample encryption box");
1248 return UUID_SAMPLE_ENCRYPT;
1252 GST_WARNING ("Not an valid UUID box..");
1258 GST_ERROR ("Error in parsing UUID atom...");
1259 return UUID_UNKNOWN;
1263 piffdemux_parse_sample_encryption(GstPiffDemux * piffdemux, GstByteReader *sample_encrypt, PiffDemuxStream * stream)
1266 guint32 sample_count = 0;
1271 if (!gst_byte_reader_skip (sample_encrypt, 1) ||
1272 !gst_byte_reader_get_uint24_be (sample_encrypt, &flags))
1273 goto invalid_encryption;
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;
1281 if (!gst_byte_reader_get_uint8 (sample_encrypt, &iv_size))
1282 goto invalid_encryption;
1284 // TODO: need to add reading of KID
1286 GST_INFO_OBJECT (piffdemux, "Override flags are not present... taking default IV_Size = 8");
1290 /* Get sample count*/
1291 if (!gst_byte_reader_get_uint32_be (sample_encrypt, &sample_count))
1292 goto invalid_encryption;
1294 GST_INFO_OBJECT (piffdemux, "Sample count = %d", sample_count);
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;
1302 for (i = 0; i < stream->n_samples; i++) {
1303 guint8 iv_idx = iv_size;
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;
1312 memset (stream->samples[i].iv, 0x00, iv_size);
1315 while (iv_idx < iv_size) {
1317 if (!gst_byte_reader_get_uint8 (sample_encrypt, &(stream->samples[i].iv[iv_idx])))
1318 goto invalid_encryption;
1326 g_print ("sample[%d] : 0x ", i);
1328 while (tmp_idx < iv_size ) {
1329 g_print ("%02x ", stream->samples[i].iv[tmp_idx]);
1336 if (flags & SE_USE_SUBSAMPLE_ENCRYPTION) {
1340 /* NumberofEntries in SubSampleEncryption */
1341 if (!gst_byte_reader_get_uint16_be (sample_encrypt, &n_entries))
1342 goto invalid_encryption;
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;
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;
1356 stream->samples[i].sub_encry->n_entries = n_entries;
1358 GST_DEBUG_OBJECT (piffdemux,"No. of subsample entries = %d", stream->samples[i].sub_encry->n_entries);
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;
1364 GST_DEBUG_OBJECT (piffdemux,"entry[%d] and lengthofClearData = %d", n_idx, stream->samples[i].sub_encry->sub_entry[n_idx].LenofClearData);
1366 if (!gst_byte_reader_get_uint32_be (sample_encrypt, &(stream->samples[i].sub_encry->sub_entry[n_idx].LenofEncryptData)))
1367 goto invalid_encryption;
1369 GST_DEBUG_OBJECT (piffdemux,"entry[%d] and lengthofEncryptData = %d", n_idx, stream->samples[i].sub_encry->sub_entry[n_idx].LenofEncryptData);
1378 GST_WARNING_OBJECT (piffdemux, "invalid sample encryption header");
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)
1391 gint32 data_offset = 0;
1392 guint32 flags = 0, first_flags = 0, samples_count = 0;
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;
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,
1405 //Resetting the samples
1406 stream->n_samples = 0;
1408 if (!gst_byte_reader_skip (trun, 1) ||
1409 !gst_byte_reader_get_uint24_be (trun, &flags))
1412 if (!gst_byte_reader_get_uint32_be (trun, &samples_count))
1415 if (flags & TR_DATA_OFFSET) {
1416 /* note this is really signed */
1417 if (!gst_byte_reader_get_int32_be (trun, &data_offset))
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;
1425 *running_offset = *base_offset + data_offset;
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");
1435 if (*running_offset == -1)
1436 *running_offset = *base_offset;
1439 GST_LOG_OBJECT (piffdemux, "running offset now %" G_GINT64_FORMAT,
1441 GST_LOG_OBJECT (piffdemux, "trun offset %d, flags 0x%x, entries %d",
1442 data_offset, flags, samples_count);
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;
1450 if (!gst_byte_reader_get_uint32_be (trun, &first_flags))
1452 GST_LOG_OBJECT (piffdemux, "first flags: 0x%x", first_flags);
1456 /* FIXME ? spec says other bits should also be checked to determine
1457 * entry size (and prefix size for that matter) */
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;
1465 if (flags & TR_SAMPLE_SIZE) {
1466 GST_LOG_OBJECT (piffdemux, "entry size present");
1467 size_offset = entry_size;
1470 if (flags & TR_SAMPLE_FLAGS) {
1471 GST_LOG_OBJECT (piffdemux, "entry flags present");
1472 flags_offset = entry_size;
1475 if (flags & TR_COMPOSITION_TIME_OFFSETS) {
1476 GST_LOG_OBJECT (piffdemux, "entry ct offset present");
1477 ct_offset = entry_size;
1481 if (!piff_atom_parser_has_chunks (trun, samples_count, entry_size))
1483 data = (guint8 *) gst_byte_reader_peek_data_unchecked (trun);
1485 if (stream->n_samples >=
1486 PIFFDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (PiffDemuxSample))
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));
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 */
1498 stream->samples = g_try_renew (PiffDemuxSample, stream->samples,
1499 stream->n_samples + samples_count);
1500 if (stream->samples == NULL)
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 */
1508 /* subsequent fragments extend stream */
1510 stream->samples[stream->n_samples - 1].timestamp +
1511 stream->samples[stream->n_samples - 1].duration;
1513 sample = stream->samples + stream->n_samples;
1514 for (i = 0; i < samples_count; i++) {
1515 guint32 dur, size, sflags, ct;
1517 /* first read sample data */
1518 if (flags & TR_SAMPLE_DURATION) {
1519 dur = PIFF_UINT32 (data + dur_offset);
1521 dur = d_sample_duration;
1523 if (flags & TR_SAMPLE_SIZE) {
1524 size = PIFF_UINT32 (data + size_offset);
1526 size = d_sample_size;
1529 GST_DEBUG_OBJECT(piffdemux,"Size of sample %d is %d", i, size);
1531 if (flags & TR_FIRST_SAMPLE_FLAGS) {
1533 sflags = first_flags;
1535 sflags = d_sample_flags;
1537 } else if (flags & TR_SAMPLE_FLAGS) {
1538 sflags = PIFF_UINT32 (data + flags_offset);
1540 sflags = d_sample_flags;
1542 if (flags & TR_COMPOSITION_TIME_OFFSETS) {
1543 ct = PIFF_UINT32 (data + ct_offset);
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);
1560 sample->sub_encry = NULL;
1562 stream->samples[i] = *sample;
1564 *running_offset += size;
1568 /* calculate total duration of the present fragment */
1569 total_duration += gst_util_uint64_scale (dur, GST_SECOND, stream->timescale);
1572 stream->sample_index = 0;
1574 stream->n_samples += samples_count;
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);
1585 GST_WARNING_OBJECT (piffdemux, "failed to parse trun");
1590 GST_WARNING_OBJECT (piffdemux, "failed to allocate %d samples",
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);
1604 piffdemux_parse_mfhd (GstPiffDemux * piffdemux, GstByteReader * mfhd)
1606 guint32 seq_num = 0;
1608 if (!gst_byte_reader_skip (mfhd, 4))
1611 if (!gst_byte_reader_get_uint32_be (mfhd, &seq_num))
1614 GST_DEBUG_OBJECT (piffdemux, "sequence number present in mfhd = %d", seq_num);
1620 GST_WARNING_OBJECT (piffdemux, "invalid movie fragment header");
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)
1633 guint32 track_id = 0;
1635 if (!gst_byte_reader_skip (tfhd, 1) ||
1636 !gst_byte_reader_get_uint24_be (tfhd, &flags))
1639 if (!gst_byte_reader_get_uint32_be (tfhd, &track_id))
1642 GST_DEBUG_OBJECT (piffdemux, "trackID = %d", track_id);
1644 if (flags & TF_BASE_DATA_OFFSET) {
1645 if (!gst_byte_reader_get_uint64_be (tfhd, (guint64 *) base_offset))
1647 GST_DEBUG ("BaseData Offset = %"G_GUINT64_FORMAT, base_offset);
1650 /* FIXME: Handle TF_SAMPLE_DESCRIPTION_INDEX properly */
1651 if (flags & TF_SAMPLE_DESCRIPTION_INDEX)
1652 if (!gst_byte_reader_skip (tfhd, 4))
1655 if (flags & TF_DEFAULT_SAMPLE_DURATION)
1656 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_duration))
1659 if (flags & TF_DEFAULT_SAMPLE_SIZE)
1660 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_size))
1663 if (flags & TF_DEFAULT_SAMPLE_FLAGS)
1664 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_flags))
1671 GST_WARNING_OBJECT (piffdemux, "invalid track fragment header");
1677 piffdemux_parse_tfxd (GstPiffDemux * piffdemux, PiffDemuxStream *stream,GstByteReader * tfxd)
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
1683 if (!gst_byte_reader_get_uint8 (tfxd, &version))
1686 if (!gst_byte_reader_skip (tfxd, 3))
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");
1695 piffdemux->param->count = 1;
1696 piffdemux->param->long_info = NULL;
1697 piffdemux->param->info = NULL;
1698 piffdemux->param->is_eos = FALSE;
1700 // TODO: presentation will be ended based on timeout in souphttpsrc in lookaheadcnt = 0 case
1704 guint64 duration = 0;
1705 guint64 timestamp = 0;
1707 GST_LOG_OBJECT (piffdemux, "Time and Duration are in 64-bit format...");
1708 if (!gst_byte_reader_get_uint64_be (tfxd, ×tamp))
1710 if (!gst_byte_reader_get_uint64_be (tfxd, &duration))
1713 GST_DEBUG_OBJECT (piffdemux, "tfxd : absolute timestamp = %"G_GUINT64_FORMAT" and duration of fragment = %"G_GUINT64_FORMAT,
1714 timestamp, duration);
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");
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;
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...");
1732 if (!gst_byte_reader_get_uint32_be (tfxd, ×tamp))
1735 if (!gst_byte_reader_get_uint32_be (tfxd, &duration))
1738 GST_DEBUG_OBJECT (piffdemux, "tfxd : absolute timestamp = %"G_GUINT32_FORMAT" and duration of fragment = %"G_GUINT32_FORMAT,
1739 timestamp, duration);
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");
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;
1752 GST_ERROR_OBJECT (piffdemux, "Invalid Version in tfxd...");
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);
1764 GST_ERROR ("Invalid TFXD atom...");
1770 piffdemux_parse_tfrf (GstPiffDemux * piffdemux, PiffDemuxStream *stream,GstByteReader * tfrf)
1773 guint8 frag_cnt = 0;
1776 /* Getting version info */
1777 if (!gst_byte_reader_get_uint8 (tfrf, &version))
1780 /* skipping reserved flags */
1781 if (!gst_byte_reader_skip (tfrf, 3))
1784 if (!gst_byte_reader_get_uint8 (tfrf, &frag_cnt))
1787 GST_INFO_OBJECT (piffdemux, "Subsequent fragments info count = %d", frag_cnt);
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");
1795 piffdemux->param->count = frag_cnt;
1796 piffdemux->param->long_info = NULL;
1797 piffdemux->param->info = NULL;
1798 piffdemux->param->is_eos = FALSE;
1800 // TODO: Duration and timestamp values need to be posted to msl using g_signal_emit
1803 guint64 duration = 0;
1804 guint64 timestamp = 0;
1805 GST_LOG_OBJECT (piffdemux, "Time and Duration are in 64-bit format...");
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");
1813 for (i = 0; i < frag_cnt; i++) {
1814 if (!gst_byte_reader_get_uint64_be (tfrf, ×tamp))
1816 if (!gst_byte_reader_get_uint64_be (tfrf, &duration))
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;
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...");
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");
1834 for (i = 0; i < frag_cnt; i++) {
1835 if (!gst_byte_reader_get_uint32_be (tfrf, ×tamp))
1837 if (!gst_byte_reader_get_uint32_be (tfrf, &duration))
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;
1846 GST_ERROR_OBJECT (piffdemux, "Invalid Version in tfrf...");
1850 g_print ("Signalling from TFRF box..\n");
1851 g_signal_emit (piffdemux, gst_piffdemux_signals[SIGNAL_LIVE_PARAM], 0, piffdemux->param);
1856 GST_ERROR_OBJECT (piffdemux, "Invalid TFRF atom...");
1862 piffdemux_parse_moof (GstPiffDemux * piffdemux, const guint8 * buffer, guint length,
1863 guint64 moof_offset, PiffDemuxStream * stream)
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;
1873 /* NOTE @stream ignored */
1875 moof_node = g_node_new ((guint8 *) buffer);
1876 piffdemux_parse_node (piffdemux, moof_node, buffer, length);
1877 //piffdemux_node_dump (piffdemux, moof_node);
1879 /* unknown base_offset to start with */
1880 base_offset = running_offset = -1;
1882 mfhd_node = piffdemux_tree_get_child_by_type_full (moof_node, FOURCC_mfhd, &mfhd_data);
1886 if (!piffdemux_parse_mfhd (piffdemux, &mfhd_data))
1889 traf_node = piffdemux_tree_get_child_by_type (moof_node, FOURCC_traf);
1891 /* Fragment Header node */
1893 piffdemux_tree_get_child_by_type_full (traf_node, FOURCC_tfhd,
1897 if (!piffdemux_parse_tfhd (piffdemux, &tfhd_data, &ds_duration,
1898 &ds_size, &ds_flags, &base_offset))
1901 if (G_UNLIKELY (base_offset < -1))
1904 /* Track Run node */
1906 piffdemux_tree_get_child_by_type_full (traf_node, FOURCC_trun,
1909 piffdemux_parse_trun (piffdemux, &trun_data, stream,
1910 ds_duration, ds_size, ds_flags, moof_offset, length, &base_offset,
1912 /* iterate all siblings */
1913 trun_node = piffdemux_tree_get_sibling_by_type_full (trun_node, FOURCC_trun,
1917 uuid_node = piffdemux_tree_get_child_by_type (traf_node, FOURCC_uuid);
1919 uuid_type_t uuid_type;
1920 guint8 *lbuffer = (guint8 *) uuid_node->data;
1922 gst_byte_reader_init (&uuid_data, lbuffer, PIFF_UINT32 (lbuffer));
1924 uuid_type = piffdemux_get_uuid_type (piffdemux, &uuid_data, &uuid_offset);
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 :(
1929 if (!piffdemux_parse_tfxd (piffdemux, stream, &uuid_data))
1931 } else if ((UUID_TFRF == uuid_type) && piffdemux->is_live && piffdemux->lookahead_cnt) {
1933 if (!piffdemux_parse_tfrf (piffdemux, stream, &uuid_data))
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))
1941 GST_WARNING_OBJECT (piffdemux, "Ignoring Wrong UUID...");
1944 /* iterate all siblings */
1945 uuid_node = piffdemux_tree_get_sibling_by_type (uuid_node, FOURCC_uuid);
1948 if (piffdemux->is_live) {
1950 GST_ERROR_OBJECT (piffdemux, "TFXD box is not present for live stream");
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..");
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");
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);
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;
1976 /* iterate all siblings */
1977 traf_node = piffdemux_tree_get_sibling_by_type (traf_node, FOURCC_traf);
1979 g_node_destroy (moof_node);
1984 GST_DEBUG_OBJECT (piffdemux, "missing mfhd box");
1990 GST_DEBUG_OBJECT (piffdemux, "missing tfhd box");
1995 GST_DEBUG_OBJECT (piffdemux, "lost offset");
2000 g_node_destroy (moof_node);
2002 GST_ELEMENT_ERROR (piffdemux, STREAM, DEMUX,
2003 ("This file is corrupt and cannot be played."), (NULL));
2010 /* activate the given segment number @seg_idx of @stream at time @offset.
2011 * @offset is an absolute global position over all the segments.
2013 * This will push out a NEWSEGMENT event with the right values and
2014 * position the stream index to the first decodable sample before
2018 gst_piffdemux_activate_segment (GstPiffDemux * piffdemux, PiffDemuxStream * stream,
2019 guint32 seg_idx, guint64 offset)
2022 PiffDemuxSegment *segment;
2024 guint64 start, stop, time;
2027 GST_LOG_OBJECT (piffdemux, "activate segment %d, offset %" G_GUINT64_FORMAT,
2030 /* update the current segment */
2031 stream->segment_index = seg_idx;
2033 /* get the segment */
2034 segment = &stream->segments[seg_idx];
2036 if (G_UNLIKELY (offset < segment->time)) {
2037 GST_WARNING_OBJECT (piffdemux, "offset < segment->time %" G_GUINT64_FORMAT,
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,
2051 /* get time in this segment */
2052 seg_time = offset - segment->time;
2054 GST_LOG_OBJECT (piffdemux, "seg_time %" GST_TIME_FORMAT,
2055 GST_TIME_ARGS (seg_time));
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));
2063 /* piffdemux->segment.stop is in outside-time-realm, whereas
2064 * segment->media_stop is in track-time-realm.
2066 * In order to compare the two, we need to bring segment.stop
2067 * into the track-time-realm */
2069 stop = piffdemux->segment.stop;
2071 stop = piffdemux->segment.duration;
2073 stop = segment->media_stop;
2076 MIN (segment->media_stop, stop - segment->time + segment->media_start);
2078 if (piffdemux->segment.rate >= 0) {
2079 start = MIN (segment->media_start + seg_time, stop);
2082 if (segment->media_start >= piffdemux->segment.start) {
2083 start = segment->media_start;
2084 time = segment->time;
2086 start = piffdemux->segment.start;
2087 time = segment->time + (piffdemux->segment.start - segment->media_start);
2090 start = MAX (segment->media_start, piffdemux->segment.start);
2091 stop = MIN (segment->media_start + seg_time, stop);
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));
2098 /* combine global rate with that of the segment */
2099 rate = segment->rate * piffdemux->segment.rate;
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,
2106 /* now prepare and send the segment */
2107 event = gst_event_new_new_segment (FALSE, rate, GST_FORMAT_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);
2119 /* prepare to get the current sample of @stream, getting essential values.
2121 * This function will also prepare and send the segment when needed.
2123 * Return FALSE if the stream is EOS.
2126 gst_piffdemux_prepare_current_sample (GstPiffDemux * piffdemux,
2127 PiffDemuxStream * stream, guint64 * offset, guint * size, guint64 * timestamp,
2128 guint64 * duration, gboolean * keyframe)
2130 PiffDemuxSample *sample;
2131 guint64 time_position;
2134 g_return_val_if_fail (stream != NULL, FALSE);
2136 time_position = stream->time_position;
2137 if (G_UNLIKELY (time_position == -1))
2140 seg_idx = stream->segment_index;
2141 if (G_UNLIKELY (seg_idx == -1)) {
2142 /* find segment corresponding to time_position if we are looking
2144 seg_idx = gst_piffdemux_find_segment (piffdemux, stream, time_position);
2146 /* nothing found, we're really eos */
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);
2155 GST_LOG_OBJECT (piffdemux, "segment active, index = %u of %u",
2156 stream->sample_index, stream->n_samples);
2158 if (G_UNLIKELY (stream->sample_index >= stream->n_samples))
2162 /* now get the info for the sample we're at */
2163 sample = &stream->samples[stream->sample_index];
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);
2176 stream->time_position = -1;
2181 /* the input buffer metadata must be writable,
2182 * but time/duration etc not yet set and need not be preserved */
2184 gst_piffdemux_process_buffer (GstPiffDemux * piffdemux, PiffDemuxStream * stream,
2188 guint size, nsize = 0;
2191 data = GST_BUFFER_DATA (buf);
2192 size = GST_BUFFER_SIZE (buf);
2194 if (G_UNLIKELY (stream->subtype != FOURCC_text)) {
2198 if (G_LIKELY (size >= 2)) {
2199 nsize = GST_READ_UINT16_BE (data);
2200 nsize = MIN (nsize, size - 2);
2203 GST_LOG_OBJECT (piffdemux, "3GPP timed text subtitle: %d/%d", nsize, size);
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);
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);
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;
2219 /* FIXME ? convert optional subsequent style info to markup */
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.
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)
2234 GstFlowReturn ret = GST_FLOW_OK;
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;
2246 /* position reporting */
2247 if (piffdemux->segment.rate >= 0) {
2248 // TODO: Segment fault is coming here for Audio stream.. need to check
2250 gst_segment_set_last_stop (&piffdemux->segment, GST_FORMAT_TIME, position);
2251 //gst_piffdemux_sync_streams (piffdemux);
2254 /* send out pending buffers */
2255 while (stream->buffers) {
2256 GstBuffer *buffer = (GstBuffer *) stream->buffers->data;
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;
2263 gst_buffer_set_caps (buffer, stream->caps);
2265 gst_pad_push (piffdemux->srcpad, buffer);
2267 stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
2270 /* we're going to modify the metadata */
2271 buf = gst_buffer_make_metadata_writable (buf);
2273 /* for subtitle processing */
2274 if (G_UNLIKELY (stream->need_process))
2275 buf = gst_piffdemux_process_buffer (piffdemux, stream, buf);
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;
2282 if (G_UNLIKELY (stream->padding)) {
2283 GST_BUFFER_DATA (buf) += stream->padding;
2284 GST_BUFFER_SIZE (buf) -= stream->padding;
2287 if (G_UNLIKELY (buf == NULL))
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;
2297 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
2299 //g_print ("\n\npad caps : %s\n\n", gst_caps_to_string (gst_pad_get_caps (stream->pad)));
2301 //gst_buffer_set_caps (buf, stream->caps); // commenting to avoid caps by setting properties
2303 // TODO: need to see how resolution switch will work
2304 gst_buffer_set_caps (buf, stream->caps);
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, };
2311 PiffDemuxSample *sample = &stream->samples[stream->sample_index];
2313 if (sample->sub_encry) {
2314 offset = sample->sub_encry->sub_entry[0].LenofClearData;
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;
2328 memcpy (read_input_data.payload_iv, sample->iv, 8);
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;
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");
2342 free (read_input_data.payload_iv);
2343 read_input_data.payload_iv = NULL;
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)));
2353 #ifdef DEC_OUT_FRAME_DUMP
2356 written = fwrite (GST_BUFFER_DATA (buf), sizeof (unsigned char), GST_BUFFER_SIZE (buf), piffdump);
2357 g_print ("PIFFDEMUX: written = %d\n", written);
2362 ret = gst_pad_push (piffdemux->srcpad, buf);
2372 * Returns the size of the first entry at the current offset.
2373 * If -1, there are none (which means EOS or empty file).
2376 next_entry_size (GstPiffDemux * demux)
2378 PiffDemuxStream *stream = demux->stream;
2379 PiffDemuxSample *sample;
2381 GST_LOG_OBJECT (demux, "Finding entry at offset %" G_GUINT64_FORMAT,
2384 GST_DEBUG_OBJECT (demux, "demux->sample_index = %d", stream->sample_index);
2386 if (stream->sample_index == -1)
2387 stream->sample_index = 0;
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);
2395 sample = &stream->samples[stream->sample_index];
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);
2402 GST_LOG_OBJECT (demux, "stream : demux->offset :%"G_GUINT64_FORMAT, demux->offset);
2404 stream = demux->stream;
2405 sample = &stream->samples[stream->sample_index];
2407 if (sample->offset >= demux->offset) {
2408 demux->todrop = sample->offset - demux->offset;
2409 return sample->size + demux->todrop;
2412 GST_DEBUG_OBJECT (demux,
2413 "There wasn't any entry at offset %" G_GUINT64_FORMAT, demux->offset);
2418 gst_piffdemux_post_progress (GstPiffDemux * demux, gint num, gint denom)
2420 gint perc = (gint) ((gdouble) num * 100.0 / (gdouble) denom);
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)));
2428 piffdemux_seek_offset (GstPiffDemux * demux, guint64 offset)
2433 GST_DEBUG_OBJECT (demux, "Seeking to %" G_GUINT64_FORMAT, offset);
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);
2440 res = gst_pad_push_event (demux->sinkpad, event);
2445 static GstFlowReturn
2446 gst_piffdemux_chain (GstPad * sinkpad, GstBuffer * inbuf)
2448 GstPiffDemux *demux;
2449 GstFlowReturn ret = GST_FLOW_OK;
2450 demux = GST_PIFFDEMUX (gst_pad_get_parent (sinkpad));
2452 if (demux->encrypt_content && !demux->decrypt_init) {
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, };
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);
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;
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;
2480 demux->decrypt_init = TRUE;
2483 gst_adapter_push (demux->adapter, inbuf);
2485 /* we never really mean to buffer that much */
2486 if (demux->neededbytes == -1)
2489 GST_DEBUG_OBJECT (demux, "pushing in inbuf %p, neededbytes:%u, available:%u",
2490 inbuf, demux->neededbytes, gst_adapter_available (demux->adapter));
2492 while (((gst_adapter_available (demux->adapter)) >= demux->neededbytes) &&
2493 (ret == GST_FLOW_OK)) {
2495 GST_DEBUG_OBJECT (demux,
2496 "state:%d , demux->neededbytes:%d, demux->offset:%" G_GUINT64_FORMAT,
2497 demux->state, demux->neededbytes, demux->offset);
2499 switch (demux->state) {
2500 case PIFFDEMUX_STATE_INITIAL:{
2505 data = gst_adapter_peek (demux->adapter, demux->neededbytes);
2507 /* get fourcc/length, set neededbytes */
2508 extract_initial_length_and_fourcc ((guint8 *) data, demux->neededbytes,
2510 GST_DEBUG_OBJECT (demux, "Peeking found [%" GST_FOURCC_FORMAT "] "
2511 "size: %" G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), size);
2513 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
2514 ("This file is invalid and cannot be played."),
2515 ("initial atom '%" GST_FOURCC_FORMAT "' has empty length",
2516 GST_FOURCC_ARGS (fourcc)));
2518 ret = GST_FLOW_ERROR;
2522 if (fourcc == FOURCC_mdat) {
2523 if (demux->moof_rcvd) {
2524 /* we have the headers, start playback */
2525 demux->state = PIFFDEMUX_STATE_MOVIE;
2526 demux->neededbytes = next_entry_size (demux);
2527 demux->mdatleft = size;
2529 /* Only post, event on pads is done after newsegment */
2530 piffdemux_post_global_tags (demux);
2532 GST_ERROR_OBJECT (demux, "mdata received before moof.. not handled");
2533 goto unknown_stream;
2535 } else if (G_UNLIKELY (size > PIFFDEMUX_MAX_ATOM_SIZE)) {
2536 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
2537 ("This file is invalid and cannot be played."),
2538 ("atom %" GST_FOURCC_FORMAT " has bogus size %" G_GUINT64_FORMAT,
2539 GST_FOURCC_ARGS (fourcc), size));
2540 ret = GST_FLOW_ERROR;
2543 demux->neededbytes = size;
2544 demux->state = PIFFDEMUX_STATE_HEADER;
2548 case PIFFDEMUX_STATE_HEADER:{
2552 GST_DEBUG_OBJECT (demux, "In header");
2554 data = gst_adapter_peek (demux->adapter, demux->neededbytes);
2556 /* parse the header */
2557 extract_initial_length_and_fourcc (data, demux->neededbytes, NULL,
2559 if (fourcc == FOURCC_moof) {
2560 GST_DEBUG_OBJECT (demux, "Parsing [moof]");
2561 if (!piffdemux_parse_moof (demux, data, demux->neededbytes,
2562 demux->offset, demux->stream)) {
2563 ret = GST_FLOW_ERROR;
2566 demux->moof_rcvd = TRUE;
2568 GST_WARNING_OBJECT (demux,
2569 "Unknown fourcc while parsing header : %" GST_FOURCC_FORMAT,
2570 GST_FOURCC_ARGS (fourcc));
2571 /* Let's jump that one and go back to initial state */
2574 if (demux->mdatbuffer) {
2575 /* the mdat was before the header */
2576 GST_DEBUG_OBJECT (demux, "We have mdatbuffer:%p",
2578 gst_adapter_clear (demux->adapter);
2579 demux->mdatbuffer = NULL;
2580 demux->offset = demux->mdatoffset;
2581 demux->neededbytes = next_entry_size (demux);
2582 demux->state = PIFFDEMUX_STATE_MOVIE;
2583 demux->mdatleft = gst_adapter_available (demux->adapter);
2585 /* Only post, event on pads is done after newsegment */
2586 piffdemux_post_global_tags (demux);
2588 GST_DEBUG_OBJECT (demux, "Carrying on normally");
2589 gst_adapter_flush (demux->adapter, demux->neededbytes);
2590 demux->offset += demux->neededbytes;
2591 demux->neededbytes = 16;
2592 demux->state = PIFFDEMUX_STATE_INITIAL;
2597 case PIFFDEMUX_STATE_BUFFER_MDAT:{
2600 GST_DEBUG_OBJECT (demux, "Got our buffer at offset %" G_GUINT64_FORMAT,
2602 buf = gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
2603 GST_DEBUG_OBJECT (demux, "mdatbuffer starts with %" GST_FOURCC_FORMAT,
2604 GST_FOURCC_ARGS (PIFF_FOURCC (GST_BUFFER_DATA (buf) + 4)));
2605 if (demux->mdatbuffer)
2606 demux->mdatbuffer = gst_buffer_join (demux->mdatbuffer, buf);
2608 demux->mdatbuffer = buf;
2609 demux->offset += demux->neededbytes;
2610 demux->neededbytes = 16;
2611 demux->state = PIFFDEMUX_STATE_INITIAL;
2612 gst_piffdemux_post_progress (demux, 1, 1);
2616 case PIFFDEMUX_STATE_MOVIE:{
2618 PiffDemuxStream *stream = demux->stream;
2619 PiffDemuxSample *sample;
2620 guint64 timestamp, duration, position;
2623 GST_DEBUG_OBJECT (demux,
2624 "BEGIN // in MOVIE for offset %" G_GUINT64_FORMAT, demux->offset);
2626 if (demux->fragmented) {
2627 GST_DEBUG_OBJECT (demux, "mdat remaining %" G_GUINT64_FORMAT,
2629 if (G_LIKELY (demux->todrop < demux->mdatleft)) {
2630 /* if needed data starts within this atom,
2631 * then it should not exceed this atom */
2632 if (G_UNLIKELY (demux->neededbytes > demux->mdatleft)) {
2634 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
2635 ("This file is invalid and cannot be played."),
2636 ("sample data crosses atom boundary"));
2638 ret = GST_FLOW_ERROR;
2641 demux->mdatleft -= demux->neededbytes;
2643 GST_DEBUG_OBJECT (demux, "data atom emptied; resuming atom scan");
2644 /* so we are dropping more than left in this atom */
2645 demux->todrop -= demux->mdatleft;
2646 demux->neededbytes -= demux->mdatleft;
2647 demux->mdatleft = 0;
2648 /* need to resume atom parsing so we do not miss any other pieces */
2649 demux->state = PIFFDEMUX_STATE_INITIAL;
2650 demux->neededbytes = 16;
2655 if (demux->todrop) {
2656 GST_LOG_OBJECT (demux, "Dropping %d bytes", demux->todrop);
2657 gst_adapter_flush (demux->adapter, demux->todrop);
2658 demux->neededbytes -= demux->todrop;
2659 demux->offset += demux->todrop;
2662 if ( !stream->sent_nsevent) {
2663 //TODO: better to parse sink event function and send that new_segment
2665 demux->pending_newsegment = gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_TIME,
2666 demux->stream->start_ts, -1, demux->stream->start_ts);
2668 demux->pending_newsegment = gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_TIME,
2669 0, gst_util_uint64_scale (stream->duration, GST_SECOND, stream->timescale), 0);
2672 GST_INFO_OBJECT (demux, "New segment event : start = %"GST_TIME_FORMAT", stop = %" GST_TIME_FORMAT,
2673 GST_TIME_ARGS (demux->stream->start_ts), GST_TIME_ARGS(gst_util_uint64_scale (stream->duration, GST_SECOND, stream->timescale)));
2675 if (!gst_pad_push_event (demux->srcpad, demux->pending_newsegment)) {
2676 GST_ERROR_OBJECT (demux, "failding to send new segment...");
2677 goto newsegment_error;
2679 stream->sent_nsevent = TRUE;
2682 /* Put data in a buffer, set timestamps, caps, ... */
2683 outbuf = gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
2685 GST_DEBUG_OBJECT (demux, "Taken %d size buffer from adapter...", outbuf ? GST_BUFFER_SIZE (outbuf) : 0);
2687 GST_DEBUG_OBJECT (demux, "stream : %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (stream->fourcc));
2689 g_return_val_if_fail (outbuf != NULL, GST_FLOW_ERROR);
2691 sample = &stream->samples[stream->sample_index];
2693 GST_DEBUG_OBJECT (demux, "start_ts = %"GST_TIME_FORMAT" ts : %"GST_TIME_FORMAT" ts = %llu, pts_offset = %u, scale = %d\n",
2694 GST_TIME_ARGS(stream->start_ts),GST_TIME_ARGS(sample->timestamp), sample->timestamp,
2695 sample->pts_offset,stream->timescale);
2697 position = PIFFSAMPLE_DTS (stream, sample);
2698 timestamp = PIFFSAMPLE_PTS (stream, sample) + stream->start_ts; // Adding to avoid resetting of timestamp
2699 duration = PIFFSAMPLE_DUR_DTS (stream, sample, position);
2700 keyframe = PIFFSAMPLE_KEYFRAME (stream, sample);
2702 ret = gst_piffdemux_decorate_and_push_buffer (demux, stream, outbuf,
2703 timestamp, duration, keyframe, position, demux->offset);
2705 stream->sample_index++;
2707 /* update current offset and figure out size of next buffer */
2708 GST_LOG_OBJECT (demux, "increasing offset %" G_GUINT64_FORMAT " by %u",
2709 demux->offset, demux->neededbytes);
2710 demux->offset += demux->neededbytes;
2711 GST_LOG_OBJECT (demux, "offset is now %" G_GUINT64_FORMAT,
2714 if ((demux->neededbytes = next_entry_size (demux)) == -1) {
2715 GST_DEBUG_OBJECT (demux, "finished parsing mdat, need to search next moof atom");
2716 demux->neededbytes = 16;
2717 demux->state = PIFFDEMUX_STATE_INITIAL;
2718 GST_DEBUG ("\n\n Storing %s last_ts %"GST_TIME_FORMAT"\n\n", stream->subtype == FOURCC_vide ? "video" : "audio", GST_TIME_ARGS(timestamp));
2719 stream->start_ts = timestamp + duration;
2729 /* when buffering movie data, at least show user something is happening */
2730 if (ret == GST_FLOW_OK && demux->state == PIFFDEMUX_STATE_BUFFER_MDAT &&
2731 gst_adapter_available (demux->adapter) <= demux->neededbytes) {
2732 gst_piffdemux_post_progress (demux, gst_adapter_available (demux->adapter),
2733 demux->neededbytes);
2736 gst_object_unref (demux);
2743 GST_ELEMENT_ERROR (demux, STREAM, FAILED, (NULL), ("unknown stream found"));
2744 ret = GST_FLOW_ERROR;
2749 GST_DEBUG_OBJECT (demux, "no next entry, EOS");
2750 ret = GST_FLOW_UNEXPECTED;
2755 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
2756 (NULL), ("piffdemuxer invalid state %d", demux->state));
2757 ret = GST_FLOW_ERROR;
2762 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
2763 (NULL), ("could not send newsegment event"));
2764 ret = GST_FLOW_ERROR;
2770 piffdemux_parse_container (GstPiffDemux * piffdemux, GNode * node, const guint8 * buf,
2773 while (G_UNLIKELY (buf < end)) {
2777 if (G_UNLIKELY (buf + 4 > end)) {
2778 GST_LOG_OBJECT (piffdemux, "buffer overrun");
2781 len = PIFF_UINT32 (buf);
2782 if (G_UNLIKELY (len == 0)) {
2783 GST_LOG_OBJECT (piffdemux, "empty container");
2786 if (G_UNLIKELY (len < 8)) {
2787 GST_WARNING_OBJECT (piffdemux, "length too short (%d < 8)", len);
2790 if (G_UNLIKELY (len > (end - buf))) {
2791 GST_WARNING_OBJECT (piffdemux, "length too long (%d > %d)", len,
2792 (gint) (end - buf));
2796 child = g_node_new ((guint8 *) buf);
2797 g_node_append (node, child);
2798 GST_LOG_OBJECT (piffdemux, "adding new node of len %d", len);
2799 piffdemux_parse_node (piffdemux, child, buf, len);
2808 piffdemux_parse_node (GstPiffDemux * piffdemux, GNode * node, const guint8 * buffer,
2812 guint32 node_length = 0;
2813 const PiffNodeType *type;
2816 GST_LOG_OBJECT (piffdemux, "piffdemux_parse buffer %p length %u", buffer, length);
2818 if (G_UNLIKELY (length < 8))
2819 goto not_enough_data;
2821 node_length = PIFF_UINT32 (buffer);
2822 fourcc = PIFF_FOURCC (buffer + 4);
2824 /* ignore empty nodes */
2825 if (G_UNLIKELY (fourcc == 0 || node_length == 8))
2828 type = piffdemux_type_get (fourcc);
2830 end = buffer + length;
2832 GST_LOG_OBJECT (piffdemux,
2833 "parsing '%" GST_FOURCC_FORMAT "', length=%u, name '%s'",
2834 GST_FOURCC_ARGS (fourcc), node_length, type->name);
2836 if (node_length > length)
2837 goto broken_atom_size;
2839 if (type->flags & PIFF_FLAG_CONTAINER) {
2840 piffdemux_parse_container (piffdemux, node, buffer + 8, end);
2842 GST_LOG_OBJECT (piffdemux, "parsed '%" GST_FOURCC_FORMAT "'",
2843 GST_FOURCC_ARGS (fourcc));
2850 GST_ELEMENT_ERROR (piffdemux, STREAM, DEMUX,
2851 ("This file is corrupt and cannot be played."),
2852 ("Not enough data for an atom header, got only %u bytes", length));
2858 GST_ELEMENT_ERROR (piffdemux, STREAM, DEMUX,
2859 ("This file is corrupt and cannot be played."),
2860 ("Atom '%" GST_FOURCC_FORMAT "' has size of %u bytes, but we have only "
2861 "%u bytes available.", GST_FOURCC_ARGS (fourcc), node_length,
2870 piffdemux_tree_get_child_by_type (GNode * node, guint32 fourcc)
2874 guint32 child_fourcc;
2876 for (child = g_node_first_child (node); child;
2877 child = g_node_next_sibling (child)) {
2878 buffer = (guint8 *) child->data;
2880 child_fourcc = PIFF_FOURCC (buffer + 4);
2882 if (G_UNLIKELY (child_fourcc == fourcc)) {
2890 piffdemux_tree_get_child_by_type_full (GNode * node, guint32 fourcc,
2891 GstByteReader * parser)
2895 guint32 child_fourcc, child_len;
2897 for (child = g_node_first_child (node); child;
2898 child = g_node_next_sibling (child)) {
2899 buffer = (guint8 *) child->data;
2901 child_len = PIFF_UINT32 (buffer);
2902 child_fourcc = PIFF_FOURCC (buffer + 4);
2904 if (G_UNLIKELY (child_fourcc == fourcc)) {
2905 if (G_UNLIKELY (child_len < (4 + 4)))
2907 /* FIXME: must verify if atom length < parent atom length */
2908 gst_byte_reader_init (parser, buffer + (4 + 4), child_len - (4 + 4));
2916 piffdemux_tree_get_sibling_by_type_full (GNode * node, guint32 fourcc,
2917 GstByteReader * parser)
2921 guint32 child_fourcc, child_len;
2923 for (child = g_node_next_sibling (node); child;
2924 child = g_node_next_sibling (child)) {
2925 buffer = (guint8 *) child->data;
2927 child_fourcc = PIFF_FOURCC (buffer + 4);
2929 if (child_fourcc == fourcc) {
2931 child_len = PIFF_UINT32 (buffer);
2932 if (G_UNLIKELY (child_len < (4 + 4)))
2934 /* FIXME: must verify if atom length < parent atom length */
2935 gst_byte_reader_init (parser, buffer + (4 + 4), child_len - (4 + 4));
2944 piffdemux_tree_get_sibling_by_type (GNode * node, guint32 fourcc)
2946 return piffdemux_tree_get_sibling_by_type_full (node, fourcc, NULL);
2949 #define _codec(name) \
2952 *codec_name = g_strdup (name); \
2957 gst_piffdemux_set_video_params (GstPiffDemux * piffdemux, guint fourcc,
2958 guint width, guint height,
2959 guint fps_n, guint fps_d, unsigned char *codec_data, unsigned int codec_data_len)
2961 GstCaps *caps = NULL;
2962 GstBuffer *dci = NULL;
2964 if (codec_data && codec_data_len) {
2965 dci = gst_buffer_new_and_alloc (codec_data_len);
2967 GST_ERROR_OBJECT (piffdemux, "failed to create codec data buffer...");
2969 memcpy (GST_BUFFER_DATA(dci), codec_data, codec_data_len);
2975 case GST_MAKE_FOURCC ('a', 'v', 'c', '1'):
2976 caps = gst_caps_new_simple ("video/x-h264",
2977 "width", G_TYPE_INT, width,
2978 "height", G_TYPE_INT, height,
2979 "framerate", GST_TYPE_FRACTION, fps_n, fps_d,
2980 "stream-format", G_TYPE_STRING, "avc",
2981 "alignment", G_TYPE_STRING, "au",
2982 "codec_data", GST_TYPE_BUFFER, dci,
2987 caps = gst_caps_new_simple ("video/x-wmv",
2988 "width", G_TYPE_INT, width,
2989 "height", G_TYPE_INT, height,
2990 "framerate", GST_TYPE_FRACTION, fps_n, fps_d,
2991 "wmvversion", G_TYPE_INT, 3,
2992 "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC ('W', 'V', 'C', '1'),
2993 "codec_data", GST_TYPE_BUFFER, dci,
2999 s = g_strdup_printf ("video/x-gst-fourcc-%" GST_FOURCC_FORMAT,
3000 GST_FOURCC_ARGS (fourcc));
3001 caps = gst_caps_new_simple (s,
3002 "width", G_TYPE_INT, width,
3003 "height", G_TYPE_INT, height,
3004 "framerate", GST_TYPE_FRACTION, fps_n, fps_d,
3005 "codec_data", GST_TYPE_BUFFER, dci,
3011 piffdemux->stream->caps = caps;
3012 gchar *caps_string = gst_caps_to_string(caps);
3013 GST_INFO_OBJECT (piffdemux, "prepared video caps : %s", caps_string);
3014 g_free(caps_string);
3019 gst_piffdemux_set_audio_params (GstPiffDemux * piffdemux, guint fourcc,
3020 guint sampling_rate, guint bps, guint channels, unsigned char *codec_data, unsigned int codec_data_len)
3022 GstCaps *caps = NULL;
3023 GstBuffer *dci = NULL;
3025 if (codec_data && codec_data_len) {
3026 dci = gst_buffer_new_and_alloc (codec_data_len);
3028 GST_ERROR_OBJECT (piffdemux, "failed to create codec data buffer...");
3030 memcpy (GST_BUFFER_DATA(dci), codec_data, codec_data_len);
3036 case GST_MAKE_FOURCC ('m', 'p', '4', 'a'):
3037 caps = gst_caps_new_simple ("audio/mpeg",
3038 "mpegversion", G_TYPE_INT, 4,
3039 "framed", G_TYPE_BOOLEAN, TRUE,
3040 "stream-format", G_TYPE_STRING, "raw",
3041 "rate", G_TYPE_INT, (int) sampling_rate,
3042 "channels", G_TYPE_INT, channels,
3047 caps = gst_caps_new_simple ("audio/x-wma",
3048 "rate", G_TYPE_INT, (int) sampling_rate,
3049 "channels", G_TYPE_INT, channels,
3055 s = g_strdup_printf ("audio/x-gst-fourcc-%" GST_FOURCC_FORMAT,
3056 GST_FOURCC_ARGS (fourcc));
3057 caps = gst_caps_new_simple (s,
3058 "rate", G_TYPE_INT, (int) sampling_rate,
3059 "channels", G_TYPE_INT, channels,
3065 piffdemux->stream->caps = caps;
3066 char *tmp_caps_name = gst_caps_to_string(caps);
3067 GST_INFO_OBJECT (piffdemux, "prepared audio caps : %s", tmp_caps_name);
3068 g_free(tmp_caps_name);
3072 #define g_marshal_value_peek_object(v) g_value_get_object (v)
3075 __gst_piffdemux_marshal_BOOLEAN__OBJECT (GClosure *closure,
3076 GValue *return_value G_GNUC_UNUSED,
3077 guint n_param_values,
3078 const GValue *param_values,
3079 gpointer invocation_hint G_GNUC_UNUSED,
3080 gpointer marshal_data)
3082 typedef gboolean (*GMarshalFunc_BOOLEAN__OBJECT) (gpointer data1,
3085 register GMarshalFunc_BOOLEAN__OBJECT callback;
3086 register GCClosure *cc = (GCClosure*) closure;
3087 register gpointer data1, data2;
3090 g_return_if_fail (return_value != NULL);
3091 g_return_if_fail (n_param_values == 2);
3093 if (G_CCLOSURE_SWAP_DATA (closure))
3095 data1 = closure->data;
3096 data2 = g_value_peek_pointer (param_values + 0);
3100 data1 = g_value_peek_pointer (param_values + 0);
3101 data2 = closure->data;
3103 callback = (GMarshalFunc_BOOLEAN__OBJECT) (marshal_data ? marshal_data : cc->callback);
3105 v_return = callback (data1,
3106 g_marshal_value_peek_object (param_values + 1),
3109 g_value_set_boolean (return_value, v_return);
3112 #define PIFFDEMUX_SPSPPS_LENGTH_SIZE 2
3115 ConvertH264_MetaDCI_to_3GPPDCI(unsigned char *dci_meta_buf, unsigned int dci_meta_size, unsigned char **dci_3gpp_buf, unsigned int *dci_3gpp_size)
3117 unsigned short unit_size = 0;
3118 unsigned int total_size = 0;
3119 unsigned char unit_nb = 0;
3120 unsigned char sps_done = 0;
3121 const unsigned char *extradata = NULL;
3122 unsigned int h264_nal_length_size = 0;
3123 unsigned char *out = NULL;
3124 //g_print ("\n\nConvertH264_MetaDCI_to_3GPPDCI Entering.............\n");
3126 /* nothing to filter */
3127 if ((dci_meta_buf == NULL) || (dci_meta_size < 6))
3129 GST_ERROR ("Insufficient codec data...\n");
3133 /* Removing unnecessary info in meta data */
3134 extradata = (unsigned char *)dci_meta_buf + 4;
3136 /* retrieve Length of Length*/
3137 h264_nal_length_size = (*extradata++ & 0x03) + 1;
3139 GST_LOG ("Length Of Length is %d\n", h264_nal_length_size);
3140 if (h264_nal_length_size == 3)
3142 GST_ERROR ("LengthOfLength is WRONG...\n");
3146 /* retrieve sps and pps unit(s) */
3147 unit_nb = *extradata++ & 0x1f; /* number of sps unit(s) */
3148 GST_LOG ("No. of SPS units = %u\n", unit_nb);
3152 GST_ERROR ("SPS is not present....\n");
3158 /* get SPS/PPS data Length*/
3159 unit_size = PIFFDEMUX_RB16(extradata);
3161 GST_LOG ("SPS size = %d", unit_size);
3163 /* Extra 4 bytes for adding size of the packet */
3164 total_size += unit_size + h264_nal_length_size;
3166 /* Check if SPS/PPS Data Length crossed buffer Length */
3167 if ((extradata + 2 + unit_size) > (dci_meta_buf + dci_meta_size))
3169 GST_ERROR ("SPS Length is wrong in DCI...\n");
3176 out = realloc(out, total_size);
3179 GST_ERROR ("realloc FAILED...\n");
3182 /* Copy length of SPS header */
3183 // tmp = (unsigned int *)(out + total_size - unit_size - h264_nal_length_size);
3184 // *tmp = unit_size;
3185 (out + total_size - unit_size - h264_nal_length_size)[0] = 0;
3186 (out + total_size - unit_size - h264_nal_length_size)[1] = 0;
3187 (out + total_size - unit_size - h264_nal_length_size)[2] = 0;
3188 (out + total_size - unit_size - h264_nal_length_size)[3] = (unsigned char)unit_size;
3190 // memcpy(out + total_size - unit_size - h264_nal_length_size, &unit_size, h264_nal_length_size);
3191 //g_print ("out[0] = %02x, out[1] = %02x, out[2] = %02x = out[3] = %02x\n",
3192 //out[total_size - unit_size - h264_nal_length_size], out[total_size - unit_size - h264_nal_length_size+1],
3193 //out[total_size - unit_size - h264_nal_length_size + 2], out[total_size - unit_size - h264_nal_length_size + 3]);
3195 /* Copy SPS/PPS Length and data */
3196 memcpy(out + total_size - unit_size, extradata + PIFFDEMUX_SPSPPS_LENGTH_SIZE, unit_size);
3198 extradata += (PIFFDEMUX_SPSPPS_LENGTH_SIZE + unit_size);
3200 if (!unit_nb && !sps_done++)
3202 /* Completed reading SPS data, now read PPS data */
3203 unit_nb = *extradata++; /* number of pps unit(s) */
3204 GST_DEBUG ("No. of PPS units = %d\n", unit_nb);
3208 *dci_3gpp_buf = malloc (total_size);
3209 if (NULL == *dci_3gpp_buf)
3211 GST_ERROR ("Memory Allocation FAILED...\n");
3216 memcpy(*dci_3gpp_buf, out, total_size);
3217 *dci_3gpp_size = total_size;
3219 GST_DEBUG ("SPS_PPS size = %d\n", total_size);
3228 piffdemux_get_playready_licence (GstPiffDemux *demux)
3231 drm_trusted_piff_get_license_info_s license_info;
3232 drm_trusted_request_type_e request_type = DRM_TRUSTED_REQ_TYPE_PIFF_GET_LICENSE;
3234 memset(&license_info, 0x00, sizeof(drm_trusted_piff_get_license_info_s));
3236 license_info.lic_header.header = (unsigned char*) GST_BUFFER_DATA (demux->protection_header);
3237 license_info.lic_header.header_len = GST_BUFFER_SIZE (demux->protection_header);
3239 ret = drm_trusted_handle_request(request_type, (void *) &license_info, NULL);
3240 if (DRM_TRUSTED_RETURN_SUCCESS != ret) {
3241 GST_ERROR_OBJECT (demux,"failed to get license...");
3242 GST_ELEMENT_ERROR (demux, RESOURCE, FAILED, ("failed to get license"), (NULL));
3246 GST_INFO_OBJECT (demux, "Got license....\n");
3248 demux->encrypt_content = TRUE;
3254 test_drm_trusted_operation_cb(drm_trusted_user_operation_info_s *operation_info, void *output_data)
3256 g_print ("Callback Hit:test_drm_trusted_operation_cb\n");
3257 g_print ("operation_status=%d\n",operation_info->operation_status);
3258 g_print ("operation_type=%d\n",operation_info->operation_type);