1 /* GStreamer ASF/WMV/WMA demuxer
2 * Copyright (C) 1999 Erik Walthinsen <omega@cse.ogi.edu>
3 * Copyright (C) 2006-2009 Tim-Philipp Müller <tim centricular net>
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
15 * You should have received a copy of the GNU Library General Public
16 * License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
24 * stop if at end of segment if != end of file, ie. demux->segment.stop
26 * - fix packet parsing:
27 * there's something wrong with timestamps for packets with keyframes,
35 #include <gst/gstutils.h>
36 #include <gst/base/gstbytereader.h>
37 #include <gst/base/gsttypefindhelper.h>
38 #include <gst/riff/riff-media.h>
39 #include <gst/tag/tag.h>
40 #include <gst/gst-i18n-plugin.h>
41 #include <gst/video/video.h>
46 #include "gstasfdemux.h"
47 #include "asfheaders.h"
48 #include "asfpacket.h"
50 static GstStaticPadTemplate gst_asf_demux_sink_template =
51 GST_STATIC_PAD_TEMPLATE ("sink",
54 GST_STATIC_CAPS ("video/x-ms-asf")
57 static GstStaticPadTemplate audio_src_template =
58 GST_STATIC_PAD_TEMPLATE ("audio_%u",
63 static GstStaticPadTemplate video_src_template =
64 GST_STATIC_PAD_TEMPLATE ("video_%u",
69 /* size of an ASF object header, ie. GUID (16 bytes) + object size (8 bytes) */
70 #define ASF_OBJECT_HEADER_SIZE (16+8)
72 /* FIXME: get rid of this */
73 /* abuse this GstFlowReturn enum for internal usage */
74 #define ASF_FLOW_NEED_MORE_DATA 99
76 #define gst_asf_get_flow_name(flow) \
77 (flow == ASF_FLOW_NEED_MORE_DATA) ? \
78 "need-more-data" : gst_flow_get_name (flow)
80 GST_DEBUG_CATEGORY (asfdemux_dbg);
82 static GstStateChangeReturn gst_asf_demux_change_state (GstElement * element,
83 GstStateChange transition);
84 static gboolean gst_asf_demux_element_send_event (GstElement * element,
86 static gboolean gst_asf_demux_send_event_unlocked (GstASFDemux * demux,
88 static gboolean gst_asf_demux_handle_src_query (GstPad * pad,
89 GstObject * parent, GstQuery * query);
90 static GstFlowReturn gst_asf_demux_chain (GstPad * pad, GstObject * parent,
92 static gboolean gst_asf_demux_sink_event (GstPad * pad, GstObject * parent,
94 static GstFlowReturn gst_asf_demux_process_object (GstASFDemux * demux,
95 guint8 ** p_data, guint64 * p_size);
96 static gboolean gst_asf_demux_activate (GstPad * sinkpad, GstObject * parent);
97 static gboolean gst_asf_demux_activate_mode (GstPad * sinkpad,
98 GstObject * parent, GstPadMode mode, gboolean active);
99 static void gst_asf_demux_loop (GstASFDemux * demux);
101 gst_asf_demux_process_queued_extended_stream_objects (GstASFDemux * demux);
102 static gboolean gst_asf_demux_pull_headers (GstASFDemux * demux,
103 GstFlowReturn * pflow);
104 static GstFlowReturn gst_asf_demux_pull_indices (GstASFDemux * demux);
105 static void gst_asf_demux_reset_stream_state_after_discont (GstASFDemux * asf);
107 gst_asf_demux_parse_data_object_start (GstASFDemux * demux, guint8 * data);
108 static void gst_asf_demux_descramble_buffer (GstASFDemux * demux,
109 AsfStream * stream, GstBuffer ** p_buffer);
110 static void gst_asf_demux_activate_stream (GstASFDemux * demux,
112 static GstStructure *gst_asf_demux_get_metadata_for_stream (GstASFDemux * d,
114 static GstFlowReturn gst_asf_demux_push_complete_payloads (GstASFDemux * demux,
117 #define gst_asf_demux_parent_class parent_class
118 G_DEFINE_TYPE (GstASFDemux, gst_asf_demux, GST_TYPE_ELEMENT);
121 gst_asf_demux_class_init (GstASFDemuxClass * klass)
123 GstElementClass *gstelement_class;
125 gstelement_class = (GstElementClass *) klass;
127 gst_element_class_set_static_metadata (gstelement_class, "ASF Demuxer",
129 "Demultiplexes ASF Streams", "Owen Fraser-Green <owen@discobabe.net>");
131 gst_element_class_add_static_pad_template (gstelement_class,
132 &audio_src_template);
133 gst_element_class_add_static_pad_template (gstelement_class,
134 &video_src_template);
135 gst_element_class_add_static_pad_template (gstelement_class,
136 &gst_asf_demux_sink_template);
138 gstelement_class->change_state =
139 GST_DEBUG_FUNCPTR (gst_asf_demux_change_state);
140 gstelement_class->send_event =
141 GST_DEBUG_FUNCPTR (gst_asf_demux_element_send_event);
145 gst_asf_demux_free_stream (GstASFDemux * demux, AsfStream * stream)
147 gst_caps_replace (&stream->caps, NULL);
148 if (stream->pending_tags) {
149 gst_tag_list_unref (stream->pending_tags);
150 stream->pending_tags = NULL;
152 if (stream->streamheader) {
153 gst_buffer_unref (stream->streamheader);
154 stream->streamheader = NULL;
157 if (stream->active) {
158 gst_element_remove_pad (GST_ELEMENT_CAST (demux), stream->pad);
159 gst_flow_combiner_remove_pad (demux->flowcombiner, stream->pad);
161 gst_object_unref (stream->pad);
165 if (stream->payloads) {
166 while (stream->payloads->len > 0) {
170 last = stream->payloads->len - 1;
171 payload = &g_array_index (stream->payloads, AsfPayload, last);
172 gst_buffer_replace (&payload->buf, NULL);
173 g_array_remove_index (stream->payloads, last);
175 g_array_free (stream->payloads, TRUE);
176 stream->payloads = NULL;
179 if (stream->payloads_rev) {
180 while (stream->payloads_rev->len > 0) {
184 last = stream->payloads_rev->len - 1;
185 payload = &g_array_index (stream->payloads_rev, AsfPayload, last);
186 gst_buffer_replace (&payload->buf, NULL);
187 g_array_remove_index (stream->payloads_rev, last);
189 g_array_free (stream->payloads_rev, TRUE);
190 stream->payloads_rev = NULL;
193 if (stream->ext_props.valid) {
194 g_free (stream->ext_props.payload_extensions);
195 stream->ext_props.payload_extensions = NULL;
200 gst_asf_demux_reset (GstASFDemux * demux, gboolean chain_reset)
202 GST_LOG_OBJECT (demux, "resetting");
204 gst_segment_init (&demux->segment, GST_FORMAT_UNDEFINED);
205 demux->segment_running = FALSE;
206 if (demux->adapter && !chain_reset) {
207 gst_adapter_clear (demux->adapter);
208 g_object_unref (demux->adapter);
209 demux->adapter = NULL;
211 if (demux->taglist) {
212 gst_tag_list_unref (demux->taglist);
213 demux->taglist = NULL;
215 if (demux->metadata) {
216 gst_caps_unref (demux->metadata);
217 demux->metadata = NULL;
219 if (demux->global_metadata) {
220 gst_structure_free (demux->global_metadata);
221 demux->global_metadata = NULL;
223 if (demux->mut_ex_streams) {
224 g_slist_free (demux->mut_ex_streams);
225 demux->mut_ex_streams = NULL;
228 demux->state = GST_ASF_DEMUX_STATE_HEADER;
229 g_free (demux->objpath);
230 demux->objpath = NULL;
231 g_strfreev (demux->languages);
232 demux->languages = NULL;
233 demux->num_languages = 0;
234 g_slist_foreach (demux->ext_stream_props, (GFunc) gst_mini_object_unref,
236 g_slist_free (demux->ext_stream_props);
237 demux->ext_stream_props = NULL;
239 while (demux->old_num_streams > 0) {
240 gst_asf_demux_free_stream (demux,
241 &demux->old_stream[demux->old_num_streams - 1]);
242 --demux->old_num_streams;
244 memset (demux->old_stream, 0, sizeof (demux->old_stream));
245 demux->old_num_streams = 0;
247 /* when resetting for a new chained asf, we don't want to remove the pads
248 * before adding the new ones */
250 memcpy (demux->old_stream, demux->stream, sizeof (demux->stream));
251 demux->old_num_streams = demux->num_streams;
252 demux->num_streams = 0;
255 while (demux->num_streams > 0) {
256 gst_asf_demux_free_stream (demux, &demux->stream[demux->num_streams - 1]);
257 --demux->num_streams;
259 memset (demux->stream, 0, sizeof (demux->stream));
261 /* do not remove those for not adding pads with same name */
262 demux->num_audio_streams = 0;
263 demux->num_video_streams = 0;
264 demux->have_group_id = FALSE;
265 demux->group_id = G_MAXUINT;
267 demux->num_streams = 0;
268 demux->activated_streams = FALSE;
269 demux->first_ts = GST_CLOCK_TIME_NONE;
270 demux->segment_ts = GST_CLOCK_TIME_NONE;
273 gst_segment_init (&demux->in_segment, GST_FORMAT_UNDEFINED);
274 demux->state = GST_ASF_DEMUX_STATE_HEADER;
275 demux->seekable = FALSE;
276 demux->broadcast = FALSE;
277 demux->sidx_interval = 0;
278 demux->sidx_num_entries = 0;
279 g_free (demux->sidx_entries);
280 demux->sidx_entries = NULL;
282 demux->speed_packets = 1;
284 demux->asf_3D_mode = GST_ASF_3D_NONE;
287 GST_LOG_OBJECT (demux, "Restarting");
288 gst_segment_init (&demux->segment, GST_FORMAT_TIME);
289 demux->need_newsegment = TRUE;
290 demux->segment_seqnum = 0;
291 demux->segment_running = FALSE;
292 demux->keyunit_sync = FALSE;
293 demux->accurate = FALSE;
294 demux->metadata = gst_caps_new_empty ();
295 demux->global_metadata = gst_structure_new_empty ("metadata");
296 demux->data_size = 0;
297 demux->data_offset = 0;
298 demux->index_offset = 0;
300 demux->base_offset = 0;
303 g_slist_free (demux->other_streams);
304 demux->other_streams = NULL;
308 gst_asf_demux_init (GstASFDemux * demux)
311 gst_pad_new_from_static_template (&gst_asf_demux_sink_template, "sink");
312 gst_pad_set_chain_function (demux->sinkpad,
313 GST_DEBUG_FUNCPTR (gst_asf_demux_chain));
314 gst_pad_set_event_function (demux->sinkpad,
315 GST_DEBUG_FUNCPTR (gst_asf_demux_sink_event));
316 gst_pad_set_activate_function (demux->sinkpad,
317 GST_DEBUG_FUNCPTR (gst_asf_demux_activate));
318 gst_pad_set_activatemode_function (demux->sinkpad,
319 GST_DEBUG_FUNCPTR (gst_asf_demux_activate_mode));
320 gst_element_add_pad (GST_ELEMENT (demux), demux->sinkpad);
322 #ifdef TIZEN_FEATURE_ASFDEMUX_DISABLE_UNSUPPORTED_FORMAT
323 demux->is_supported_format = TRUE;
326 /* set initial state */
327 gst_asf_demux_reset (demux, FALSE);
331 gst_asf_demux_activate (GstPad * sinkpad, GstObject * parent)
336 query = gst_query_new_scheduling ();
338 if (!gst_pad_peer_query (sinkpad, query)) {
339 gst_query_unref (query);
343 pull_mode = gst_query_has_scheduling_mode_with_flags (query,
344 GST_PAD_MODE_PULL, GST_SCHEDULING_FLAG_SEEKABLE);
345 gst_query_unref (query);
350 GST_DEBUG_OBJECT (sinkpad, "activating pull");
351 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PULL, TRUE);
355 GST_DEBUG_OBJECT (sinkpad, "activating push");
356 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PUSH, TRUE);
361 gst_asf_demux_activate_mode (GstPad * sinkpad, GstObject * parent,
362 GstPadMode mode, gboolean active)
367 demux = GST_ASF_DEMUX (parent);
370 case GST_PAD_MODE_PUSH:
371 demux->state = GST_ASF_DEMUX_STATE_HEADER;
372 demux->streaming = TRUE;
375 case GST_PAD_MODE_PULL:
377 demux->state = GST_ASF_DEMUX_STATE_HEADER;
378 demux->streaming = FALSE;
380 res = gst_pad_start_task (sinkpad, (GstTaskFunction) gst_asf_demux_loop,
383 res = gst_pad_stop_task (sinkpad);
394 gst_asf_demux_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
399 demux = GST_ASF_DEMUX (parent);
401 GST_LOG_OBJECT (demux, "handling %s event", GST_EVENT_TYPE_NAME (event));
402 switch (GST_EVENT_TYPE (event)) {
403 case GST_EVENT_SEGMENT:{
404 const GstSegment *segment;
406 gst_event_parse_segment (event, &segment);
408 if (segment->format == GST_FORMAT_BYTES) {
409 if (demux->packet_size && segment->start > demux->data_offset)
410 demux->packet = (segment->start - demux->data_offset) /
414 } else if (segment->format == GST_FORMAT_TIME) {
415 /* do not know packet position, not really a problem */
418 GST_WARNING_OBJECT (demux, "unsupported newsegment format, ignoring");
419 gst_event_unref (event);
423 /* record upstream segment for interpolation */
424 if (segment->format != demux->in_segment.format)
425 gst_segment_init (&demux->in_segment, GST_FORMAT_UNDEFINED);
426 gst_segment_copy_into (segment, &demux->in_segment);
428 /* in either case, clear some state and generate newsegment later on */
429 GST_OBJECT_LOCK (demux);
430 demux->segment_ts = GST_CLOCK_TIME_NONE;
431 demux->in_gap = GST_CLOCK_TIME_NONE;
432 demux->need_newsegment = TRUE;
433 demux->segment_seqnum = gst_event_get_seqnum (event);
434 gst_asf_demux_reset_stream_state_after_discont (demux);
435 /* if we seek back after reaching EOS, go back to packet reading state */
436 if (demux->data_offset > 0 && segment->start >= demux->data_offset
437 && demux->state == GST_ASF_DEMUX_STATE_INDEX) {
438 demux->state = GST_ASF_DEMUX_STATE_DATA;
440 GST_OBJECT_UNLOCK (demux);
442 gst_event_unref (event);
448 if (demux->state == GST_ASF_DEMUX_STATE_HEADER) {
449 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
450 (_("This stream contains no data.")),
451 ("got eos and didn't receive a complete header object"));
454 flow = gst_asf_demux_push_complete_payloads (demux, TRUE);
455 if (!demux->activated_streams) {
456 /* If we still haven't got activated streams, the file is most likely corrupt */
457 GST_ELEMENT_ERROR (demux, STREAM, WRONG_TYPE,
458 (_("This stream contains no data.")),
459 ("got eos and didn't receive a complete header object"));
462 if (flow < GST_FLOW_EOS || flow == GST_FLOW_NOT_LINKED) {
463 GST_ELEMENT_FLOW_ERROR (demux, flow);
467 GST_OBJECT_LOCK (demux);
468 gst_adapter_clear (demux->adapter);
469 GST_OBJECT_UNLOCK (demux);
470 gst_asf_demux_send_event_unlocked (demux, event);
474 case GST_EVENT_FLUSH_STOP:
475 GST_OBJECT_LOCK (demux);
476 gst_asf_demux_reset_stream_state_after_discont (demux);
477 GST_OBJECT_UNLOCK (demux);
478 gst_asf_demux_send_event_unlocked (demux, event);
479 /* upon activation, latency is no longer introduced, e.g. after seek */
480 if (demux->activated_streams)
485 ret = gst_pad_event_default (pad, parent, event);
493 gst_asf_demux_seek_index_lookup (GstASFDemux * demux, guint * packet,
494 GstClockTime seek_time, GstClockTime * p_idx_time, guint * speed,
495 gboolean next, gboolean * eos)
497 GstClockTime idx_time;
503 if (G_UNLIKELY (demux->sidx_num_entries == 0 || demux->sidx_interval == 0))
506 idx = (guint) ((seek_time + demux->preroll) / demux->sidx_interval);
509 /* if we want the next keyframe, we have to go forward till we find
510 a different packet number */
512 if (idx >= demux->sidx_num_entries - 1) {
513 /* If we get here, we're asking for next keyframe after the last one. There isn't one. */
518 for (idx2 = idx + 1; idx2 < demux->sidx_num_entries; ++idx2) {
519 if (demux->sidx_entries[idx].packet != demux->sidx_entries[idx2].packet) {
526 if (G_UNLIKELY (idx >= demux->sidx_num_entries)) {
532 *packet = demux->sidx_entries[idx].packet;
534 *speed = demux->sidx_entries[idx].count;
536 /* so we get closer to the actual time of the packet ... actually, let's not
537 * do this, since we throw away superfluous payloads before the seek position
538 * anyway; this way, our key unit seek 'snap resolution' is a bit better
539 * (ie. same as index resolution) */
541 while (idx > 0 && demux->sidx_entries[idx-1] == demux->sidx_entries[idx])
545 idx_time = demux->sidx_interval * idx;
546 if (G_LIKELY (idx_time >= demux->preroll))
547 idx_time -= demux->preroll;
549 GST_DEBUG_OBJECT (demux, "%" GST_TIME_FORMAT " => packet %u at %"
550 GST_TIME_FORMAT, GST_TIME_ARGS (seek_time), *packet,
551 GST_TIME_ARGS (idx_time));
553 if (G_LIKELY (p_idx_time))
554 *p_idx_time = idx_time;
560 gst_asf_demux_reset_stream_state_after_discont (GstASFDemux * demux)
564 gst_adapter_clear (demux->adapter);
566 GST_DEBUG_OBJECT (demux, "reset stream state");
568 gst_flow_combiner_reset (demux->flowcombiner);
569 for (n = 0; n < demux->num_streams; n++) {
570 demux->stream[n].discont = TRUE;
571 demux->stream[n].first_buffer = TRUE;
573 while (demux->stream[n].payloads->len > 0) {
577 last = demux->stream[n].payloads->len - 1;
578 payload = &g_array_index (demux->stream[n].payloads, AsfPayload, last);
579 gst_buffer_replace (&payload->buf, NULL);
580 g_array_remove_index (demux->stream[n].payloads, last);
586 gst_asf_demux_mark_discont (GstASFDemux * demux)
590 GST_DEBUG_OBJECT (demux, "Mark stream discont");
592 for (n = 0; n < demux->num_streams; n++)
593 demux->stream[n].discont = TRUE;
596 /* do a seek in push based mode */
598 gst_asf_demux_handle_seek_push (GstASFDemux * demux, GstEvent * event)
603 GstSeekType cur_type, stop_type;
607 GstEvent *byte_event;
609 gst_event_parse_seek (event, &rate, &format, &flags, &cur_type, &cur,
612 stop_type = GST_SEEK_TYPE_NONE;
615 GST_DEBUG_OBJECT (demux, "seeking to %" GST_TIME_FORMAT, GST_TIME_ARGS (cur));
617 /* determine packet, by index or by estimation */
618 if (!gst_asf_demux_seek_index_lookup (demux, &packet, cur, NULL, NULL, FALSE,
621 (guint) gst_util_uint64_scale (demux->num_packets, cur,
625 if (packet > demux->num_packets) {
626 GST_DEBUG_OBJECT (demux, "could not determine packet to seek to, "
631 GST_DEBUG_OBJECT (demux, "seeking to packet %d", packet);
633 cur = demux->data_offset + ((guint64) packet * demux->packet_size);
635 GST_DEBUG_OBJECT (demux, "Pushing BYTE seek rate %g, "
636 "start %" G_GINT64_FORMAT ", stop %" G_GINT64_FORMAT, rate, cur, stop);
637 /* BYTE seek event */
638 byte_event = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags, cur_type,
639 cur, stop_type, stop);
640 gst_event_set_seqnum (byte_event, gst_event_get_seqnum (event));
641 res = gst_pad_push_event (demux->sinkpad, byte_event);
647 gst_asf_demux_handle_seek_event (GstASFDemux * demux, GstEvent * event)
649 GstClockTime idx_time;
652 GstSeekType cur_type, stop_type;
654 gboolean only_need_update;
655 gboolean after, before, next;
660 guint packet, speed_count = 1;
666 gst_event_parse_seek (event, &rate, &format, &flags, &cur_type, &cur,
669 if (G_UNLIKELY (format != GST_FORMAT_TIME)) {
670 GST_LOG_OBJECT (demux, "seeking is only supported in TIME format");
674 /* upstream might handle TIME seek, e.g. mms or rtsp, or not, e.g. http,
675 * so first try to let it handle the seek event. */
676 if (gst_pad_push_event (demux->sinkpad, gst_event_ref (event)))
679 if (G_UNLIKELY (demux->seekable == FALSE || demux->packet_size == 0 ||
680 demux->num_packets == 0 || demux->play_time == 0)) {
681 GST_LOG_OBJECT (demux, "stream is not seekable");
685 if (G_UNLIKELY (!demux->activated_streams)) {
686 GST_LOG_OBJECT (demux, "streams not yet activated, ignoring seek");
690 if (G_UNLIKELY (rate <= 0.0)) {
691 GST_LOG_OBJECT (demux, "backward playback");
692 demux->seek_to_cur_pos = TRUE;
693 for (i = 0; i < demux->num_streams; i++) {
694 demux->stream[i].reverse_kf_ready = FALSE;
698 seqnum = gst_event_get_seqnum (event);
699 flush = ((flags & GST_SEEK_FLAG_FLUSH) == GST_SEEK_FLAG_FLUSH);
701 ((flags & GST_SEEK_FLAG_ACCURATE) == GST_SEEK_FLAG_ACCURATE);
702 demux->keyunit_sync =
703 ((flags & GST_SEEK_FLAG_KEY_UNIT) == GST_SEEK_FLAG_KEY_UNIT);
704 after = ((flags & GST_SEEK_FLAG_SNAP_AFTER) == GST_SEEK_FLAG_SNAP_AFTER);
705 before = ((flags & GST_SEEK_FLAG_SNAP_BEFORE) == GST_SEEK_FLAG_SNAP_BEFORE);
706 next = after && !before;
708 if (G_UNLIKELY (demux->streaming)) {
709 /* support it safely needs more segment handling, e.g. closing etc */
711 GST_LOG_OBJECT (demux, "streaming; non-flushing seek not supported");
714 /* we can (re)construct the start later on, but not the end */
715 if (stop_type != GST_SEEK_TYPE_NONE &&
716 (stop_type != GST_SEEK_TYPE_SET || GST_CLOCK_TIME_IS_VALID (stop))) {
717 GST_LOG_OBJECT (demux, "streaming; end position must be NONE");
720 return gst_asf_demux_handle_seek_push (demux, event);
723 /* unlock the streaming thread */
724 if (G_LIKELY (flush)) {
725 fevent = gst_event_new_flush_start ();
727 gst_event_set_seqnum (fevent, seqnum);
728 gst_pad_push_event (demux->sinkpad, gst_event_ref (fevent));
729 gst_asf_demux_send_event_unlocked (demux, fevent);
731 gst_pad_pause_task (demux->sinkpad);
734 /* grab the stream lock so that streaming cannot continue, for
735 * non flushing seeks when the element is in PAUSED this could block
737 GST_PAD_STREAM_LOCK (demux->sinkpad);
739 if (G_LIKELY (flush)) {
740 /* we now can stop flushing, since we have the stream lock now */
741 fevent = gst_event_new_flush_stop (TRUE);
742 gst_event_set_seqnum (fevent, seqnum);
743 gst_pad_push_event (demux->sinkpad, gst_event_ref (fevent));
744 gst_asf_demux_send_event_unlocked (demux, fevent);
747 /* operating on copy of segment until we know the seek worked */
748 segment = demux->segment;
750 gst_segment_do_seek (&segment, rate, format, flags, cur_type,
751 cur, stop_type, stop, &only_need_update);
753 GST_DEBUG_OBJECT (demux, "seeking to time %" GST_TIME_FORMAT ", segment: "
754 "%" GST_SEGMENT_FORMAT, GST_TIME_ARGS (segment.start), &segment);
756 if (cur_type != GST_SEEK_TYPE_SET)
757 seek_time = segment.start;
761 /* FIXME: should check the KEY_UNIT flag; need to adjust position to
762 * real start of data and segment_start to indexed time for key unit seek*/
763 if (G_UNLIKELY (!gst_asf_demux_seek_index_lookup (demux, &packet, seek_time,
764 &idx_time, &speed_count, next, &eos))) {
768 demux->packet = demux->num_packets;
772 /* First try to query our source to see if it can convert for us. This is
773 the case when our source is an mms stream, notice that in this case
774 gstmms will do a time based seek to get the byte offset, this is not a
775 problem as the seek to this offset needs to happen anway. */
776 if (gst_pad_peer_query_convert (demux->sinkpad, GST_FORMAT_TIME, seek_time,
777 GST_FORMAT_BYTES, &offset)) {
778 packet = (offset - demux->data_offset) / demux->packet_size;
779 GST_LOG_OBJECT (demux, "convert %" GST_TIME_FORMAT
780 " to bytes query result: %" G_GINT64_FORMAT ", data_ofset: %"
781 G_GINT64_FORMAT ", packet_size: %u," " resulting packet: %u\n",
782 GST_TIME_ARGS (seek_time), offset, demux->data_offset,
783 demux->packet_size, packet);
785 /* FIXME: For streams containing video, seek to an earlier position in
786 * the hope of hitting a keyframe and let the sinks throw away the stuff
787 * before the segment start. For audio-only this is unnecessary as every
789 if (flush && (demux->accurate || (demux->keyunit_sync && !next))
790 && demux->num_video_streams > 0) {
791 seek_time -= 5 * GST_SECOND;
796 packet = (guint) gst_util_uint64_scale (demux->num_packets,
797 seek_time, demux->play_time);
799 if (packet > demux->num_packets)
800 packet = demux->num_packets;
803 if (G_LIKELY (demux->keyunit_sync && !demux->accurate)) {
804 GST_DEBUG_OBJECT (demux, "key unit seek, adjust seek_time = %"
805 GST_TIME_FORMAT " to index_time = %" GST_TIME_FORMAT,
806 GST_TIME_ARGS (seek_time), GST_TIME_ARGS (idx_time));
807 segment.start = idx_time;
808 segment.position = idx_time;
809 segment.time = idx_time;
813 GST_DEBUG_OBJECT (demux, "seeking to packet %u (%d)", packet, speed_count);
815 GST_OBJECT_LOCK (demux);
816 demux->segment = segment;
817 if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment)) {
818 demux->packet = (gint64) gst_util_uint64_scale (demux->num_packets,
819 stop, demux->play_time);
821 demux->packet = packet;
824 demux->need_newsegment = TRUE;
825 demux->segment_seqnum = seqnum;
826 demux->speed_packets =
827 GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment) ? 1 : speed_count;
828 gst_asf_demux_reset_stream_state_after_discont (demux);
829 GST_OBJECT_UNLOCK (demux);
832 /* restart our task since it might have been stopped when we did the flush */
833 gst_pad_start_task (demux->sinkpad, (GstTaskFunction) gst_asf_demux_loop,
836 /* streaming can continue now */
837 GST_PAD_STREAM_UNLOCK (demux->sinkpad);
843 gst_asf_demux_handle_src_event (GstPad * pad, GstObject * parent,
849 demux = GST_ASF_DEMUX (parent);
851 switch (GST_EVENT_TYPE (event)) {
853 GST_LOG_OBJECT (pad, "seek event");
854 ret = gst_asf_demux_handle_seek_event (demux, event);
855 gst_event_unref (event);
858 case GST_EVENT_NAVIGATION:
859 /* just drop these two silently */
860 gst_event_unref (event);
864 GST_LOG_OBJECT (pad, "%s event", GST_EVENT_TYPE_NAME (event));
865 ret = gst_pad_event_default (pad, parent, event);
872 static inline guint32
873 gst_asf_demux_identify_guid (const ASFGuidHash * guids, ASFGuid * guid)
877 ret = gst_asf_identify_guid (guids, guid);
879 GST_LOG ("%s 0x%08x-0x%08x-0x%08x-0x%08x",
880 gst_asf_get_guid_nick (guids, ret),
881 guid->v1, guid->v2, guid->v3, guid->v4);
893 /* Peek for an object.
895 * Returns FALSE is the object is corrupted (such as the reported
896 * object size being greater than 2**32bits.
899 asf_demux_peek_object (GstASFDemux * demux, const guint8 * data,
900 guint data_len, AsfObject * object, gboolean expect)
904 /* Callers should have made sure that data_len is big enough */
905 g_assert (data_len >= ASF_OBJECT_HEADER_SIZE);
907 if (data_len < ASF_OBJECT_HEADER_SIZE)
910 guid.v1 = GST_READ_UINT32_LE (data + 0);
911 guid.v2 = GST_READ_UINT32_LE (data + 4);
912 guid.v3 = GST_READ_UINT32_LE (data + 8);
913 guid.v4 = GST_READ_UINT32_LE (data + 12);
915 /* FIXME: make asf_demux_identify_object_guid() */
916 object->id = gst_asf_demux_identify_guid (asf_object_guids, &guid);
917 if (object->id == ASF_OBJ_UNDEFINED && expect) {
918 GST_WARNING_OBJECT (demux, "Unknown object %08x-%08x-%08x-%08x",
919 guid.v1, guid.v2, guid.v3, guid.v4);
922 object->size = GST_READ_UINT64_LE (data + 16);
923 if (object->id != ASF_OBJ_DATA && object->size >= G_MAXUINT) {
924 GST_WARNING_OBJECT (demux,
925 "ASF Object size corrupted (greater than 32bit)");
934 gst_asf_demux_release_old_pads (GstASFDemux * demux)
936 GST_DEBUG_OBJECT (demux, "Releasing old pads");
938 while (demux->old_num_streams > 0) {
939 gst_pad_push_event (demux->old_stream[demux->old_num_streams - 1].pad,
940 gst_event_new_eos ());
941 gst_asf_demux_free_stream (demux,
942 &demux->old_stream[demux->old_num_streams - 1]);
943 --demux->old_num_streams;
945 memset (demux->old_stream, 0, sizeof (demux->old_stream));
946 demux->old_num_streams = 0;
950 gst_asf_demux_chain_headers (GstASFDemux * demux)
953 guint8 *header_data, *data = NULL;
954 const guint8 *cdata = NULL;
956 GstFlowReturn flow = GST_FLOW_OK;
958 cdata = (guint8 *) gst_adapter_map (demux->adapter, ASF_OBJECT_HEADER_SIZE);
962 if (!asf_demux_peek_object (demux, cdata, ASF_OBJECT_HEADER_SIZE, &obj, TRUE))
964 if (obj.id != ASF_OBJ_HEADER)
967 GST_LOG_OBJECT (demux, "header size = %u", (guint) obj.size);
969 /* + 50 for non-packet data at beginning of ASF_OBJ_DATA */
970 if (gst_adapter_available (demux->adapter) < obj.size + 50)
973 data = gst_adapter_take (demux->adapter, obj.size + 50);
976 header_size = obj.size;
977 flow = gst_asf_demux_process_object (demux, &header_data, &header_size);
978 if (flow != GST_FLOW_OK)
981 /* calculate where the packet data starts */
982 demux->data_offset = obj.size + 50;
984 /* now parse the beginning of the ASF_OBJ_DATA object */
985 if (!gst_asf_demux_parse_data_object_start (demux, data + obj.size))
988 if (demux->num_streams == 0)
997 GST_LOG_OBJECT (demux, "not enough data in adapter yet");
1004 GST_ELEMENT_ERROR (demux, STREAM, WRONG_TYPE, (NULL),
1005 ("This doesn't seem to be an ASF file"));
1007 return GST_FLOW_ERROR;
1012 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
1013 ("header parsing failed, or no streams found, flow = %s",
1014 gst_flow_get_name (flow)));
1016 return GST_FLOW_ERROR;
1021 gst_asf_demux_pull_data (GstASFDemux * demux, guint64 offset, guint size,
1022 GstBuffer ** p_buf, GstFlowReturn * p_flow)
1027 GST_LOG_OBJECT (demux, "pulling buffer at %" G_GUINT64_FORMAT "+%u",
1030 flow = gst_pad_pull_range (demux->sinkpad, offset, size, p_buf);
1032 if (G_LIKELY (p_flow))
1035 if (G_UNLIKELY (flow != GST_FLOW_OK)) {
1036 GST_DEBUG_OBJECT (demux, "flow %s pulling buffer at %" G_GUINT64_FORMAT
1037 "+%u", gst_flow_get_name (flow), offset, size);
1042 g_assert (*p_buf != NULL);
1044 buffer_size = gst_buffer_get_size (*p_buf);
1045 if (G_UNLIKELY (buffer_size < size)) {
1046 GST_DEBUG_OBJECT (demux, "short read pulling buffer at %" G_GUINT64_FORMAT
1047 "+%u (got only %" G_GSIZE_FORMAT " bytes)", offset, size, buffer_size);
1048 gst_buffer_unref (*p_buf);
1049 if (G_LIKELY (p_flow))
1050 *p_flow = GST_FLOW_EOS;
1058 static GstFlowReturn
1059 gst_asf_demux_pull_indices (GstASFDemux * demux)
1061 GstBuffer *buf = NULL;
1064 GstFlowReturn ret = GST_FLOW_OK;
1066 offset = demux->index_offset;
1068 if (G_UNLIKELY (offset == 0)) {
1069 GST_DEBUG_OBJECT (demux, "can't read indices, don't know index offset");
1074 while (gst_asf_demux_pull_data (demux, offset, 16 + 8, &buf, NULL)) {
1080 gst_buffer_map (buf, &map, GST_MAP_READ);
1081 g_assert (map.size >= 16 + 8);
1082 if (!asf_demux_peek_object (demux, map.data, 16 + 8, &obj, TRUE)) {
1083 GST_DEBUG_OBJECT (demux, "No valid object, corrupted index, ignoring");
1084 GST_MEMDUMP_OBJECT (demux, "Corrupted index ?", map.data, MIN (map.size,
1086 gst_buffer_unmap (buf, &map);
1087 gst_buffer_replace (&buf, NULL);
1088 /* Non-fatal, return */
1091 gst_buffer_unmap (buf, &map);
1092 gst_buffer_replace (&buf, NULL);
1094 /* check for sanity */
1095 if (G_UNLIKELY (obj.size > (5 * 1024 * 1024))) {
1096 GST_DEBUG_OBJECT (demux, "implausible index object size, bailing out");
1100 if (G_UNLIKELY (!gst_asf_demux_pull_data (demux, offset, obj.size, &buf,
1104 GST_LOG_OBJECT (demux, "index object at offset 0x%" G_GINT64_MODIFIER "X"
1105 ", size %u", offset, (guint) obj.size);
1107 offset += obj.size; /* increase before _process_object changes it */
1109 gst_buffer_map (buf, &map, GST_MAP_READ);
1110 g_assert (map.size >= obj.size);
1111 bufdata = (guint8 *) map.data;
1112 obj_size = obj.size;
1113 ret = gst_asf_demux_process_object (demux, &bufdata, &obj_size);
1114 gst_buffer_unmap (buf, &map);
1115 gst_buffer_replace (&buf, NULL);
1117 if (ret == ASF_FLOW_NEED_MORE_DATA) {
1118 /* Since indices are at the end of the file, if we need more data,
1119 * we consider it as a non-fatal corrupted index */
1124 if (G_UNLIKELY (ret != GST_FLOW_OK))
1130 GST_DEBUG_OBJECT (demux, "read %u index objects , returning %s", num_read,
1131 gst_flow_get_name (ret));
1136 gst_asf_demux_parse_data_object_start (GstASFDemux * demux, guint8 * data)
1140 if (!asf_demux_peek_object (demux, data, 50, &obj, TRUE)) {
1141 GST_WARNING_OBJECT (demux, "Corrupted data");
1144 if (obj.id != ASF_OBJ_DATA) {
1145 GST_WARNING_OBJECT (demux, "headers not followed by a DATA object");
1149 demux->state = GST_ASF_DEMUX_STATE_DATA;
1151 if (!demux->broadcast && obj.size > 50) {
1152 demux->data_size = obj.size - 50;
1153 /* CHECKME: for at least one file this is off by +158 bytes?! */
1154 demux->index_offset = demux->data_offset + demux->data_size;
1156 demux->data_size = 0;
1157 demux->index_offset = 0;
1162 if (!demux->broadcast) {
1163 /* skip object header (24 bytes) and file GUID (16 bytes) */
1164 demux->num_packets = GST_READ_UINT64_LE (data + (16 + 8) + 16);
1166 demux->num_packets = 0;
1169 if (demux->num_packets == 0)
1170 demux->seekable = FALSE;
1172 /* fallback in the unlikely case that headers are inconsistent, can't hurt */
1173 if (demux->data_size == 0 && demux->num_packets > 0) {
1174 demux->data_size = demux->num_packets * demux->packet_size;
1175 demux->index_offset = demux->data_offset + demux->data_size;
1178 /* process pending stream objects and create pads for those */
1179 gst_asf_demux_process_queued_extended_stream_objects (demux);
1181 GST_INFO_OBJECT (demux, "Stream has %" G_GUINT64_FORMAT " packets, "
1182 "data_offset=%" G_GINT64_FORMAT ", data_size=%" G_GINT64_FORMAT
1183 ", index_offset=%" G_GUINT64_FORMAT, demux->num_packets,
1184 demux->data_offset, demux->data_size, demux->index_offset);
1185 #ifdef TIZEN_FEATURE_ASFDEMUX_CHECK_DATA_SIZE
1186 if (demux->data_size == 0) {
1187 GST_WARNING_OBJECT (demux, "DATA object size is zero");
1195 gst_asf_demux_pull_headers (GstASFDemux * demux, GstFlowReturn * pflow)
1197 GstFlowReturn flow = GST_FLOW_OK;
1199 GstBuffer *buf = NULL;
1204 GST_LOG_OBJECT (demux, "reading headers");
1206 /* pull HEADER object header, so we know its size */
1207 if (!gst_asf_demux_pull_data (demux, demux->base_offset, 16 + 8, &buf, &flow))
1210 gst_buffer_map (buf, &map, GST_MAP_READ);
1211 g_assert (map.size >= 16 + 8);
1212 if (!asf_demux_peek_object (demux, map.data, 16 + 8, &obj, TRUE)) {
1213 gst_buffer_unmap (buf, &map);
1214 gst_buffer_replace (&buf, NULL);
1215 flow = GST_FLOW_ERROR;
1218 gst_buffer_unmap (buf, &map);
1219 gst_buffer_replace (&buf, NULL);
1221 if (obj.id != ASF_OBJ_HEADER)
1224 GST_LOG_OBJECT (demux, "header size = %" G_GUINT64_FORMAT, obj.size);
1226 /* pull HEADER object */
1227 if (!gst_asf_demux_pull_data (demux, demux->base_offset, obj.size, &buf,
1231 size = obj.size; /* don't want obj.size changed */
1232 gst_buffer_map (buf, &map, GST_MAP_READ);
1233 g_assert (map.size >= size);
1234 bufdata = (guint8 *) map.data;
1235 flow = gst_asf_demux_process_object (demux, &bufdata, &size);
1236 gst_buffer_unmap (buf, &map);
1237 gst_buffer_replace (&buf, NULL);
1239 if (flow != GST_FLOW_OK) {
1240 GST_WARNING_OBJECT (demux, "process_object: %s", gst_flow_get_name (flow));
1244 /* calculate where the packet data starts */
1245 demux->data_offset = demux->base_offset + obj.size + 50;
1247 /* now pull beginning of DATA object before packet data */
1248 if (!gst_asf_demux_pull_data (demux, demux->base_offset + obj.size, 50, &buf,
1252 gst_buffer_map (buf, &map, GST_MAP_READ);
1253 g_assert (map.size >= size);
1254 bufdata = (guint8 *) map.data;
1255 if (!gst_asf_demux_parse_data_object_start (demux, bufdata))
1258 if (demux->num_streams == 0)
1261 gst_buffer_unmap (buf, &map);
1262 gst_buffer_replace (&buf, NULL);
1270 gst_buffer_unmap (buf, &map);
1271 gst_buffer_replace (&buf, NULL);
1273 GST_ELEMENT_ERROR (demux, STREAM, WRONG_TYPE, (NULL),
1274 ("This doesn't seem to be an ASF file"));
1275 *pflow = GST_FLOW_ERROR;
1280 flow = GST_FLOW_ERROR;
1281 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
1282 ("header parsing failed, or no streams found, flow = %s",
1283 gst_flow_get_name (flow)));
1288 gst_buffer_unmap (buf, &map);
1289 gst_buffer_replace (&buf, NULL);
1290 if (flow == ASF_FLOW_NEED_MORE_DATA)
1291 flow = GST_FLOW_ERROR;
1298 all_streams_prerolled (GstASFDemux * demux)
1300 GstClockTime preroll_time;
1301 guint i, num_no_data = 0;
1302 AsfStreamType prerolled_types = 0, all_types = 0;
1304 /* Allow at least 500ms of preroll_time */
1305 preroll_time = MAX (demux->preroll, 500 * GST_MSECOND);
1307 /* returns TRUE as long as there isn't a stream which (a) has data queued
1308 * and (b) the timestamp of last piece of data queued is < demux->preroll
1309 * AND there is at least one other stream with data queued */
1310 for (i = 0; i < demux->num_streams; ++i) {
1311 AsfPayload *last_payload = NULL;
1315 stream = &demux->stream[i];
1317 all_types |= stream->type;
1319 if (G_UNLIKELY (stream->payloads->len == 0)) {
1321 GST_LOG_OBJECT (stream->pad, "no data queued");
1325 prerolled_types |= stream->type;
1327 /* find last payload with timestamp */
1328 for (last_idx = stream->payloads->len - 1;
1329 last_idx >= 0 && (last_payload == NULL
1330 || !GST_CLOCK_TIME_IS_VALID (last_payload->ts)); --last_idx) {
1331 last_payload = &g_array_index (stream->payloads, AsfPayload, last_idx);
1334 GST_LOG_OBJECT (stream->pad, "checking if %" GST_TIME_FORMAT " > %"
1335 GST_TIME_FORMAT, GST_TIME_ARGS (last_payload->ts),
1336 GST_TIME_ARGS (preroll_time));
1337 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (last_payload->ts)
1338 || last_payload->ts <= preroll_time)) {
1339 GST_LOG_OBJECT (stream->pad, "not beyond preroll point yet");
1344 GST_LOG_OBJECT (demux, "all_types:%d prerolled_types:%d",
1345 all_types, prerolled_types);
1347 /* If streams of each present type have prerolled, we are good to go */
1348 if (all_types != 0 && prerolled_types == all_types)
1351 if (G_UNLIKELY (num_no_data > 0))
1359 gst_asf_demux_have_mutually_exclusive_active_stream (GstASFDemux * demux,
1364 for (l = demux->mut_ex_streams; l != NULL; l = l->next) {
1367 /* check for each mutual exclusion group whether it affects this stream */
1368 for (mes = (guint8 *) l->data; mes != NULL && *mes != 0xff; ++mes) {
1369 if (*mes == stream->id) {
1370 /* we are in this group; let's check if we've already activated streams
1371 * that are in the same group (and hence mutually exclusive to this
1373 for (mes = (guint8 *) l->data; mes != NULL && *mes != 0xff; ++mes) {
1376 for (i = 0; i < demux->num_streams; ++i) {
1377 if (demux->stream[i].id == *mes && demux->stream[i].active) {
1378 GST_LOG_OBJECT (demux, "stream with ID %d is mutually exclusive "
1379 "to already active stream with ID %d", stream->id,
1380 demux->stream[i].id);
1385 /* we can only be in this group once, let's break out and move on to
1386 * the next mutual exclusion group */
1397 gst_asf_demux_check_segment_ts (GstASFDemux * demux, GstClockTime payload_ts)
1399 /* remember the first queued timestamp for the segment */
1400 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (demux->segment_ts) &&
1401 GST_CLOCK_TIME_IS_VALID (demux->first_ts))) {
1402 GST_DEBUG_OBJECT (demux, "segment ts: %" GST_TIME_FORMAT,
1403 GST_TIME_ARGS (demux->first_ts));
1404 demux->segment_ts = payload_ts;
1405 /* always note, but only determines segment when streaming */
1406 if (demux->streaming)
1407 gst_segment_do_seek (&demux->segment, demux->in_segment.rate,
1408 GST_FORMAT_TIME, (GstSeekFlags) demux->segment.flags,
1409 GST_SEEK_TYPE_SET, demux->segment_ts, GST_SEEK_TYPE_NONE, 0, NULL);
1414 gst_asf_demux_get_first_ts (GstASFDemux * demux)
1416 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (demux->first_ts))) {
1417 GstClockTime first_ts = GST_CLOCK_TIME_NONE;
1420 /* go trhough each stream, find smallest timestamp */
1421 for (i = 0; i < demux->num_streams; ++i) {
1424 GstClockTime stream_min_ts = GST_CLOCK_TIME_NONE;
1425 GstClockTime stream_min_ts2 = GST_CLOCK_TIME_NONE; /* second smallest timestamp */
1426 stream = &demux->stream[i];
1428 for (j = 0; j < stream->payloads->len; ++j) {
1429 AsfPayload *payload = &g_array_index (stream->payloads, AsfPayload, j);
1430 if (GST_CLOCK_TIME_IS_VALID (payload->ts) &&
1431 (!GST_CLOCK_TIME_IS_VALID (stream_min_ts)
1432 || stream_min_ts > payload->ts)) {
1433 stream_min_ts = payload->ts;
1435 if (GST_CLOCK_TIME_IS_VALID (payload->ts) &&
1436 payload->ts > stream_min_ts &&
1437 (!GST_CLOCK_TIME_IS_VALID (stream_min_ts2)
1438 || stream_min_ts2 > payload->ts)) {
1439 stream_min_ts2 = payload->ts;
1443 /* there are some DVR ms files where first packet has TS of 0 (instead of -1) while subsequent packets have
1444 regular (singificantly larger) timestamps. If we don't deal with it, we may end up with huge gap in timestamps
1445 which makes playback stuck. The 0 timestamp may also be valid though, if the second packet timestamp continues
1446 from it. I havent found a better way to distinguish between these two, except to set an arbitrary boundary
1447 and disregard the first 0 timestamp if the second timestamp is bigger than the boundary) */
1449 GST_DEBUG_OBJECT (demux,
1450 "stream #%u stream_min_ts %" GST_TIME_FORMAT " stream_min_ts2 %"
1451 GST_TIME_FORMAT, stream->id, GST_TIME_ARGS (stream_min_ts),
1452 GST_TIME_ARGS (stream_min_ts2));
1454 if (stream_min_ts == 0 && stream_min_ts2 > GST_SECOND) /* first timestamp is 0 and second is significantly larger, disregard the 0 */
1455 stream_min_ts = stream_min_ts2;
1457 if (GST_CLOCK_TIME_IS_VALID (stream_min_ts) &&
1458 (!GST_CLOCK_TIME_IS_VALID (first_ts) || first_ts > stream_min_ts))
1459 first_ts = stream_min_ts;
1462 if (!GST_CLOCK_TIME_IS_VALID (first_ts)) /* can happen */
1465 demux->first_ts = first_ts;
1467 /* update packets queued before we knew first timestamp */
1468 for (i = 0; i < demux->num_streams; ++i) {
1471 stream = &demux->stream[i];
1473 for (j = 0; j < stream->payloads->len; ++j) {
1474 AsfPayload *payload = &g_array_index (stream->payloads, AsfPayload, j);
1475 if (GST_CLOCK_TIME_IS_VALID (payload->ts)) {
1476 if (payload->ts > first_ts)
1477 payload->ts -= first_ts;
1485 gst_asf_demux_check_segment_ts (demux, 0);
1491 gst_asf_demux_update_caps_from_payload (GstASFDemux * demux, AsfStream * stream)
1493 /* try to determine whether the stream is AC-3 or MPEG; In dvr-ms the codecTag is unreliable
1494 and often set wrong, inspecting the data is the only way that seem to be working */
1495 GstTypeFindProbability prob = GST_TYPE_FIND_NONE;
1496 GstCaps *caps = NULL;
1498 GstAdapter *adapter = gst_adapter_new ();
1500 for (i = 0; i < stream->payloads->len && prob < GST_TYPE_FIND_LIKELY; ++i) {
1502 AsfPayload *payload;
1505 payload = &g_array_index (stream->payloads, AsfPayload, i);
1506 gst_adapter_push (adapter, gst_buffer_ref (payload->buf));
1507 len = gst_adapter_available (adapter);
1508 data = gst_adapter_map (adapter, len);
1512 #define MIN_LENGTH 128
1514 /* look for the sync points */
1516 if (len < MIN_LENGTH || /* give typefind something to work on */
1517 (data[0] == 0x0b && data[1] == 0x77) || /* AC-3 sync point */
1518 (data[0] == 0xFF && ((data[1] & 0xF0) >> 4) == 0xF)) /* MPEG sync point */
1524 gst_caps_take (&caps, gst_type_find_helper_for_data (GST_OBJECT (demux),
1527 if (prob < GST_TYPE_FIND_LIKELY) {
1530 if (len > MIN_LENGTH)
1531 /* this wasn't it, look for another sync point */
1535 gst_adapter_unmap (adapter);
1538 gst_object_unref (adapter);
1541 gst_caps_take (&stream->caps, caps);
1549 gst_asf_demux_check_activate_streams (GstASFDemux * demux, gboolean force)
1551 guint i, actual_streams = 0;
1553 if (demux->activated_streams)
1556 if (!all_streams_prerolled (demux) && !force) {
1557 GST_DEBUG_OBJECT (demux, "not all streams with data beyond preroll yet");
1561 if (G_UNLIKELY (!gst_asf_demux_get_first_ts (demux)))
1564 for (i = 0; i < demux->num_streams; ++i) {
1565 AsfStream *stream = &demux->stream[i];
1567 if (stream->payloads->len > 0) {
1569 if (stream->inspect_payload && /* dvr-ms required payload inspection */
1570 !stream->active && /* do not inspect active streams (caps were already set) */
1571 !gst_asf_demux_update_caps_from_payload (demux, stream) && /* failed to determine caps */
1572 stream->payloads->len < 20) { /* if we couldn't determine the caps from 20 packets then just give up and use whatever was in codecTag */
1573 /* try to gather some more data */
1576 /* we don't check mutual exclusion stuff here; either we have data for
1577 * a stream, then we active it, or we don't, then we'll ignore it */
1578 GST_LOG_OBJECT (stream->pad, "is prerolled - activate!");
1579 gst_asf_demux_activate_stream (demux, stream);
1580 actual_streams += 1;
1582 GST_LOG_OBJECT (stream->pad, "no data, ignoring stream");
1586 if (actual_streams == 0) {
1587 /* We don't have any streams activated ! */
1588 GST_ERROR_OBJECT (demux, "No streams activated!");
1592 gst_asf_demux_release_old_pads (demux);
1594 demux->activated_streams = TRUE;
1595 GST_LOG_OBJECT (demux, "signalling no more pads");
1596 gst_element_no_more_pads (GST_ELEMENT (demux));
1600 /* returns the stream that has a complete payload with the lowest timestamp
1601 * queued, or NULL (we push things by timestamp because during the internal
1602 * prerolling we might accumulate more data then the external queues can take,
1603 * so we'd lock up if we pushed all accumulated data for stream N in one go) */
1605 gst_asf_demux_find_stream_with_complete_payload (GstASFDemux * demux)
1607 AsfPayload *best_payload = NULL;
1608 AsfStream *best_stream = NULL;
1611 for (i = 0; i < demux->num_streams; ++i) {
1615 stream = &demux->stream[i];
1617 /* Don't push any data until we have at least one payload that falls within
1618 * the current segment. This way we can remove out-of-segment payloads that
1619 * don't need to be decoded after a seek, sending only data from the
1620 * keyframe directly before our segment start */
1621 if (stream->payloads->len > 0) {
1622 AsfPayload *payload = NULL;
1625 if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment)) {
1626 /* Reverse playback */
1628 if (stream->is_video) {
1629 /* We have to push payloads from KF to the first frame we accumulated (reverse order) */
1630 if (stream->reverse_kf_ready) {
1632 &g_array_index (stream->payloads, AsfPayload, stream->kf_pos);
1633 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (payload->ts))) {
1634 /* TODO : remove payload from the list? */
1641 /* find first complete payload with timestamp */
1642 for (j = stream->payloads->len - 1;
1643 j >= 0 && (payload == NULL
1644 || !GST_CLOCK_TIME_IS_VALID (payload->ts)); --j) {
1645 payload = &g_array_index (stream->payloads, AsfPayload, j);
1648 /* If there's a complete payload queued for this stream */
1649 if (!gst_asf_payload_is_complete (payload))
1655 /* find last payload with timestamp */
1656 for (last_idx = stream->payloads->len - 1;
1657 last_idx >= 0 && (payload == NULL
1658 || !GST_CLOCK_TIME_IS_VALID (payload->ts)); --last_idx) {
1659 payload = &g_array_index (stream->payloads, AsfPayload, last_idx);
1662 /* if this is first payload after seek we might need to update the segment */
1663 if (GST_CLOCK_TIME_IS_VALID (payload->ts))
1664 gst_asf_demux_check_segment_ts (demux, payload->ts);
1666 if (G_UNLIKELY (GST_CLOCK_TIME_IS_VALID (payload->ts) &&
1667 (payload->ts < demux->segment.start))) {
1668 if (G_UNLIKELY ((demux->keyunit_sync) && (!demux->accurate)
1669 && payload->keyframe)) {
1670 GST_DEBUG_OBJECT (stream->pad,
1671 "Found keyframe, updating segment start to %" GST_TIME_FORMAT,
1672 GST_TIME_ARGS (payload->ts));
1673 demux->segment.start = payload->ts;
1674 demux->segment.time = payload->ts;
1676 GST_DEBUG_OBJECT (stream->pad, "Last queued payload has timestamp %"
1677 GST_TIME_FORMAT " which is before our segment start %"
1678 GST_TIME_FORMAT ", not pushing yet",
1679 GST_TIME_ARGS (payload->ts),
1680 GST_TIME_ARGS (demux->segment.start));
1685 /* find first complete payload with timestamp */
1687 j < stream->payloads->len && (payload == NULL
1688 || !GST_CLOCK_TIME_IS_VALID (payload->ts)); ++j) {
1689 payload = &g_array_index (stream->payloads, AsfPayload, j);
1692 /* Now see if there's a complete payload queued for this stream */
1693 if (!gst_asf_payload_is_complete (payload))
1697 /* ... and whether its timestamp is lower than the current best */
1698 if (best_stream == NULL || best_payload->ts > payload->ts) {
1699 best_stream = stream;
1700 best_payload = payload;
1708 static GstFlowReturn
1709 gst_asf_demux_push_complete_payloads (GstASFDemux * demux, gboolean force)
1712 GstFlowReturn ret = GST_FLOW_OK;
1714 if (G_UNLIKELY (!demux->activated_streams)) {
1715 if (!gst_asf_demux_check_activate_streams (demux, force))
1717 /* streams are now activated */
1720 while ((stream = gst_asf_demux_find_stream_with_complete_payload (demux))) {
1721 AsfPayload *payload;
1722 GstClockTime timestamp = GST_CLOCK_TIME_NONE;
1723 GstClockTime duration = GST_CLOCK_TIME_NONE;
1725 /* wait until we had a chance to "lock on" some payload's timestamp */
1726 if (G_UNLIKELY (demux->need_newsegment
1727 && !GST_CLOCK_TIME_IS_VALID (demux->segment_ts)))
1730 if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment) && stream->is_video
1731 && stream->payloads->len) {
1732 payload = &g_array_index (stream->payloads, AsfPayload, stream->kf_pos);
1734 payload = &g_array_index (stream->payloads, AsfPayload, 0);
1737 /* do we need to send a newsegment event */
1738 if ((G_UNLIKELY (demux->need_newsegment))) {
1739 GstEvent *segment_event;
1741 /* safe default if insufficient upstream info */
1742 if (!GST_CLOCK_TIME_IS_VALID (demux->in_gap))
1745 if (demux->segment.stop == GST_CLOCK_TIME_NONE &&
1746 demux->segment.duration > 0) {
1747 /* slight HACK; prevent clipping of last bit */
1748 demux->segment.stop = demux->segment.duration + demux->in_gap;
1751 /* FIXME : only if ACCURATE ! */
1752 if (G_LIKELY (demux->keyunit_sync && !demux->accurate
1753 && (GST_CLOCK_TIME_IS_VALID (payload->ts)))
1754 && !GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment)) {
1755 GST_DEBUG ("Adjusting newsegment start to %" GST_TIME_FORMAT,
1756 GST_TIME_ARGS (payload->ts));
1757 demux->segment.start = payload->ts;
1758 demux->segment.time = payload->ts;
1761 GST_DEBUG_OBJECT (demux, "sending new-segment event %" GST_SEGMENT_FORMAT,
1764 /* note: we fix up all timestamps to start from 0, so this should be ok */
1765 segment_event = gst_event_new_segment (&demux->segment);
1766 if (demux->segment_seqnum)
1767 gst_event_set_seqnum (segment_event, demux->segment_seqnum);
1768 gst_asf_demux_send_event_unlocked (demux, segment_event);
1770 /* now post any global tags we may have found */
1771 if (demux->taglist == NULL) {
1772 demux->taglist = gst_tag_list_new_empty ();
1773 gst_tag_list_set_scope (demux->taglist, GST_TAG_SCOPE_GLOBAL);
1776 gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
1777 GST_TAG_CONTAINER_FORMAT, "ASF", NULL);
1779 GST_DEBUG_OBJECT (demux, "global tags: %" GST_PTR_FORMAT, demux->taglist);
1780 gst_asf_demux_send_event_unlocked (demux,
1781 gst_event_new_tag (demux->taglist));
1782 demux->taglist = NULL;
1784 demux->need_newsegment = FALSE;
1785 demux->segment_seqnum = 0;
1786 demux->segment_running = TRUE;
1789 /* Do we have tags pending for this stream? */
1790 if (G_UNLIKELY (stream->pending_tags)) {
1791 GST_LOG_OBJECT (stream->pad, "%" GST_PTR_FORMAT, stream->pending_tags);
1792 gst_pad_push_event (stream->pad,
1793 gst_event_new_tag (stream->pending_tags));
1794 stream->pending_tags = NULL;
1797 /* We have the whole packet now so we should push the packet to
1798 * the src pad now. First though we should check if we need to do
1800 if (G_UNLIKELY (stream->span > 1)) {
1801 gst_asf_demux_descramble_buffer (demux, stream, &payload->buf);
1804 payload->buf = gst_buffer_make_writable (payload->buf);
1806 if (G_LIKELY (!payload->keyframe)) {
1807 GST_BUFFER_FLAG_SET (payload->buf, GST_BUFFER_FLAG_DELTA_UNIT);
1810 if (G_UNLIKELY (stream->discont)) {
1811 GST_DEBUG_OBJECT (stream->pad, "marking DISCONT on stream");
1812 GST_BUFFER_FLAG_SET (payload->buf, GST_BUFFER_FLAG_DISCONT);
1813 stream->discont = FALSE;
1816 if (G_UNLIKELY (stream->is_video && payload->par_x && payload->par_y &&
1817 (payload->par_x != stream->par_x) &&
1818 (payload->par_y != stream->par_y))) {
1819 GST_DEBUG ("Updating PAR (%d/%d => %d/%d)",
1820 stream->par_x, stream->par_y, payload->par_x, payload->par_y);
1821 stream->par_x = payload->par_x;
1822 stream->par_y = payload->par_y;
1823 stream->caps = gst_caps_make_writable (stream->caps);
1824 gst_caps_set_simple (stream->caps, "pixel-aspect-ratio",
1825 GST_TYPE_FRACTION, stream->par_x, stream->par_y, NULL);
1826 gst_pad_set_caps (stream->pad, stream->caps);
1829 if (G_UNLIKELY (stream->interlaced != payload->interlaced)) {
1830 GST_DEBUG ("Updating interlaced status (%d => %d)", stream->interlaced,
1831 payload->interlaced);
1832 stream->interlaced = payload->interlaced;
1833 stream->caps = gst_caps_make_writable (stream->caps);
1834 gst_caps_set_simple (stream->caps, "interlace-mode", G_TYPE_BOOLEAN,
1835 (stream->interlaced ? "mixed" : "progressive"), NULL);
1836 gst_pad_set_caps (stream->pad, stream->caps);
1839 /* (sort of) interpolate timestamps using upstream "frame of reference",
1840 * typically useful for live src, but might (unavoidably) mess with
1841 * position reporting if a live src is playing not so live content
1842 * (e.g. rtspsrc taking some time to fall back to tcp) */
1843 timestamp = payload->ts;
1844 if (GST_CLOCK_TIME_IS_VALID (timestamp)
1845 && !GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment)) {
1846 timestamp += demux->in_gap;
1848 /* Check if we're after the segment already, if so no need to push
1850 if (demux->segment.stop != -1 && timestamp > demux->segment.stop) {
1851 GST_DEBUG_OBJECT (stream->pad,
1852 "Payload after segment stop %" GST_TIME_FORMAT,
1853 GST_TIME_ARGS (demux->segment.stop));
1855 gst_flow_combiner_update_pad_flow (demux->flowcombiner, stream->pad,
1857 gst_buffer_unref (payload->buf);
1858 payload->buf = NULL;
1859 g_array_remove_index (stream->payloads, 0);
1860 /* Break out as soon as we have an issue */
1861 if (G_UNLIKELY (ret != GST_FLOW_OK))
1868 GST_BUFFER_PTS (payload->buf) = timestamp;
1870 if (payload->duration == GST_CLOCK_TIME_NONE
1871 && stream->ext_props.avg_time_per_frame != 0) {
1872 duration = stream->ext_props.avg_time_per_frame * 100;
1874 duration = payload->duration;
1876 GST_BUFFER_DURATION (payload->buf) = duration;
1878 /* FIXME: we should really set durations on buffers if we can */
1880 GST_LOG_OBJECT (stream->pad, "pushing buffer, %" GST_PTR_FORMAT,
1883 if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment) && stream->is_video) {
1884 if (stream->reverse_kf_ready == TRUE && stream->kf_pos == 0) {
1885 GST_BUFFER_FLAG_SET (payload->buf, GST_BUFFER_FLAG_DISCONT);
1887 } else if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment)) {
1888 GST_BUFFER_FLAG_SET (payload->buf, GST_BUFFER_FLAG_DISCONT);
1892 if (stream->active) {
1893 if (G_UNLIKELY (stream->first_buffer)) {
1894 if (stream->streamheader != NULL) {
1895 GST_DEBUG_OBJECT (stream->pad,
1896 "Pushing streamheader before first buffer");
1897 gst_pad_push (stream->pad, gst_buffer_ref (stream->streamheader));
1899 stream->first_buffer = FALSE;
1902 if (GST_CLOCK_TIME_IS_VALID (timestamp)
1903 && timestamp > demux->segment.position) {
1904 demux->segment.position = timestamp;
1905 if (GST_CLOCK_TIME_IS_VALID (duration))
1906 demux->segment.position += timestamp;
1909 ret = gst_pad_push (stream->pad, payload->buf);
1911 gst_flow_combiner_update_pad_flow (demux->flowcombiner, stream->pad,
1914 gst_buffer_unref (payload->buf);
1917 payload->buf = NULL;
1918 if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment) && stream->is_video
1919 && stream->reverse_kf_ready) {
1920 g_array_remove_index (stream->payloads, stream->kf_pos);
1923 if (stream->reverse_kf_ready == TRUE && stream->kf_pos < 0) {
1925 stream->reverse_kf_ready = FALSE;
1928 g_array_remove_index (stream->payloads, 0);
1931 /* Break out as soon as we have an issue */
1932 if (G_UNLIKELY (ret != GST_FLOW_OK))
1940 gst_asf_demux_check_buffer_is_header (GstASFDemux * demux, GstBuffer * buf)
1945 g_assert (buf != NULL);
1947 GST_LOG_OBJECT (demux, "Checking if buffer is a header");
1949 gst_buffer_map (buf, &map, GST_MAP_READ);
1951 /* we return false on buffer too small */
1952 if (map.size < ASF_OBJECT_HEADER_SIZE) {
1953 gst_buffer_unmap (buf, &map);
1957 /* check if it is a header */
1959 asf_demux_peek_object (demux, map.data, ASF_OBJECT_HEADER_SIZE, &obj,
1961 gst_buffer_unmap (buf, &map);
1962 if (valid && obj.id == ASF_OBJ_HEADER) {
1969 gst_asf_demux_check_chained_asf (GstASFDemux * demux)
1971 guint64 off = demux->data_offset + (demux->packet * demux->packet_size);
1972 GstFlowReturn ret = GST_FLOW_OK;
1973 GstBuffer *buf = NULL;
1974 gboolean header = FALSE;
1976 /* TODO maybe we should skip index objects after the data and look
1977 * further for a new header */
1978 if (gst_asf_demux_pull_data (demux, off, ASF_OBJECT_HEADER_SIZE, &buf, &ret)) {
1979 g_assert (buf != NULL);
1980 /* check if it is a header */
1981 if (gst_asf_demux_check_buffer_is_header (demux, buf)) {
1982 GST_DEBUG_OBJECT (demux, "new base offset: %" G_GUINT64_FORMAT, off);
1983 demux->base_offset = off;
1987 gst_buffer_unref (buf);
1994 gst_asf_demux_loop (GstASFDemux * demux)
1996 GstFlowReturn flow = GST_FLOW_OK;
1997 GstBuffer *buf = NULL;
2000 if (G_UNLIKELY (demux->state == GST_ASF_DEMUX_STATE_HEADER)) {
2001 if (!gst_asf_demux_pull_headers (demux, &flow)) {
2005 flow = gst_asf_demux_pull_indices (demux);
2006 if (flow != GST_FLOW_OK)
2010 g_assert (demux->state == GST_ASF_DEMUX_STATE_DATA);
2012 if (G_UNLIKELY (demux->num_packets != 0
2013 && demux->packet >= demux->num_packets))
2016 GST_LOG_OBJECT (demux, "packet %u/%u", (guint) demux->packet + 1,
2017 (guint) demux->num_packets);
2019 off = demux->data_offset + (demux->packet * demux->packet_size);
2021 if (G_UNLIKELY (!gst_asf_demux_pull_data (demux, off,
2022 demux->packet_size * demux->speed_packets, &buf, &flow))) {
2023 GST_DEBUG_OBJECT (demux, "got flow %s", gst_flow_get_name (flow));
2024 if (flow == GST_FLOW_EOS) {
2026 } else if (flow == GST_FLOW_FLUSHING) {
2027 GST_DEBUG_OBJECT (demux, "Not fatal");
2034 if (G_LIKELY (demux->speed_packets == 1)) {
2035 GstAsfDemuxParsePacketError err;
2036 err = gst_asf_demux_parse_packet (demux, buf);
2037 if (G_UNLIKELY (err != GST_ASF_DEMUX_PARSE_PACKET_ERROR_NONE)) {
2038 /* when we don't know when the data object ends, we should check
2039 * for a chained asf */
2040 if (demux->num_packets == 0) {
2041 if (gst_asf_demux_check_buffer_is_header (demux, buf)) {
2042 GST_INFO_OBJECT (demux, "Chained asf found");
2043 demux->base_offset = off;
2044 gst_asf_demux_reset (demux, TRUE);
2045 gst_buffer_unref (buf);
2049 /* FIXME: We should tally up fatal errors and error out only
2050 * after a few broken packets in a row? */
2052 GST_INFO_OBJECT (demux, "Ignoring recoverable parse error");
2053 gst_buffer_unref (buf);
2055 if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment)
2056 && !demux->seek_to_cur_pos) {
2058 if (demux->packet < 0) {
2068 flow = gst_asf_demux_push_complete_payloads (demux, FALSE);
2070 if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment)
2071 && !demux->seek_to_cur_pos) {
2073 if (demux->packet < 0) {
2082 for (n = 0; n < demux->speed_packets; n++) {
2084 GstAsfDemuxParsePacketError err;
2087 gst_buffer_copy_region (buf, GST_BUFFER_COPY_ALL,
2088 n * demux->packet_size, demux->packet_size);
2089 err = gst_asf_demux_parse_packet (demux, sub);
2090 if (G_UNLIKELY (err != GST_ASF_DEMUX_PARSE_PACKET_ERROR_NONE)) {
2091 /* when we don't know when the data object ends, we should check
2092 * for a chained asf */
2093 if (demux->num_packets == 0) {
2094 if (gst_asf_demux_check_buffer_is_header (demux, sub)) {
2095 GST_INFO_OBJECT (demux, "Chained asf found");
2096 demux->base_offset = off + n * demux->packet_size;
2097 gst_asf_demux_reset (demux, TRUE);
2098 gst_buffer_unref (sub);
2099 gst_buffer_unref (buf);
2103 /* FIXME: We should tally up fatal errors and error out only
2104 * after a few broken packets in a row? */
2106 GST_INFO_OBJECT (demux, "Ignoring recoverable parse error");
2110 gst_buffer_unref (sub);
2112 if (err == GST_ASF_DEMUX_PARSE_PACKET_ERROR_NONE)
2113 flow = gst_asf_demux_push_complete_payloads (demux, FALSE);
2119 /* reset speed pull */
2120 demux->speed_packets = 1;
2123 gst_buffer_unref (buf);
2125 if (G_UNLIKELY ((demux->num_packets > 0
2126 && demux->packet >= demux->num_packets)
2127 || flow == GST_FLOW_EOS)) {
2128 GST_LOG_OBJECT (demux, "reached EOS");
2132 if (G_UNLIKELY (flow != GST_FLOW_OK)) {
2133 GST_DEBUG_OBJECT (demux, "pushing complete payloads failed");
2137 /* check if we're at the end of the configured segment */
2138 /* FIXME: check if segment end reached etc. */
2144 /* if we haven't activated our streams yet, this might be because we have
2145 * less data queued than required for preroll; force stream activation and
2146 * send any pending payloads before sending EOS */
2147 if (!demux->activated_streams)
2148 flow = gst_asf_demux_push_complete_payloads (demux, TRUE);
2150 /* we want to push an eos or post a segment-done in any case */
2151 if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
2154 /* for segment playback we need to post when (in stream time)
2155 * we stopped, this is either stop (when set) or the duration. */
2156 if ((stop = demux->segment.stop) == -1)
2157 stop = demux->segment.duration;
2159 GST_INFO_OBJECT (demux, "Posting segment-done, at end of segment");
2160 gst_element_post_message (GST_ELEMENT_CAST (demux),
2161 gst_message_new_segment_done (GST_OBJECT (demux), GST_FORMAT_TIME,
2163 gst_asf_demux_send_event_unlocked (demux,
2164 gst_event_new_segment_done (GST_FORMAT_TIME, stop));
2165 } else if (flow != GST_FLOW_EOS) {
2166 /* check if we have a chained asf, in case, we don't eos yet */
2167 if (gst_asf_demux_check_chained_asf (demux)) {
2168 GST_INFO_OBJECT (demux, "Chained ASF starting");
2169 gst_asf_demux_reset (demux, TRUE);
2174 if (!(demux->segment.flags & GST_SEEK_FLAG_SEGMENT)) {
2175 if (demux->activated_streams) {
2176 /* normal playback, send EOS to all linked pads */
2177 GST_INFO_OBJECT (demux, "Sending EOS, at end of stream");
2178 gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
2180 GST_WARNING_OBJECT (demux, "EOS without exposed streams");
2181 flow = GST_FLOW_EOS;
2184 /* ... and fall through to pause */
2188 GST_DEBUG_OBJECT (demux, "pausing task, flow return: %s",
2189 gst_flow_get_name (flow));
2190 demux->segment_running = FALSE;
2191 gst_pad_pause_task (demux->sinkpad);
2193 /* For the error cases */
2194 if (flow == GST_FLOW_EOS && !demux->activated_streams) {
2195 GST_ELEMENT_ERROR (demux, STREAM, WRONG_TYPE, (NULL),
2196 ("This doesn't seem to be an ASF file"));
2197 } else if (flow < GST_FLOW_EOS || flow == GST_FLOW_NOT_LINKED) {
2198 /* Post an error. Hopefully something else already has, but if not... */
2199 GST_ELEMENT_FLOW_ERROR (demux, flow);
2200 gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
2209 GST_DEBUG_OBJECT (demux, "Read failed, doh");
2210 flow = GST_FLOW_EOS;
2214 /* See FIXMEs above */
2217 gst_buffer_unref (buf);
2218 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
2219 ("Error parsing ASF packet %u", (guint) demux->packet));
2220 gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
2221 flow = GST_FLOW_ERROR;
2227 #define GST_ASF_DEMUX_CHECK_HEADER_YES 0
2228 #define GST_ASF_DEMUX_CHECK_HEADER_NO 1
2229 #define GST_ASF_DEMUX_CHECK_HEADER_NEED_DATA 2
2232 gst_asf_demux_check_header (GstASFDemux * demux)
2235 guint8 *cdata = (guint8 *) gst_adapter_map (demux->adapter,
2236 ASF_OBJECT_HEADER_SIZE);
2237 if (cdata == NULL) /* need more data */
2238 return GST_ASF_DEMUX_CHECK_HEADER_NEED_DATA;
2240 if (asf_demux_peek_object (demux, cdata, ASF_OBJECT_HEADER_SIZE, &obj, FALSE)
2241 && obj.id == ASF_OBJ_HEADER) {
2242 return GST_ASF_DEMUX_CHECK_HEADER_YES;
2245 return GST_ASF_DEMUX_CHECK_HEADER_NO;
2248 static GstFlowReturn
2249 gst_asf_demux_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
2251 GstFlowReturn ret = GST_FLOW_OK;
2254 demux = GST_ASF_DEMUX (parent);
2256 GST_LOG_OBJECT (demux,
2257 "buffer: size=%" G_GSIZE_FORMAT ", offset=%" G_GINT64_FORMAT ", time=%"
2258 GST_TIME_FORMAT, gst_buffer_get_size (buf), GST_BUFFER_OFFSET (buf),
2259 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)));
2261 if (G_UNLIKELY (GST_BUFFER_IS_DISCONT (buf))) {
2262 GST_DEBUG_OBJECT (demux, "received DISCONT");
2263 gst_asf_demux_mark_discont (demux);
2266 if (G_UNLIKELY ((!GST_CLOCK_TIME_IS_VALID (demux->in_gap) &&
2267 GST_BUFFER_TIMESTAMP_IS_VALID (buf)))) {
2268 demux->in_gap = GST_BUFFER_TIMESTAMP (buf) - demux->in_segment.start;
2269 GST_DEBUG_OBJECT (demux, "upstream segment start %" GST_TIME_FORMAT
2270 ", interpolation gap: %" GST_TIME_FORMAT,
2271 GST_TIME_ARGS (demux->in_segment.start), GST_TIME_ARGS (demux->in_gap));
2274 gst_adapter_push (demux->adapter, buf);
2276 switch (demux->state) {
2277 case GST_ASF_DEMUX_STATE_INDEX:{
2278 gint result = gst_asf_demux_check_header (demux);
2279 if (result == GST_ASF_DEMUX_CHECK_HEADER_NEED_DATA) /* need more data */
2282 if (result == GST_ASF_DEMUX_CHECK_HEADER_NO) {
2283 /* we don't care about this, probably an index */
2284 /* TODO maybe would be smarter to skip all the indices
2285 * until we got a new header or EOS to decide */
2286 GST_LOG_OBJECT (demux, "Received index object, its EOS");
2289 GST_INFO_OBJECT (demux, "Chained asf starting");
2290 /* cleanup and get ready for a chained asf */
2291 gst_asf_demux_reset (demux, TRUE);
2295 case GST_ASF_DEMUX_STATE_HEADER:{
2296 ret = gst_asf_demux_chain_headers (demux);
2297 if (demux->state != GST_ASF_DEMUX_STATE_DATA)
2299 /* otherwise fall through */
2301 case GST_ASF_DEMUX_STATE_DATA:
2305 data_size = demux->packet_size;
2307 while (gst_adapter_available (demux->adapter) >= data_size) {
2309 GstAsfDemuxParsePacketError err;
2311 /* we don't know the length of the stream
2312 * check for a chained asf everytime */
2313 if (demux->num_packets == 0) {
2314 gint result = gst_asf_demux_check_header (demux);
2316 if (result == GST_ASF_DEMUX_CHECK_HEADER_YES) {
2317 GST_INFO_OBJECT (demux, "Chained asf starting");
2318 /* cleanup and get ready for a chained asf */
2319 gst_asf_demux_reset (demux, TRUE);
2322 } else if (G_UNLIKELY (demux->num_packets != 0 && demux->packet >= 0
2323 && demux->packet >= demux->num_packets)) {
2324 /* do not overshoot data section when streaming */
2328 buf = gst_adapter_take_buffer (demux->adapter, data_size);
2330 /* FIXME: We should tally up fatal errors and error out only
2331 * after a few broken packets in a row? */
2332 err = gst_asf_demux_parse_packet (demux, buf);
2334 gst_buffer_unref (buf);
2336 if (G_LIKELY (err == GST_ASF_DEMUX_PARSE_PACKET_ERROR_NONE))
2337 ret = gst_asf_demux_push_complete_payloads (demux, FALSE);
2339 GST_WARNING_OBJECT (demux, "Parse error");
2341 if (demux->packet >= 0)
2344 if (G_UNLIKELY (demux->num_packets != 0 && demux->packet >= 0
2345 && demux->packet >= demux->num_packets)) {
2346 demux->state = GST_ASF_DEMUX_STATE_INDEX;
2351 g_assert_not_reached ();
2355 if (ret != GST_FLOW_OK)
2356 GST_DEBUG_OBJECT (demux, "flow: %s", gst_flow_get_name (ret));
2362 GST_DEBUG_OBJECT (demux, "Handled last packet, setting EOS");
2368 static inline gboolean
2369 gst_asf_demux_skip_bytes (guint num_bytes, guint8 ** p_data, guint64 * p_size)
2371 if (*p_size < num_bytes)
2374 *p_data += num_bytes;
2375 *p_size -= num_bytes;
2379 static inline guint8
2380 gst_asf_demux_get_uint8 (guint8 ** p_data, guint64 * p_size)
2384 g_assert (*p_size >= 1);
2385 ret = GST_READ_UINT8 (*p_data);
2386 *p_data += sizeof (guint8);
2387 *p_size -= sizeof (guint8);
2391 static inline guint16
2392 gst_asf_demux_get_uint16 (guint8 ** p_data, guint64 * p_size)
2396 g_assert (*p_size >= 2);
2397 ret = GST_READ_UINT16_LE (*p_data);
2398 *p_data += sizeof (guint16);
2399 *p_size -= sizeof (guint16);
2403 static inline guint32
2404 gst_asf_demux_get_uint32 (guint8 ** p_data, guint64 * p_size)
2408 g_assert (*p_size >= 4);
2409 ret = GST_READ_UINT32_LE (*p_data);
2410 *p_data += sizeof (guint32);
2411 *p_size -= sizeof (guint32);
2415 static inline guint64
2416 gst_asf_demux_get_uint64 (guint8 ** p_data, guint64 * p_size)
2420 g_assert (*p_size >= 8);
2421 ret = GST_READ_UINT64_LE (*p_data);
2422 *p_data += sizeof (guint64);
2423 *p_size -= sizeof (guint64);
2428 gst_asf_demux_get_buffer (GstBuffer ** p_buf, guint num_bytes_to_read,
2429 guint8 ** p_data, guint64 * p_size)
2433 if (*p_size < num_bytes_to_read)
2436 *p_buf = gst_buffer_new_and_alloc (num_bytes_to_read);
2437 gst_buffer_fill (*p_buf, 0, *p_data, num_bytes_to_read);
2439 *p_data += num_bytes_to_read;
2440 *p_size -= num_bytes_to_read;
2446 gst_asf_demux_get_bytes (guint8 ** p_buf, guint num_bytes_to_read,
2447 guint8 ** p_data, guint64 * p_size)
2451 if (*p_size < num_bytes_to_read)
2454 *p_buf = g_memdup (*p_data, num_bytes_to_read);
2455 *p_data += num_bytes_to_read;
2456 *p_size -= num_bytes_to_read;
2461 gst_asf_demux_get_string (gchar ** p_str, guint16 * p_strlen,
2462 guint8 ** p_data, guint64 * p_size)
2472 s_length = gst_asf_demux_get_uint16 (p_data, p_size);
2475 *p_strlen = s_length;
2477 if (s_length == 0) {
2478 GST_WARNING ("zero-length string");
2479 *p_str = g_strdup ("");
2483 if (!gst_asf_demux_get_bytes (&s, s_length, p_data, p_size))
2486 g_assert (s != NULL);
2488 /* just because They don't exist doesn't
2489 * mean They are not out to get you ... */
2490 if (s[s_length - 1] != '\0') {
2491 s = g_realloc (s, s_length + 1);
2495 *p_str = (gchar *) s;
2501 gst_asf_demux_get_guid (ASFGuid * guid, guint8 ** p_data, guint64 * p_size)
2503 g_assert (*p_size >= 4 * sizeof (guint32));
2505 guid->v1 = gst_asf_demux_get_uint32 (p_data, p_size);
2506 guid->v2 = gst_asf_demux_get_uint32 (p_data, p_size);
2507 guid->v3 = gst_asf_demux_get_uint32 (p_data, p_size);
2508 guid->v4 = gst_asf_demux_get_uint32 (p_data, p_size);
2512 gst_asf_demux_get_stream_audio (asf_stream_audio * audio, guint8 ** p_data,
2515 if (*p_size < (2 + 2 + 4 + 4 + 2 + 2 + 2))
2518 /* WAVEFORMATEX Structure */
2519 audio->codec_tag = gst_asf_demux_get_uint16 (p_data, p_size);
2520 audio->channels = gst_asf_demux_get_uint16 (p_data, p_size);
2521 audio->sample_rate = gst_asf_demux_get_uint32 (p_data, p_size);
2522 audio->byte_rate = gst_asf_demux_get_uint32 (p_data, p_size);
2523 audio->block_align = gst_asf_demux_get_uint16 (p_data, p_size);
2524 audio->word_size = gst_asf_demux_get_uint16 (p_data, p_size);
2525 /* Codec specific data size */
2526 audio->size = gst_asf_demux_get_uint16 (p_data, p_size);
2527 if (audio->size > *p_size) {
2528 GST_WARNING ("Corrupted audio codec_data (should be at least %u bytes, is %"
2529 G_GUINT64_FORMAT " long)", audio->size, *p_size);
2536 gst_asf_demux_get_stream_video (asf_stream_video * video, guint8 ** p_data,
2539 if (*p_size < (4 + 4 + 1 + 2))
2542 video->width = gst_asf_demux_get_uint32 (p_data, p_size);
2543 video->height = gst_asf_demux_get_uint32 (p_data, p_size);
2544 video->unknown = gst_asf_demux_get_uint8 (p_data, p_size);
2545 video->size = gst_asf_demux_get_uint16 (p_data, p_size);
2550 gst_asf_demux_get_stream_video_format (asf_stream_video_format * fmt,
2551 guint8 ** p_data, guint64 * p_size)
2553 if (*p_size < (4 + 4 + 4 + 2 + 2 + 4 + 4 + 4 + 4 + 4 + 4))
2556 fmt->size = gst_asf_demux_get_uint32 (p_data, p_size);
2558 if (fmt->size < 40) {
2559 GST_WARNING ("Corrupted asf_stream_video_format (size < 40)");
2562 if ((guint64) fmt->size - 4 > *p_size) {
2563 GST_WARNING ("Corrupted asf_stream_video_format (codec_data is too small)");
2566 fmt->width = gst_asf_demux_get_uint32 (p_data, p_size);
2567 fmt->height = gst_asf_demux_get_uint32 (p_data, p_size);
2568 fmt->planes = gst_asf_demux_get_uint16 (p_data, p_size);
2569 fmt->depth = gst_asf_demux_get_uint16 (p_data, p_size);
2570 fmt->tag = gst_asf_demux_get_uint32 (p_data, p_size);
2571 fmt->image_size = gst_asf_demux_get_uint32 (p_data, p_size);
2572 fmt->xpels_meter = gst_asf_demux_get_uint32 (p_data, p_size);
2573 fmt->ypels_meter = gst_asf_demux_get_uint32 (p_data, p_size);
2574 fmt->num_colors = gst_asf_demux_get_uint32 (p_data, p_size);
2575 fmt->imp_colors = gst_asf_demux_get_uint32 (p_data, p_size);
2580 gst_asf_demux_get_stream (GstASFDemux * demux, guint16 id)
2584 for (i = 0; i < demux->num_streams; i++) {
2585 if (demux->stream[i].id == id)
2586 return &demux->stream[i];
2589 if (gst_asf_demux_is_unknown_stream (demux, id))
2590 GST_WARNING ("Segment found for undefined stream: (%d)", id);
2595 gst_asf_demux_setup_pad (GstASFDemux * demux, GstPad * src_pad,
2596 GstCaps * caps, guint16 id, gboolean is_video, GstBuffer * streamheader,
2601 gst_pad_use_fixed_caps (src_pad);
2602 gst_pad_set_caps (src_pad, caps);
2604 gst_pad_set_event_function (src_pad,
2605 GST_DEBUG_FUNCPTR (gst_asf_demux_handle_src_event));
2606 gst_pad_set_query_function (src_pad,
2607 GST_DEBUG_FUNCPTR (gst_asf_demux_handle_src_query));
2609 stream = &demux->stream[demux->num_streams];
2610 stream->caps = caps;
2611 stream->pad = src_pad;
2613 stream->fps_known = !is_video; /* bit hacky for audio */
2614 stream->is_video = is_video;
2615 stream->pending_tags = tags;
2616 stream->discont = TRUE;
2617 stream->first_buffer = TRUE;
2618 stream->streamheader = streamheader;
2619 if (stream->streamheader) {
2620 stream->streamheader = gst_buffer_make_writable (streamheader);
2621 GST_BUFFER_FLAG_SET (stream->streamheader, GST_BUFFER_FLAG_HEADER);
2626 st = gst_caps_get_structure (caps, 0);
2627 if (gst_structure_get_fraction (st, "pixel-aspect-ratio", &par_x, &par_y) &&
2628 par_x > 0 && par_y > 0) {
2629 GST_DEBUG ("PAR %d/%d", par_x, par_y);
2630 stream->par_x = par_x;
2631 stream->par_y = par_y;
2635 stream->payloads = g_array_new (FALSE, FALSE, sizeof (AsfPayload));
2637 /* TODO: create this array during reverse play? */
2638 stream->payloads_rev = g_array_new (FALSE, FALSE, sizeof (AsfPayload));
2640 GST_INFO ("Created pad %s for stream %u with caps %" GST_PTR_FORMAT,
2641 GST_PAD_NAME (src_pad), demux->num_streams, caps);
2643 ++demux->num_streams;
2645 stream->active = FALSE;
2651 gst_asf_demux_add_stream_headers_to_caps (GstASFDemux * demux,
2652 GstBuffer * buffer, GstStructure * structure)
2654 GValue arr_val = G_VALUE_INIT;
2655 GValue buf_val = G_VALUE_INIT;
2657 g_value_init (&arr_val, GST_TYPE_ARRAY);
2658 g_value_init (&buf_val, GST_TYPE_BUFFER);
2660 gst_value_set_buffer (&buf_val, buffer);
2661 gst_value_array_append_and_take_value (&arr_val, &buf_val);
2663 gst_structure_take_value (structure, "streamheader", &arr_val);
2667 gst_asf_demux_add_audio_stream (GstASFDemux * demux,
2668 asf_stream_audio * audio, guint16 id, guint8 ** p_data, guint64 * p_size)
2670 GstTagList *tags = NULL;
2671 GstBuffer *extradata = NULL;
2674 guint16 size_left = 0;
2675 gchar *codec_name = NULL;
2678 size_left = audio->size;
2680 /* Create the audio pad */
2681 name = g_strdup_printf ("audio_%u", demux->num_audio_streams);
2683 src_pad = gst_pad_new_from_static_template (&audio_src_template, name);
2686 /* Swallow up any left over data and set up the
2687 * standard properties from the header info */
2689 GST_INFO_OBJECT (demux, "Audio header contains %d bytes of "
2690 "codec specific data", size_left);
2692 g_assert (size_left <= *p_size);
2693 gst_asf_demux_get_buffer (&extradata, size_left, p_data, p_size);
2696 /* asf_stream_audio is the same as gst_riff_strf_auds, but with an
2697 * additional two bytes indicating extradata. */
2698 /* FIXME: Handle the channel reorder map here */
2699 caps = gst_riff_create_audio_caps (audio->codec_tag, NULL,
2700 (gst_riff_strf_auds *) audio, extradata, NULL, &codec_name, NULL);
2703 caps = gst_caps_new_simple ("audio/x-asf-unknown", "codec_id",
2704 G_TYPE_INT, (gint) audio->codec_tag, NULL);
2707 /* Informing about that audio format we just added */
2709 tags = gst_tag_list_new (GST_TAG_AUDIO_CODEC, codec_name, NULL);
2710 g_free (codec_name);
2713 if (audio->byte_rate > 0) {
2714 /* Some ASF files have no bitrate props object (often seen with
2715 * ASF files that contain raw audio data). Example files can
2716 * be generated with FFmpeg (tested with v2.8.6), like this:
2718 * ffmpeg -i sine-wave.wav -c:a pcm_alaw file.asf
2720 * In this case, if audio->byte_rate is nonzero, use that as
2723 guint bitrate = audio->byte_rate * 8;
2726 tags = gst_tag_list_new_empty ();
2728 /* Add bitrate, but only if there is none set already, since
2729 * this is just a fallback in case there is no bitrate tag
2730 * already present */
2731 gst_tag_list_add (tags, GST_TAG_MERGE_KEEP, GST_TAG_BITRATE, bitrate, NULL);
2735 gst_buffer_unref (extradata);
2737 GST_INFO ("Adding audio stream #%u, id %u codec %u (0x%04x), tags=%"
2738 GST_PTR_FORMAT, demux->num_audio_streams, id, audio->codec_tag,
2739 audio->codec_tag, tags);
2741 ++demux->num_audio_streams;
2743 #ifdef TIZEN_FEATURE_ASFDEMUX_POST_TAG_MSG
2745 /* post now, send event on pad later */
2746 gst_element_post_message (GST_ELEMENT_CAST (demux),
2747 gst_message_new_tag (GST_OBJECT_CAST (demux), gst_tag_list_copy (tags)));
2751 return gst_asf_demux_setup_pad (demux, src_pad, caps, id, FALSE, NULL, tags);
2755 gst_asf_demux_add_video_stream (GstASFDemux * demux,
2756 asf_stream_video_format * video, guint16 id,
2757 guint8 ** p_data, guint64 * p_size)
2759 GstTagList *tags = NULL;
2760 GstStructure *caps_s;
2761 GstBuffer *extradata = NULL;
2766 gchar *codec_name = NULL;
2767 guint64 size_left = video->size - 40;
2768 GstBuffer *streamheader = NULL;
2769 guint par_w = 1, par_h = 1;
2771 /* Create the video pad */
2772 name = g_strdup_printf ("video_%u", demux->num_video_streams);
2773 src_pad = gst_pad_new_from_static_template (&video_src_template, name);
2776 /* Now try some gstreamer formatted MIME types (from gst_avi_demux_strf_vids) */
2778 GST_LOG ("Video header has %" G_GUINT64_FORMAT
2779 " bytes of codec specific data (vs %" G_GUINT64_FORMAT ")", size_left,
2781 g_assert (size_left <= *p_size);
2782 gst_asf_demux_get_buffer (&extradata, size_left, p_data, p_size);
2785 GST_DEBUG ("video codec %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (video->tag));
2787 /* yes, asf_stream_video_format and gst_riff_strf_vids are the same */
2788 caps = gst_riff_create_video_caps (video->tag, NULL,
2789 (gst_riff_strf_vids *) video, extradata, NULL, &codec_name);
2792 caps = gst_caps_new_simple ("video/x-asf-unknown", "fourcc",
2793 G_TYPE_UINT, video->tag, NULL);
2798 s = gst_asf_demux_get_metadata_for_stream (demux, id);
2799 if (gst_structure_get_int (s, "AspectRatioX", &ax) &&
2800 gst_structure_get_int (s, "AspectRatioY", &ay) && (ax > 0 && ay > 0)) {
2803 gst_caps_set_simple (caps, "pixel-aspect-ratio", GST_TYPE_FRACTION,
2807 /* retry with the global metadata */
2808 GST_DEBUG ("Retrying with global metadata %" GST_PTR_FORMAT,
2809 demux->global_metadata);
2810 s = demux->global_metadata;
2811 if (gst_structure_get_uint (s, "AspectRatioX", &ax) &&
2812 gst_structure_get_uint (s, "AspectRatioY", &ay)) {
2813 GST_DEBUG ("ax:%d, ay:%d", ax, ay);
2814 if (ax > 0 && ay > 0) {
2817 gst_caps_set_simple (caps, "pixel-aspect-ratio", GST_TYPE_FRACTION,
2822 s = gst_caps_get_structure (caps, 0);
2823 gst_structure_remove_field (s, "framerate");
2826 caps_s = gst_caps_get_structure (caps, 0);
2828 /* add format field with fourcc to WMV/VC1 caps to differentiate variants */
2829 if (gst_structure_has_name (caps_s, "video/x-wmv")) {
2830 str = g_strdup_printf ("%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (video->tag));
2831 gst_caps_set_simple (caps, "format", G_TYPE_STRING, str, NULL);
2834 /* check if h264 has codec_data (avc) or streamheaders (bytestream) */
2835 } else if (gst_structure_has_name (caps_s, "video/x-h264")) {
2836 const GValue *value = gst_structure_get_value (caps_s, "codec_data");
2838 GstBuffer *buf = gst_value_get_buffer (value);
2841 if (gst_buffer_map (buf, &mapinfo, GST_MAP_READ)) {
2842 if (mapinfo.size >= 4 && GST_READ_UINT32_BE (mapinfo.data) == 1) {
2843 /* this looks like a bytestream start */
2844 streamheader = gst_buffer_ref (buf);
2845 gst_asf_demux_add_stream_headers_to_caps (demux, buf, caps_s);
2846 gst_structure_remove_field (caps_s, "codec_data");
2847 gst_structure_set (caps_s, "stream-format", G_TYPE_STRING,
2848 "byte-stream", NULL);
2850 gst_structure_set (caps_s, "stream-format", G_TYPE_STRING, "avc",
2854 gst_buffer_unmap (buf, &mapinfo);
2857 gst_structure_set (caps_s, "stream-format", G_TYPE_STRING, "byte-stream",
2862 /* For a 3D video, set multiview information into the caps based on
2863 * what was detected during object parsing */
2864 if (demux->asf_3D_mode != GST_ASF_3D_NONE) {
2865 GstVideoMultiviewMode mv_mode = GST_VIDEO_MULTIVIEW_MODE_NONE;
2866 GstVideoMultiviewFlags mv_flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
2867 const gchar *mview_mode_str;
2869 switch (demux->asf_3D_mode) {
2870 case GST_ASF_3D_SIDE_BY_SIDE_HALF_LR:
2871 mv_mode = GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE;
2873 case GST_ASF_3D_SIDE_BY_SIDE_HALF_RL:
2874 mv_mode = GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE;
2875 mv_flags = GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST;
2877 case GST_ASF_3D_TOP_AND_BOTTOM_HALF_LR:
2878 mv_mode = GST_VIDEO_MULTIVIEW_MODE_TOP_BOTTOM;
2880 case GST_ASF_3D_TOP_AND_BOTTOM_HALF_RL:
2881 mv_mode = GST_VIDEO_MULTIVIEW_MODE_TOP_BOTTOM;
2882 mv_flags = GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST;
2884 case GST_ASF_3D_DUAL_STREAM:{
2885 gboolean is_right_view = FALSE;
2886 /* if Advanced_Mutual_Exclusion object exists, use it
2887 * to figure out which is the left view (lower ID) */
2888 if (demux->mut_ex_streams != NULL) {
2892 length = g_slist_length (demux->mut_ex_streams);
2894 for (i = 0; i < length; i++) {
2897 v_s_id = g_slist_nth_data (demux->mut_ex_streams, i);
2899 GST_DEBUG_OBJECT (demux,
2900 "has Mutual_Exclusion object. stream id in object is %d",
2901 GPOINTER_TO_INT (v_s_id));
2903 if (id > GPOINTER_TO_INT (v_s_id))
2904 is_right_view = TRUE;
2907 /* if the Advaced_Mutual_Exclusion object doesn't exist, assume the
2908 * first video stream encountered has the lower ID */
2909 if (demux->num_video_streams > 0) {
2910 /* This is not the first video stream, assuming right eye view */
2911 is_right_view = TRUE;
2915 mv_mode = GST_VIDEO_MULTIVIEW_MODE_RIGHT;
2917 mv_mode = GST_VIDEO_MULTIVIEW_MODE_LEFT;
2924 GST_INFO_OBJECT (demux,
2925 "stream_id %d, has multiview-mode %d flags 0x%x", id, mv_mode,
2928 mview_mode_str = gst_video_multiview_mode_to_caps_string (mv_mode);
2929 if (mview_mode_str != NULL) {
2930 if (gst_video_multiview_guess_half_aspect (mv_mode, video->width,
2931 video->height, par_w, par_h))
2932 mv_flags |= GST_VIDEO_MULTIVIEW_FLAGS_HALF_ASPECT;
2934 gst_caps_set_simple (caps,
2935 "multiview-mode", G_TYPE_STRING, mview_mode_str,
2936 "multiview-flags", GST_TYPE_VIDEO_MULTIVIEW_FLAGSET, mv_flags,
2937 GST_FLAG_SET_MASK_EXACT, NULL);
2942 tags = gst_tag_list_new (GST_TAG_VIDEO_CODEC, codec_name, NULL);
2943 g_free (codec_name);
2947 gst_buffer_unref (extradata);
2949 GST_INFO ("Adding video stream #%u, id %u, codec %"
2950 GST_FOURCC_FORMAT " (0x%08x)", demux->num_video_streams, id,
2951 GST_FOURCC_ARGS (video->tag), video->tag);
2953 ++demux->num_video_streams;
2955 #ifdef TIZEN_FEATURE_ASFDEMUX_POST_TAG_MSG
2957 /* post now, send event on pad later */
2958 gst_element_post_message (GST_ELEMENT_CAST (demux),
2959 gst_message_new_tag (GST_OBJECT_CAST (demux), gst_tag_list_copy (tags)));
2963 return gst_asf_demux_setup_pad (demux, src_pad, caps, id, TRUE,
2964 streamheader, tags);
2968 gst_asf_demux_activate_stream (GstASFDemux * demux, AsfStream * stream)
2970 if (!stream->active) {
2974 GST_INFO_OBJECT (demux, "Activating stream %2u, pad %s, caps %"
2975 GST_PTR_FORMAT, stream->id, GST_PAD_NAME (stream->pad), stream->caps);
2976 gst_pad_set_active (stream->pad, TRUE);
2979 gst_pad_create_stream_id_printf (stream->pad, GST_ELEMENT_CAST (demux),
2980 "%03u", stream->id);
2983 gst_pad_get_sticky_event (demux->sinkpad, GST_EVENT_STREAM_START, 0);
2985 if (gst_event_parse_group_id (event, &demux->group_id))
2986 demux->have_group_id = TRUE;
2988 demux->have_group_id = FALSE;
2989 gst_event_unref (event);
2990 } else if (!demux->have_group_id) {
2991 demux->have_group_id = TRUE;
2992 demux->group_id = gst_util_group_id_next ();
2995 event = gst_event_new_stream_start (stream_id);
2996 if (demux->have_group_id)
2997 gst_event_set_group_id (event, demux->group_id);
2999 gst_pad_push_event (stream->pad, event);
3001 gst_pad_set_caps (stream->pad, stream->caps);
3003 gst_element_add_pad (GST_ELEMENT_CAST (demux), stream->pad);
3004 gst_flow_combiner_add_pad (demux->flowcombiner, stream->pad);
3005 stream->active = TRUE;
3010 gst_asf_demux_parse_stream_object (GstASFDemux * demux, guint8 * data,
3013 AsfCorrectionType correction_type;
3014 AsfStreamType stream_type;
3015 GstClockTime time_offset;
3016 gboolean is_encrypted G_GNUC_UNUSED;
3020 guint stream_specific_size;
3021 guint type_specific_size G_GNUC_UNUSED;
3022 guint unknown G_GNUC_UNUSED;
3023 gboolean inspect_payload = FALSE;
3024 AsfStream *stream = NULL;
3026 /* Get the rest of the header's header */
3027 if (size < (16 + 16 + 8 + 4 + 4 + 2 + 4))
3028 goto not_enough_data;
3030 gst_asf_demux_get_guid (&guid, &data, &size);
3031 stream_type = gst_asf_demux_identify_guid (asf_stream_guids, &guid);
3033 gst_asf_demux_get_guid (&guid, &data, &size);
3034 correction_type = gst_asf_demux_identify_guid (asf_correction_guids, &guid);
3036 time_offset = gst_asf_demux_get_uint64 (&data, &size) * 100;
3038 type_specific_size = gst_asf_demux_get_uint32 (&data, &size);
3039 stream_specific_size = gst_asf_demux_get_uint32 (&data, &size);
3041 flags = gst_asf_demux_get_uint16 (&data, &size);
3042 stream_id = flags & 0x7f;
3043 is_encrypted = ! !(flags & 0x8000);
3044 unknown = gst_asf_demux_get_uint32 (&data, &size);
3046 GST_DEBUG_OBJECT (demux, "Found stream %u, time_offset=%" GST_TIME_FORMAT,
3047 stream_id, GST_TIME_ARGS (time_offset));
3049 /* dvr-ms has audio stream declared in stream specific data */
3050 if (stream_type == ASF_STREAM_EXT_EMBED_HEADER) {
3051 AsfExtStreamType ext_stream_type;
3052 gst_asf_demux_get_guid (&guid, &data, &size);
3053 ext_stream_type = gst_asf_demux_identify_guid (asf_ext_stream_guids, &guid);
3055 if (ext_stream_type == ASF_EXT_STREAM_AUDIO) {
3056 inspect_payload = TRUE;
3058 gst_asf_demux_get_guid (&guid, &data, &size);
3059 gst_asf_demux_get_uint32 (&data, &size);
3060 gst_asf_demux_get_uint32 (&data, &size);
3061 gst_asf_demux_get_uint32 (&data, &size);
3062 gst_asf_demux_get_guid (&guid, &data, &size);
3063 gst_asf_demux_get_uint32 (&data, &size);
3064 stream_type = ASF_STREAM_AUDIO;
3068 switch (stream_type) {
3069 case ASF_STREAM_AUDIO:{
3070 asf_stream_audio audio_object;
3072 if (!gst_asf_demux_get_stream_audio (&audio_object, &data, &size))
3073 goto not_enough_data;
3075 GST_INFO ("Object is an audio stream with %u bytes of additional data",
3078 stream = gst_asf_demux_add_audio_stream (demux, &audio_object, stream_id,
3081 switch (correction_type) {
3082 case ASF_CORRECTION_ON:{
3083 guint span, packet_size, chunk_size, data_size, silence_data;
3085 GST_INFO ("Using error correction");
3087 if (size < (1 + 2 + 2 + 2 + 1))
3088 goto not_enough_data;
3090 span = gst_asf_demux_get_uint8 (&data, &size);
3091 packet_size = gst_asf_demux_get_uint16 (&data, &size);
3092 chunk_size = gst_asf_demux_get_uint16 (&data, &size);
3093 data_size = gst_asf_demux_get_uint16 (&data, &size);
3094 silence_data = gst_asf_demux_get_uint8 (&data, &size);
3096 stream->span = span;
3098 GST_DEBUG_OBJECT (demux, "Descrambling ps:%u cs:%u ds:%u s:%u sd:%u",
3099 packet_size, chunk_size, data_size, span, silence_data);
3101 if (stream->span > 1) {
3102 if (chunk_size == 0 || ((packet_size / chunk_size) <= 1)) {
3103 /* Disable descrambling */
3106 /* FIXME: this else branch was added for
3107 * weird_al_yankovic - the saga begins.asf */
3108 stream->ds_packet_size = packet_size;
3109 stream->ds_chunk_size = chunk_size;
3112 /* Descambling is enabled */
3113 stream->ds_packet_size = packet_size;
3114 stream->ds_chunk_size = chunk_size;
3117 /* Now skip the rest of the silence data */
3119 gst_bytestream_flush (demux->bs, data_size - 1);
3121 /* FIXME: CHECKME. And why -1? */
3122 if (data_size > 1) {
3123 if (!gst_asf_demux_skip_bytes (data_size - 1, &data, &size)) {
3124 goto not_enough_data;
3130 case ASF_CORRECTION_OFF:{
3131 GST_INFO ("Error correction off");
3132 if (!gst_asf_demux_skip_bytes (stream_specific_size, &data, &size))
3133 goto not_enough_data;
3137 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3138 ("Audio stream using unknown error correction"));
3145 case ASF_STREAM_VIDEO:{
3146 asf_stream_video_format video_format_object;
3147 asf_stream_video video_object;
3150 if (!gst_asf_demux_get_stream_video (&video_object, &data, &size))
3151 goto not_enough_data;
3153 vsize = video_object.size - 40; /* Byte order gets offset by single byte */
3155 GST_INFO ("object is a video stream with %u bytes of "
3156 "additional data", vsize);
3158 if (!gst_asf_demux_get_stream_video_format (&video_format_object,
3160 goto not_enough_data;
3162 #ifdef TIZEN_FEATURE_ASFDEMUX_DISABLE_UNSUPPORTED_FORMAT
3163 /* Compare video format WMV*, WVC* */
3164 if (((video_format_object.tag & 0x00ffffff) == (guint32)(('W')|('M')<<8|('V')<<16))
3165 || ((video_format_object.tag & 0x00ffffff) == (guint32)(('W')|('V')<<8|('C')<<16))) {
3166 GST_ERROR_OBJECT (demux, "WMV file format is not supported.");
3167 demux->is_supported_format = FALSE;
3171 stream = gst_asf_demux_add_video_stream (demux, &video_format_object,
3172 stream_id, &data, &size);
3178 GST_WARNING_OBJECT (demux, "Unknown stream type for stream %u",
3180 demux->other_streams =
3181 g_slist_append (demux->other_streams, GINT_TO_POINTER (stream_id));
3186 stream->inspect_payload = inspect_payload;
3187 stream->type = stream_type;
3193 GST_WARNING_OBJECT (demux, "Unexpected end of data parsing stream object");
3194 /* we'll error out later if we found no streams */
3199 static const gchar *
3200 gst_asf_demux_get_gst_tag_from_tag_name (const gchar * name_utf8)
3204 const gchar *asf_name;
3205 const gchar *gst_name;
3208 "WM/Genre", GST_TAG_GENRE}, {
3209 "WM/AlbumTitle", GST_TAG_ALBUM}, {
3210 "WM/AlbumArtist", GST_TAG_ARTIST}, {
3211 "WM/Picture", GST_TAG_IMAGE}, {
3212 "WM/Track", GST_TAG_TRACK_NUMBER}, {
3213 "WM/TrackNumber", GST_TAG_TRACK_NUMBER}, {
3214 "WM/Year", GST_TAG_DATE_TIME}
3215 /* { "WM/Composer", GST_TAG_COMPOSER } */
3220 if (name_utf8 == NULL) {
3221 GST_WARNING ("Failed to convert name to UTF8, skipping");
3225 out = strlen (name_utf8);
3227 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
3228 if (strncmp (tags[i].asf_name, name_utf8, out) == 0) {
3229 GST_LOG ("map tagname '%s' -> '%s'", name_utf8, tags[i].gst_name);
3230 return tags[i].gst_name;
3237 /* gst_asf_demux_add_global_tags() takes ownership of taglist! */
3239 gst_asf_demux_add_global_tags (GstASFDemux * demux, GstTagList * taglist)
3243 GST_DEBUG_OBJECT (demux, "adding global tags: %" GST_PTR_FORMAT, taglist);
3245 if (taglist == NULL)
3248 if (gst_tag_list_is_empty (taglist)) {
3249 gst_tag_list_unref (taglist);
3253 t = gst_tag_list_merge (demux->taglist, taglist, GST_TAG_MERGE_APPEND);
3254 gst_tag_list_set_scope (t, GST_TAG_SCOPE_GLOBAL);
3256 gst_tag_list_unref (demux->taglist);
3257 gst_tag_list_unref (taglist);
3259 GST_LOG_OBJECT (demux, "global tags now: %" GST_PTR_FORMAT, demux->taglist);
3262 #define ASF_DEMUX_DATA_TYPE_UTF16LE_STRING 0
3263 #define ASF_DEMUX_DATA_TYPE_BYTE_ARRAY 1
3264 #define ASF_DEMUX_DATA_TYPE_BOOL 2
3265 #define ASF_DEMUX_DATA_TYPE_DWORD 3
3268 asf_demux_parse_picture_tag (GstTagList * tags, const guint8 * tag_data,
3272 const guint8 *img_data = NULL;
3273 guint32 img_data_len = 0;
3274 guint8 pic_type = 0;
3276 gst_byte_reader_init (&r, tag_data, tag_data_len);
3278 /* skip mime type string (we don't trust it and do our own typefinding),
3279 * and also skip the description string, since we don't use it */
3280 if (!gst_byte_reader_get_uint8 (&r, &pic_type) ||
3281 !gst_byte_reader_get_uint32_le (&r, &img_data_len) ||
3282 !gst_byte_reader_skip_string_utf16 (&r) ||
3283 !gst_byte_reader_skip_string_utf16 (&r) ||
3284 !gst_byte_reader_get_data (&r, img_data_len, &img_data)) {
3285 goto not_enough_data;
3289 if (!gst_tag_list_add_id3_image (tags, img_data, img_data_len, pic_type))
3290 GST_DEBUG ("failed to add image extracted from WM/Picture tag to taglist");
3296 GST_DEBUG ("Failed to read WM/Picture tag: not enough data");
3297 GST_MEMDUMP ("WM/Picture data", tag_data, tag_data_len);
3302 /* Extended Content Description Object */
3303 static GstFlowReturn
3304 gst_asf_demux_process_ext_content_desc (GstASFDemux * demux, guint8 * data,
3307 /* Other known (and unused) 'text/unicode' metadata available :
3310 * WM/MediaPrimaryClassID = {D1607DBC-E323-4BE2-86A1-48A42A28441E}
3311 * WMFSDKVersion = 9.00.00.2980
3312 * WMFSDKNeeded = 0.0.0.0000
3313 * WM/UniqueFileIdentifier = AMGa_id=R 15334;AMGp_id=P 5149;AMGt_id=T 2324984
3314 * WM/Publisher = 4AD
3316 * WM/ProviderRating = 8
3317 * WM/ProviderStyle = Rock (similar to WM/Genre)
3318 * WM/GenreID (similar to WM/Genre)
3319 * WM/TrackNumber (same as WM/Track but as a string)
3321 * Other known (and unused) 'non-text' metadata available :
3327 * We might want to read WM/TrackNumber and use atoi() if we don't have
3331 GstTagList *taglist;
3332 guint16 blockcount, i;
3333 gboolean content3D = FALSE;
3337 const gchar *interleave_name;
3338 GstASF3DMode interleaving_type;
3339 } stereoscopic_layout_map[] = {
3341 "SideBySideRF", GST_ASF_3D_SIDE_BY_SIDE_HALF_RL}, {
3342 "SideBySideLF", GST_ASF_3D_SIDE_BY_SIDE_HALF_LR}, {
3343 "OverUnderRT", GST_ASF_3D_TOP_AND_BOTTOM_HALF_RL}, {
3344 "OverUnderLT", GST_ASF_3D_TOP_AND_BOTTOM_HALF_LR}, {
3345 "DualStream", GST_ASF_3D_DUAL_STREAM}
3347 GST_INFO_OBJECT (demux, "object is an extended content description");
3349 taglist = gst_tag_list_new_empty ();
3351 /* Content Descriptor Count */
3353 goto not_enough_data;
3355 blockcount = gst_asf_demux_get_uint16 (&data, &size);
3357 for (i = 1; i <= blockcount; ++i) {
3358 const gchar *gst_tag_name;
3362 GValue tag_value = { 0, };
3365 gchar *name_utf8 = NULL;
3369 if (!gst_asf_demux_get_string (&name, &name_len, &data, &size))
3370 goto not_enough_data;
3374 goto not_enough_data;
3376 /* Descriptor Value Data Type */
3377 datatype = gst_asf_demux_get_uint16 (&data, &size);
3379 /* Descriptor Value (not really a string, but same thing reading-wise) */
3380 if (!gst_asf_demux_get_string (&value, &value_len, &data, &size)) {
3382 goto not_enough_data;
3386 g_convert (name, name_len, "UTF-8", "UTF-16LE", &in, &out, NULL);
3388 if (name_utf8 != NULL) {
3389 GST_DEBUG ("Found tag/metadata %s", name_utf8);
3391 gst_tag_name = gst_asf_demux_get_gst_tag_from_tag_name (name_utf8);
3392 GST_DEBUG ("gst_tag_name %s", GST_STR_NULL (gst_tag_name));
3395 case ASF_DEMUX_DATA_TYPE_UTF16LE_STRING:{
3398 value_utf8 = g_convert (value, value_len, "UTF-8", "UTF-16LE",
3401 /* get rid of tags with empty value */
3402 if (value_utf8 != NULL && *value_utf8 != '\0') {
3403 GST_DEBUG ("string value %s", value_utf8);
3405 value_utf8[out] = '\0';
3407 if (gst_tag_name != NULL) {
3408 if (strcmp (gst_tag_name, GST_TAG_DATE_TIME) == 0) {
3409 guint year = atoi (value_utf8);
3412 g_value_init (&tag_value, GST_TYPE_DATE_TIME);
3413 g_value_take_boxed (&tag_value, gst_date_time_new_y (year));
3415 } else if (strcmp (gst_tag_name, GST_TAG_GENRE) == 0) {
3416 guint id3v1_genre_id;
3417 const gchar *genre_str;
3419 if (sscanf (value_utf8, "(%u)", &id3v1_genre_id) == 1 &&
3420 ((genre_str = gst_tag_id3_genre_get (id3v1_genre_id)))) {
3421 GST_DEBUG ("Genre: %s -> %s", value_utf8, genre_str);
3422 g_free (value_utf8);
3423 value_utf8 = g_strdup (genre_str);
3428 /* convert tag from string to other type if required */
3429 tag_type = gst_tag_get_type (gst_tag_name);
3430 g_value_init (&tag_value, tag_type);
3431 if (!gst_value_deserialize (&tag_value, value_utf8)) {
3432 GValue from_val = { 0, };
3434 g_value_init (&from_val, G_TYPE_STRING);
3435 g_value_set_string (&from_val, value_utf8);
3436 if (!g_value_transform (&from_val, &tag_value)) {
3437 GST_WARNING_OBJECT (demux,
3438 "Could not transform string tag to " "%s tag type %s",
3439 gst_tag_name, g_type_name (tag_type));
3440 g_value_unset (&tag_value);
3442 g_value_unset (&from_val);
3447 GST_DEBUG ("Setting metadata");
3448 g_value_init (&tag_value, G_TYPE_STRING);
3449 g_value_set_string (&tag_value, value_utf8);
3450 /* If we found a stereoscopic marker, look for StereoscopicLayout
3454 if (strncmp ("StereoscopicLayout", name_utf8,
3455 strlen (name_utf8)) == 0) {
3456 for (i = 0; i < G_N_ELEMENTS (stereoscopic_layout_map); i++) {
3457 if (g_str_equal (stereoscopic_layout_map[i].interleave_name,
3459 demux->asf_3D_mode =
3460 stereoscopic_layout_map[i].interleaving_type;
3461 GST_INFO ("find interleave type %u", demux->asf_3D_mode);
3465 GST_INFO_OBJECT (demux, "3d type is %u", demux->asf_3D_mode);
3467 demux->asf_3D_mode = GST_ASF_3D_NONE;
3468 GST_INFO_OBJECT (demux, "None 3d type");
3471 } else if (value_utf8 == NULL) {
3472 GST_WARNING ("Failed to convert string value to UTF8, skipping");
3474 GST_DEBUG ("Skipping empty string value for %s",
3475 GST_STR_NULL (gst_tag_name));
3477 g_free (value_utf8);
3480 case ASF_DEMUX_DATA_TYPE_BYTE_ARRAY:{
3482 if (!g_str_equal (gst_tag_name, GST_TAG_IMAGE)) {
3483 GST_FIXME ("Unhandled byte array tag %s",
3484 GST_STR_NULL (gst_tag_name));
3487 asf_demux_parse_picture_tag (taglist, (guint8 *) value,
3493 case ASF_DEMUX_DATA_TYPE_DWORD:{
3499 uint_val = GST_READ_UINT32_LE (value);
3501 /* this is the track number */
3502 g_value_init (&tag_value, G_TYPE_UINT);
3504 /* WM/Track counts from 0 */
3505 if (!strcmp (name_utf8, "WM/Track"))
3508 g_value_set_uint (&tag_value, uint_val);
3512 case ASF_DEMUX_DATA_TYPE_BOOL:{
3518 bool_val = GST_READ_UINT32_LE (value);
3520 if (strncmp ("Stereoscopic", name_utf8, strlen (name_utf8)) == 0) {
3522 GST_INFO_OBJECT (demux, "This is 3D contents");
3525 GST_INFO_OBJECT (demux, "This is not 3D contenst");
3533 GST_DEBUG ("Skipping tag %s of type %d", gst_tag_name, datatype);
3538 if (G_IS_VALUE (&tag_value)) {
3540 GstTagMergeMode merge_mode = GST_TAG_MERGE_APPEND;
3542 /* WM/TrackNumber is more reliable than WM/Track, since the latter
3543 * is supposed to have a 0 base but is often wrongly written to start
3544 * from 1 as well, so prefer WM/TrackNumber when we have it: either
3545 * replace the value added earlier from WM/Track or put it first in
3546 * the list, so that it will get picked up by _get_uint() */
3547 if (strcmp (name_utf8, "WM/TrackNumber") == 0)
3548 merge_mode = GST_TAG_MERGE_REPLACE;
3550 gst_tag_list_add_values (taglist, merge_mode, gst_tag_name,
3553 GST_DEBUG ("Setting global metadata %s", name_utf8);
3554 gst_structure_set_value (demux->global_metadata, name_utf8,
3558 g_value_unset (&tag_value);
3567 gst_asf_demux_add_global_tags (demux, taglist);
3574 GST_WARNING ("Unexpected end of data parsing ext content desc object");
3575 gst_tag_list_unref (taglist);
3576 return GST_FLOW_OK; /* not really fatal */
3580 static GstStructure *
3581 gst_asf_demux_get_metadata_for_stream (GstASFDemux * demux, guint stream_num)
3586 g_snprintf (sname, sizeof (sname), "stream-%u", stream_num);
3588 for (i = 0; i < gst_caps_get_size (demux->metadata); ++i) {
3591 s = gst_caps_get_structure (demux->metadata, i);
3592 if (gst_structure_has_name (s, sname))
3596 gst_caps_append_structure (demux->metadata, gst_structure_new_empty (sname));
3598 /* try lookup again; demux->metadata took ownership of the structure, so we
3599 * can't really make any assumptions about what happened to it, so we can't
3600 * just return it directly after appending it */
3601 return gst_asf_demux_get_metadata_for_stream (demux, stream_num);
3604 static GstFlowReturn
3605 gst_asf_demux_process_metadata (GstASFDemux * demux, guint8 * data,
3608 guint16 blockcount, i;
3610 GST_INFO_OBJECT (demux, "object is a metadata object");
3612 /* Content Descriptor Count */
3614 goto not_enough_data;
3616 blockcount = gst_asf_demux_get_uint16 (&data, &size);
3618 for (i = 0; i < blockcount; ++i) {
3620 guint16 stream_num, name_len, data_type, lang_idx G_GNUC_UNUSED;
3621 guint32 data_len, ival;
3624 if (size < (2 + 2 + 2 + 2 + 4))
3625 goto not_enough_data;
3627 lang_idx = gst_asf_demux_get_uint16 (&data, &size);
3628 stream_num = gst_asf_demux_get_uint16 (&data, &size);
3629 name_len = gst_asf_demux_get_uint16 (&data, &size);
3630 data_type = gst_asf_demux_get_uint16 (&data, &size);
3631 data_len = gst_asf_demux_get_uint32 (&data, &size);
3633 if (size < name_len + data_len)
3634 goto not_enough_data;
3636 /* convert name to UTF-8 */
3637 name_utf8 = g_convert ((gchar *) data, name_len, "UTF-8", "UTF-16LE",
3639 gst_asf_demux_skip_bytes (name_len, &data, &size);
3641 if (name_utf8 == NULL) {
3642 GST_WARNING ("Failed to convert value name to UTF8, skipping");
3643 gst_asf_demux_skip_bytes (data_len, &data, &size);
3647 if (data_type != ASF_DEMUX_DATA_TYPE_DWORD) {
3648 gst_asf_demux_skip_bytes (data_len, &data, &size);
3656 goto not_enough_data;
3659 ival = gst_asf_demux_get_uint32 (&data, &size);
3661 /* skip anything else there may be, just in case */
3662 gst_asf_demux_skip_bytes (data_len - 4, &data, &size);
3664 s = gst_asf_demux_get_metadata_for_stream (demux, stream_num);
3665 gst_structure_set (s, name_utf8, G_TYPE_INT, ival, NULL);
3669 GST_INFO_OBJECT (demux, "metadata = %" GST_PTR_FORMAT, demux->metadata);
3675 GST_WARNING ("Unexpected end of data parsing metadata object");
3676 return GST_FLOW_OK; /* not really fatal */
3680 static GstFlowReturn
3681 gst_asf_demux_process_header (GstASFDemux * demux, guint8 * data, guint64 size)
3683 GstFlowReturn ret = GST_FLOW_OK;
3684 guint32 i, num_objects;
3685 guint8 unknown G_GNUC_UNUSED;
3687 /* Get the rest of the header's header */
3688 if (size < (4 + 1 + 1))
3689 goto not_enough_data;
3691 num_objects = gst_asf_demux_get_uint32 (&data, &size);
3692 unknown = gst_asf_demux_get_uint8 (&data, &size);
3693 unknown = gst_asf_demux_get_uint8 (&data, &size);
3695 GST_INFO_OBJECT (demux, "object is a header with %u parts", num_objects);
3696 demux->saw_file_header = FALSE;
3697 /* Loop through the header's objects, processing those */
3698 for (i = 0; i < num_objects; ++i) {
3699 GST_INFO_OBJECT (demux, "reading header part %u", i);
3700 ret = gst_asf_demux_process_object (demux, &data, &size);
3701 if (ret != GST_FLOW_OK) {
3702 GST_WARNING ("process_object returned %s", gst_asf_get_flow_name (ret));
3706 if (!demux->saw_file_header) {
3707 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3708 ("Header does not have mandatory FILE section"));
3709 return GST_FLOW_ERROR;
3716 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3717 ("short read parsing HEADER object"));
3718 return GST_FLOW_ERROR;
3722 static GstFlowReturn
3723 gst_asf_demux_process_file (GstASFDemux * demux, guint8 * data, guint64 size)
3725 guint64 creation_time G_GNUC_UNUSED;
3726 guint64 file_size G_GNUC_UNUSED;
3727 guint64 send_time G_GNUC_UNUSED;
3728 guint64 packets_count, play_time, preroll;
3729 guint32 flags, min_pktsize, max_pktsize, min_bitrate G_GNUC_UNUSED;
3731 if (size < (16 + 8 + 8 + 8 + 8 + 8 + 8 + 4 + 4 + 4 + 4))
3732 goto not_enough_data;
3734 gst_asf_demux_skip_bytes (16, &data, &size); /* skip GUID */
3735 file_size = gst_asf_demux_get_uint64 (&data, &size);
3736 creation_time = gst_asf_demux_get_uint64 (&data, &size);
3737 packets_count = gst_asf_demux_get_uint64 (&data, &size);
3738 play_time = gst_asf_demux_get_uint64 (&data, &size);
3739 send_time = gst_asf_demux_get_uint64 (&data, &size);
3740 preroll = gst_asf_demux_get_uint64 (&data, &size);
3741 flags = gst_asf_demux_get_uint32 (&data, &size);
3742 min_pktsize = gst_asf_demux_get_uint32 (&data, &size);
3743 max_pktsize = gst_asf_demux_get_uint32 (&data, &size);
3744 min_bitrate = gst_asf_demux_get_uint32 (&data, &size);
3746 demux->broadcast = ! !(flags & 0x01);
3747 demux->seekable = ! !(flags & 0x02);
3749 GST_DEBUG_OBJECT (demux, "min_pktsize = %u", min_pktsize);
3750 GST_DEBUG_OBJECT (demux, "flags::broadcast = %d", demux->broadcast);
3751 GST_DEBUG_OBJECT (demux, "flags::seekable = %d", demux->seekable);
3753 if (demux->broadcast) {
3754 /* these fields are invalid if the broadcast flag is set */
3759 if (min_pktsize != max_pktsize)
3760 goto non_fixed_packet_size;
3762 demux->packet_size = max_pktsize;
3764 /* FIXME: do we need send_time as well? what is it? */
3765 if ((play_time * 100) >= (preroll * GST_MSECOND))
3766 demux->play_time = (play_time * 100) - (preroll * GST_MSECOND);
3768 demux->play_time = 0;
3770 demux->preroll = preroll * GST_MSECOND;
3772 /* initial latency */
3773 demux->latency = demux->preroll;
3775 if (demux->play_time == 0)
3776 demux->seekable = FALSE;
3778 GST_DEBUG_OBJECT (demux, "play_time %" GST_TIME_FORMAT,
3779 GST_TIME_ARGS (demux->play_time));
3780 GST_DEBUG_OBJECT (demux, "preroll %" GST_TIME_FORMAT,
3781 GST_TIME_ARGS (demux->preroll));
3783 if (demux->play_time > 0) {
3784 demux->segment.duration = demux->play_time;
3787 GST_INFO ("object is a file with %" G_GUINT64_FORMAT " data packets",
3789 GST_INFO ("preroll = %" G_GUINT64_FORMAT, demux->preroll);
3791 demux->saw_file_header = TRUE;
3796 non_fixed_packet_size:
3798 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3799 ("packet size must be fixed"));
3800 return GST_FLOW_ERROR;
3804 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3805 ("short read parsing FILE object"));
3806 return GST_FLOW_ERROR;
3810 /* Content Description Object */
3811 static GstFlowReturn
3812 gst_asf_demux_process_comment (GstASFDemux * demux, guint8 * data, guint64 size)
3816 const gchar *gst_tag;
3821 GST_TAG_TITLE, 0, NULL}, {
3822 GST_TAG_ARTIST, 0, NULL}, {
3823 GST_TAG_COPYRIGHT, 0, NULL}, {
3824 GST_TAG_DESCRIPTION, 0, NULL}, {
3825 GST_TAG_COMMENT, 0, NULL}
3827 GstTagList *taglist;
3828 GValue value = { 0 };
3832 GST_INFO_OBJECT (demux, "object is a comment");
3834 if (size < (2 + 2 + 2 + 2 + 2))
3835 goto not_enough_data;
3837 tags[0].val_length = gst_asf_demux_get_uint16 (&data, &size);
3838 tags[1].val_length = gst_asf_demux_get_uint16 (&data, &size);
3839 tags[2].val_length = gst_asf_demux_get_uint16 (&data, &size);
3840 tags[3].val_length = gst_asf_demux_get_uint16 (&data, &size);
3841 tags[4].val_length = gst_asf_demux_get_uint16 (&data, &size);
3843 GST_DEBUG_OBJECT (demux, "Comment lengths: title=%d author=%d copyright=%d "
3844 "description=%d rating=%d", tags[0].val_length, tags[1].val_length,
3845 tags[2].val_length, tags[3].val_length, tags[4].val_length);
3847 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
3848 if (size < tags[i].val_length)
3849 goto not_enough_data;
3851 /* might be just '/0', '/0'... */
3852 if (tags[i].val_length > 2 && tags[i].val_length % 2 == 0) {
3853 /* convert to UTF-8 */
3854 tags[i].val_utf8 = g_convert ((gchar *) data, tags[i].val_length,
3855 "UTF-8", "UTF-16LE", &in, &out, NULL);
3857 gst_asf_demux_skip_bytes (tags[i].val_length, &data, &size);
3860 /* parse metadata into taglist */
3861 taglist = gst_tag_list_new_empty ();
3862 g_value_init (&value, G_TYPE_STRING);
3863 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
3864 if (tags[i].val_utf8 && strlen (tags[i].val_utf8) > 0 && tags[i].gst_tag) {
3865 g_value_set_string (&value, tags[i].val_utf8);
3866 gst_tag_list_add_values (taglist, GST_TAG_MERGE_APPEND,
3867 tags[i].gst_tag, &value, NULL);
3870 g_value_unset (&value);
3872 gst_asf_demux_add_global_tags (demux, taglist);
3874 for (i = 0; i < G_N_ELEMENTS (tags); ++i)
3875 g_free (tags[i].val_utf8);
3881 GST_WARNING_OBJECT (demux, "unexpectedly short of data while processing "
3882 "comment tag section %d, skipping comment object", i);
3883 for (i = 0; i < G_N_ELEMENTS (tags); i++)
3884 g_free (tags[i].val_utf8);
3885 return GST_FLOW_OK; /* not really fatal */
3889 static GstFlowReturn
3890 gst_asf_demux_process_bitrate_props_object (GstASFDemux * demux, guint8 * data,
3893 guint16 num_streams, i;
3897 goto not_enough_data;
3899 num_streams = gst_asf_demux_get_uint16 (&data, &size);
3901 GST_INFO ("object is a bitrate properties object with %u streams",
3904 if (size < (num_streams * (2 + 4)))
3905 goto not_enough_data;
3907 for (i = 0; i < num_streams; ++i) {
3911 stream_id = gst_asf_demux_get_uint16 (&data, &size);
3912 bitrate = gst_asf_demux_get_uint32 (&data, &size);
3914 if (stream_id < GST_ASF_DEMUX_NUM_STREAM_IDS) {
3915 GST_DEBUG_OBJECT (demux, "bitrate of stream %u = %u", stream_id, bitrate);
3916 stream = gst_asf_demux_get_stream (demux, stream_id);
3918 if (stream->pending_tags == NULL)
3919 stream->pending_tags = gst_tag_list_new_empty ();
3920 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
3921 GST_TAG_BITRATE, bitrate, NULL);
3923 GST_WARNING_OBJECT (demux, "Stream id %u wasn't found", stream_id);
3926 GST_WARNING ("stream id %u is too large", stream_id);
3934 GST_WARNING_OBJECT (demux, "short read parsing bitrate props object!");
3935 return GST_FLOW_OK; /* not really fatal */
3939 static GstFlowReturn
3940 gst_asf_demux_process_header_ext (GstASFDemux * demux, guint8 * data,
3943 GstFlowReturn ret = GST_FLOW_OK;
3946 /* Get the rest of the header's header */
3947 if (size < (16 + 2 + 4))
3948 goto not_enough_data;
3950 /* skip GUID and two other bytes */
3951 gst_asf_demux_skip_bytes (16 + 2, &data, &size);
3952 hdr_size = gst_asf_demux_get_uint32 (&data, &size);
3954 GST_INFO ("extended header object with a size of %u bytes", (guint) size);
3956 /* FIXME: does data_size include the rest of the header that we have read? */
3957 if (hdr_size > size)
3958 goto not_enough_data;
3960 while (hdr_size > 0) {
3961 ret = gst_asf_demux_process_object (demux, &data, &hdr_size);
3962 if (ret != GST_FLOW_OK)
3970 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3971 ("short read parsing extended header object"));
3972 return GST_FLOW_ERROR;
3976 static GstFlowReturn
3977 gst_asf_demux_process_language_list (GstASFDemux * demux, guint8 * data,
3983 goto not_enough_data;
3985 if (demux->languages) {
3986 GST_WARNING ("More than one LANGUAGE_LIST object in stream");
3987 g_strfreev (demux->languages);
3988 demux->languages = NULL;
3989 demux->num_languages = 0;
3992 demux->num_languages = gst_asf_demux_get_uint16 (&data, &size);
3993 GST_LOG ("%u languages:", demux->num_languages);
3995 demux->languages = g_new0 (gchar *, demux->num_languages + 1);
3996 for (i = 0; i < demux->num_languages; ++i) {
3997 guint8 len, *lang_data = NULL;
4000 goto not_enough_data;
4001 len = gst_asf_demux_get_uint8 (&data, &size);
4002 if (gst_asf_demux_get_bytes (&lang_data, len, &data, &size)) {
4005 utf8 = g_convert ((gchar *) lang_data, len, "UTF-8", "UTF-16LE", NULL,
4008 /* truncate "en-us" etc. to just "en" */
4009 if (utf8 && strlen (utf8) >= 5 && (utf8[2] == '-' || utf8[2] == '_')) {
4012 GST_DEBUG ("[%u] %s", i, GST_STR_NULL (utf8));
4013 demux->languages[i] = utf8;
4016 goto not_enough_data;
4024 GST_WARNING_OBJECT (demux, "short read parsing language list object!");
4025 g_free (demux->languages);
4026 demux->languages = NULL;
4027 demux->num_languages = 0;
4028 return GST_FLOW_OK; /* not fatal */
4032 static GstFlowReturn
4033 gst_asf_demux_process_simple_index (GstASFDemux * demux, guint8 * data,
4036 GstClockTime interval;
4039 if (size < (16 + 8 + 4 + 4))
4040 goto not_enough_data;
4043 gst_asf_demux_skip_bytes (16, &data, &size);
4044 interval = gst_asf_demux_get_uint64 (&data, &size) * (GstClockTime) 100;
4045 gst_asf_demux_skip_bytes (4, &data, &size);
4046 count = gst_asf_demux_get_uint32 (&data, &size);
4048 demux->sidx_interval = interval;
4049 demux->sidx_num_entries = count;
4050 g_free (demux->sidx_entries);
4051 demux->sidx_entries = g_new0 (AsfSimpleIndexEntry, count);
4053 for (i = 0; i < count; ++i) {
4054 if (G_UNLIKELY (size < 6)) {
4055 /* adjust for broken files, to avoid having entries at the end
4056 * of the parsed index that point to time=0. Resulting in seeking to
4057 * the end of the file leading back to the beginning */
4058 demux->sidx_num_entries -= (count - i);
4061 demux->sidx_entries[i].packet = gst_asf_demux_get_uint32 (&data, &size);
4062 demux->sidx_entries[i].count = gst_asf_demux_get_uint16 (&data, &size);
4063 GST_LOG_OBJECT (demux, "%" GST_TIME_FORMAT " = packet %4u count : %2d",
4064 GST_TIME_ARGS (i * interval), demux->sidx_entries[i].packet,
4065 demux->sidx_entries[i].count);
4068 GST_DEBUG_OBJECT (demux, "simple index object with 0 entries");
4075 GST_WARNING_OBJECT (demux, "short read parsing simple index object!");
4076 return GST_FLOW_OK; /* not fatal */
4080 static GstFlowReturn
4081 gst_asf_demux_process_advanced_mutual_exclusion (GstASFDemux * demux,
4082 guint8 * data, guint64 size)
4087 if (size < 16 + 2 + (2 * 2))
4088 goto not_enough_data;
4090 gst_asf_demux_get_guid (&guid, &data, &size);
4091 num = gst_asf_demux_get_uint16 (&data, &size);
4094 GST_WARNING_OBJECT (demux, "nonsensical mutually exclusive streams count");
4098 if (size < (num * sizeof (guint16)))
4099 goto not_enough_data;
4101 /* read mutually exclusive stream numbers */
4102 for (i = 0; i < num; ++i) {
4104 mes = gst_asf_demux_get_uint16 (&data, &size) & 0x7f;
4105 GST_LOG_OBJECT (demux, "mutually exclusive: stream %d", mes);
4107 demux->mut_ex_streams =
4108 g_slist_append (demux->mut_ex_streams, GINT_TO_POINTER (mes));
4117 GST_WARNING_OBJECT (demux, "short read parsing advanced mutual exclusion");
4118 return GST_FLOW_OK; /* not absolutely fatal */
4123 gst_asf_demux_is_unknown_stream (GstASFDemux * demux, guint stream_num)
4125 return g_slist_find (demux->other_streams,
4126 GINT_TO_POINTER (stream_num)) == NULL;
4129 static GstFlowReturn
4130 gst_asf_demux_process_ext_stream_props (GstASFDemux * demux, guint8 * data,
4133 AsfStreamExtProps esp;
4134 AsfStream *stream = NULL;
4135 AsfObject stream_obj;
4136 guint16 stream_name_count;
4137 guint16 num_payload_ext;
4139 guint8 *stream_obj_data = NULL;
4142 guint i, stream_num;
4145 obj_size = (guint) size;
4147 esp.payload_extensions = NULL;
4150 goto not_enough_data;
4153 esp.start_time = gst_asf_demux_get_uint64 (&data, &size) * GST_MSECOND;
4154 esp.end_time = gst_asf_demux_get_uint64 (&data, &size) * GST_MSECOND;
4155 esp.data_bitrate = gst_asf_demux_get_uint32 (&data, &size);
4156 esp.buffer_size = gst_asf_demux_get_uint32 (&data, &size);
4157 esp.intial_buf_fullness = gst_asf_demux_get_uint32 (&data, &size);
4158 esp.data_bitrate2 = gst_asf_demux_get_uint32 (&data, &size);
4159 esp.buffer_size2 = gst_asf_demux_get_uint32 (&data, &size);
4160 esp.intial_buf_fullness2 = gst_asf_demux_get_uint32 (&data, &size);
4161 esp.max_obj_size = gst_asf_demux_get_uint32 (&data, &size);
4162 esp.flags = gst_asf_demux_get_uint32 (&data, &size);
4163 stream_num = gst_asf_demux_get_uint16 (&data, &size);
4164 esp.lang_idx = gst_asf_demux_get_uint16 (&data, &size);
4165 esp.avg_time_per_frame = gst_asf_demux_get_uint64 (&data, &size);
4166 stream_name_count = gst_asf_demux_get_uint16 (&data, &size);
4167 num_payload_ext = gst_asf_demux_get_uint16 (&data, &size);
4169 GST_INFO ("start_time = %" GST_TIME_FORMAT,
4170 GST_TIME_ARGS (esp.start_time));
4171 GST_INFO ("end_time = %" GST_TIME_FORMAT,
4172 GST_TIME_ARGS (esp.end_time));
4173 GST_INFO ("flags = %08x", esp.flags);
4174 GST_INFO ("average time per frame = %" GST_TIME_FORMAT,
4175 GST_TIME_ARGS (esp.avg_time_per_frame * 100));
4176 GST_INFO ("stream number = %u", stream_num);
4177 GST_INFO ("stream language ID idx = %u (%s)", esp.lang_idx,
4178 (esp.lang_idx < demux->num_languages) ?
4179 GST_STR_NULL (demux->languages[esp.lang_idx]) : "??");
4180 GST_INFO ("stream name count = %u", stream_name_count);
4182 /* read stream names */
4183 for (i = 0; i < stream_name_count; ++i) {
4184 guint16 stream_lang_idx G_GNUC_UNUSED;
4185 gchar *stream_name = NULL;
4188 goto not_enough_data;
4189 stream_lang_idx = gst_asf_demux_get_uint16 (&data, &size);
4190 if (!gst_asf_demux_get_string (&stream_name, NULL, &data, &size))
4191 goto not_enough_data;
4192 GST_INFO ("stream name %d: %s", i, GST_STR_NULL (stream_name));
4193 g_free (stream_name); /* TODO: store names in struct */
4196 /* read payload extension systems stuff */
4197 GST_LOG ("payload extension systems count = %u", num_payload_ext);
4199 if (num_payload_ext > 0)
4200 esp.payload_extensions = g_new0 (AsfPayloadExtension, num_payload_ext + 1);
4202 for (i = 0; i < num_payload_ext; ++i) {
4203 AsfPayloadExtension ext;
4205 guint32 sys_info_len;
4207 if (size < 16 + 2 + 4)
4208 goto not_enough_data;
4210 gst_asf_demux_get_guid (&ext_guid, &data, &size);
4211 ext.id = gst_asf_demux_identify_guid (asf_payload_ext_guids, &ext_guid);
4212 ext.len = gst_asf_demux_get_uint16 (&data, &size);
4214 sys_info_len = gst_asf_demux_get_uint32 (&data, &size);
4215 GST_LOG ("payload systems info len = %u", sys_info_len);
4216 if (!gst_asf_demux_skip_bytes (sys_info_len, &data, &size))
4217 goto not_enough_data;
4219 esp.payload_extensions[i] = ext;
4222 GST_LOG ("bytes read: %u/%u", (guint) (data - data_start), obj_size);
4224 /* there might be an optional STREAM_INFO object here now; if not, we
4225 * should have parsed the corresponding stream info object already (since
4226 * we are parsing the extended stream properties objects delayed) */
4228 stream = gst_asf_demux_get_stream (demux, stream_num);
4232 if (size < ASF_OBJECT_HEADER_SIZE)
4233 goto not_enough_data;
4235 /* get size of the stream object */
4236 if (!asf_demux_peek_object (demux, data, size, &stream_obj, TRUE))
4237 goto corrupted_stream;
4239 if (stream_obj.id != ASF_OBJ_STREAM)
4240 goto expected_stream_object;
4242 if (stream_obj.size < ASF_OBJECT_HEADER_SIZE ||
4243 stream_obj.size > (10 * 1024 * 1024))
4244 goto not_enough_data;
4246 gst_asf_demux_skip_bytes (ASF_OBJECT_HEADER_SIZE, &data, &size);
4248 /* process this stream object later after all the other 'normal' ones
4249 * have been processed (since the others are more important/non-hidden) */
4250 len = stream_obj.size - ASF_OBJECT_HEADER_SIZE;
4251 if (!gst_asf_demux_get_bytes (&stream_obj_data, len, &data, &size))
4252 goto not_enough_data;
4254 /* parse stream object */
4255 stream = gst_asf_demux_parse_stream_object (demux, stream_obj_data, len);
4256 g_free (stream_obj_data);
4258 #ifdef TIZEN_FEATURE_ASFDEMUX_DISABLE_UNSUPPORTED_FORMAT
4259 if ((stream == NULL) && (demux->is_supported_format == FALSE)) {
4260 g_free (esp.payload_extensions);
4261 return GST_FLOW_NOT_SUPPORTED;
4268 stream->ext_props = esp;
4270 /* try to set the framerate */
4271 if (stream->is_video && stream->caps) {
4272 GValue framerate = { 0 };
4276 g_value_init (&framerate, GST_TYPE_FRACTION);
4278 num = GST_SECOND / 100;
4279 denom = esp.avg_time_per_frame;
4281 /* avoid division by 0, assume 25/1 framerate */
4282 denom = GST_SECOND / 2500;
4285 gst_value_set_fraction (&framerate, num, denom);
4287 stream->caps = gst_caps_make_writable (stream->caps);
4288 s = gst_caps_get_structure (stream->caps, 0);
4289 gst_structure_set_value (s, "framerate", &framerate);
4290 g_value_unset (&framerate);
4291 GST_DEBUG_OBJECT (demux, "setting framerate of %d/%d = %f",
4292 num, denom, ((gdouble) num) / denom);
4295 /* add language info now if we have it */
4296 if (stream->ext_props.lang_idx < demux->num_languages) {
4297 if (stream->pending_tags == NULL)
4298 stream->pending_tags = gst_tag_list_new_empty ();
4299 GST_LOG_OBJECT (demux, "stream %u has language '%s'", stream->id,
4300 demux->languages[stream->ext_props.lang_idx]);
4301 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_APPEND,
4302 GST_TAG_LANGUAGE_CODE, demux->languages[stream->ext_props.lang_idx],
4305 } else if (gst_asf_demux_is_unknown_stream (demux, stream_num)) {
4306 GST_WARNING_OBJECT (demux, "Ext. stream properties for unknown stream");
4310 g_free (esp.payload_extensions);
4317 GST_WARNING_OBJECT (demux, "short read parsing ext stream props object!");
4318 g_free (esp.payload_extensions);
4319 return GST_FLOW_OK; /* not absolutely fatal */
4321 expected_stream_object:
4323 GST_WARNING_OBJECT (demux, "error parsing extended stream properties "
4324 "object: expected embedded stream object, but got %s object instead!",
4325 gst_asf_get_guid_nick (asf_object_guids, stream_obj.id));
4326 g_free (esp.payload_extensions);
4327 return GST_FLOW_OK; /* not absolutely fatal */
4331 GST_WARNING_OBJECT (demux, "Corrupted stream");
4332 g_free (esp.payload_extensions);
4333 return GST_FLOW_ERROR;
4337 static const gchar *
4338 gst_asf_demux_push_obj (GstASFDemux * demux, guint32 obj_id)
4342 nick = gst_asf_get_guid_nick (asf_object_guids, obj_id);
4343 if (g_str_has_prefix (nick, "ASF_OBJ_"))
4344 nick += strlen ("ASF_OBJ_");
4346 if (demux->objpath == NULL) {
4347 demux->objpath = g_strdup (nick);
4351 newpath = g_strdup_printf ("%s/%s", demux->objpath, nick);
4352 g_free (demux->objpath);
4353 demux->objpath = newpath;
4356 return (const gchar *) demux->objpath;
4360 gst_asf_demux_pop_obj (GstASFDemux * demux)
4364 if ((s = g_strrstr (demux->objpath, "/"))) {
4367 g_free (demux->objpath);
4368 demux->objpath = NULL;
4373 gst_asf_demux_process_queued_extended_stream_objects (GstASFDemux * demux)
4378 /* Parse the queued extended stream property objects and add the info
4379 * to the existing streams or add the new embedded streams, but without
4380 * activating them yet */
4381 GST_LOG_OBJECT (demux, "%u queued extended stream properties objects",
4382 g_slist_length (demux->ext_stream_props));
4384 for (l = demux->ext_stream_props, i = 0; l != NULL; l = l->next, ++i) {
4385 GstBuffer *buf = GST_BUFFER (l->data);
4388 gst_buffer_map (buf, &map, GST_MAP_READ);
4390 GST_LOG_OBJECT (demux, "parsing ext. stream properties object #%u", i);
4391 gst_asf_demux_process_ext_stream_props (demux, map.data, map.size);
4392 gst_buffer_unmap (buf, &map);
4393 gst_buffer_unref (buf);
4395 g_slist_free (demux->ext_stream_props);
4396 demux->ext_stream_props = NULL;
4401 gst_asf_demux_activate_ext_props_streams (GstASFDemux * demux)
4405 for (i = 0; i < demux->num_streams; ++i) {
4410 stream = &demux->stream[i];
4412 GST_LOG_OBJECT (demux, "checking stream %2u", stream->id);
4414 if (stream->active) {
4415 GST_LOG_OBJECT (demux, "stream %2u is already activated", stream->id);
4420 for (x = demux->mut_ex_streams; x != NULL; x = x->next) {
4423 /* check for each mutual exclusion whether it affects this stream */
4424 for (mes = (guint8 *) x->data; mes != NULL && *mes != 0xff; ++mes) {
4425 if (*mes == stream->id) {
4426 /* if yes, check if we've already added streams that are mutually
4427 * exclusive with the stream we're about to add */
4428 for (mes = (guint8 *) x->data; mes != NULL && *mes != 0xff; ++mes) {
4429 for (j = 0; j < demux->num_streams; ++j) {
4430 /* if the broadcast flag is set, assume the hidden streams aren't
4431 * actually streamed and hide them (or playbin won't work right),
4432 * otherwise assume their data is available */
4433 if (demux->stream[j].id == *mes && demux->broadcast) {
4435 GST_LOG_OBJECT (demux, "broadcast stream ID %d to be added is "
4436 "mutually exclusive with already existing stream ID %d, "
4437 "hiding stream", stream->id, demux->stream[j].id);
4449 /* FIXME: we should do stream activation based on preroll data in
4450 * streaming mode too */
4451 if (demux->streaming && !is_hidden)
4452 gst_asf_demux_activate_stream (demux, stream);
4457 static GstFlowReturn
4458 gst_asf_demux_process_object (GstASFDemux * demux, guint8 ** p_data,
4461 GstFlowReturn ret = GST_FLOW_OK;
4463 guint64 obj_data_size;
4465 if (*p_size < ASF_OBJECT_HEADER_SIZE)
4466 return ASF_FLOW_NEED_MORE_DATA;
4468 if (!asf_demux_peek_object (demux, *p_data, ASF_OBJECT_HEADER_SIZE, &obj,
4470 return GST_FLOW_ERROR;
4471 gst_asf_demux_skip_bytes (ASF_OBJECT_HEADER_SIZE, p_data, p_size);
4473 obj_data_size = obj.size - ASF_OBJECT_HEADER_SIZE;
4475 if (*p_size < obj_data_size)
4476 return ASF_FLOW_NEED_MORE_DATA;
4478 gst_asf_demux_push_obj (demux, obj.id);
4480 GST_INFO ("%s: size %" G_GUINT64_FORMAT, demux->objpath, obj.size);
4483 case ASF_OBJ_STREAM:
4484 gst_asf_demux_parse_stream_object (demux, *p_data, obj_data_size);
4485 #ifdef TIZEN_FEATURE_ASFDEMUX_MODIFICATION
4486 if (demux->is_supported_format == FALSE) {
4487 ret = GST_FLOW_NOT_SUPPORTED;
4494 ret = gst_asf_demux_process_file (demux, *p_data, obj_data_size);
4496 case ASF_OBJ_HEADER:
4497 ret = gst_asf_demux_process_header (demux, *p_data, obj_data_size);
4499 case ASF_OBJ_COMMENT:
4500 ret = gst_asf_demux_process_comment (demux, *p_data, obj_data_size);
4503 ret = gst_asf_demux_process_header_ext (demux, *p_data, obj_data_size);
4505 case ASF_OBJ_BITRATE_PROPS:
4507 gst_asf_demux_process_bitrate_props_object (demux, *p_data,
4510 case ASF_OBJ_EXT_CONTENT_DESC:
4512 gst_asf_demux_process_ext_content_desc (demux, *p_data,
4515 case ASF_OBJ_METADATA_OBJECT:
4516 ret = gst_asf_demux_process_metadata (demux, *p_data, obj_data_size);
4518 case ASF_OBJ_EXTENDED_STREAM_PROPS:{
4521 /* process these later, we might not have parsed the corresponding
4522 * stream object yet */
4523 GST_LOG ("%s: queued for later parsing", demux->objpath);
4524 buf = gst_buffer_new_and_alloc (obj_data_size);
4525 gst_buffer_fill (buf, 0, *p_data, obj_data_size);
4526 demux->ext_stream_props = g_slist_append (demux->ext_stream_props, buf);
4530 case ASF_OBJ_LANGUAGE_LIST:
4531 ret = gst_asf_demux_process_language_list (demux, *p_data, obj_data_size);
4533 case ASF_OBJ_ADVANCED_MUTUAL_EXCLUSION:
4534 ret = gst_asf_demux_process_advanced_mutual_exclusion (demux, *p_data,
4537 case ASF_OBJ_SIMPLE_INDEX:
4538 ret = gst_asf_demux_process_simple_index (demux, *p_data, obj_data_size);
4540 case ASF_OBJ_CONTENT_ENCRYPTION:
4541 case ASF_OBJ_EXT_CONTENT_ENCRYPTION:
4542 case ASF_OBJ_DIGITAL_SIGNATURE_OBJECT:
4543 case ASF_OBJ_UNKNOWN_ENCRYPTION_OBJECT:
4544 goto error_encrypted;
4545 case ASF_OBJ_CONCEAL_NONE:
4547 case ASF_OBJ_UNDEFINED:
4548 case ASF_OBJ_CODEC_COMMENT:
4550 case ASF_OBJ_PADDING:
4551 case ASF_OBJ_BITRATE_MUTEX:
4552 case ASF_OBJ_COMPATIBILITY:
4553 case ASF_OBJ_INDEX_PLACEHOLDER:
4554 case ASF_OBJ_INDEX_PARAMETERS:
4555 case ASF_OBJ_STREAM_PRIORITIZATION:
4556 case ASF_OBJ_SCRIPT_COMMAND:
4557 case ASF_OBJ_METADATA_LIBRARY_OBJECT:
4559 /* Unknown/unhandled object, skip it and hope for the best */
4560 GST_INFO ("%s: skipping object", demux->objpath);
4565 /* this can't fail, we checked the number of bytes available before */
4566 gst_asf_demux_skip_bytes (obj_data_size, p_data, p_size);
4568 GST_LOG ("%s: ret = %s", demux->objpath, gst_asf_get_flow_name (ret));
4570 gst_asf_demux_pop_obj (demux);
4577 GST_ELEMENT_ERROR (demux, STREAM, DECRYPT, (NULL), (NULL));
4578 return GST_FLOW_ERROR;
4583 gst_asf_demux_descramble_buffer (GstASFDemux * demux, AsfStream * stream,
4584 GstBuffer ** p_buffer)
4586 GstBuffer *descrambled_buffer;
4587 GstBuffer *scrambled_buffer;
4588 GstBuffer *sub_buffer;
4595 /* descrambled_buffer is initialised in the first iteration */
4596 descrambled_buffer = NULL;
4597 scrambled_buffer = *p_buffer;
4599 if (gst_buffer_get_size (scrambled_buffer) <
4600 stream->ds_packet_size * stream->span)
4603 for (offset = 0; offset < gst_buffer_get_size (scrambled_buffer);
4604 offset += stream->ds_chunk_size) {
4605 off = offset / stream->ds_chunk_size;
4606 row = off / stream->span;
4607 col = off % stream->span;
4608 idx = row + col * stream->ds_packet_size / stream->ds_chunk_size;
4609 GST_DEBUG ("idx=%u, row=%u, col=%u, off=%u, ds_chunk_size=%u", idx, row,
4610 col, off, stream->ds_chunk_size);
4611 GST_DEBUG ("scrambled buffer size=%" G_GSIZE_FORMAT
4612 ", span=%u, packet_size=%u", gst_buffer_get_size (scrambled_buffer),
4613 stream->span, stream->ds_packet_size);
4614 GST_DEBUG ("gst_buffer_get_size (scrambled_buffer) = %" G_GSIZE_FORMAT,
4615 gst_buffer_get_size (scrambled_buffer));
4617 gst_buffer_copy_region (scrambled_buffer, GST_BUFFER_COPY_MEMORY,
4618 idx * stream->ds_chunk_size, stream->ds_chunk_size);
4620 descrambled_buffer = sub_buffer;
4622 descrambled_buffer = gst_buffer_append (descrambled_buffer, sub_buffer);
4626 GST_BUFFER_TIMESTAMP (descrambled_buffer) =
4627 GST_BUFFER_TIMESTAMP (scrambled_buffer);
4628 GST_BUFFER_DURATION (descrambled_buffer) =
4629 GST_BUFFER_DURATION (scrambled_buffer);
4630 GST_BUFFER_OFFSET (descrambled_buffer) = GST_BUFFER_OFFSET (scrambled_buffer);
4631 GST_BUFFER_OFFSET_END (descrambled_buffer) =
4632 GST_BUFFER_OFFSET_END (scrambled_buffer);
4634 /* FIXME/CHECK: do we need to transfer buffer flags here too? */
4636 gst_buffer_unref (scrambled_buffer);
4637 *p_buffer = descrambled_buffer;
4641 gst_asf_demux_element_send_event (GstElement * element, GstEvent * event)
4643 GstASFDemux *demux = GST_ASF_DEMUX (element);
4646 GST_DEBUG ("handling element event of type %s", GST_EVENT_TYPE_NAME (event));
4648 for (i = 0; i < demux->num_streams; ++i) {
4649 gst_event_ref (event);
4650 if (gst_asf_demux_handle_src_event (demux->stream[i].pad,
4651 GST_OBJECT_CAST (element), event)) {
4652 gst_event_unref (event);
4657 gst_event_unref (event);
4661 /* takes ownership of the passed event */
4663 gst_asf_demux_send_event_unlocked (GstASFDemux * demux, GstEvent * event)
4665 gboolean ret = TRUE;
4668 GST_DEBUG_OBJECT (demux, "sending %s event to all source pads",
4669 GST_EVENT_TYPE_NAME (event));
4671 for (i = 0; i < demux->num_streams; ++i) {
4672 gst_event_ref (event);
4673 ret &= gst_pad_push_event (demux->stream[i].pad, event);
4675 gst_event_unref (event);
4680 gst_asf_demux_handle_src_query (GstPad * pad, GstObject * parent,
4684 gboolean res = FALSE;
4686 demux = GST_ASF_DEMUX (parent);
4688 GST_DEBUG ("handling %s query",
4689 gst_query_type_get_name (GST_QUERY_TYPE (query)));
4691 switch (GST_QUERY_TYPE (query)) {
4692 case GST_QUERY_DURATION:
4696 gst_query_parse_duration (query, &format, NULL);
4698 if (format != GST_FORMAT_TIME) {
4699 GST_LOG ("only support duration queries in TIME format");
4703 res = gst_pad_query_default (pad, parent, query);
4705 GST_OBJECT_LOCK (demux);
4707 if (demux->segment.duration != GST_CLOCK_TIME_NONE) {
4708 GST_LOG ("returning duration: %" GST_TIME_FORMAT,
4709 GST_TIME_ARGS (demux->segment.duration));
4711 gst_query_set_duration (query, GST_FORMAT_TIME,
4712 demux->segment.duration);
4716 GST_LOG ("duration not known yet");
4719 GST_OBJECT_UNLOCK (demux);
4724 case GST_QUERY_POSITION:{
4727 gst_query_parse_position (query, &format, NULL);
4729 if (format != GST_FORMAT_TIME) {
4730 GST_LOG ("only support position queries in TIME format");
4734 GST_OBJECT_LOCK (demux);
4736 if (demux->segment.position != GST_CLOCK_TIME_NONE) {
4737 GST_LOG ("returning position: %" GST_TIME_FORMAT,
4738 GST_TIME_ARGS (demux->segment.position));
4740 gst_query_set_position (query, GST_FORMAT_TIME,
4741 demux->segment.position);
4745 GST_LOG ("position not known yet");
4748 GST_OBJECT_UNLOCK (demux);
4752 case GST_QUERY_SEEKING:{
4755 gst_query_parse_seeking (query, &format, NULL, NULL, NULL);
4756 if (format == GST_FORMAT_TIME) {
4759 GST_OBJECT_LOCK (demux);
4760 duration = demux->segment.duration;
4761 GST_OBJECT_UNLOCK (demux);
4763 if (!demux->streaming || !demux->seekable) {
4764 gst_query_set_seeking (query, GST_FORMAT_TIME, demux->seekable, 0,
4771 /* try upstream first in TIME */
4772 res = gst_pad_query_default (pad, parent, query);
4774 gst_query_parse_seeking (query, &fmt, &seekable, NULL, NULL);
4775 GST_LOG_OBJECT (demux, "upstream %s seekable %d",
4776 GST_STR_NULL (gst_format_get_name (fmt)), seekable);
4777 /* if no luck, maybe in BYTES */
4778 if (!seekable || fmt != GST_FORMAT_TIME) {
4781 q = gst_query_new_seeking (GST_FORMAT_BYTES);
4782 if ((res = gst_pad_peer_query (demux->sinkpad, q))) {
4783 gst_query_parse_seeking (q, &fmt, &seekable, NULL, NULL);
4784 GST_LOG_OBJECT (demux, "upstream %s seekable %d",
4785 GST_STR_NULL (gst_format_get_name (fmt)), seekable);
4786 if (fmt != GST_FORMAT_BYTES)
4789 gst_query_unref (q);
4790 gst_query_set_seeking (query, GST_FORMAT_TIME, seekable, 0,
4796 GST_LOG_OBJECT (demux, "only support seeking in TIME format");
4800 case GST_QUERY_LATENCY:
4803 GstClockTime min, max;
4805 /* preroll delay does not matter in non-live pipeline,
4806 * but we might end up in a live (rtsp) one ... */
4809 res = gst_pad_query_default (pad, parent, query);
4813 gst_query_parse_latency (query, &live, &min, &max);
4815 GST_DEBUG_OBJECT (demux, "Peer latency: live %d, min %"
4816 GST_TIME_FORMAT " max %" GST_TIME_FORMAT, live,
4817 GST_TIME_ARGS (min), GST_TIME_ARGS (max));
4819 GST_OBJECT_LOCK (demux);
4820 min += demux->latency;
4822 max += demux->latency;
4823 GST_OBJECT_UNLOCK (demux);
4825 gst_query_set_latency (query, live, min, max);
4828 case GST_QUERY_SEGMENT:
4833 format = demux->segment.format;
4836 gst_segment_to_stream_time (&demux->segment, format,
4837 demux->segment.start);
4838 if ((stop = demux->segment.stop) == -1)
4839 stop = demux->segment.duration;
4841 stop = gst_segment_to_stream_time (&demux->segment, format, stop);
4843 gst_query_set_segment (query, demux->segment.rate, format, start, stop);
4848 res = gst_pad_query_default (pad, parent, query);
4855 static GstStateChangeReturn
4856 gst_asf_demux_change_state (GstElement * element, GstStateChange transition)
4858 GstASFDemux *demux = GST_ASF_DEMUX (element);
4859 GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
4861 switch (transition) {
4862 case GST_STATE_CHANGE_NULL_TO_READY:{
4863 gst_segment_init (&demux->segment, GST_FORMAT_TIME);
4864 demux->need_newsegment = TRUE;
4865 demux->segment_running = FALSE;
4866 demux->keyunit_sync = FALSE;
4867 demux->accurate = FALSE;
4868 demux->adapter = gst_adapter_new ();
4869 demux->metadata = gst_caps_new_empty ();
4870 demux->global_metadata = gst_structure_new_empty ("metadata");
4871 demux->data_size = 0;
4872 demux->data_offset = 0;
4873 demux->index_offset = 0;
4874 demux->base_offset = 0;
4875 demux->flowcombiner = gst_flow_combiner_new ();
4883 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
4884 if (ret == GST_STATE_CHANGE_FAILURE)
4887 switch (transition) {
4888 case GST_STATE_CHANGE_PAUSED_TO_READY:
4889 gst_asf_demux_reset (demux, FALSE);
4892 case GST_STATE_CHANGE_READY_TO_NULL:
4893 gst_asf_demux_reset (demux, FALSE);
4894 gst_flow_combiner_free (demux->flowcombiner);
4895 demux->flowcombiner = NULL;