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 void 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 /* set initial state */
323 gst_asf_demux_reset (demux, FALSE);
327 gst_asf_demux_activate (GstPad * sinkpad, GstObject * parent)
332 query = gst_query_new_scheduling ();
334 if (!gst_pad_peer_query (sinkpad, query)) {
335 gst_query_unref (query);
339 pull_mode = gst_query_has_scheduling_mode_with_flags (query,
340 GST_PAD_MODE_PULL, GST_SCHEDULING_FLAG_SEEKABLE);
341 gst_query_unref (query);
346 GST_DEBUG_OBJECT (sinkpad, "activating pull");
347 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PULL, TRUE);
351 GST_DEBUG_OBJECT (sinkpad, "activating push");
352 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PUSH, TRUE);
357 gst_asf_demux_activate_mode (GstPad * sinkpad, GstObject * parent,
358 GstPadMode mode, gboolean active)
363 demux = GST_ASF_DEMUX (parent);
366 case GST_PAD_MODE_PUSH:
367 demux->state = GST_ASF_DEMUX_STATE_HEADER;
368 demux->streaming = TRUE;
371 case GST_PAD_MODE_PULL:
373 demux->state = GST_ASF_DEMUX_STATE_HEADER;
374 demux->streaming = FALSE;
376 res = gst_pad_start_task (sinkpad, (GstTaskFunction) gst_asf_demux_loop,
379 res = gst_pad_stop_task (sinkpad);
390 gst_asf_demux_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
395 demux = GST_ASF_DEMUX (parent);
397 GST_LOG_OBJECT (demux, "handling %s event", GST_EVENT_TYPE_NAME (event));
398 switch (GST_EVENT_TYPE (event)) {
399 case GST_EVENT_SEGMENT:{
400 const GstSegment *segment;
402 gst_event_parse_segment (event, &segment);
404 if (segment->format == GST_FORMAT_BYTES) {
405 if (demux->packet_size && segment->start > demux->data_offset)
406 demux->packet = (segment->start - demux->data_offset) /
410 } else if (segment->format == GST_FORMAT_TIME) {
411 /* do not know packet position, not really a problem */
414 GST_WARNING_OBJECT (demux, "unsupported newsegment format, ignoring");
415 gst_event_unref (event);
419 /* record upstream segment for interpolation */
420 if (segment->format != demux->in_segment.format)
421 gst_segment_init (&demux->in_segment, GST_FORMAT_UNDEFINED);
422 gst_segment_copy_into (segment, &demux->in_segment);
424 /* in either case, clear some state and generate newsegment later on */
425 GST_OBJECT_LOCK (demux);
426 demux->segment_ts = GST_CLOCK_TIME_NONE;
427 demux->in_gap = GST_CLOCK_TIME_NONE;
428 demux->need_newsegment = TRUE;
429 demux->segment_seqnum = gst_event_get_seqnum (event);
430 gst_asf_demux_reset_stream_state_after_discont (demux);
431 /* if we seek back after reaching EOS, go back to packet reading state */
432 if (demux->data_offset > 0 && segment->start >= demux->data_offset
433 && demux->state == GST_ASF_DEMUX_STATE_INDEX) {
434 demux->state = GST_ASF_DEMUX_STATE_DATA;
436 GST_OBJECT_UNLOCK (demux);
438 gst_event_unref (event);
444 if (demux->state == GST_ASF_DEMUX_STATE_HEADER) {
445 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
446 (_("This stream contains no data.")),
447 ("got eos and didn't receive a complete header object"));
450 flow = gst_asf_demux_push_complete_payloads (demux, TRUE);
451 if (flow < GST_FLOW_EOS || flow == GST_FLOW_NOT_LINKED) {
452 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
453 (_("Internal data stream error.")),
454 ("streaming stopped, reason %s", gst_flow_get_name (flow)));
458 GST_OBJECT_LOCK (demux);
459 gst_adapter_clear (demux->adapter);
460 GST_OBJECT_UNLOCK (demux);
461 gst_asf_demux_send_event_unlocked (demux, event);
465 case GST_EVENT_FLUSH_STOP:
466 GST_OBJECT_LOCK (demux);
467 gst_asf_demux_reset_stream_state_after_discont (demux);
468 GST_OBJECT_UNLOCK (demux);
469 gst_asf_demux_send_event_unlocked (demux, event);
470 /* upon activation, latency is no longer introduced, e.g. after seek */
471 if (demux->activated_streams)
476 ret = gst_pad_event_default (pad, parent, event);
484 gst_asf_demux_seek_index_lookup (GstASFDemux * demux, guint * packet,
485 GstClockTime seek_time, GstClockTime * p_idx_time, guint * speed,
486 gboolean next, gboolean * eos)
488 GstClockTime idx_time;
494 if (G_UNLIKELY (demux->sidx_num_entries == 0 || demux->sidx_interval == 0))
497 idx = (guint) ((seek_time + demux->preroll) / demux->sidx_interval);
500 /* if we want the next keyframe, we have to go forward till we find
501 a different packet number */
503 if (idx >= demux->sidx_num_entries - 1) {
504 /* If we get here, we're asking for next keyframe after the last one. There isn't one. */
509 for (idx2 = idx + 1; idx2 < demux->sidx_num_entries; ++idx2) {
510 if (demux->sidx_entries[idx].packet != demux->sidx_entries[idx2].packet) {
517 if (G_UNLIKELY (idx >= demux->sidx_num_entries)) {
523 *packet = demux->sidx_entries[idx].packet;
525 *speed = demux->sidx_entries[idx].count;
527 /* so we get closer to the actual time of the packet ... actually, let's not
528 * do this, since we throw away superfluous payloads before the seek position
529 * anyway; this way, our key unit seek 'snap resolution' is a bit better
530 * (ie. same as index resolution) */
532 while (idx > 0 && demux->sidx_entries[idx-1] == demux->sidx_entries[idx])
536 idx_time = demux->sidx_interval * idx;
537 if (G_LIKELY (idx_time >= demux->preroll))
538 idx_time -= demux->preroll;
540 GST_DEBUG_OBJECT (demux, "%" GST_TIME_FORMAT " => packet %u at %"
541 GST_TIME_FORMAT, GST_TIME_ARGS (seek_time), *packet,
542 GST_TIME_ARGS (idx_time));
544 if (G_LIKELY (p_idx_time))
545 *p_idx_time = idx_time;
551 gst_asf_demux_reset_stream_state_after_discont (GstASFDemux * demux)
555 gst_adapter_clear (demux->adapter);
557 GST_DEBUG_OBJECT (demux, "reset stream state");
559 gst_flow_combiner_reset (demux->flowcombiner);
560 for (n = 0; n < demux->num_streams; n++) {
561 demux->stream[n].discont = TRUE;
562 demux->stream[n].first_buffer = TRUE;
564 while (demux->stream[n].payloads->len > 0) {
568 last = demux->stream[n].payloads->len - 1;
569 payload = &g_array_index (demux->stream[n].payloads, AsfPayload, last);
570 gst_buffer_replace (&payload->buf, NULL);
571 g_array_remove_index (demux->stream[n].payloads, last);
577 gst_asf_demux_mark_discont (GstASFDemux * demux)
581 GST_DEBUG_OBJECT (demux, "Mark stream discont");
583 for (n = 0; n < demux->num_streams; n++)
584 demux->stream[n].discont = TRUE;
587 /* do a seek in push based mode */
589 gst_asf_demux_handle_seek_push (GstASFDemux * demux, GstEvent * event)
594 GstSeekType cur_type, stop_type;
598 GstEvent *byte_event;
600 gst_event_parse_seek (event, &rate, &format, &flags, &cur_type, &cur,
603 stop_type = GST_SEEK_TYPE_NONE;
606 GST_DEBUG_OBJECT (demux, "seeking to %" GST_TIME_FORMAT, GST_TIME_ARGS (cur));
608 /* determine packet, by index or by estimation */
609 if (!gst_asf_demux_seek_index_lookup (demux, &packet, cur, NULL, NULL, FALSE,
612 (guint) gst_util_uint64_scale (demux->num_packets, cur,
616 if (packet > demux->num_packets) {
617 GST_DEBUG_OBJECT (demux, "could not determine packet to seek to, "
622 GST_DEBUG_OBJECT (demux, "seeking to packet %d", packet);
624 cur = demux->data_offset + ((guint64) packet * demux->packet_size);
626 GST_DEBUG_OBJECT (demux, "Pushing BYTE seek rate %g, "
627 "start %" G_GINT64_FORMAT ", stop %" G_GINT64_FORMAT, rate, cur, stop);
628 /* BYTE seek event */
629 byte_event = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags, cur_type,
630 cur, stop_type, stop);
631 gst_event_set_seqnum (byte_event, gst_event_get_seqnum (event));
632 res = gst_pad_push_event (demux->sinkpad, byte_event);
638 gst_asf_demux_handle_seek_event (GstASFDemux * demux, GstEvent * event)
640 GstClockTime idx_time;
643 GstSeekType cur_type, stop_type;
645 gboolean only_need_update;
646 gboolean after, before, next;
651 guint packet, speed_count = 1;
657 gst_event_parse_seek (event, &rate, &format, &flags, &cur_type, &cur,
660 if (G_UNLIKELY (format != GST_FORMAT_TIME)) {
661 GST_LOG_OBJECT (demux, "seeking is only supported in TIME format");
665 /* upstream might handle TIME seek, e.g. mms or rtsp, or not, e.g. http,
666 * so first try to let it handle the seek event. */
667 if (gst_pad_push_event (demux->sinkpad, gst_event_ref (event)))
670 if (G_UNLIKELY (demux->seekable == FALSE || demux->packet_size == 0 ||
671 demux->num_packets == 0 || demux->play_time == 0)) {
672 GST_LOG_OBJECT (demux, "stream is not seekable");
676 if (G_UNLIKELY (!demux->activated_streams)) {
677 GST_LOG_OBJECT (demux, "streams not yet activated, ignoring seek");
681 if (G_UNLIKELY (rate <= 0.0)) {
682 GST_LOG_OBJECT (demux, "backward playback");
683 demux->seek_to_cur_pos = TRUE;
684 for (i = 0; i < demux->num_streams; i++) {
685 demux->stream[i].reverse_kf_ready = FALSE;
689 seqnum = gst_event_get_seqnum (event);
690 flush = ((flags & GST_SEEK_FLAG_FLUSH) == GST_SEEK_FLAG_FLUSH);
692 ((flags & GST_SEEK_FLAG_ACCURATE) == GST_SEEK_FLAG_ACCURATE);
693 demux->keyunit_sync =
694 ((flags & GST_SEEK_FLAG_KEY_UNIT) == GST_SEEK_FLAG_KEY_UNIT);
695 after = ((flags & GST_SEEK_FLAG_SNAP_AFTER) == GST_SEEK_FLAG_SNAP_AFTER);
696 before = ((flags & GST_SEEK_FLAG_SNAP_BEFORE) == GST_SEEK_FLAG_SNAP_BEFORE);
697 next = after && !before;
699 if (G_UNLIKELY (demux->streaming)) {
700 /* support it safely needs more segment handling, e.g. closing etc */
702 GST_LOG_OBJECT (demux, "streaming; non-flushing seek not supported");
705 /* we can (re)construct the start later on, but not the end */
706 if (stop_type != GST_SEEK_TYPE_NONE &&
707 (stop_type != GST_SEEK_TYPE_SET || GST_CLOCK_TIME_IS_VALID (stop))) {
708 GST_LOG_OBJECT (demux, "streaming; end position must be NONE");
711 return gst_asf_demux_handle_seek_push (demux, event);
714 /* unlock the streaming thread */
715 if (G_LIKELY (flush)) {
716 fevent = gst_event_new_flush_start ();
718 gst_event_set_seqnum (fevent, seqnum);
719 gst_pad_push_event (demux->sinkpad, gst_event_ref (fevent));
720 gst_asf_demux_send_event_unlocked (demux, fevent);
722 gst_pad_pause_task (demux->sinkpad);
725 /* grab the stream lock so that streaming cannot continue, for
726 * non flushing seeks when the element is in PAUSED this could block
728 GST_PAD_STREAM_LOCK (demux->sinkpad);
730 /* we now can stop flushing, since we have the stream lock now */
731 fevent = gst_event_new_flush_stop (TRUE);
732 gst_event_set_seqnum (fevent, seqnum);
733 gst_pad_push_event (demux->sinkpad, gst_event_ref (fevent));
735 if (G_LIKELY (flush))
736 gst_asf_demux_send_event_unlocked (demux, fevent);
738 gst_event_unref (fevent);
740 /* operating on copy of segment until we know the seek worked */
741 segment = demux->segment;
743 if (G_UNLIKELY (demux->segment_running && !flush)) {
744 GstSegment newsegment;
747 /* create the segment event to close the current segment */
748 gst_segment_copy_into (&segment, &newsegment);
749 newseg = gst_event_new_segment (&newsegment);
750 gst_event_set_seqnum (newseg, seqnum);
752 gst_asf_demux_send_event_unlocked (demux, newseg);
755 gst_segment_do_seek (&segment, rate, format, flags, cur_type,
756 cur, stop_type, stop, &only_need_update);
758 GST_DEBUG_OBJECT (demux, "seeking to time %" GST_TIME_FORMAT ", segment: "
759 "%" GST_SEGMENT_FORMAT, GST_TIME_ARGS (segment.start), &segment);
761 if (cur_type != GST_SEEK_TYPE_SET)
762 seek_time = segment.start;
766 /* FIXME: should check the KEY_UNIT flag; need to adjust position to
767 * real start of data and segment_start to indexed time for key unit seek*/
768 if (G_UNLIKELY (!gst_asf_demux_seek_index_lookup (demux, &packet, seek_time,
769 &idx_time, &speed_count, next, &eos))) {
773 demux->packet = demux->num_packets;
777 /* First try to query our source to see if it can convert for us. This is
778 the case when our source is an mms stream, notice that in this case
779 gstmms will do a time based seek to get the byte offset, this is not a
780 problem as the seek to this offset needs to happen anway. */
781 if (gst_pad_peer_query_convert (demux->sinkpad, GST_FORMAT_TIME, seek_time,
782 GST_FORMAT_BYTES, &offset)) {
783 packet = (offset - demux->data_offset) / demux->packet_size;
784 GST_LOG_OBJECT (demux, "convert %" GST_TIME_FORMAT
785 " to bytes query result: %" G_GINT64_FORMAT ", data_ofset: %"
786 G_GINT64_FORMAT ", packet_size: %u," " resulting packet: %u\n",
787 GST_TIME_ARGS (seek_time), offset, demux->data_offset,
788 demux->packet_size, packet);
790 /* FIXME: For streams containing video, seek to an earlier position in
791 * the hope of hitting a keyframe and let the sinks throw away the stuff
792 * before the segment start. For audio-only this is unnecessary as every
794 if (flush && (demux->accurate || (demux->keyunit_sync && !next))
795 && demux->num_video_streams > 0) {
796 seek_time -= 5 * GST_SECOND;
801 packet = (guint) gst_util_uint64_scale (demux->num_packets,
802 seek_time, demux->play_time);
804 if (packet > demux->num_packets)
805 packet = demux->num_packets;
808 if (G_LIKELY (demux->keyunit_sync && !demux->accurate)) {
809 GST_DEBUG_OBJECT (demux, "key unit seek, adjust seek_time = %"
810 GST_TIME_FORMAT " to index_time = %" GST_TIME_FORMAT,
811 GST_TIME_ARGS (seek_time), GST_TIME_ARGS (idx_time));
812 segment.start = idx_time;
813 segment.position = idx_time;
814 segment.time = idx_time;
818 GST_DEBUG_OBJECT (demux, "seeking to packet %u (%d)", packet, speed_count);
820 GST_OBJECT_LOCK (demux);
821 demux->segment = segment;
822 if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment)) {
823 demux->packet = (gint64) gst_util_uint64_scale (demux->num_packets,
824 stop, demux->play_time);
826 demux->packet = packet;
829 demux->need_newsegment = TRUE;
830 demux->segment_seqnum = seqnum;
831 demux->speed_packets =
832 GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment) ? 1 : speed_count;
833 gst_asf_demux_reset_stream_state_after_discont (demux);
834 GST_OBJECT_UNLOCK (demux);
837 /* restart our task since it might have been stopped when we did the flush */
838 gst_pad_start_task (demux->sinkpad, (GstTaskFunction) gst_asf_demux_loop,
841 /* streaming can continue now */
842 GST_PAD_STREAM_UNLOCK (demux->sinkpad);
848 gst_asf_demux_handle_src_event (GstPad * pad, GstObject * parent,
854 demux = GST_ASF_DEMUX (parent);
856 switch (GST_EVENT_TYPE (event)) {
858 GST_LOG_OBJECT (pad, "seek event");
859 ret = gst_asf_demux_handle_seek_event (demux, event);
860 gst_event_unref (event);
863 case GST_EVENT_NAVIGATION:
864 /* just drop these two silently */
865 gst_event_unref (event);
869 GST_LOG_OBJECT (pad, "%s event", GST_EVENT_TYPE_NAME (event));
870 ret = gst_pad_event_default (pad, parent, event);
877 static inline guint32
878 gst_asf_demux_identify_guid (const ASFGuidHash * guids, ASFGuid * guid)
882 ret = gst_asf_identify_guid (guids, guid);
884 GST_LOG ("%s 0x%08x-0x%08x-0x%08x-0x%08x",
885 gst_asf_get_guid_nick (guids, ret),
886 guid->v1, guid->v2, guid->v3, guid->v4);
898 /* expect is true when the user is expeting an object,
899 * when false, it will give no warnings if the object
903 asf_demux_peek_object (GstASFDemux * demux, const guint8 * data,
904 guint data_len, AsfObject * object, gboolean expect)
908 if (data_len < ASF_OBJECT_HEADER_SIZE)
911 guid.v1 = GST_READ_UINT32_LE (data + 0);
912 guid.v2 = GST_READ_UINT32_LE (data + 4);
913 guid.v3 = GST_READ_UINT32_LE (data + 8);
914 guid.v4 = GST_READ_UINT32_LE (data + 12);
916 object->size = GST_READ_UINT64_LE (data + 16);
918 /* FIXME: make asf_demux_identify_object_guid() */
919 object->id = gst_asf_demux_identify_guid (asf_object_guids, &guid);
920 if (object->id == ASF_OBJ_UNDEFINED && expect) {
921 GST_WARNING_OBJECT (demux, "Unknown object %08x-%08x-%08x-%08x",
922 guid.v1, guid.v2, guid.v3, guid.v4);
929 gst_asf_demux_release_old_pads (GstASFDemux * demux)
931 GST_DEBUG_OBJECT (demux, "Releasing old pads");
933 while (demux->old_num_streams > 0) {
934 gst_pad_push_event (demux->old_stream[demux->old_num_streams - 1].pad,
935 gst_event_new_eos ());
936 gst_asf_demux_free_stream (demux,
937 &demux->old_stream[demux->old_num_streams - 1]);
938 --demux->old_num_streams;
940 memset (demux->old_stream, 0, sizeof (demux->old_stream));
941 demux->old_num_streams = 0;
945 gst_asf_demux_chain_headers (GstASFDemux * demux)
949 guint8 *header_data, *data = NULL;
950 const guint8 *cdata = NULL;
953 cdata = (guint8 *) gst_adapter_map (demux->adapter, ASF_OBJECT_HEADER_SIZE);
957 asf_demux_peek_object (demux, cdata, ASF_OBJECT_HEADER_SIZE, &obj, TRUE);
958 if (obj.id != ASF_OBJ_HEADER)
961 GST_LOG_OBJECT (demux, "header size = %u", (guint) obj.size);
963 /* + 50 for non-packet data at beginning of ASF_OBJ_DATA */
964 if (gst_adapter_available (demux->adapter) < obj.size + 50)
967 data = gst_adapter_take (demux->adapter, obj.size + 50);
970 header_size = obj.size;
971 flow = gst_asf_demux_process_object (demux, &header_data, &header_size);
972 if (flow != GST_FLOW_OK)
975 /* calculate where the packet data starts */
976 demux->data_offset = obj.size + 50;
978 /* now parse the beginning of the ASF_OBJ_DATA object */
979 if (!gst_asf_demux_parse_data_object_start (demux, data + obj.size))
982 if (demux->num_streams == 0)
991 GST_LOG_OBJECT (demux, "not enough data in adapter yet");
998 GST_ELEMENT_ERROR (demux, STREAM, WRONG_TYPE, (NULL),
999 ("This doesn't seem to be an ASF file"));
1001 return GST_FLOW_ERROR;
1006 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
1007 ("header parsing failed, or no streams found, flow = %s",
1008 gst_flow_get_name (flow)));
1010 return GST_FLOW_ERROR;
1015 gst_asf_demux_pull_data (GstASFDemux * demux, guint64 offset, guint size,
1016 GstBuffer ** p_buf, GstFlowReturn * p_flow)
1021 GST_LOG_OBJECT (demux, "pulling buffer at %" G_GUINT64_FORMAT "+%u",
1024 flow = gst_pad_pull_range (demux->sinkpad, offset, size, p_buf);
1026 if (G_LIKELY (p_flow))
1029 if (G_UNLIKELY (flow != GST_FLOW_OK)) {
1030 GST_DEBUG_OBJECT (demux, "flow %s pulling buffer at %" G_GUINT64_FORMAT
1031 "+%u", gst_flow_get_name (flow), offset, size);
1036 g_assert (*p_buf != NULL);
1038 buffer_size = gst_buffer_get_size (*p_buf);
1039 if (G_UNLIKELY (buffer_size < size)) {
1040 GST_DEBUG_OBJECT (demux, "short read pulling buffer at %" G_GUINT64_FORMAT
1041 "+%u (got only %" G_GSIZE_FORMAT " bytes)", offset, size, buffer_size);
1042 gst_buffer_unref (*p_buf);
1043 if (G_LIKELY (p_flow))
1044 *p_flow = GST_FLOW_EOS;
1053 gst_asf_demux_pull_indices (GstASFDemux * demux)
1055 GstBuffer *buf = NULL;
1059 offset = demux->index_offset;
1061 if (G_UNLIKELY (offset == 0)) {
1062 GST_DEBUG_OBJECT (demux, "can't read indices, don't know index offset");
1066 while (gst_asf_demux_pull_data (demux, offset, 16 + 8, &buf, NULL)) {
1072 gst_buffer_map (buf, &map, GST_MAP_READ);
1073 g_assert (map.size >= 16 + 8);
1074 asf_demux_peek_object (demux, map.data, 16 + 8, &obj, TRUE);
1075 gst_buffer_unmap (buf, &map);
1076 gst_buffer_replace (&buf, NULL);
1078 /* check for sanity */
1079 if (G_UNLIKELY (obj.size > (5 * 1024 * 1024))) {
1080 GST_DEBUG_OBJECT (demux, "implausible index object size, bailing out");
1084 if (G_UNLIKELY (!gst_asf_demux_pull_data (demux, offset, obj.size, &buf,
1088 GST_LOG_OBJECT (demux, "index object at offset 0x%" G_GINT64_MODIFIER "X"
1089 ", size %u", offset, (guint) obj.size);
1091 offset += obj.size; /* increase before _process_object changes it */
1093 gst_buffer_map (buf, &map, GST_MAP_READ);
1094 g_assert (map.size >= obj.size);
1095 bufdata = (guint8 *) map.data;
1096 flow = gst_asf_demux_process_object (demux, &bufdata, &obj.size);
1097 gst_buffer_unmap (buf, &map);
1098 gst_buffer_replace (&buf, NULL);
1100 if (G_UNLIKELY (flow != GST_FLOW_OK))
1105 GST_DEBUG_OBJECT (demux, "read %u index objects", num_read);
1109 gst_asf_demux_parse_data_object_start (GstASFDemux * demux, guint8 * data)
1113 asf_demux_peek_object (demux, data, 50, &obj, TRUE);
1114 if (obj.id != ASF_OBJ_DATA) {
1115 GST_WARNING_OBJECT (demux, "headers not followed by a DATA object");
1119 demux->state = GST_ASF_DEMUX_STATE_DATA;
1121 if (!demux->broadcast && obj.size > 50) {
1122 demux->data_size = obj.size - 50;
1123 /* CHECKME: for at least one file this is off by +158 bytes?! */
1124 demux->index_offset = demux->data_offset + demux->data_size;
1126 demux->data_size = 0;
1127 demux->index_offset = 0;
1132 if (!demux->broadcast) {
1133 /* skip object header (24 bytes) and file GUID (16 bytes) */
1134 demux->num_packets = GST_READ_UINT64_LE (data + (16 + 8) + 16);
1136 demux->num_packets = 0;
1139 if (demux->num_packets == 0)
1140 demux->seekable = FALSE;
1142 /* fallback in the unlikely case that headers are inconsistent, can't hurt */
1143 if (demux->data_size == 0 && demux->num_packets > 0) {
1144 demux->data_size = demux->num_packets * demux->packet_size;
1145 demux->index_offset = demux->data_offset + demux->data_size;
1148 /* process pending stream objects and create pads for those */
1149 gst_asf_demux_process_queued_extended_stream_objects (demux);
1151 GST_INFO_OBJECT (demux, "Stream has %" G_GUINT64_FORMAT " packets, "
1152 "data_offset=%" G_GINT64_FORMAT ", data_size=%" G_GINT64_FORMAT
1153 ", index_offset=%" G_GUINT64_FORMAT, demux->num_packets,
1154 demux->data_offset, demux->data_size, demux->index_offset);
1160 gst_asf_demux_pull_headers (GstASFDemux * demux, GstFlowReturn * pflow)
1162 GstFlowReturn flow = GST_FLOW_OK;
1164 GstBuffer *buf = NULL;
1169 GST_LOG_OBJECT (demux, "reading headers");
1171 /* pull HEADER object header, so we know its size */
1172 if (!gst_asf_demux_pull_data (demux, demux->base_offset, 16 + 8, &buf, &flow))
1175 gst_buffer_map (buf, &map, GST_MAP_READ);
1176 g_assert (map.size >= 16 + 8);
1177 asf_demux_peek_object (demux, map.data, 16 + 8, &obj, TRUE);
1178 gst_buffer_unmap (buf, &map);
1179 gst_buffer_replace (&buf, NULL);
1181 if (obj.id != ASF_OBJ_HEADER)
1184 GST_LOG_OBJECT (demux, "header size = %u", (guint) obj.size);
1186 /* pull HEADER object */
1187 if (!gst_asf_demux_pull_data (demux, demux->base_offset, obj.size, &buf,
1191 size = obj.size; /* don't want obj.size changed */
1192 gst_buffer_map (buf, &map, GST_MAP_READ);
1193 g_assert (map.size >= size);
1194 bufdata = (guint8 *) map.data;
1195 flow = gst_asf_demux_process_object (demux, &bufdata, &size);
1196 gst_buffer_unmap (buf, &map);
1197 gst_buffer_replace (&buf, NULL);
1199 if (flow != GST_FLOW_OK) {
1200 GST_WARNING_OBJECT (demux, "process_object: %s", gst_flow_get_name (flow));
1204 /* calculate where the packet data starts */
1205 demux->data_offset = demux->base_offset + obj.size + 50;
1207 /* now pull beginning of DATA object before packet data */
1208 if (!gst_asf_demux_pull_data (demux, demux->base_offset + obj.size, 50, &buf,
1212 gst_buffer_map (buf, &map, GST_MAP_READ);
1213 g_assert (map.size >= size);
1214 bufdata = (guint8 *) map.data;
1215 if (!gst_asf_demux_parse_data_object_start (demux, bufdata))
1218 if (demux->num_streams == 0)
1221 gst_buffer_unmap (buf, &map);
1222 gst_buffer_replace (&buf, NULL);
1230 gst_buffer_unmap (buf, &map);
1231 gst_buffer_replace (&buf, NULL);
1233 GST_ELEMENT_ERROR (demux, STREAM, WRONG_TYPE, (NULL),
1234 ("This doesn't seem to be an ASF file"));
1235 *pflow = GST_FLOW_ERROR;
1240 flow = GST_FLOW_ERROR;
1241 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
1242 ("header parsing failed, or no streams found, flow = %s",
1243 gst_flow_get_name (flow)));
1248 gst_buffer_unmap (buf, &map);
1249 gst_buffer_replace (&buf, NULL);
1256 all_streams_prerolled (GstASFDemux * demux)
1258 GstClockTime preroll_time;
1259 guint i, num_no_data = 0;
1261 /* Allow at least 500ms of preroll_time */
1262 preroll_time = MAX (demux->preroll, 500 * GST_MSECOND);
1264 /* returns TRUE as long as there isn't a stream which (a) has data queued
1265 * and (b) the timestamp of last piece of data queued is < demux->preroll
1266 * AND there is at least one other stream with data queued */
1267 for (i = 0; i < demux->num_streams; ++i) {
1268 AsfPayload *last_payload = NULL;
1272 stream = &demux->stream[i];
1273 if (G_UNLIKELY (stream->payloads->len == 0)) {
1275 GST_LOG_OBJECT (stream->pad, "no data queued");
1279 /* find last payload with timestamp */
1280 for (last_idx = stream->payloads->len - 1;
1281 last_idx >= 0 && (last_payload == NULL
1282 || !GST_CLOCK_TIME_IS_VALID (last_payload->ts)); --last_idx) {
1283 last_payload = &g_array_index (stream->payloads, AsfPayload, last_idx);
1286 GST_LOG_OBJECT (stream->pad, "checking if %" GST_TIME_FORMAT " > %"
1287 GST_TIME_FORMAT, GST_TIME_ARGS (last_payload->ts),
1288 GST_TIME_ARGS (preroll_time));
1289 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (last_payload->ts)
1290 || last_payload->ts <= preroll_time)) {
1291 GST_LOG_OBJECT (stream->pad, "not beyond preroll point yet");
1296 if (G_UNLIKELY (num_no_data > 0))
1304 gst_asf_demux_have_mutually_exclusive_active_stream (GstASFDemux * demux,
1309 for (l = demux->mut_ex_streams; l != NULL; l = l->next) {
1312 /* check for each mutual exclusion group whether it affects this stream */
1313 for (mes = (guint8 *) l->data; mes != NULL && *mes != 0xff; ++mes) {
1314 if (*mes == stream->id) {
1315 /* we are in this group; let's check if we've already activated streams
1316 * that are in the same group (and hence mutually exclusive to this
1318 for (mes = (guint8 *) l->data; mes != NULL && *mes != 0xff; ++mes) {
1321 for (i = 0; i < demux->num_streams; ++i) {
1322 if (demux->stream[i].id == *mes && demux->stream[i].active) {
1323 GST_LOG_OBJECT (demux, "stream with ID %d is mutually exclusive "
1324 "to already active stream with ID %d", stream->id,
1325 demux->stream[i].id);
1330 /* we can only be in this group once, let's break out and move on to
1331 * the next mutual exclusion group */
1342 gst_asf_demux_check_segment_ts (GstASFDemux * demux, GstClockTime payload_ts)
1344 /* remember the first queued timestamp for the segment */
1345 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (demux->segment_ts) &&
1346 GST_CLOCK_TIME_IS_VALID (demux->first_ts))) {
1347 GST_DEBUG_OBJECT (demux, "segment ts: %" GST_TIME_FORMAT,
1348 GST_TIME_ARGS (demux->first_ts));
1349 demux->segment_ts = payload_ts;
1350 /* always note, but only determines segment when streaming */
1351 if (demux->streaming)
1352 gst_segment_do_seek (&demux->segment, demux->in_segment.rate,
1353 GST_FORMAT_TIME, (GstSeekFlags) demux->segment.flags,
1354 GST_SEEK_TYPE_SET, demux->segment_ts, GST_SEEK_TYPE_NONE, 0, NULL);
1359 gst_asf_demux_check_first_ts (GstASFDemux * demux, gboolean force)
1361 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (demux->first_ts))) {
1362 GstClockTime first_ts = GST_CLOCK_TIME_NONE;
1365 /* go trhough each stream, find smallest timestamp */
1366 for (i = 0; i < demux->num_streams; ++i) {
1369 GstClockTime stream_min_ts = GST_CLOCK_TIME_NONE;
1370 GstClockTime stream_min_ts2 = GST_CLOCK_TIME_NONE; /* second smallest timestamp */
1371 stream = &demux->stream[i];
1373 for (j = 0; j < stream->payloads->len; ++j) {
1374 AsfPayload *payload = &g_array_index (stream->payloads, AsfPayload, j);
1375 if (GST_CLOCK_TIME_IS_VALID (payload->ts) &&
1376 (!GST_CLOCK_TIME_IS_VALID (stream_min_ts)
1377 || stream_min_ts > payload->ts)) {
1378 stream_min_ts = payload->ts;
1380 if (GST_CLOCK_TIME_IS_VALID (payload->ts) &&
1381 payload->ts > stream_min_ts &&
1382 (!GST_CLOCK_TIME_IS_VALID (stream_min_ts2)
1383 || stream_min_ts2 > payload->ts)) {
1384 stream_min_ts2 = payload->ts;
1388 /* there are some DVR ms files where first packet has TS of 0 (instead of -1) while subsequent packets have
1389 regular (singificantly larger) timestamps. If we don't deal with it, we may end up with huge gap in timestamps
1390 which makes playback stuck. The 0 timestamp may also be valid though, if the second packet timestamp continues
1391 from it. I havent found a better way to distinguish between these two, except to set an arbitrary boundary
1392 and disregard the first 0 timestamp if the second timestamp is bigger than the boundary) */
1394 if (stream_min_ts == 0 && stream_min_ts2 == GST_CLOCK_TIME_NONE && !force) /* still waiting for the second timestamp */
1397 if (stream_min_ts == 0 && stream_min_ts2 > GST_SECOND) /* first timestamp is 0 and second is significantly larger, disregard the 0 */
1398 stream_min_ts = stream_min_ts2;
1400 /* if we don't have timestamp for this stream, wait for more data */
1401 if (!GST_CLOCK_TIME_IS_VALID (stream_min_ts) && !force)
1404 if (GST_CLOCK_TIME_IS_VALID (stream_min_ts) &&
1405 (!GST_CLOCK_TIME_IS_VALID (first_ts) || first_ts > stream_min_ts))
1406 first_ts = stream_min_ts;
1409 if (!GST_CLOCK_TIME_IS_VALID (first_ts)) /* can happen with force = TRUE */
1412 demux->first_ts = first_ts;
1414 /* update packets queued before we knew first timestamp */
1415 for (i = 0; i < demux->num_streams; ++i) {
1418 stream = &demux->stream[i];
1420 for (j = 0; j < stream->payloads->len; ++j) {
1421 AsfPayload *payload = &g_array_index (stream->payloads, AsfPayload, j);
1422 if (GST_CLOCK_TIME_IS_VALID (payload->ts)) {
1423 if (payload->ts > first_ts)
1424 payload->ts -= first_ts;
1432 gst_asf_demux_check_segment_ts (demux, 0);
1438 gst_asf_demux_update_caps_from_payload (GstASFDemux * demux, AsfStream * stream)
1440 /* try to determine whether the stream is AC-3 or MPEG; In dvr-ms the codecTag is unreliable
1441 and often set wrong, inspecting the data is the only way that seem to be working */
1442 GstTypeFindProbability prob = GST_TYPE_FIND_NONE;
1443 GstCaps *caps = NULL;
1445 GstAdapter *adapter = gst_adapter_new ();
1447 for (i = 0; i < stream->payloads->len && prob < GST_TYPE_FIND_LIKELY; ++i) {
1449 AsfPayload *payload;
1452 payload = &g_array_index (stream->payloads, AsfPayload, i);
1453 gst_adapter_push (adapter, gst_buffer_ref (payload->buf));
1454 len = gst_adapter_available (adapter);
1455 data = gst_adapter_map (adapter, len);
1459 #define MIN_LENGTH 128
1461 /* look for the sync points */
1463 if (len < MIN_LENGTH || /* give typefind something to work on */
1464 (data[0] == 0x0b && data[1] == 0x77) || /* AC-3 sync point */
1465 (data[0] == 0xFF && ((data[1] & 0xF0) >> 4) == 0xF)) /* MPEG sync point */
1471 gst_caps_take (&caps, gst_type_find_helper_for_data (GST_OBJECT (demux),
1474 if (prob < GST_TYPE_FIND_LIKELY) {
1477 if (len > MIN_LENGTH)
1478 /* this wasn't it, look for another sync point */
1482 gst_adapter_unmap (adapter);
1485 gst_object_unref (adapter);
1488 gst_caps_take (&stream->caps, caps);
1496 gst_asf_demux_check_activate_streams (GstASFDemux * demux, gboolean force)
1500 if (demux->activated_streams)
1503 if (G_UNLIKELY (!gst_asf_demux_check_first_ts (demux, force)))
1506 if (!all_streams_prerolled (demux) && !force) {
1507 GST_DEBUG_OBJECT (demux, "not all streams with data beyond preroll yet");
1511 for (i = 0; i < demux->num_streams; ++i) {
1512 AsfStream *stream = &demux->stream[i];
1514 if (stream->payloads->len > 0) {
1516 if (stream->inspect_payload && /* dvr-ms required payload inspection */
1517 !stream->active && /* do not inspect active streams (caps were already set) */
1518 !gst_asf_demux_update_caps_from_payload (demux, stream) && /* failed to determine caps */
1519 stream->payloads->len < 20) { /* if we couldn't determine the caps from 20 packets then just give up and use whatever was in codecTag */
1520 /* try to gather some more data */
1523 /* we don't check mutual exclusion stuff here; either we have data for
1524 * a stream, then we active it, or we don't, then we'll ignore it */
1525 GST_LOG_OBJECT (stream->pad, "is prerolled - activate!");
1526 gst_asf_demux_activate_stream (demux, stream);
1528 GST_LOG_OBJECT (stream->pad, "no data, ignoring stream");
1532 gst_asf_demux_release_old_pads (demux);
1534 demux->activated_streams = TRUE;
1535 GST_LOG_OBJECT (demux, "signalling no more pads");
1536 gst_element_no_more_pads (GST_ELEMENT (demux));
1540 /* returns the stream that has a complete payload with the lowest timestamp
1541 * queued, or NULL (we push things by timestamp because during the internal
1542 * prerolling we might accumulate more data then the external queues can take,
1543 * so we'd lock up if we pushed all accumulated data for stream N in one go) */
1545 gst_asf_demux_find_stream_with_complete_payload (GstASFDemux * demux)
1547 AsfPayload *best_payload = NULL;
1548 AsfStream *best_stream = NULL;
1551 for (i = 0; i < demux->num_streams; ++i) {
1555 stream = &demux->stream[i];
1557 /* Don't push any data until we have at least one payload that falls within
1558 * the current segment. This way we can remove out-of-segment payloads that
1559 * don't need to be decoded after a seek, sending only data from the
1560 * keyframe directly before our segment start */
1561 if (stream->payloads->len > 0) {
1562 AsfPayload *payload = NULL;
1565 if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment)) {
1566 /* Reverse playback */
1568 if (stream->is_video) {
1569 /* We have to push payloads from KF to the first frame we accumulated (reverse order) */
1570 if (stream->reverse_kf_ready) {
1572 &g_array_index (stream->payloads, AsfPayload, stream->kf_pos);
1573 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (payload->ts))) {
1574 /* TODO : remove payload from the list? */
1581 /* find first complete payload with timestamp */
1582 for (j = stream->payloads->len - 1;
1583 j >= 0 && (payload == NULL
1584 || !GST_CLOCK_TIME_IS_VALID (payload->ts)); --j) {
1585 payload = &g_array_index (stream->payloads, AsfPayload, j);
1588 /* If there's a complete payload queued for this stream */
1589 if (!gst_asf_payload_is_complete (payload))
1595 /* find last payload with timestamp */
1596 for (last_idx = stream->payloads->len - 1;
1597 last_idx >= 0 && (payload == NULL
1598 || !GST_CLOCK_TIME_IS_VALID (payload->ts)); --last_idx) {
1599 payload = &g_array_index (stream->payloads, AsfPayload, last_idx);
1602 /* if this is first payload after seek we might need to update the segment */
1603 if (GST_CLOCK_TIME_IS_VALID (payload->ts))
1604 gst_asf_demux_check_segment_ts (demux, payload->ts);
1606 if (G_UNLIKELY (GST_CLOCK_TIME_IS_VALID (payload->ts) &&
1607 (payload->ts < demux->segment.start))) {
1608 if (G_UNLIKELY ((!demux->keyunit_sync) && (!demux->accurate)
1609 && payload->keyframe)) {
1610 GST_DEBUG_OBJECT (stream->pad,
1611 "Found keyframe, updating segment start to %" GST_TIME_FORMAT,
1612 GST_TIME_ARGS (payload->ts));
1613 demux->segment.start = payload->ts;
1614 demux->segment.time = payload->ts;
1616 GST_DEBUG_OBJECT (stream->pad, "Last queued payload has timestamp %"
1617 GST_TIME_FORMAT " which is before our segment start %"
1618 GST_TIME_FORMAT ", not pushing yet",
1619 GST_TIME_ARGS (payload->ts),
1620 GST_TIME_ARGS (demux->segment.start));
1625 /* find first complete payload with timestamp */
1627 j < stream->payloads->len && (payload == NULL
1628 || !GST_CLOCK_TIME_IS_VALID (payload->ts)); ++j) {
1629 payload = &g_array_index (stream->payloads, AsfPayload, j);
1632 /* Now see if there's a complete payload queued for this stream */
1633 if (!gst_asf_payload_is_complete (payload))
1637 /* ... and whether its timestamp is lower than the current best */
1638 if (best_stream == NULL || best_payload->ts > payload->ts) {
1639 best_stream = stream;
1640 best_payload = payload;
1648 static GstFlowReturn
1649 gst_asf_demux_push_complete_payloads (GstASFDemux * demux, gboolean force)
1652 GstFlowReturn ret = GST_FLOW_OK;
1654 if (G_UNLIKELY (!demux->activated_streams)) {
1655 if (!gst_asf_demux_check_activate_streams (demux, force))
1657 /* streams are now activated */
1660 while ((stream = gst_asf_demux_find_stream_with_complete_payload (demux))) {
1661 AsfPayload *payload;
1662 GstClockTime timestamp = GST_CLOCK_TIME_NONE;
1663 GstClockTime duration = GST_CLOCK_TIME_NONE;
1665 /* wait until we had a chance to "lock on" some payload's timestamp */
1666 if (G_UNLIKELY (demux->need_newsegment
1667 && !GST_CLOCK_TIME_IS_VALID (demux->segment_ts)))
1670 if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment) && stream->is_video
1671 && stream->payloads->len) {
1672 payload = &g_array_index (stream->payloads, AsfPayload, stream->kf_pos);
1674 payload = &g_array_index (stream->payloads, AsfPayload, 0);
1677 /* do we need to send a newsegment event */
1678 if ((G_UNLIKELY (demux->need_newsegment))) {
1679 GstEvent *segment_event;
1681 /* safe default if insufficient upstream info */
1682 if (!GST_CLOCK_TIME_IS_VALID (demux->in_gap))
1685 if (demux->segment.stop == GST_CLOCK_TIME_NONE &&
1686 demux->segment.duration > 0) {
1687 /* slight HACK; prevent clipping of last bit */
1688 demux->segment.stop = demux->segment.duration + demux->in_gap;
1691 /* FIXME : only if ACCURATE ! */
1692 if (G_LIKELY (!demux->keyunit_sync && !demux->accurate
1693 && (GST_CLOCK_TIME_IS_VALID (payload->ts)))
1694 && !GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment)) {
1695 GST_DEBUG ("Adjusting newsegment start to %" GST_TIME_FORMAT,
1696 GST_TIME_ARGS (payload->ts));
1697 demux->segment.start = payload->ts;
1698 demux->segment.time = payload->ts;
1701 GST_DEBUG_OBJECT (demux, "sending new-segment event %" GST_SEGMENT_FORMAT,
1704 /* note: we fix up all timestamps to start from 0, so this should be ok */
1705 segment_event = gst_event_new_segment (&demux->segment);
1706 if (demux->segment_seqnum)
1707 gst_event_set_seqnum (segment_event, demux->segment_seqnum);
1708 gst_asf_demux_send_event_unlocked (demux, segment_event);
1710 /* now post any global tags we may have found */
1711 if (demux->taglist == NULL) {
1712 demux->taglist = gst_tag_list_new_empty ();
1713 gst_tag_list_set_scope (demux->taglist, GST_TAG_SCOPE_GLOBAL);
1716 gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
1717 GST_TAG_CONTAINER_FORMAT, "ASF", NULL);
1719 GST_DEBUG_OBJECT (demux, "global tags: %" GST_PTR_FORMAT, demux->taglist);
1720 gst_asf_demux_send_event_unlocked (demux,
1721 gst_event_new_tag (demux->taglist));
1722 demux->taglist = NULL;
1724 demux->need_newsegment = FALSE;
1725 demux->segment_seqnum = 0;
1726 demux->segment_running = TRUE;
1729 /* Do we have tags pending for this stream? */
1730 if (G_UNLIKELY (stream->pending_tags)) {
1731 GST_LOG_OBJECT (stream->pad, "%" GST_PTR_FORMAT, stream->pending_tags);
1732 gst_pad_push_event (stream->pad,
1733 gst_event_new_tag (stream->pending_tags));
1734 stream->pending_tags = NULL;
1737 /* We have the whole packet now so we should push the packet to
1738 * the src pad now. First though we should check if we need to do
1740 if (G_UNLIKELY (stream->span > 1)) {
1741 gst_asf_demux_descramble_buffer (demux, stream, &payload->buf);
1744 payload->buf = gst_buffer_make_writable (payload->buf);
1746 if (G_LIKELY (!payload->keyframe)) {
1747 GST_BUFFER_FLAG_SET (payload->buf, GST_BUFFER_FLAG_DELTA_UNIT);
1750 if (G_UNLIKELY (stream->discont)) {
1751 GST_DEBUG_OBJECT (stream->pad, "marking DISCONT on stream");
1752 GST_BUFFER_FLAG_SET (payload->buf, GST_BUFFER_FLAG_DISCONT);
1753 stream->discont = FALSE;
1756 if (G_UNLIKELY (stream->is_video && payload->par_x && payload->par_y &&
1757 (payload->par_x != stream->par_x) &&
1758 (payload->par_y != stream->par_y))) {
1759 GST_DEBUG ("Updating PAR (%d/%d => %d/%d)",
1760 stream->par_x, stream->par_y, payload->par_x, payload->par_y);
1761 stream->par_x = payload->par_x;
1762 stream->par_y = payload->par_y;
1763 stream->caps = gst_caps_make_writable (stream->caps);
1764 gst_caps_set_simple (stream->caps, "pixel-aspect-ratio",
1765 GST_TYPE_FRACTION, stream->par_x, stream->par_y, NULL);
1766 gst_pad_set_caps (stream->pad, stream->caps);
1769 if (G_UNLIKELY (stream->interlaced != payload->interlaced)) {
1770 GST_DEBUG ("Updating interlaced status (%d => %d)", stream->interlaced,
1771 payload->interlaced);
1772 stream->interlaced = payload->interlaced;
1773 stream->caps = gst_caps_make_writable (stream->caps);
1774 gst_caps_set_simple (stream->caps, "interlace-mode", G_TYPE_BOOLEAN,
1775 (stream->interlaced ? "mixed" : "progressive"), NULL);
1776 gst_pad_set_caps (stream->pad, stream->caps);
1779 /* (sort of) interpolate timestamps using upstream "frame of reference",
1780 * typically useful for live src, but might (unavoidably) mess with
1781 * position reporting if a live src is playing not so live content
1782 * (e.g. rtspsrc taking some time to fall back to tcp) */
1783 timestamp = payload->ts;
1784 if (GST_CLOCK_TIME_IS_VALID (timestamp)
1785 && !GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment)) {
1786 timestamp += demux->in_gap;
1788 /* Check if we're after the segment already, if so no need to push
1790 if (demux->segment.stop != -1 && timestamp > demux->segment.stop) {
1791 GST_DEBUG_OBJECT (stream->pad,
1792 "Payload after segment stop %" GST_TIME_FORMAT,
1793 GST_TIME_ARGS (demux->segment.stop));
1795 gst_flow_combiner_update_pad_flow (demux->flowcombiner, stream->pad,
1797 gst_buffer_unref (payload->buf);
1798 payload->buf = NULL;
1799 g_array_remove_index (stream->payloads, 0);
1800 /* Break out as soon as we have an issue */
1801 if (G_UNLIKELY (ret != GST_FLOW_OK))
1808 GST_BUFFER_PTS (payload->buf) = timestamp;
1810 if (payload->duration == GST_CLOCK_TIME_NONE
1811 && stream->ext_props.avg_time_per_frame != 0) {
1812 duration = stream->ext_props.avg_time_per_frame * 100;
1814 duration = payload->duration;
1816 GST_BUFFER_DURATION (payload->buf) = duration;
1818 /* FIXME: we should really set durations on buffers if we can */
1820 GST_LOG_OBJECT (stream->pad, "pushing buffer, %" GST_PTR_FORMAT,
1823 if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment) && stream->is_video) {
1824 if (stream->reverse_kf_ready == TRUE && stream->kf_pos == 0) {
1825 GST_BUFFER_FLAG_SET (payload->buf, GST_BUFFER_FLAG_DISCONT);
1827 } else if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment)) {
1828 GST_BUFFER_FLAG_SET (payload->buf, GST_BUFFER_FLAG_DISCONT);
1832 if (stream->active) {
1833 if (G_UNLIKELY (stream->first_buffer)) {
1834 if (stream->streamheader != NULL) {
1835 GST_DEBUG_OBJECT (stream->pad,
1836 "Pushing streamheader before first buffer");
1837 gst_pad_push (stream->pad, gst_buffer_ref (stream->streamheader));
1839 stream->first_buffer = FALSE;
1842 if (GST_CLOCK_TIME_IS_VALID (timestamp)
1843 && timestamp > demux->segment.position) {
1844 demux->segment.position = timestamp;
1845 if (GST_CLOCK_TIME_IS_VALID (duration))
1846 demux->segment.position += timestamp;
1849 ret = gst_pad_push (stream->pad, payload->buf);
1851 gst_flow_combiner_update_pad_flow (demux->flowcombiner, stream->pad,
1854 gst_buffer_unref (payload->buf);
1857 payload->buf = NULL;
1858 if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment) && stream->is_video
1859 && stream->reverse_kf_ready) {
1860 g_array_remove_index (stream->payloads, stream->kf_pos);
1863 if (stream->reverse_kf_ready == TRUE && stream->kf_pos < 0) {
1865 stream->reverse_kf_ready = FALSE;
1868 g_array_remove_index (stream->payloads, 0);
1871 /* Break out as soon as we have an issue */
1872 if (G_UNLIKELY (ret != GST_FLOW_OK))
1880 gst_asf_demux_check_buffer_is_header (GstASFDemux * demux, GstBuffer * buf)
1884 g_assert (buf != NULL);
1886 GST_LOG_OBJECT (demux, "Checking if buffer is a header");
1888 gst_buffer_map (buf, &map, GST_MAP_READ);
1890 /* we return false on buffer too small */
1891 if (map.size < ASF_OBJECT_HEADER_SIZE) {
1892 gst_buffer_unmap (buf, &map);
1896 /* check if it is a header */
1897 asf_demux_peek_object (demux, map.data, ASF_OBJECT_HEADER_SIZE, &obj, TRUE);
1898 gst_buffer_unmap (buf, &map);
1899 if (obj.id == ASF_OBJ_HEADER) {
1906 gst_asf_demux_check_chained_asf (GstASFDemux * demux)
1908 guint64 off = demux->data_offset + (demux->packet * demux->packet_size);
1909 GstFlowReturn ret = GST_FLOW_OK;
1910 GstBuffer *buf = NULL;
1911 gboolean header = FALSE;
1913 /* TODO maybe we should skip index objects after the data and look
1914 * further for a new header */
1915 if (gst_asf_demux_pull_data (demux, off, ASF_OBJECT_HEADER_SIZE, &buf, &ret)) {
1916 g_assert (buf != NULL);
1917 /* check if it is a header */
1918 if (gst_asf_demux_check_buffer_is_header (demux, buf)) {
1919 GST_DEBUG_OBJECT (demux, "new base offset: %" G_GUINT64_FORMAT, off);
1920 demux->base_offset = off;
1924 gst_buffer_unref (buf);
1931 gst_asf_demux_loop (GstASFDemux * demux)
1933 GstFlowReturn flow = GST_FLOW_OK;
1934 GstBuffer *buf = NULL;
1937 if (G_UNLIKELY (demux->state == GST_ASF_DEMUX_STATE_HEADER)) {
1938 if (!gst_asf_demux_pull_headers (demux, &flow)) {
1942 gst_asf_demux_pull_indices (demux);
1945 g_assert (demux->state == GST_ASF_DEMUX_STATE_DATA);
1947 if (G_UNLIKELY (demux->num_packets != 0
1948 && demux->packet >= demux->num_packets))
1951 GST_LOG_OBJECT (demux, "packet %u/%u", (guint) demux->packet + 1,
1952 (guint) demux->num_packets);
1954 off = demux->data_offset + (demux->packet * demux->packet_size);
1956 if (G_UNLIKELY (!gst_asf_demux_pull_data (demux, off,
1957 demux->packet_size * demux->speed_packets, &buf, &flow))) {
1958 GST_DEBUG_OBJECT (demux, "got flow %s", gst_flow_get_name (flow));
1959 if (flow == GST_FLOW_EOS) {
1961 } else if (flow == GST_FLOW_FLUSHING) {
1962 GST_DEBUG_OBJECT (demux, "Not fatal");
1969 if (G_LIKELY (demux->speed_packets == 1)) {
1970 GstAsfDemuxParsePacketError err;
1971 err = gst_asf_demux_parse_packet (demux, buf);
1972 if (G_UNLIKELY (err != GST_ASF_DEMUX_PARSE_PACKET_ERROR_NONE)) {
1973 /* when we don't know when the data object ends, we should check
1974 * for a chained asf */
1975 if (demux->num_packets == 0) {
1976 if (gst_asf_demux_check_buffer_is_header (demux, buf)) {
1977 GST_INFO_OBJECT (demux, "Chained asf found");
1978 demux->base_offset = off;
1979 gst_asf_demux_reset (demux, TRUE);
1980 gst_buffer_unref (buf);
1984 /* FIXME: We should tally up fatal errors and error out only
1985 * after a few broken packets in a row? */
1987 GST_INFO_OBJECT (demux, "Ignoring recoverable parse error");
1988 gst_buffer_unref (buf);
1990 if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment)
1991 && !demux->seek_to_cur_pos) {
1993 if (demux->packet < 0) {
2003 flow = gst_asf_demux_push_complete_payloads (demux, FALSE);
2005 if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment)
2006 && !demux->seek_to_cur_pos) {
2008 if (demux->packet < 0) {
2017 for (n = 0; n < demux->speed_packets; n++) {
2019 GstAsfDemuxParsePacketError err;
2022 gst_buffer_copy_region (buf, GST_BUFFER_COPY_ALL,
2023 n * demux->packet_size, demux->packet_size);
2024 err = gst_asf_demux_parse_packet (demux, sub);
2025 if (G_UNLIKELY (err != GST_ASF_DEMUX_PARSE_PACKET_ERROR_NONE)) {
2026 /* when we don't know when the data object ends, we should check
2027 * for a chained asf */
2028 if (demux->num_packets == 0) {
2029 if (gst_asf_demux_check_buffer_is_header (demux, sub)) {
2030 GST_INFO_OBJECT (demux, "Chained asf found");
2031 demux->base_offset = off + n * demux->packet_size;
2032 gst_asf_demux_reset (demux, TRUE);
2033 gst_buffer_unref (sub);
2034 gst_buffer_unref (buf);
2038 /* FIXME: We should tally up fatal errors and error out only
2039 * after a few broken packets in a row? */
2041 GST_INFO_OBJECT (demux, "Ignoring recoverable parse error");
2045 gst_buffer_unref (sub);
2047 if (err == GST_ASF_DEMUX_PARSE_PACKET_ERROR_NONE)
2048 flow = gst_asf_demux_push_complete_payloads (demux, FALSE);
2054 /* reset speed pull */
2055 demux->speed_packets = 1;
2058 gst_buffer_unref (buf);
2060 if (G_UNLIKELY ((demux->num_packets > 0
2061 && demux->packet >= demux->num_packets)
2062 || flow == GST_FLOW_EOS)) {
2063 GST_LOG_OBJECT (demux, "reached EOS");
2067 if (G_UNLIKELY (flow != GST_FLOW_OK)) {
2068 GST_DEBUG_OBJECT (demux, "pushing complete payloads failed");
2072 /* check if we're at the end of the configured segment */
2073 /* FIXME: check if segment end reached etc. */
2079 /* if we haven't activated our streams yet, this might be because we have
2080 * less data queued than required for preroll; force stream activation and
2081 * send any pending payloads before sending EOS */
2082 if (!demux->activated_streams)
2083 gst_asf_demux_push_complete_payloads (demux, TRUE);
2085 /* we want to push an eos or post a segment-done in any case */
2086 if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
2089 /* for segment playback we need to post when (in stream time)
2090 * we stopped, this is either stop (when set) or the duration. */
2091 if ((stop = demux->segment.stop) == -1)
2092 stop = demux->segment.duration;
2094 GST_INFO_OBJECT (demux, "Posting segment-done, at end of segment");
2095 gst_element_post_message (GST_ELEMENT_CAST (demux),
2096 gst_message_new_segment_done (GST_OBJECT (demux), GST_FORMAT_TIME,
2098 gst_asf_demux_send_event_unlocked (demux,
2099 gst_event_new_segment_done (GST_FORMAT_TIME, stop));
2100 } else if (flow != GST_FLOW_EOS) {
2101 /* check if we have a chained asf, in case, we don't eos yet */
2102 if (gst_asf_demux_check_chained_asf (demux)) {
2103 GST_INFO_OBJECT (demux, "Chained ASF starting");
2104 gst_asf_demux_reset (demux, TRUE);
2109 if (!(demux->segment.flags & GST_SEEK_FLAG_SEGMENT)) {
2110 /* normal playback, send EOS to all linked pads */
2111 GST_INFO_OBJECT (demux, "Sending EOS, at end of stream");
2112 gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
2114 /* ... and fall through to pause */
2118 GST_DEBUG_OBJECT (demux, "pausing task, flow return: %s",
2119 gst_flow_get_name (flow));
2120 demux->segment_running = FALSE;
2121 gst_pad_pause_task (demux->sinkpad);
2123 /* For the error cases */
2124 if (flow < GST_FLOW_EOS || flow == GST_FLOW_NOT_LINKED) {
2125 /* Post an error. Hopefully something else already has, but if not... */
2126 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
2127 (_("Internal data stream error.")),
2128 ("streaming stopped, reason %s", gst_flow_get_name (flow)));
2129 gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
2138 GST_DEBUG_OBJECT (demux, "Read failed, doh");
2139 flow = GST_FLOW_EOS;
2143 /* See FIXMEs above */
2146 gst_buffer_unref (buf);
2147 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
2148 ("Error parsing ASF packet %u", (guint) demux->packet));
2149 gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
2150 flow = GST_FLOW_ERROR;
2156 #define GST_ASF_DEMUX_CHECK_HEADER_YES 0
2157 #define GST_ASF_DEMUX_CHECK_HEADER_NO 1
2158 #define GST_ASF_DEMUX_CHECK_HEADER_NEED_DATA 2
2161 gst_asf_demux_check_header (GstASFDemux * demux)
2164 guint8 *cdata = (guint8 *) gst_adapter_map (demux->adapter,
2165 ASF_OBJECT_HEADER_SIZE);
2166 if (cdata == NULL) /* need more data */
2167 return GST_ASF_DEMUX_CHECK_HEADER_NEED_DATA;
2169 asf_demux_peek_object (demux, cdata, ASF_OBJECT_HEADER_SIZE, &obj, FALSE);
2170 if (obj.id != ASF_OBJ_HEADER) {
2171 return GST_ASF_DEMUX_CHECK_HEADER_NO;
2173 return GST_ASF_DEMUX_CHECK_HEADER_YES;
2177 static GstFlowReturn
2178 gst_asf_demux_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
2180 GstFlowReturn ret = GST_FLOW_OK;
2183 demux = GST_ASF_DEMUX (parent);
2185 GST_LOG_OBJECT (demux,
2186 "buffer: size=%" G_GSIZE_FORMAT ", offset=%" G_GINT64_FORMAT ", time=%"
2187 GST_TIME_FORMAT, gst_buffer_get_size (buf), GST_BUFFER_OFFSET (buf),
2188 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)));
2190 if (G_UNLIKELY (GST_BUFFER_IS_DISCONT (buf))) {
2191 GST_DEBUG_OBJECT (demux, "received DISCONT");
2192 gst_asf_demux_mark_discont (demux);
2195 if (G_UNLIKELY ((!GST_CLOCK_TIME_IS_VALID (demux->in_gap) &&
2196 GST_BUFFER_TIMESTAMP_IS_VALID (buf)))) {
2197 demux->in_gap = GST_BUFFER_TIMESTAMP (buf) - demux->in_segment.start;
2198 GST_DEBUG_OBJECT (demux, "upstream segment start %" GST_TIME_FORMAT
2199 ", interpolation gap: %" GST_TIME_FORMAT,
2200 GST_TIME_ARGS (demux->in_segment.start), GST_TIME_ARGS (demux->in_gap));
2203 gst_adapter_push (demux->adapter, buf);
2205 switch (demux->state) {
2206 case GST_ASF_DEMUX_STATE_INDEX:{
2207 gint result = gst_asf_demux_check_header (demux);
2208 if (result == GST_ASF_DEMUX_CHECK_HEADER_NEED_DATA) /* need more data */
2211 if (result == GST_ASF_DEMUX_CHECK_HEADER_NO) {
2212 /* we don't care about this, probably an index */
2213 /* TODO maybe would be smarter to skip all the indices
2214 * until we got a new header or EOS to decide */
2215 GST_LOG_OBJECT (demux, "Received index object, its EOS");
2218 GST_INFO_OBJECT (demux, "Chained asf starting");
2219 /* cleanup and get ready for a chained asf */
2220 gst_asf_demux_reset (demux, TRUE);
2224 case GST_ASF_DEMUX_STATE_HEADER:{
2225 ret = gst_asf_demux_chain_headers (demux);
2226 if (demux->state != GST_ASF_DEMUX_STATE_DATA)
2228 /* otherwise fall through */
2230 case GST_ASF_DEMUX_STATE_DATA:
2234 data_size = demux->packet_size;
2236 while (gst_adapter_available (demux->adapter) >= data_size) {
2238 GstAsfDemuxParsePacketError err;
2240 /* we don't know the length of the stream
2241 * check for a chained asf everytime */
2242 if (demux->num_packets == 0) {
2243 gint result = gst_asf_demux_check_header (demux);
2245 if (result == GST_ASF_DEMUX_CHECK_HEADER_YES) {
2246 GST_INFO_OBJECT (demux, "Chained asf starting");
2247 /* cleanup and get ready for a chained asf */
2248 gst_asf_demux_reset (demux, TRUE);
2251 } else if (G_UNLIKELY (demux->num_packets != 0 && demux->packet >= 0
2252 && demux->packet >= demux->num_packets)) {
2253 /* do not overshoot data section when streaming */
2257 buf = gst_adapter_take_buffer (demux->adapter, data_size);
2259 /* FIXME: We should tally up fatal errors and error out only
2260 * after a few broken packets in a row? */
2261 err = gst_asf_demux_parse_packet (demux, buf);
2263 gst_buffer_unref (buf);
2265 if (G_LIKELY (err == GST_ASF_DEMUX_PARSE_PACKET_ERROR_NONE))
2266 ret = gst_asf_demux_push_complete_payloads (demux, FALSE);
2268 GST_WARNING_OBJECT (demux, "Parse error");
2270 if (demux->packet >= 0)
2273 if (G_UNLIKELY (demux->num_packets != 0 && demux->packet >= 0
2274 && demux->packet >= demux->num_packets)) {
2275 demux->state = GST_ASF_DEMUX_STATE_INDEX;
2280 g_assert_not_reached ();
2284 if (ret != GST_FLOW_OK)
2285 GST_DEBUG_OBJECT (demux, "flow: %s", gst_flow_get_name (ret));
2291 GST_DEBUG_OBJECT (demux, "Handled last packet, setting EOS");
2297 static inline gboolean
2298 gst_asf_demux_skip_bytes (guint num_bytes, guint8 ** p_data, guint64 * p_size)
2300 if (*p_size < num_bytes)
2303 *p_data += num_bytes;
2304 *p_size -= num_bytes;
2308 static inline guint8
2309 gst_asf_demux_get_uint8 (guint8 ** p_data, guint64 * p_size)
2313 g_assert (*p_size >= 1);
2314 ret = GST_READ_UINT8 (*p_data);
2315 *p_data += sizeof (guint8);
2316 *p_size -= sizeof (guint8);
2320 static inline guint16
2321 gst_asf_demux_get_uint16 (guint8 ** p_data, guint64 * p_size)
2325 g_assert (*p_size >= 2);
2326 ret = GST_READ_UINT16_LE (*p_data);
2327 *p_data += sizeof (guint16);
2328 *p_size -= sizeof (guint16);
2332 static inline guint32
2333 gst_asf_demux_get_uint32 (guint8 ** p_data, guint64 * p_size)
2337 g_assert (*p_size >= 4);
2338 ret = GST_READ_UINT32_LE (*p_data);
2339 *p_data += sizeof (guint32);
2340 *p_size -= sizeof (guint32);
2344 static inline guint64
2345 gst_asf_demux_get_uint64 (guint8 ** p_data, guint64 * p_size)
2349 g_assert (*p_size >= 8);
2350 ret = GST_READ_UINT64_LE (*p_data);
2351 *p_data += sizeof (guint64);
2352 *p_size -= sizeof (guint64);
2357 gst_asf_demux_get_buffer (GstBuffer ** p_buf, guint num_bytes_to_read,
2358 guint8 ** p_data, guint64 * p_size)
2362 if (*p_size < num_bytes_to_read)
2365 *p_buf = gst_buffer_new_and_alloc (num_bytes_to_read);
2366 gst_buffer_fill (*p_buf, 0, *p_data, num_bytes_to_read);
2368 *p_data += num_bytes_to_read;
2369 *p_size -= num_bytes_to_read;
2375 gst_asf_demux_get_bytes (guint8 ** p_buf, guint num_bytes_to_read,
2376 guint8 ** p_data, guint64 * p_size)
2380 if (*p_size < num_bytes_to_read)
2383 *p_buf = g_memdup (*p_data, num_bytes_to_read);
2384 *p_data += num_bytes_to_read;
2385 *p_size -= num_bytes_to_read;
2390 gst_asf_demux_get_string (gchar ** p_str, guint16 * p_strlen,
2391 guint8 ** p_data, guint64 * p_size)
2401 s_length = gst_asf_demux_get_uint16 (p_data, p_size);
2404 *p_strlen = s_length;
2406 if (s_length == 0) {
2407 GST_WARNING ("zero-length string");
2408 *p_str = g_strdup ("");
2412 if (!gst_asf_demux_get_bytes (&s, s_length, p_data, p_size))
2415 g_assert (s != NULL);
2417 /* just because They don't exist doesn't
2418 * mean They are not out to get you ... */
2419 if (s[s_length - 1] != '\0') {
2420 s = g_realloc (s, s_length + 1);
2424 *p_str = (gchar *) s;
2430 gst_asf_demux_get_guid (ASFGuid * guid, guint8 ** p_data, guint64 * p_size)
2432 g_assert (*p_size >= 4 * sizeof (guint32));
2434 guid->v1 = gst_asf_demux_get_uint32 (p_data, p_size);
2435 guid->v2 = gst_asf_demux_get_uint32 (p_data, p_size);
2436 guid->v3 = gst_asf_demux_get_uint32 (p_data, p_size);
2437 guid->v4 = gst_asf_demux_get_uint32 (p_data, p_size);
2441 gst_asf_demux_get_stream_audio (asf_stream_audio * audio, guint8 ** p_data,
2444 if (*p_size < (2 + 2 + 4 + 4 + 2 + 2 + 2))
2447 /* WAVEFORMATEX Structure */
2448 audio->codec_tag = gst_asf_demux_get_uint16 (p_data, p_size);
2449 audio->channels = gst_asf_demux_get_uint16 (p_data, p_size);
2450 audio->sample_rate = gst_asf_demux_get_uint32 (p_data, p_size);
2451 audio->byte_rate = gst_asf_demux_get_uint32 (p_data, p_size);
2452 audio->block_align = gst_asf_demux_get_uint16 (p_data, p_size);
2453 audio->word_size = gst_asf_demux_get_uint16 (p_data, p_size);
2454 /* Codec specific data size */
2455 audio->size = gst_asf_demux_get_uint16 (p_data, p_size);
2460 gst_asf_demux_get_stream_video (asf_stream_video * video, guint8 ** p_data,
2463 if (*p_size < (4 + 4 + 1 + 2))
2466 video->width = gst_asf_demux_get_uint32 (p_data, p_size);
2467 video->height = gst_asf_demux_get_uint32 (p_data, p_size);
2468 video->unknown = gst_asf_demux_get_uint8 (p_data, p_size);
2469 video->size = gst_asf_demux_get_uint16 (p_data, p_size);
2474 gst_asf_demux_get_stream_video_format (asf_stream_video_format * fmt,
2475 guint8 ** p_data, guint64 * p_size)
2477 if (*p_size < (4 + 4 + 4 + 2 + 2 + 4 + 4 + 4 + 4 + 4 + 4))
2480 fmt->size = gst_asf_demux_get_uint32 (p_data, p_size);
2481 fmt->width = gst_asf_demux_get_uint32 (p_data, p_size);
2482 fmt->height = gst_asf_demux_get_uint32 (p_data, p_size);
2483 fmt->planes = gst_asf_demux_get_uint16 (p_data, p_size);
2484 fmt->depth = gst_asf_demux_get_uint16 (p_data, p_size);
2485 fmt->tag = gst_asf_demux_get_uint32 (p_data, p_size);
2486 fmt->image_size = gst_asf_demux_get_uint32 (p_data, p_size);
2487 fmt->xpels_meter = gst_asf_demux_get_uint32 (p_data, p_size);
2488 fmt->ypels_meter = gst_asf_demux_get_uint32 (p_data, p_size);
2489 fmt->num_colors = gst_asf_demux_get_uint32 (p_data, p_size);
2490 fmt->imp_colors = gst_asf_demux_get_uint32 (p_data, p_size);
2495 gst_asf_demux_get_stream (GstASFDemux * demux, guint16 id)
2499 for (i = 0; i < demux->num_streams; i++) {
2500 if (demux->stream[i].id == id)
2501 return &demux->stream[i];
2504 if (gst_asf_demux_is_unknown_stream (demux, id))
2505 GST_WARNING ("Segment found for undefined stream: (%d)", id);
2510 gst_asf_demux_setup_pad (GstASFDemux * demux, GstPad * src_pad,
2511 GstCaps * caps, guint16 id, gboolean is_video, GstBuffer * streamheader,
2516 gst_pad_use_fixed_caps (src_pad);
2517 gst_pad_set_caps (src_pad, caps);
2519 gst_pad_set_event_function (src_pad,
2520 GST_DEBUG_FUNCPTR (gst_asf_demux_handle_src_event));
2521 gst_pad_set_query_function (src_pad,
2522 GST_DEBUG_FUNCPTR (gst_asf_demux_handle_src_query));
2524 stream = &demux->stream[demux->num_streams];
2525 stream->caps = caps;
2526 stream->pad = src_pad;
2528 stream->fps_known = !is_video; /* bit hacky for audio */
2529 stream->is_video = is_video;
2530 stream->pending_tags = tags;
2531 stream->discont = TRUE;
2532 stream->first_buffer = TRUE;
2533 stream->streamheader = streamheader;
2534 if (stream->streamheader) {
2535 stream->streamheader = gst_buffer_make_writable (streamheader);
2536 GST_BUFFER_FLAG_SET (stream->streamheader, GST_BUFFER_FLAG_HEADER);
2541 st = gst_caps_get_structure (caps, 0);
2542 if (gst_structure_get_fraction (st, "pixel-aspect-ratio", &par_x, &par_y) &&
2543 par_x > 0 && par_y > 0) {
2544 GST_DEBUG ("PAR %d/%d", par_x, par_y);
2545 stream->par_x = par_x;
2546 stream->par_y = par_y;
2550 stream->payloads = g_array_new (FALSE, FALSE, sizeof (AsfPayload));
2552 /* TODO: create this array during reverse play? */
2553 stream->payloads_rev = g_array_new (FALSE, FALSE, sizeof (AsfPayload));
2555 GST_INFO ("Created pad %s for stream %u with caps %" GST_PTR_FORMAT,
2556 GST_PAD_NAME (src_pad), demux->num_streams, caps);
2558 ++demux->num_streams;
2560 stream->active = FALSE;
2566 gst_asf_demux_add_stream_headers_to_caps (GstASFDemux * demux,
2567 GstBuffer * buffer, GstStructure * structure)
2569 GValue arr_val = G_VALUE_INIT;
2570 GValue buf_val = G_VALUE_INIT;
2572 g_value_init (&arr_val, GST_TYPE_ARRAY);
2573 g_value_init (&buf_val, GST_TYPE_BUFFER);
2575 gst_value_set_buffer (&buf_val, buffer);
2576 gst_value_array_append_and_take_value (&arr_val, &buf_val);
2578 gst_structure_take_value (structure, "streamheader", &arr_val);
2582 gst_asf_demux_add_audio_stream (GstASFDemux * demux,
2583 asf_stream_audio * audio, guint16 id, guint8 ** p_data, guint64 * p_size)
2585 GstTagList *tags = NULL;
2586 GstBuffer *extradata = NULL;
2589 guint16 size_left = 0;
2590 gchar *codec_name = NULL;
2593 size_left = audio->size;
2595 /* Create the audio pad */
2596 name = g_strdup_printf ("audio_%u", demux->num_audio_streams);
2598 src_pad = gst_pad_new_from_static_template (&audio_src_template, name);
2601 /* Swallow up any left over data and set up the
2602 * standard properties from the header info */
2604 GST_INFO_OBJECT (demux, "Audio header contains %d bytes of "
2605 "codec specific data", size_left);
2607 g_assert (size_left <= *p_size);
2608 gst_asf_demux_get_buffer (&extradata, size_left, p_data, p_size);
2611 /* asf_stream_audio is the same as gst_riff_strf_auds, but with an
2612 * additional two bytes indicating extradata. */
2613 /* FIXME: Handle the channel reorder map here */
2614 caps = gst_riff_create_audio_caps (audio->codec_tag, NULL,
2615 (gst_riff_strf_auds *) audio, extradata, NULL, &codec_name, NULL);
2618 caps = gst_caps_new_simple ("audio/x-asf-unknown", "codec_id",
2619 G_TYPE_INT, (gint) audio->codec_tag, NULL);
2622 /* Informing about that audio format we just added */
2624 tags = gst_tag_list_new (GST_TAG_AUDIO_CODEC, codec_name, NULL);
2625 g_free (codec_name);
2628 if (audio->byte_rate > 0) {
2629 /* Some ASF files have no bitrate props object (often seen with
2630 * ASF files that contain raw audio data). Example files can
2631 * be generated with FFmpeg (tested with v2.8.6), like this:
2633 * ffmpeg -i sine-wave.wav -c:a pcm_alaw file.asf
2635 * In this case, if audio->byte_rate is nonzero, use that as
2638 guint bitrate = audio->byte_rate * 8;
2641 tags = gst_tag_list_new_empty ();
2643 /* Add bitrate, but only if there is none set already, since
2644 * this is just a fallback in case there is no bitrate tag
2645 * already present */
2646 gst_tag_list_add (tags, GST_TAG_MERGE_KEEP, GST_TAG_BITRATE, bitrate, NULL);
2650 gst_buffer_unref (extradata);
2652 GST_INFO ("Adding audio stream #%u, id %u codec %u (0x%04x), tags=%"
2653 GST_PTR_FORMAT, demux->num_audio_streams, id, audio->codec_tag,
2654 audio->codec_tag, tags);
2656 ++demux->num_audio_streams;
2658 return gst_asf_demux_setup_pad (demux, src_pad, caps, id, FALSE, NULL, tags);
2662 gst_asf_demux_add_video_stream (GstASFDemux * demux,
2663 asf_stream_video_format * video, guint16 id,
2664 guint8 ** p_data, guint64 * p_size)
2666 GstTagList *tags = NULL;
2667 GstStructure *caps_s;
2668 GstBuffer *extradata = NULL;
2673 gchar *codec_name = NULL;
2674 gint size_left = video->size - 40;
2675 GstBuffer *streamheader = NULL;
2676 guint par_w = 1, par_h = 1;
2678 /* Create the video pad */
2679 name = g_strdup_printf ("video_%u", demux->num_video_streams);
2680 src_pad = gst_pad_new_from_static_template (&video_src_template, name);
2683 /* Now try some gstreamer formatted MIME types (from gst_avi_demux_strf_vids) */
2685 GST_LOG ("Video header has %d bytes of codec specific data", size_left);
2686 g_assert (size_left <= *p_size);
2687 gst_asf_demux_get_buffer (&extradata, size_left, p_data, p_size);
2690 GST_DEBUG ("video codec %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (video->tag));
2692 /* yes, asf_stream_video_format and gst_riff_strf_vids are the same */
2693 caps = gst_riff_create_video_caps (video->tag, NULL,
2694 (gst_riff_strf_vids *) video, extradata, NULL, &codec_name);
2697 caps = gst_caps_new_simple ("video/x-asf-unknown", "fourcc",
2698 G_TYPE_UINT, video->tag, NULL);
2703 s = gst_asf_demux_get_metadata_for_stream (demux, id);
2704 if (gst_structure_get_int (s, "AspectRatioX", &ax) &&
2705 gst_structure_get_int (s, "AspectRatioY", &ay) && (ax > 0 && ay > 0)) {
2708 gst_caps_set_simple (caps, "pixel-aspect-ratio", GST_TYPE_FRACTION,
2712 /* retry with the global metadata */
2713 GST_DEBUG ("Retrying with global metadata %" GST_PTR_FORMAT,
2714 demux->global_metadata);
2715 s = demux->global_metadata;
2716 if (gst_structure_get_uint (s, "AspectRatioX", &ax) &&
2717 gst_structure_get_uint (s, "AspectRatioY", &ay)) {
2718 GST_DEBUG ("ax:%d, ay:%d", ax, ay);
2719 if (ax > 0 && ay > 0) {
2722 gst_caps_set_simple (caps, "pixel-aspect-ratio", GST_TYPE_FRACTION,
2727 s = gst_caps_get_structure (caps, 0);
2728 gst_structure_remove_field (s, "framerate");
2731 caps_s = gst_caps_get_structure (caps, 0);
2733 /* add format field with fourcc to WMV/VC1 caps to differentiate variants */
2734 if (gst_structure_has_name (caps_s, "video/x-wmv")) {
2735 str = g_strdup_printf ("%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (video->tag));
2736 gst_caps_set_simple (caps, "format", G_TYPE_STRING, str, NULL);
2739 /* check if h264 has codec_data (avc) or streamheaders (bytestream) */
2740 } else if (gst_structure_has_name (caps_s, "video/x-h264")) {
2741 const GValue *value = gst_structure_get_value (caps_s, "codec_data");
2743 GstBuffer *buf = gst_value_get_buffer (value);
2746 if (gst_buffer_map (buf, &mapinfo, GST_MAP_READ)) {
2747 if (mapinfo.size >= 4 && GST_READ_UINT32_BE (mapinfo.data) == 1) {
2748 /* this looks like a bytestream start */
2749 streamheader = gst_buffer_ref (buf);
2750 gst_asf_demux_add_stream_headers_to_caps (demux, buf, caps_s);
2751 gst_structure_remove_field (caps_s, "codec_data");
2754 gst_buffer_unmap (buf, &mapinfo);
2759 /* For a 3D video, set multiview information into the caps based on
2760 * what was detected during object parsing */
2761 if (demux->asf_3D_mode != GST_ASF_3D_NONE) {
2762 GstVideoMultiviewMode mv_mode = GST_VIDEO_MULTIVIEW_MODE_NONE;
2763 GstVideoMultiviewFlags mv_flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
2764 const gchar *mview_mode_str;
2766 switch (demux->asf_3D_mode) {
2767 case GST_ASF_3D_SIDE_BY_SIDE_HALF_LR:
2768 mv_mode = GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE;
2770 case GST_ASF_3D_SIDE_BY_SIDE_HALF_RL:
2771 mv_mode = GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE;
2772 mv_flags = GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST;
2774 case GST_ASF_3D_TOP_AND_BOTTOM_HALF_LR:
2775 mv_mode = GST_VIDEO_MULTIVIEW_MODE_TOP_BOTTOM;
2777 case GST_ASF_3D_TOP_AND_BOTTOM_HALF_RL:
2778 mv_mode = GST_VIDEO_MULTIVIEW_MODE_TOP_BOTTOM;
2779 mv_flags = GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST;
2781 case GST_ASF_3D_DUAL_STREAM:{
2782 gboolean is_right_view = FALSE;
2783 /* if Advanced_Mutual_Exclusion object exists, use it
2784 * to figure out which is the left view (lower ID) */
2785 if (demux->mut_ex_streams != NULL) {
2789 length = g_slist_length (demux->mut_ex_streams);
2791 for (i = 0; i < length; i++) {
2794 v_s_id = g_slist_nth_data (demux->mut_ex_streams, i);
2796 GST_DEBUG_OBJECT (demux,
2797 "has Mutual_Exclusion object. stream id in object is %d",
2798 GPOINTER_TO_INT (v_s_id));
2800 if (id > GPOINTER_TO_INT (v_s_id))
2801 is_right_view = TRUE;
2804 /* if the Advaced_Mutual_Exclusion object doesn't exist, assume the
2805 * first video stream encountered has the lower ID */
2806 if (demux->num_video_streams > 0) {
2807 /* This is not the first video stream, assuming right eye view */
2808 is_right_view = TRUE;
2812 mv_mode = GST_VIDEO_MULTIVIEW_MODE_RIGHT;
2814 mv_mode = GST_VIDEO_MULTIVIEW_MODE_LEFT;
2821 GST_INFO_OBJECT (demux,
2822 "stream_id %d, has multiview-mode %d flags 0x%x", id, mv_mode,
2825 mview_mode_str = gst_video_multiview_mode_to_caps_string (mv_mode);
2826 if (mview_mode_str != NULL) {
2827 if (gst_video_multiview_guess_half_aspect (mv_mode, video->width,
2828 video->height, par_w, par_h))
2829 mv_flags |= GST_VIDEO_MULTIVIEW_FLAGS_HALF_ASPECT;
2831 gst_caps_set_simple (caps,
2832 "multiview-mode", G_TYPE_STRING, mview_mode_str,
2833 "multiview-flags", GST_TYPE_VIDEO_MULTIVIEW_FLAGSET, mv_flags,
2834 GST_FLAG_SET_MASK_EXACT, NULL);
2839 tags = gst_tag_list_new (GST_TAG_VIDEO_CODEC, codec_name, NULL);
2840 g_free (codec_name);
2844 gst_buffer_unref (extradata);
2846 GST_INFO ("Adding video stream #%u, id %u, codec %"
2847 GST_FOURCC_FORMAT " (0x%08x)", demux->num_video_streams, id,
2848 GST_FOURCC_ARGS (video->tag), video->tag);
2850 ++demux->num_video_streams;
2852 return gst_asf_demux_setup_pad (demux, src_pad, caps, id, TRUE,
2853 streamheader, tags);
2857 gst_asf_demux_activate_stream (GstASFDemux * demux, AsfStream * stream)
2859 if (!stream->active) {
2863 GST_INFO_OBJECT (demux, "Activating stream %2u, pad %s, caps %"
2864 GST_PTR_FORMAT, stream->id, GST_PAD_NAME (stream->pad), stream->caps);
2865 gst_pad_set_active (stream->pad, TRUE);
2868 gst_pad_create_stream_id_printf (stream->pad, GST_ELEMENT_CAST (demux),
2869 "%03u", stream->id);
2872 gst_pad_get_sticky_event (demux->sinkpad, GST_EVENT_STREAM_START, 0);
2874 if (gst_event_parse_group_id (event, &demux->group_id))
2875 demux->have_group_id = TRUE;
2877 demux->have_group_id = FALSE;
2878 gst_event_unref (event);
2879 } else if (!demux->have_group_id) {
2880 demux->have_group_id = TRUE;
2881 demux->group_id = gst_util_group_id_next ();
2884 event = gst_event_new_stream_start (stream_id);
2885 if (demux->have_group_id)
2886 gst_event_set_group_id (event, demux->group_id);
2888 gst_pad_push_event (stream->pad, event);
2890 gst_pad_set_caps (stream->pad, stream->caps);
2892 gst_element_add_pad (GST_ELEMENT_CAST (demux), stream->pad);
2893 gst_flow_combiner_add_pad (demux->flowcombiner, stream->pad);
2894 stream->active = TRUE;
2899 gst_asf_demux_parse_stream_object (GstASFDemux * demux, guint8 * data,
2902 AsfCorrectionType correction_type;
2903 AsfStreamType stream_type;
2904 GstClockTime time_offset;
2905 gboolean is_encrypted G_GNUC_UNUSED;
2909 guint stream_specific_size;
2910 guint type_specific_size G_GNUC_UNUSED;
2911 guint unknown G_GNUC_UNUSED;
2912 gboolean inspect_payload = FALSE;
2913 AsfStream *stream = NULL;
2915 /* Get the rest of the header's header */
2916 if (size < (16 + 16 + 8 + 4 + 4 + 2 + 4))
2917 goto not_enough_data;
2919 gst_asf_demux_get_guid (&guid, &data, &size);
2920 stream_type = gst_asf_demux_identify_guid (asf_stream_guids, &guid);
2922 gst_asf_demux_get_guid (&guid, &data, &size);
2923 correction_type = gst_asf_demux_identify_guid (asf_correction_guids, &guid);
2925 time_offset = gst_asf_demux_get_uint64 (&data, &size) * 100;
2927 type_specific_size = gst_asf_demux_get_uint32 (&data, &size);
2928 stream_specific_size = gst_asf_demux_get_uint32 (&data, &size);
2930 flags = gst_asf_demux_get_uint16 (&data, &size);
2931 stream_id = flags & 0x7f;
2932 is_encrypted = ! !((flags & 0x8000) << 15);
2933 unknown = gst_asf_demux_get_uint32 (&data, &size);
2935 GST_DEBUG_OBJECT (demux, "Found stream %u, time_offset=%" GST_TIME_FORMAT,
2936 stream_id, GST_TIME_ARGS (time_offset));
2938 /* dvr-ms has audio stream declared in stream specific data */
2939 if (stream_type == ASF_STREAM_EXT_EMBED_HEADER) {
2940 AsfExtStreamType ext_stream_type;
2941 gst_asf_demux_get_guid (&guid, &data, &size);
2942 ext_stream_type = gst_asf_demux_identify_guid (asf_ext_stream_guids, &guid);
2944 if (ext_stream_type == ASF_EXT_STREAM_AUDIO) {
2945 inspect_payload = TRUE;
2947 gst_asf_demux_get_guid (&guid, &data, &size);
2948 gst_asf_demux_get_uint32 (&data, &size);
2949 gst_asf_demux_get_uint32 (&data, &size);
2950 gst_asf_demux_get_uint32 (&data, &size);
2951 gst_asf_demux_get_guid (&guid, &data, &size);
2952 gst_asf_demux_get_uint32 (&data, &size);
2953 stream_type = ASF_STREAM_AUDIO;
2957 switch (stream_type) {
2958 case ASF_STREAM_AUDIO:{
2959 asf_stream_audio audio_object;
2961 if (!gst_asf_demux_get_stream_audio (&audio_object, &data, &size))
2962 goto not_enough_data;
2964 GST_INFO ("Object is an audio stream with %u bytes of additional data",
2967 stream = gst_asf_demux_add_audio_stream (demux, &audio_object, stream_id,
2970 switch (correction_type) {
2971 case ASF_CORRECTION_ON:{
2972 guint span, packet_size, chunk_size, data_size, silence_data;
2974 GST_INFO ("Using error correction");
2976 if (size < (1 + 2 + 2 + 2 + 1))
2977 goto not_enough_data;
2979 span = gst_asf_demux_get_uint8 (&data, &size);
2980 packet_size = gst_asf_demux_get_uint16 (&data, &size);
2981 chunk_size = gst_asf_demux_get_uint16 (&data, &size);
2982 data_size = gst_asf_demux_get_uint16 (&data, &size);
2983 silence_data = gst_asf_demux_get_uint8 (&data, &size);
2985 stream->span = span;
2987 GST_DEBUG_OBJECT (demux, "Descrambling ps:%u cs:%u ds:%u s:%u sd:%u",
2988 packet_size, chunk_size, data_size, span, silence_data);
2990 if (stream->span > 1) {
2991 if (chunk_size == 0 || ((packet_size / chunk_size) <= 1)) {
2992 /* Disable descrambling */
2995 /* FIXME: this else branch was added for
2996 * weird_al_yankovic - the saga begins.asf */
2997 stream->ds_packet_size = packet_size;
2998 stream->ds_chunk_size = chunk_size;
3001 /* Descambling is enabled */
3002 stream->ds_packet_size = packet_size;
3003 stream->ds_chunk_size = chunk_size;
3006 /* Now skip the rest of the silence data */
3008 gst_bytestream_flush (demux->bs, data_size - 1);
3010 /* FIXME: CHECKME. And why -1? */
3011 if (data_size > 1) {
3012 if (!gst_asf_demux_skip_bytes (data_size - 1, &data, &size)) {
3013 goto not_enough_data;
3019 case ASF_CORRECTION_OFF:{
3020 GST_INFO ("Error correction off");
3021 if (!gst_asf_demux_skip_bytes (stream_specific_size, &data, &size))
3022 goto not_enough_data;
3026 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3027 ("Audio stream using unknown error correction"));
3034 case ASF_STREAM_VIDEO:{
3035 asf_stream_video_format video_format_object;
3036 asf_stream_video video_object;
3039 if (!gst_asf_demux_get_stream_video (&video_object, &data, &size))
3040 goto not_enough_data;
3042 vsize = video_object.size - 40; /* Byte order gets offset by single byte */
3044 GST_INFO ("object is a video stream with %u bytes of "
3045 "additional data", vsize);
3047 if (!gst_asf_demux_get_stream_video_format (&video_format_object,
3049 goto not_enough_data;
3052 stream = gst_asf_demux_add_video_stream (demux, &video_format_object,
3053 stream_id, &data, &size);
3059 GST_WARNING_OBJECT (demux, "Unknown stream type for stream %u",
3061 demux->other_streams =
3062 g_slist_append (demux->other_streams, GINT_TO_POINTER (stream_id));
3067 stream->inspect_payload = inspect_payload;
3072 GST_WARNING_OBJECT (demux, "Unexpected end of data parsing stream object");
3073 /* we'll error out later if we found no streams */
3078 static const gchar *
3079 gst_asf_demux_get_gst_tag_from_tag_name (const gchar * name_utf8)
3083 const gchar *asf_name;
3084 const gchar *gst_name;
3087 "WM/Genre", GST_TAG_GENRE}, {
3088 "WM/AlbumTitle", GST_TAG_ALBUM}, {
3089 "WM/AlbumArtist", GST_TAG_ARTIST}, {
3090 "WM/Picture", GST_TAG_IMAGE}, {
3091 "WM/Track", GST_TAG_TRACK_NUMBER}, {
3092 "WM/TrackNumber", GST_TAG_TRACK_NUMBER}, {
3093 "WM/Year", GST_TAG_DATE_TIME}
3094 /* { "WM/Composer", GST_TAG_COMPOSER } */
3099 if (name_utf8 == NULL) {
3100 GST_WARNING ("Failed to convert name to UTF8, skipping");
3104 out = strlen (name_utf8);
3106 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
3107 if (strncmp (tags[i].asf_name, name_utf8, out) == 0) {
3108 GST_LOG ("map tagname '%s' -> '%s'", name_utf8, tags[i].gst_name);
3109 return tags[i].gst_name;
3116 /* gst_asf_demux_add_global_tags() takes ownership of taglist! */
3118 gst_asf_demux_add_global_tags (GstASFDemux * demux, GstTagList * taglist)
3122 GST_DEBUG_OBJECT (demux, "adding global tags: %" GST_PTR_FORMAT, taglist);
3124 if (taglist == NULL)
3127 if (gst_tag_list_is_empty (taglist)) {
3128 gst_tag_list_unref (taglist);
3132 t = gst_tag_list_merge (demux->taglist, taglist, GST_TAG_MERGE_APPEND);
3133 gst_tag_list_set_scope (t, GST_TAG_SCOPE_GLOBAL);
3135 gst_tag_list_unref (demux->taglist);
3136 gst_tag_list_unref (taglist);
3138 GST_LOG_OBJECT (demux, "global tags now: %" GST_PTR_FORMAT, demux->taglist);
3141 #define ASF_DEMUX_DATA_TYPE_UTF16LE_STRING 0
3142 #define ASF_DEMUX_DATA_TYPE_BYTE_ARRAY 1
3143 #define ASF_DEMUX_DATA_TYPE_BOOL 2
3144 #define ASF_DEMUX_DATA_TYPE_DWORD 3
3147 asf_demux_parse_picture_tag (GstTagList * tags, const guint8 * tag_data,
3151 const guint8 *img_data = NULL;
3152 guint32 img_data_len = 0;
3153 guint8 pic_type = 0;
3155 gst_byte_reader_init (&r, tag_data, tag_data_len);
3157 /* skip mime type string (we don't trust it and do our own typefinding),
3158 * and also skip the description string, since we don't use it */
3159 if (!gst_byte_reader_get_uint8 (&r, &pic_type) ||
3160 !gst_byte_reader_get_uint32_le (&r, &img_data_len) ||
3161 !gst_byte_reader_skip_string_utf16 (&r) ||
3162 !gst_byte_reader_skip_string_utf16 (&r) ||
3163 !gst_byte_reader_get_data (&r, img_data_len, &img_data)) {
3164 goto not_enough_data;
3168 if (!gst_tag_list_add_id3_image (tags, img_data, img_data_len, pic_type))
3169 GST_DEBUG ("failed to add image extracted from WM/Picture tag to taglist");
3175 GST_DEBUG ("Failed to read WM/Picture tag: not enough data");
3176 GST_MEMDUMP ("WM/Picture data", tag_data, tag_data_len);
3181 /* Extended Content Description Object */
3182 static GstFlowReturn
3183 gst_asf_demux_process_ext_content_desc (GstASFDemux * demux, guint8 * data,
3186 /* Other known (and unused) 'text/unicode' metadata available :
3189 * WM/MediaPrimaryClassID = {D1607DBC-E323-4BE2-86A1-48A42A28441E}
3190 * WMFSDKVersion = 9.00.00.2980
3191 * WMFSDKNeeded = 0.0.0.0000
3192 * WM/UniqueFileIdentifier = AMGa_id=R 15334;AMGp_id=P 5149;AMGt_id=T 2324984
3193 * WM/Publisher = 4AD
3195 * WM/ProviderRating = 8
3196 * WM/ProviderStyle = Rock (similar to WM/Genre)
3197 * WM/GenreID (similar to WM/Genre)
3198 * WM/TrackNumber (same as WM/Track but as a string)
3200 * Other known (and unused) 'non-text' metadata available :
3206 * We might want to read WM/TrackNumber and use atoi() if we don't have
3210 GstTagList *taglist;
3211 guint16 blockcount, i;
3212 gboolean content3D = FALSE;
3216 const gchar *interleave_name;
3217 GstASF3DMode interleaving_type;
3218 } stereoscopic_layout_map[] = {
3220 "SideBySideRF", GST_ASF_3D_SIDE_BY_SIDE_HALF_RL}, {
3221 "SideBySideLF", GST_ASF_3D_SIDE_BY_SIDE_HALF_LR}, {
3222 "OverUnderRT", GST_ASF_3D_TOP_AND_BOTTOM_HALF_RL}, {
3223 "OverUnderLT", GST_ASF_3D_TOP_AND_BOTTOM_HALF_LR}, {
3224 "DualStream", GST_ASF_3D_DUAL_STREAM}
3226 GST_INFO_OBJECT (demux, "object is an extended content description");
3228 taglist = gst_tag_list_new_empty ();
3230 /* Content Descriptor Count */
3232 goto not_enough_data;
3234 blockcount = gst_asf_demux_get_uint16 (&data, &size);
3236 for (i = 1; i <= blockcount; ++i) {
3237 const gchar *gst_tag_name;
3241 GValue tag_value = { 0, };
3244 gchar *name_utf8 = NULL;
3248 if (!gst_asf_demux_get_string (&name, &name_len, &data, &size))
3249 goto not_enough_data;
3253 goto not_enough_data;
3255 /* Descriptor Value Data Type */
3256 datatype = gst_asf_demux_get_uint16 (&data, &size);
3258 /* Descriptor Value (not really a string, but same thing reading-wise) */
3259 if (!gst_asf_demux_get_string (&value, &value_len, &data, &size)) {
3261 goto not_enough_data;
3265 g_convert (name, name_len, "UTF-8", "UTF-16LE", &in, &out, NULL);
3267 if (name_utf8 != NULL) {
3268 GST_DEBUG ("Found tag/metadata %s", name_utf8);
3270 gst_tag_name = gst_asf_demux_get_gst_tag_from_tag_name (name_utf8);
3271 GST_DEBUG ("gst_tag_name %s", GST_STR_NULL (gst_tag_name));
3274 case ASF_DEMUX_DATA_TYPE_UTF16LE_STRING:{
3277 value_utf8 = g_convert (value, value_len, "UTF-8", "UTF-16LE",
3280 /* get rid of tags with empty value */
3281 if (value_utf8 != NULL && *value_utf8 != '\0') {
3282 GST_DEBUG ("string value %s", value_utf8);
3284 value_utf8[out] = '\0';
3286 if (gst_tag_name != NULL) {
3287 if (strcmp (gst_tag_name, GST_TAG_DATE_TIME) == 0) {
3288 guint year = atoi (value_utf8);
3291 g_value_init (&tag_value, GST_TYPE_DATE_TIME);
3292 g_value_take_boxed (&tag_value, gst_date_time_new_y (year));
3294 } else if (strcmp (gst_tag_name, GST_TAG_GENRE) == 0) {
3295 guint id3v1_genre_id;
3296 const gchar *genre_str;
3298 if (sscanf (value_utf8, "(%u)", &id3v1_genre_id) == 1 &&
3299 ((genre_str = gst_tag_id3_genre_get (id3v1_genre_id)))) {
3300 GST_DEBUG ("Genre: %s -> %s", value_utf8, genre_str);
3301 g_free (value_utf8);
3302 value_utf8 = g_strdup (genre_str);
3307 /* convert tag from string to other type if required */
3308 tag_type = gst_tag_get_type (gst_tag_name);
3309 g_value_init (&tag_value, tag_type);
3310 if (!gst_value_deserialize (&tag_value, value_utf8)) {
3311 GValue from_val = { 0, };
3313 g_value_init (&from_val, G_TYPE_STRING);
3314 g_value_set_string (&from_val, value_utf8);
3315 if (!g_value_transform (&from_val, &tag_value)) {
3316 GST_WARNING_OBJECT (demux,
3317 "Could not transform string tag to " "%s tag type %s",
3318 gst_tag_name, g_type_name (tag_type));
3319 g_value_unset (&tag_value);
3321 g_value_unset (&from_val);
3326 GST_DEBUG ("Setting metadata");
3327 g_value_init (&tag_value, G_TYPE_STRING);
3328 g_value_set_string (&tag_value, value_utf8);
3329 /* If we found a stereoscopic marker, look for StereoscopicLayout
3333 if (strncmp ("StereoscopicLayout", name_utf8,
3334 strlen (name_utf8)) == 0) {
3335 for (i = 0; i < G_N_ELEMENTS (stereoscopic_layout_map); i++) {
3336 if (g_str_equal (stereoscopic_layout_map[i].interleave_name,
3338 demux->asf_3D_mode =
3339 stereoscopic_layout_map[i].interleaving_type;
3340 GST_INFO ("find interleave type %u", demux->asf_3D_mode);
3344 GST_INFO_OBJECT (demux, "3d type is %u", demux->asf_3D_mode);
3346 demux->asf_3D_mode = GST_ASF_3D_NONE;
3347 GST_INFO_OBJECT (demux, "None 3d type");
3350 } else if (value_utf8 == NULL) {
3351 GST_WARNING ("Failed to convert string value to UTF8, skipping");
3353 GST_DEBUG ("Skipping empty string value for %s",
3354 GST_STR_NULL (gst_tag_name));
3356 g_free (value_utf8);
3359 case ASF_DEMUX_DATA_TYPE_BYTE_ARRAY:{
3361 if (!g_str_equal (gst_tag_name, GST_TAG_IMAGE)) {
3362 GST_FIXME ("Unhandled byte array tag %s",
3363 GST_STR_NULL (gst_tag_name));
3366 asf_demux_parse_picture_tag (taglist, (guint8 *) value,
3372 case ASF_DEMUX_DATA_TYPE_DWORD:{
3373 guint uint_val = GST_READ_UINT32_LE (value);
3375 /* this is the track number */
3376 g_value_init (&tag_value, G_TYPE_UINT);
3378 /* WM/Track counts from 0 */
3379 if (!strcmp (name_utf8, "WM/Track"))
3382 g_value_set_uint (&tag_value, uint_val);
3386 case ASF_DEMUX_DATA_TYPE_BOOL:{
3387 gboolean bool_val = GST_READ_UINT32_LE (value);
3389 if (strncmp ("Stereoscopic", name_utf8, strlen (name_utf8)) == 0) {
3391 GST_INFO_OBJECT (demux, "This is 3D contents");
3394 GST_INFO_OBJECT (demux, "This is not 3D contenst");
3402 GST_DEBUG ("Skipping tag %s of type %d", gst_tag_name, datatype);
3407 if (G_IS_VALUE (&tag_value)) {
3409 GstTagMergeMode merge_mode = GST_TAG_MERGE_APPEND;
3411 /* WM/TrackNumber is more reliable than WM/Track, since the latter
3412 * is supposed to have a 0 base but is often wrongly written to start
3413 * from 1 as well, so prefer WM/TrackNumber when we have it: either
3414 * replace the value added earlier from WM/Track or put it first in
3415 * the list, so that it will get picked up by _get_uint() */
3416 if (strcmp (name_utf8, "WM/TrackNumber") == 0)
3417 merge_mode = GST_TAG_MERGE_REPLACE;
3419 gst_tag_list_add_values (taglist, merge_mode, gst_tag_name,
3422 GST_DEBUG ("Setting global metadata %s", name_utf8);
3423 gst_structure_set_value (demux->global_metadata, name_utf8,
3427 g_value_unset (&tag_value);
3436 gst_asf_demux_add_global_tags (demux, taglist);
3443 GST_WARNING ("Unexpected end of data parsing ext content desc object");
3444 gst_tag_list_unref (taglist);
3445 return GST_FLOW_OK; /* not really fatal */
3449 static GstStructure *
3450 gst_asf_demux_get_metadata_for_stream (GstASFDemux * demux, guint stream_num)
3455 g_snprintf (sname, sizeof (sname), "stream-%u", stream_num);
3457 for (i = 0; i < gst_caps_get_size (demux->metadata); ++i) {
3460 s = gst_caps_get_structure (demux->metadata, i);
3461 if (gst_structure_has_name (s, sname))
3465 gst_caps_append_structure (demux->metadata, gst_structure_new_empty (sname));
3467 /* try lookup again; demux->metadata took ownership of the structure, so we
3468 * can't really make any assumptions about what happened to it, so we can't
3469 * just return it directly after appending it */
3470 return gst_asf_demux_get_metadata_for_stream (demux, stream_num);
3473 static GstFlowReturn
3474 gst_asf_demux_process_metadata (GstASFDemux * demux, guint8 * data,
3477 guint16 blockcount, i;
3479 GST_INFO_OBJECT (demux, "object is a metadata object");
3481 /* Content Descriptor Count */
3483 goto not_enough_data;
3485 blockcount = gst_asf_demux_get_uint16 (&data, &size);
3487 for (i = 0; i < blockcount; ++i) {
3489 guint16 stream_num, name_len, data_type, lang_idx G_GNUC_UNUSED;
3490 guint32 data_len, ival;
3493 if (size < (2 + 2 + 2 + 2 + 4))
3494 goto not_enough_data;
3496 lang_idx = gst_asf_demux_get_uint16 (&data, &size);
3497 stream_num = gst_asf_demux_get_uint16 (&data, &size);
3498 name_len = gst_asf_demux_get_uint16 (&data, &size);
3499 data_type = gst_asf_demux_get_uint16 (&data, &size);
3500 data_len = gst_asf_demux_get_uint32 (&data, &size);
3502 if (size < name_len + data_len)
3503 goto not_enough_data;
3505 /* convert name to UTF-8 */
3506 name_utf8 = g_convert ((gchar *) data, name_len, "UTF-8", "UTF-16LE",
3508 gst_asf_demux_skip_bytes (name_len, &data, &size);
3510 if (name_utf8 == NULL) {
3511 GST_WARNING ("Failed to convert value name to UTF8, skipping");
3512 gst_asf_demux_skip_bytes (data_len, &data, &size);
3516 if (data_type != ASF_DEMUX_DATA_TYPE_DWORD) {
3517 gst_asf_demux_skip_bytes (data_len, &data, &size);
3525 goto not_enough_data;
3528 ival = gst_asf_demux_get_uint32 (&data, &size);
3530 /* skip anything else there may be, just in case */
3531 gst_asf_demux_skip_bytes (data_len - 4, &data, &size);
3533 s = gst_asf_demux_get_metadata_for_stream (demux, stream_num);
3534 gst_structure_set (s, name_utf8, G_TYPE_INT, ival, NULL);
3538 GST_INFO_OBJECT (demux, "metadata = %" GST_PTR_FORMAT, demux->metadata);
3544 GST_WARNING ("Unexpected end of data parsing metadata object");
3545 return GST_FLOW_OK; /* not really fatal */
3549 static GstFlowReturn
3550 gst_asf_demux_process_header (GstASFDemux * demux, guint8 * data, guint64 size)
3552 GstFlowReturn ret = GST_FLOW_OK;
3553 guint32 i, num_objects;
3554 guint8 unknown G_GNUC_UNUSED;
3556 /* Get the rest of the header's header */
3557 if (size < (4 + 1 + 1))
3558 goto not_enough_data;
3560 num_objects = gst_asf_demux_get_uint32 (&data, &size);
3561 unknown = gst_asf_demux_get_uint8 (&data, &size);
3562 unknown = gst_asf_demux_get_uint8 (&data, &size);
3564 GST_INFO_OBJECT (demux, "object is a header with %u parts", num_objects);
3566 /* Loop through the header's objects, processing those */
3567 for (i = 0; i < num_objects; ++i) {
3568 GST_INFO_OBJECT (demux, "reading header part %u", i);
3569 ret = gst_asf_demux_process_object (demux, &data, &size);
3570 if (ret != GST_FLOW_OK) {
3571 GST_WARNING ("process_object returned %s", gst_asf_get_flow_name (ret));
3580 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3581 ("short read parsing HEADER object"));
3582 return GST_FLOW_ERROR;
3586 static GstFlowReturn
3587 gst_asf_demux_process_file (GstASFDemux * demux, guint8 * data, guint64 size)
3589 guint64 creation_time G_GNUC_UNUSED;
3590 guint64 file_size G_GNUC_UNUSED;
3591 guint64 send_time G_GNUC_UNUSED;
3592 guint64 packets_count, play_time, preroll;
3593 guint32 flags, min_pktsize, max_pktsize, min_bitrate G_GNUC_UNUSED;
3595 if (size < (16 + 8 + 8 + 8 + 8 + 8 + 8 + 4 + 4 + 4 + 4))
3596 goto not_enough_data;
3598 gst_asf_demux_skip_bytes (16, &data, &size); /* skip GUID */
3599 file_size = gst_asf_demux_get_uint64 (&data, &size);
3600 creation_time = gst_asf_demux_get_uint64 (&data, &size);
3601 packets_count = gst_asf_demux_get_uint64 (&data, &size);
3602 play_time = gst_asf_demux_get_uint64 (&data, &size);
3603 send_time = gst_asf_demux_get_uint64 (&data, &size);
3604 preroll = gst_asf_demux_get_uint64 (&data, &size);
3605 flags = gst_asf_demux_get_uint32 (&data, &size);
3606 min_pktsize = gst_asf_demux_get_uint32 (&data, &size);
3607 max_pktsize = gst_asf_demux_get_uint32 (&data, &size);
3608 min_bitrate = gst_asf_demux_get_uint32 (&data, &size);
3610 demux->broadcast = ! !(flags & 0x01);
3611 demux->seekable = ! !(flags & 0x02);
3613 GST_DEBUG_OBJECT (demux, "min_pktsize = %u", min_pktsize);
3614 GST_DEBUG_OBJECT (demux, "flags::broadcast = %d", demux->broadcast);
3615 GST_DEBUG_OBJECT (demux, "flags::seekable = %d", demux->seekable);
3617 if (demux->broadcast) {
3618 /* these fields are invalid if the broadcast flag is set */
3623 if (min_pktsize != max_pktsize)
3624 goto non_fixed_packet_size;
3626 demux->packet_size = max_pktsize;
3628 /* FIXME: do we need send_time as well? what is it? */
3629 if ((play_time * 100) >= (preroll * GST_MSECOND))
3630 demux->play_time = (play_time * 100) - (preroll * GST_MSECOND);
3632 demux->play_time = 0;
3634 demux->preroll = preroll * GST_MSECOND;
3636 /* initial latency */
3637 demux->latency = demux->preroll;
3639 if (demux->play_time == 0)
3640 demux->seekable = FALSE;
3642 GST_DEBUG_OBJECT (demux, "play_time %" GST_TIME_FORMAT,
3643 GST_TIME_ARGS (demux->play_time));
3644 GST_DEBUG_OBJECT (demux, "preroll %" GST_TIME_FORMAT,
3645 GST_TIME_ARGS (demux->preroll));
3647 if (demux->play_time > 0) {
3648 demux->segment.duration = demux->play_time;
3651 GST_INFO ("object is a file with %" G_GUINT64_FORMAT " data packets",
3653 GST_INFO ("preroll = %" G_GUINT64_FORMAT, demux->preroll);
3658 non_fixed_packet_size:
3660 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3661 ("packet size must be fixed"));
3662 return GST_FLOW_ERROR;
3666 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3667 ("short read parsing FILE object"));
3668 return GST_FLOW_ERROR;
3672 /* Content Description Object */
3673 static GstFlowReturn
3674 gst_asf_demux_process_comment (GstASFDemux * demux, guint8 * data, guint64 size)
3678 const gchar *gst_tag;
3683 GST_TAG_TITLE, 0, NULL}, {
3684 GST_TAG_ARTIST, 0, NULL}, {
3685 GST_TAG_COPYRIGHT, 0, NULL}, {
3686 GST_TAG_DESCRIPTION, 0, NULL}, {
3687 GST_TAG_COMMENT, 0, NULL}
3689 GstTagList *taglist;
3690 GValue value = { 0 };
3694 GST_INFO_OBJECT (demux, "object is a comment");
3696 if (size < (2 + 2 + 2 + 2 + 2))
3697 goto not_enough_data;
3699 tags[0].val_length = gst_asf_demux_get_uint16 (&data, &size);
3700 tags[1].val_length = gst_asf_demux_get_uint16 (&data, &size);
3701 tags[2].val_length = gst_asf_demux_get_uint16 (&data, &size);
3702 tags[3].val_length = gst_asf_demux_get_uint16 (&data, &size);
3703 tags[4].val_length = gst_asf_demux_get_uint16 (&data, &size);
3705 GST_DEBUG_OBJECT (demux, "Comment lengths: title=%d author=%d copyright=%d "
3706 "description=%d rating=%d", tags[0].val_length, tags[1].val_length,
3707 tags[2].val_length, tags[3].val_length, tags[4].val_length);
3709 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
3710 if (size < tags[i].val_length)
3711 goto not_enough_data;
3713 /* might be just '/0', '/0'... */
3714 if (tags[i].val_length > 2 && tags[i].val_length % 2 == 0) {
3715 /* convert to UTF-8 */
3716 tags[i].val_utf8 = g_convert ((gchar *) data, tags[i].val_length,
3717 "UTF-8", "UTF-16LE", &in, &out, NULL);
3719 gst_asf_demux_skip_bytes (tags[i].val_length, &data, &size);
3722 /* parse metadata into taglist */
3723 taglist = gst_tag_list_new_empty ();
3724 g_value_init (&value, G_TYPE_STRING);
3725 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
3726 if (tags[i].val_utf8 && strlen (tags[i].val_utf8) > 0 && tags[i].gst_tag) {
3727 g_value_set_string (&value, tags[i].val_utf8);
3728 gst_tag_list_add_values (taglist, GST_TAG_MERGE_APPEND,
3729 tags[i].gst_tag, &value, NULL);
3732 g_value_unset (&value);
3734 gst_asf_demux_add_global_tags (demux, taglist);
3736 for (i = 0; i < G_N_ELEMENTS (tags); ++i)
3737 g_free (tags[i].val_utf8);
3743 GST_WARNING_OBJECT (demux, "unexpectedly short of data while processing "
3744 "comment tag section %d, skipping comment object", i);
3745 for (i = 0; i < G_N_ELEMENTS (tags); i++)
3746 g_free (tags[i].val_utf8);
3747 return GST_FLOW_OK; /* not really fatal */
3751 static GstFlowReturn
3752 gst_asf_demux_process_bitrate_props_object (GstASFDemux * demux, guint8 * data,
3755 guint16 num_streams, i;
3759 goto not_enough_data;
3761 num_streams = gst_asf_demux_get_uint16 (&data, &size);
3763 GST_INFO ("object is a bitrate properties object with %u streams",
3766 if (size < (num_streams * (2 + 4)))
3767 goto not_enough_data;
3769 for (i = 0; i < num_streams; ++i) {
3773 stream_id = gst_asf_demux_get_uint16 (&data, &size);
3774 bitrate = gst_asf_demux_get_uint32 (&data, &size);
3776 if (stream_id < GST_ASF_DEMUX_NUM_STREAM_IDS) {
3777 GST_DEBUG_OBJECT (demux, "bitrate of stream %u = %u", stream_id, bitrate);
3778 stream = gst_asf_demux_get_stream (demux, stream_id);
3780 if (stream->pending_tags == NULL)
3781 stream->pending_tags = gst_tag_list_new_empty ();
3782 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
3783 GST_TAG_BITRATE, bitrate, NULL);
3785 GST_WARNING_OBJECT (demux, "Stream id %u wasn't found", stream_id);
3788 GST_WARNING ("stream id %u is too large", stream_id);
3796 GST_WARNING_OBJECT (demux, "short read parsing bitrate props object!");
3797 return GST_FLOW_OK; /* not really fatal */
3801 static GstFlowReturn
3802 gst_asf_demux_process_header_ext (GstASFDemux * demux, guint8 * data,
3805 GstFlowReturn ret = GST_FLOW_OK;
3808 /* Get the rest of the header's header */
3809 if (size < (16 + 2 + 4))
3810 goto not_enough_data;
3812 /* skip GUID and two other bytes */
3813 gst_asf_demux_skip_bytes (16 + 2, &data, &size);
3814 hdr_size = gst_asf_demux_get_uint32 (&data, &size);
3816 GST_INFO ("extended header object with a size of %u bytes", (guint) size);
3818 /* FIXME: does data_size include the rest of the header that we have read? */
3819 if (hdr_size > size)
3820 goto not_enough_data;
3822 while (hdr_size > 0) {
3823 ret = gst_asf_demux_process_object (demux, &data, &hdr_size);
3824 if (ret != GST_FLOW_OK)
3832 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3833 ("short read parsing extended header object"));
3834 return GST_FLOW_ERROR;
3838 static GstFlowReturn
3839 gst_asf_demux_process_language_list (GstASFDemux * demux, guint8 * data,
3845 goto not_enough_data;
3847 if (demux->languages) {
3848 GST_WARNING ("More than one LANGUAGE_LIST object in stream");
3849 g_strfreev (demux->languages);
3850 demux->languages = NULL;
3851 demux->num_languages = 0;
3854 demux->num_languages = gst_asf_demux_get_uint16 (&data, &size);
3855 GST_LOG ("%u languages:", demux->num_languages);
3857 demux->languages = g_new0 (gchar *, demux->num_languages + 1);
3858 for (i = 0; i < demux->num_languages; ++i) {
3859 guint8 len, *lang_data = NULL;
3862 goto not_enough_data;
3863 len = gst_asf_demux_get_uint8 (&data, &size);
3864 if (gst_asf_demux_get_bytes (&lang_data, len, &data, &size)) {
3867 utf8 = g_convert ((gchar *) lang_data, len, "UTF-8", "UTF-16LE", NULL,
3870 /* truncate "en-us" etc. to just "en" */
3871 if (utf8 && strlen (utf8) >= 5 && (utf8[2] == '-' || utf8[2] == '_')) {
3874 GST_DEBUG ("[%u] %s", i, GST_STR_NULL (utf8));
3875 demux->languages[i] = utf8;
3878 goto not_enough_data;
3886 GST_WARNING_OBJECT (demux, "short read parsing language list object!");
3887 g_free (demux->languages);
3888 demux->languages = NULL;
3889 return GST_FLOW_OK; /* not fatal */
3893 static GstFlowReturn
3894 gst_asf_demux_process_simple_index (GstASFDemux * demux, guint8 * data,
3897 GstClockTime interval;
3900 if (size < (16 + 8 + 4 + 4))
3901 goto not_enough_data;
3904 gst_asf_demux_skip_bytes (16, &data, &size);
3905 interval = gst_asf_demux_get_uint64 (&data, &size) * (GstClockTime) 100;
3906 gst_asf_demux_skip_bytes (4, &data, &size);
3907 count = gst_asf_demux_get_uint32 (&data, &size);
3909 demux->sidx_interval = interval;
3910 demux->sidx_num_entries = count;
3911 g_free (demux->sidx_entries);
3912 demux->sidx_entries = g_new0 (AsfSimpleIndexEntry, count);
3914 for (i = 0; i < count; ++i) {
3915 if (G_UNLIKELY (size < 6)) {
3916 /* adjust for broken files, to avoid having entries at the end
3917 * of the parsed index that point to time=0. Resulting in seeking to
3918 * the end of the file leading back to the beginning */
3919 demux->sidx_num_entries -= (count - i);
3922 demux->sidx_entries[i].packet = gst_asf_demux_get_uint32 (&data, &size);
3923 demux->sidx_entries[i].count = gst_asf_demux_get_uint16 (&data, &size);
3924 GST_LOG_OBJECT (demux, "%" GST_TIME_FORMAT " = packet %4u count : %2d",
3925 GST_TIME_ARGS (i * interval), demux->sidx_entries[i].packet,
3926 demux->sidx_entries[i].count);
3929 GST_DEBUG_OBJECT (demux, "simple index object with 0 entries");
3936 GST_WARNING_OBJECT (demux, "short read parsing simple index object!");
3937 return GST_FLOW_OK; /* not fatal */
3941 static GstFlowReturn
3942 gst_asf_demux_process_advanced_mutual_exclusion (GstASFDemux * demux,
3943 guint8 * data, guint64 size)
3948 if (size < 16 + 2 + (2 * 2))
3949 goto not_enough_data;
3951 gst_asf_demux_get_guid (&guid, &data, &size);
3952 num = gst_asf_demux_get_uint16 (&data, &size);
3955 GST_WARNING_OBJECT (demux, "nonsensical mutually exclusive streams count");
3959 if (size < (num * sizeof (guint16)))
3960 goto not_enough_data;
3962 /* read mutually exclusive stream numbers */
3963 for (i = 0; i < num; ++i) {
3965 mes = gst_asf_demux_get_uint16 (&data, &size) & 0x7f;
3966 GST_LOG_OBJECT (demux, "mutually exclusive: stream %d", mes);
3968 demux->mut_ex_streams =
3969 g_slist_append (demux->mut_ex_streams, GINT_TO_POINTER (mes));
3978 GST_WARNING_OBJECT (demux, "short read parsing advanced mutual exclusion");
3979 return GST_FLOW_OK; /* not absolutely fatal */
3984 gst_asf_demux_is_unknown_stream (GstASFDemux * demux, guint stream_num)
3986 return g_slist_find (demux->other_streams,
3987 GINT_TO_POINTER (stream_num)) == NULL;
3990 static GstFlowReturn
3991 gst_asf_demux_process_ext_stream_props (GstASFDemux * demux, guint8 * data,
3994 AsfStreamExtProps esp;
3995 AsfStream *stream = NULL;
3996 AsfObject stream_obj;
3997 guint16 stream_name_count;
3998 guint16 num_payload_ext;
4000 guint8 *stream_obj_data = NULL;
4003 guint i, stream_num;
4006 obj_size = (guint) size;
4009 goto not_enough_data;
4012 esp.start_time = gst_asf_demux_get_uint64 (&data, &size) * GST_MSECOND;
4013 esp.end_time = gst_asf_demux_get_uint64 (&data, &size) * GST_MSECOND;
4014 esp.data_bitrate = gst_asf_demux_get_uint32 (&data, &size);
4015 esp.buffer_size = gst_asf_demux_get_uint32 (&data, &size);
4016 esp.intial_buf_fullness = gst_asf_demux_get_uint32 (&data, &size);
4017 esp.data_bitrate2 = gst_asf_demux_get_uint32 (&data, &size);
4018 esp.buffer_size2 = gst_asf_demux_get_uint32 (&data, &size);
4019 esp.intial_buf_fullness2 = gst_asf_demux_get_uint32 (&data, &size);
4020 esp.max_obj_size = gst_asf_demux_get_uint32 (&data, &size);
4021 esp.flags = gst_asf_demux_get_uint32 (&data, &size);
4022 stream_num = gst_asf_demux_get_uint16 (&data, &size);
4023 esp.lang_idx = gst_asf_demux_get_uint16 (&data, &size);
4024 esp.avg_time_per_frame = gst_asf_demux_get_uint64 (&data, &size);
4025 stream_name_count = gst_asf_demux_get_uint16 (&data, &size);
4026 num_payload_ext = gst_asf_demux_get_uint16 (&data, &size);
4028 GST_INFO ("start_time = %" GST_TIME_FORMAT,
4029 GST_TIME_ARGS (esp.start_time));
4030 GST_INFO ("end_time = %" GST_TIME_FORMAT,
4031 GST_TIME_ARGS (esp.end_time));
4032 GST_INFO ("flags = %08x", esp.flags);
4033 GST_INFO ("average time per frame = %" GST_TIME_FORMAT,
4034 GST_TIME_ARGS (esp.avg_time_per_frame * 100));
4035 GST_INFO ("stream number = %u", stream_num);
4036 GST_INFO ("stream language ID idx = %u (%s)", esp.lang_idx,
4037 (esp.lang_idx < demux->num_languages) ?
4038 GST_STR_NULL (demux->languages[esp.lang_idx]) : "??");
4039 GST_INFO ("stream name count = %u", stream_name_count);
4041 /* read stream names */
4042 for (i = 0; i < stream_name_count; ++i) {
4043 guint16 stream_lang_idx G_GNUC_UNUSED;
4044 gchar *stream_name = NULL;
4047 goto not_enough_data;
4048 stream_lang_idx = gst_asf_demux_get_uint16 (&data, &size);
4049 if (!gst_asf_demux_get_string (&stream_name, NULL, &data, &size))
4050 goto not_enough_data;
4051 GST_INFO ("stream name %d: %s", i, GST_STR_NULL (stream_name));
4052 g_free (stream_name); /* TODO: store names in struct */
4055 /* read payload extension systems stuff */
4056 GST_LOG ("payload extension systems count = %u", num_payload_ext);
4058 if (num_payload_ext > 0)
4059 esp.payload_extensions = g_new0 (AsfPayloadExtension, num_payload_ext + 1);
4061 esp.payload_extensions = NULL;
4063 for (i = 0; i < num_payload_ext; ++i) {
4064 AsfPayloadExtension ext;
4066 guint32 sys_info_len;
4068 if (size < 16 + 2 + 4)
4069 goto not_enough_data;
4071 gst_asf_demux_get_guid (&ext_guid, &data, &size);
4072 ext.id = gst_asf_demux_identify_guid (asf_payload_ext_guids, &ext_guid);
4073 ext.len = gst_asf_demux_get_uint16 (&data, &size);
4075 sys_info_len = gst_asf_demux_get_uint32 (&data, &size);
4076 GST_LOG ("payload systems info len = %u", sys_info_len);
4077 if (!gst_asf_demux_skip_bytes (sys_info_len, &data, &size))
4078 goto not_enough_data;
4080 esp.payload_extensions[i] = ext;
4083 GST_LOG ("bytes read: %u/%u", (guint) (data - data_start), obj_size);
4085 /* there might be an optional STREAM_INFO object here now; if not, we
4086 * should have parsed the corresponding stream info object already (since
4087 * we are parsing the extended stream properties objects delayed) */
4089 stream = gst_asf_demux_get_stream (demux, stream_num);
4093 /* get size of the stream object */
4094 if (!asf_demux_peek_object (demux, data, size, &stream_obj, TRUE))
4095 goto not_enough_data;
4097 if (stream_obj.id != ASF_OBJ_STREAM)
4098 goto expected_stream_object;
4100 if (stream_obj.size < ASF_OBJECT_HEADER_SIZE ||
4101 stream_obj.size > (10 * 1024 * 1024))
4102 goto not_enough_data;
4104 gst_asf_demux_skip_bytes (ASF_OBJECT_HEADER_SIZE, &data, &size);
4106 /* process this stream object later after all the other 'normal' ones
4107 * have been processed (since the others are more important/non-hidden) */
4108 len = stream_obj.size - ASF_OBJECT_HEADER_SIZE;
4109 if (!gst_asf_demux_get_bytes (&stream_obj_data, len, &data, &size))
4110 goto not_enough_data;
4112 /* parse stream object */
4113 stream = gst_asf_demux_parse_stream_object (demux, stream_obj_data, len);
4114 g_free (stream_obj_data);
4119 stream->ext_props = esp;
4121 /* try to set the framerate */
4122 if (stream->is_video && stream->caps) {
4123 GValue framerate = { 0 };
4127 g_value_init (&framerate, GST_TYPE_FRACTION);
4129 num = GST_SECOND / 100;
4130 denom = esp.avg_time_per_frame;
4132 /* avoid division by 0, assume 25/1 framerate */
4133 denom = GST_SECOND / 2500;
4136 gst_value_set_fraction (&framerate, num, denom);
4138 stream->caps = gst_caps_make_writable (stream->caps);
4139 s = gst_caps_get_structure (stream->caps, 0);
4140 gst_structure_set_value (s, "framerate", &framerate);
4141 g_value_unset (&framerate);
4142 GST_DEBUG_OBJECT (demux, "setting framerate of %d/%d = %f",
4143 num, denom, ((gdouble) num) / denom);
4146 /* add language info now if we have it */
4147 if (stream->ext_props.lang_idx < demux->num_languages) {
4148 if (stream->pending_tags == NULL)
4149 stream->pending_tags = gst_tag_list_new_empty ();
4150 GST_LOG_OBJECT (demux, "stream %u has language '%s'", stream->id,
4151 demux->languages[stream->ext_props.lang_idx]);
4152 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_APPEND,
4153 GST_TAG_LANGUAGE_CODE, demux->languages[stream->ext_props.lang_idx],
4156 } else if (gst_asf_demux_is_unknown_stream (demux, stream_num)) {
4157 GST_WARNING_OBJECT (demux, "Ext. stream properties for unknown stream");
4165 GST_WARNING_OBJECT (demux, "short read parsing ext stream props object!");
4166 return GST_FLOW_OK; /* not absolutely fatal */
4168 expected_stream_object:
4170 GST_WARNING_OBJECT (demux, "error parsing extended stream properties "
4171 "object: expected embedded stream object, but got %s object instead!",
4172 gst_asf_get_guid_nick (asf_object_guids, stream_obj.id));
4173 return GST_FLOW_OK; /* not absolutely fatal */
4177 static const gchar *
4178 gst_asf_demux_push_obj (GstASFDemux * demux, guint32 obj_id)
4182 nick = gst_asf_get_guid_nick (asf_object_guids, obj_id);
4183 if (g_str_has_prefix (nick, "ASF_OBJ_"))
4184 nick += strlen ("ASF_OBJ_");
4186 if (demux->objpath == NULL) {
4187 demux->objpath = g_strdup (nick);
4191 newpath = g_strdup_printf ("%s/%s", demux->objpath, nick);
4192 g_free (demux->objpath);
4193 demux->objpath = newpath;
4196 return (const gchar *) demux->objpath;
4200 gst_asf_demux_pop_obj (GstASFDemux * demux)
4204 if ((s = g_strrstr (demux->objpath, "/"))) {
4207 g_free (demux->objpath);
4208 demux->objpath = NULL;
4213 gst_asf_demux_process_queued_extended_stream_objects (GstASFDemux * demux)
4218 /* Parse the queued extended stream property objects and add the info
4219 * to the existing streams or add the new embedded streams, but without
4220 * activating them yet */
4221 GST_LOG_OBJECT (demux, "%u queued extended stream properties objects",
4222 g_slist_length (demux->ext_stream_props));
4224 for (l = demux->ext_stream_props, i = 0; l != NULL; l = l->next, ++i) {
4225 GstBuffer *buf = GST_BUFFER (l->data);
4228 gst_buffer_map (buf, &map, GST_MAP_READ);
4230 GST_LOG_OBJECT (demux, "parsing ext. stream properties object #%u", i);
4231 gst_asf_demux_process_ext_stream_props (demux, map.data, map.size);
4232 gst_buffer_unmap (buf, &map);
4233 gst_buffer_unref (buf);
4235 g_slist_free (demux->ext_stream_props);
4236 demux->ext_stream_props = NULL;
4241 gst_asf_demux_activate_ext_props_streams (GstASFDemux * demux)
4245 for (i = 0; i < demux->num_streams; ++i) {
4250 stream = &demux->stream[i];
4252 GST_LOG_OBJECT (demux, "checking stream %2u", stream->id);
4254 if (stream->active) {
4255 GST_LOG_OBJECT (demux, "stream %2u is already activated", stream->id);
4260 for (x = demux->mut_ex_streams; x != NULL; x = x->next) {
4263 /* check for each mutual exclusion whether it affects this stream */
4264 for (mes = (guint8 *) x->data; mes != NULL && *mes != 0xff; ++mes) {
4265 if (*mes == stream->id) {
4266 /* if yes, check if we've already added streams that are mutually
4267 * exclusive with the stream we're about to add */
4268 for (mes = (guint8 *) x->data; mes != NULL && *mes != 0xff; ++mes) {
4269 for (j = 0; j < demux->num_streams; ++j) {
4270 /* if the broadcast flag is set, assume the hidden streams aren't
4271 * actually streamed and hide them (or playbin won't work right),
4272 * otherwise assume their data is available */
4273 if (demux->stream[j].id == *mes && demux->broadcast) {
4275 GST_LOG_OBJECT (demux, "broadcast stream ID %d to be added is "
4276 "mutually exclusive with already existing stream ID %d, "
4277 "hiding stream", stream->id, demux->stream[j].id);
4289 /* FIXME: we should do stream activation based on preroll data in
4290 * streaming mode too */
4291 if (demux->streaming && !is_hidden)
4292 gst_asf_demux_activate_stream (demux, stream);
4297 static GstFlowReturn
4298 gst_asf_demux_process_object (GstASFDemux * demux, guint8 ** p_data,
4301 GstFlowReturn ret = GST_FLOW_OK;
4303 guint64 obj_data_size;
4305 if (*p_size < ASF_OBJECT_HEADER_SIZE)
4306 return ASF_FLOW_NEED_MORE_DATA;
4308 asf_demux_peek_object (demux, *p_data, ASF_OBJECT_HEADER_SIZE, &obj, TRUE);
4309 gst_asf_demux_skip_bytes (ASF_OBJECT_HEADER_SIZE, p_data, p_size);
4311 obj_data_size = obj.size - ASF_OBJECT_HEADER_SIZE;
4313 if (*p_size < obj_data_size)
4314 return ASF_FLOW_NEED_MORE_DATA;
4316 gst_asf_demux_push_obj (demux, obj.id);
4318 GST_INFO ("%s: size %" G_GUINT64_FORMAT, demux->objpath, obj.size);
4321 case ASF_OBJ_STREAM:
4322 gst_asf_demux_parse_stream_object (demux, *p_data, obj_data_size);
4326 ret = gst_asf_demux_process_file (demux, *p_data, obj_data_size);
4328 case ASF_OBJ_HEADER:
4329 ret = gst_asf_demux_process_header (demux, *p_data, obj_data_size);
4331 case ASF_OBJ_COMMENT:
4332 ret = gst_asf_demux_process_comment (demux, *p_data, obj_data_size);
4335 ret = gst_asf_demux_process_header_ext (demux, *p_data, obj_data_size);
4337 case ASF_OBJ_BITRATE_PROPS:
4339 gst_asf_demux_process_bitrate_props_object (demux, *p_data,
4342 case ASF_OBJ_EXT_CONTENT_DESC:
4344 gst_asf_demux_process_ext_content_desc (demux, *p_data,
4347 case ASF_OBJ_METADATA_OBJECT:
4348 ret = gst_asf_demux_process_metadata (demux, *p_data, obj_data_size);
4350 case ASF_OBJ_EXTENDED_STREAM_PROPS:{
4353 /* process these later, we might not have parsed the corresponding
4354 * stream object yet */
4355 GST_LOG ("%s: queued for later parsing", demux->objpath);
4356 buf = gst_buffer_new_and_alloc (obj_data_size);
4357 gst_buffer_fill (buf, 0, *p_data, obj_data_size);
4358 demux->ext_stream_props = g_slist_append (demux->ext_stream_props, buf);
4362 case ASF_OBJ_LANGUAGE_LIST:
4363 ret = gst_asf_demux_process_language_list (demux, *p_data, obj_data_size);
4365 case ASF_OBJ_ADVANCED_MUTUAL_EXCLUSION:
4366 ret = gst_asf_demux_process_advanced_mutual_exclusion (demux, *p_data,
4369 case ASF_OBJ_SIMPLE_INDEX:
4370 ret = gst_asf_demux_process_simple_index (demux, *p_data, obj_data_size);
4372 case ASF_OBJ_CONTENT_ENCRYPTION:
4373 case ASF_OBJ_EXT_CONTENT_ENCRYPTION:
4374 case ASF_OBJ_DIGITAL_SIGNATURE_OBJECT:
4375 case ASF_OBJ_UNKNOWN_ENCRYPTION_OBJECT:
4376 goto error_encrypted;
4377 case ASF_OBJ_CONCEAL_NONE:
4379 case ASF_OBJ_UNDEFINED:
4380 case ASF_OBJ_CODEC_COMMENT:
4382 case ASF_OBJ_PADDING:
4383 case ASF_OBJ_BITRATE_MUTEX:
4384 case ASF_OBJ_COMPATIBILITY:
4385 case ASF_OBJ_INDEX_PLACEHOLDER:
4386 case ASF_OBJ_INDEX_PARAMETERS:
4387 case ASF_OBJ_STREAM_PRIORITIZATION:
4388 case ASF_OBJ_SCRIPT_COMMAND:
4389 case ASF_OBJ_METADATA_LIBRARY_OBJECT:
4391 /* Unknown/unhandled object, skip it and hope for the best */
4392 GST_INFO ("%s: skipping object", demux->objpath);
4397 /* this can't fail, we checked the number of bytes available before */
4398 gst_asf_demux_skip_bytes (obj_data_size, p_data, p_size);
4400 GST_LOG ("%s: ret = %s", demux->objpath, gst_asf_get_flow_name (ret));
4402 gst_asf_demux_pop_obj (demux);
4409 GST_ELEMENT_ERROR (demux, STREAM, DECRYPT, (NULL), (NULL));
4410 return GST_FLOW_ERROR;
4415 gst_asf_demux_descramble_buffer (GstASFDemux * demux, AsfStream * stream,
4416 GstBuffer ** p_buffer)
4418 GstBuffer *descrambled_buffer;
4419 GstBuffer *scrambled_buffer;
4420 GstBuffer *sub_buffer;
4427 /* descrambled_buffer is initialised in the first iteration */
4428 descrambled_buffer = NULL;
4429 scrambled_buffer = *p_buffer;
4431 if (gst_buffer_get_size (scrambled_buffer) <
4432 stream->ds_packet_size * stream->span)
4435 for (offset = 0; offset < gst_buffer_get_size (scrambled_buffer);
4436 offset += stream->ds_chunk_size) {
4437 off = offset / stream->ds_chunk_size;
4438 row = off / stream->span;
4439 col = off % stream->span;
4440 idx = row + col * stream->ds_packet_size / stream->ds_chunk_size;
4441 GST_DEBUG ("idx=%u, row=%u, col=%u, off=%u, ds_chunk_size=%u", idx, row,
4442 col, off, stream->ds_chunk_size);
4443 GST_DEBUG ("scrambled buffer size=%" G_GSIZE_FORMAT
4444 ", span=%u, packet_size=%u", gst_buffer_get_size (scrambled_buffer),
4445 stream->span, stream->ds_packet_size);
4446 GST_DEBUG ("gst_buffer_get_size (scrambled_buffer) = %" G_GSIZE_FORMAT,
4447 gst_buffer_get_size (scrambled_buffer));
4449 gst_buffer_copy_region (scrambled_buffer, GST_BUFFER_COPY_MEMORY,
4450 idx * stream->ds_chunk_size, stream->ds_chunk_size);
4452 descrambled_buffer = sub_buffer;
4454 descrambled_buffer = gst_buffer_append (descrambled_buffer, sub_buffer);
4458 GST_BUFFER_TIMESTAMP (descrambled_buffer) =
4459 GST_BUFFER_TIMESTAMP (scrambled_buffer);
4460 GST_BUFFER_DURATION (descrambled_buffer) =
4461 GST_BUFFER_DURATION (scrambled_buffer);
4462 GST_BUFFER_OFFSET (descrambled_buffer) = GST_BUFFER_OFFSET (scrambled_buffer);
4463 GST_BUFFER_OFFSET_END (descrambled_buffer) =
4464 GST_BUFFER_OFFSET_END (scrambled_buffer);
4466 /* FIXME/CHECK: do we need to transfer buffer flags here too? */
4468 gst_buffer_unref (scrambled_buffer);
4469 *p_buffer = descrambled_buffer;
4473 gst_asf_demux_element_send_event (GstElement * element, GstEvent * event)
4475 GstASFDemux *demux = GST_ASF_DEMUX (element);
4478 GST_DEBUG ("handling element event of type %s", GST_EVENT_TYPE_NAME (event));
4480 for (i = 0; i < demux->num_streams; ++i) {
4481 gst_event_ref (event);
4482 if (gst_asf_demux_handle_src_event (demux->stream[i].pad,
4483 GST_OBJECT_CAST (element), event)) {
4484 gst_event_unref (event);
4489 gst_event_unref (event);
4493 /* takes ownership of the passed event */
4495 gst_asf_demux_send_event_unlocked (GstASFDemux * demux, GstEvent * event)
4497 gboolean ret = TRUE;
4500 GST_DEBUG_OBJECT (demux, "sending %s event to all source pads",
4501 GST_EVENT_TYPE_NAME (event));
4503 for (i = 0; i < demux->num_streams; ++i) {
4504 gst_event_ref (event);
4505 ret &= gst_pad_push_event (demux->stream[i].pad, event);
4507 gst_event_unref (event);
4512 gst_asf_demux_handle_src_query (GstPad * pad, GstObject * parent,
4516 gboolean res = FALSE;
4518 demux = GST_ASF_DEMUX (parent);
4520 GST_DEBUG ("handling %s query",
4521 gst_query_type_get_name (GST_QUERY_TYPE (query)));
4523 switch (GST_QUERY_TYPE (query)) {
4524 case GST_QUERY_DURATION:
4528 gst_query_parse_duration (query, &format, NULL);
4530 if (format != GST_FORMAT_TIME) {
4531 GST_LOG ("only support duration queries in TIME format");
4535 res = gst_pad_query_default (pad, parent, query);
4537 GST_OBJECT_LOCK (demux);
4539 if (demux->segment.duration != GST_CLOCK_TIME_NONE) {
4540 GST_LOG ("returning duration: %" GST_TIME_FORMAT,
4541 GST_TIME_ARGS (demux->segment.duration));
4543 gst_query_set_duration (query, GST_FORMAT_TIME,
4544 demux->segment.duration);
4548 GST_LOG ("duration not known yet");
4551 GST_OBJECT_UNLOCK (demux);
4556 case GST_QUERY_POSITION:{
4559 gst_query_parse_position (query, &format, NULL);
4561 if (format != GST_FORMAT_TIME) {
4562 GST_LOG ("only support position queries in TIME format");
4566 GST_OBJECT_LOCK (demux);
4568 if (demux->segment.position != GST_CLOCK_TIME_NONE) {
4569 GST_LOG ("returning position: %" GST_TIME_FORMAT,
4570 GST_TIME_ARGS (demux->segment.position));
4572 gst_query_set_position (query, GST_FORMAT_TIME,
4573 demux->segment.position);
4577 GST_LOG ("position not known yet");
4580 GST_OBJECT_UNLOCK (demux);
4584 case GST_QUERY_SEEKING:{
4587 gst_query_parse_seeking (query, &format, NULL, NULL, NULL);
4588 if (format == GST_FORMAT_TIME) {
4591 GST_OBJECT_LOCK (demux);
4592 duration = demux->segment.duration;
4593 GST_OBJECT_UNLOCK (demux);
4595 if (!demux->streaming || !demux->seekable) {
4596 gst_query_set_seeking (query, GST_FORMAT_TIME, demux->seekable, 0,
4603 /* try upstream first in TIME */
4604 res = gst_pad_query_default (pad, parent, query);
4606 gst_query_parse_seeking (query, &fmt, &seekable, NULL, NULL);
4607 GST_LOG_OBJECT (demux, "upstream %s seekable %d",
4608 GST_STR_NULL (gst_format_get_name (fmt)), seekable);
4609 /* if no luck, maybe in BYTES */
4610 if (!seekable || fmt != GST_FORMAT_TIME) {
4613 q = gst_query_new_seeking (GST_FORMAT_BYTES);
4614 if ((res = gst_pad_peer_query (demux->sinkpad, q))) {
4615 gst_query_parse_seeking (q, &fmt, &seekable, NULL, NULL);
4616 GST_LOG_OBJECT (demux, "upstream %s seekable %d",
4617 GST_STR_NULL (gst_format_get_name (fmt)), seekable);
4618 if (fmt != GST_FORMAT_BYTES)
4621 gst_query_unref (q);
4622 gst_query_set_seeking (query, GST_FORMAT_TIME, seekable, 0,
4628 GST_LOG_OBJECT (demux, "only support seeking in TIME format");
4632 case GST_QUERY_LATENCY:
4635 GstClockTime min, max;
4637 /* preroll delay does not matter in non-live pipeline,
4638 * but we might end up in a live (rtsp) one ... */
4641 res = gst_pad_query_default (pad, parent, query);
4645 gst_query_parse_latency (query, &live, &min, &max);
4647 GST_DEBUG_OBJECT (demux, "Peer latency: live %d, min %"
4648 GST_TIME_FORMAT " max %" GST_TIME_FORMAT, live,
4649 GST_TIME_ARGS (min), GST_TIME_ARGS (max));
4651 GST_OBJECT_LOCK (demux);
4652 min += demux->latency;
4654 max += demux->latency;
4655 GST_OBJECT_UNLOCK (demux);
4657 gst_query_set_latency (query, live, min, max);
4660 case GST_QUERY_SEGMENT:
4665 format = demux->segment.format;
4668 gst_segment_to_stream_time (&demux->segment, format,
4669 demux->segment.start);
4670 if ((stop = demux->segment.stop) == -1)
4671 stop = demux->segment.duration;
4673 stop = gst_segment_to_stream_time (&demux->segment, format, stop);
4675 gst_query_set_segment (query, demux->segment.rate, format, start, stop);
4680 res = gst_pad_query_default (pad, parent, query);
4687 static GstStateChangeReturn
4688 gst_asf_demux_change_state (GstElement * element, GstStateChange transition)
4690 GstASFDemux *demux = GST_ASF_DEMUX (element);
4691 GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
4693 switch (transition) {
4694 case GST_STATE_CHANGE_NULL_TO_READY:{
4695 gst_segment_init (&demux->segment, GST_FORMAT_TIME);
4696 demux->need_newsegment = TRUE;
4697 demux->segment_running = FALSE;
4698 demux->keyunit_sync = FALSE;
4699 demux->accurate = FALSE;
4700 demux->adapter = gst_adapter_new ();
4701 demux->metadata = gst_caps_new_empty ();
4702 demux->global_metadata = gst_structure_new_empty ("metadata");
4703 demux->data_size = 0;
4704 demux->data_offset = 0;
4705 demux->index_offset = 0;
4706 demux->base_offset = 0;
4707 demux->flowcombiner = gst_flow_combiner_new ();
4715 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
4716 if (ret == GST_STATE_CHANGE_FAILURE)
4719 switch (transition) {
4720 case GST_STATE_CHANGE_PAUSED_TO_READY:
4721 gst_asf_demux_reset (demux, FALSE);
4724 case GST_STATE_CHANGE_READY_TO_NULL:
4725 gst_asf_demux_reset (demux, FALSE);
4726 gst_flow_combiner_free (demux->flowcombiner);
4727 demux->flowcombiner = NULL;