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_pad_template (gstelement_class,
132 gst_static_pad_template_get (&audio_src_template));
133 gst_element_class_add_pad_template (gstelement_class,
134 gst_static_pad_template_get (&video_src_template));
135 gst_element_class_add_pad_template (gstelement_class,
136 gst_static_pad_template_get (&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;
178 if (stream->ext_props.valid) {
179 g_free (stream->ext_props.payload_extensions);
180 stream->ext_props.payload_extensions = NULL;
185 gst_asf_demux_reset (GstASFDemux * demux, gboolean chain_reset)
187 GST_LOG_OBJECT (demux, "resetting");
189 gst_segment_init (&demux->segment, GST_FORMAT_UNDEFINED);
190 demux->segment_running = FALSE;
191 if (demux->adapter && !chain_reset) {
192 gst_adapter_clear (demux->adapter);
193 g_object_unref (demux->adapter);
194 demux->adapter = NULL;
196 if (demux->taglist) {
197 gst_tag_list_unref (demux->taglist);
198 demux->taglist = NULL;
200 if (demux->metadata) {
201 gst_caps_unref (demux->metadata);
202 demux->metadata = NULL;
204 if (demux->global_metadata) {
205 gst_structure_free (demux->global_metadata);
206 demux->global_metadata = NULL;
208 if (demux->mut_ex_streams) {
209 g_slist_free (demux->mut_ex_streams);
210 demux->mut_ex_streams = NULL;
213 demux->state = GST_ASF_DEMUX_STATE_HEADER;
214 g_free (demux->objpath);
215 demux->objpath = NULL;
216 g_strfreev (demux->languages);
217 demux->languages = NULL;
218 demux->num_languages = 0;
219 g_slist_foreach (demux->ext_stream_props, (GFunc) gst_mini_object_unref,
221 g_slist_free (demux->ext_stream_props);
222 demux->ext_stream_props = NULL;
224 while (demux->old_num_streams > 0) {
225 gst_asf_demux_free_stream (demux,
226 &demux->old_stream[demux->old_num_streams - 1]);
227 --demux->old_num_streams;
229 memset (demux->old_stream, 0, sizeof (demux->old_stream));
230 demux->old_num_streams = 0;
232 /* when resetting for a new chained asf, we don't want to remove the pads
233 * before adding the new ones */
235 memcpy (demux->old_stream, demux->stream, sizeof (demux->stream));
236 demux->old_num_streams = demux->num_streams;
237 demux->num_streams = 0;
240 while (demux->num_streams > 0) {
241 gst_asf_demux_free_stream (demux, &demux->stream[demux->num_streams - 1]);
242 --demux->num_streams;
244 memset (demux->stream, 0, sizeof (demux->stream));
246 /* do not remove those for not adding pads with same name */
247 demux->num_audio_streams = 0;
248 demux->num_video_streams = 0;
249 demux->have_group_id = FALSE;
250 demux->group_id = G_MAXUINT;
252 demux->num_streams = 0;
253 demux->activated_streams = FALSE;
254 demux->first_ts = GST_CLOCK_TIME_NONE;
255 demux->segment_ts = GST_CLOCK_TIME_NONE;
258 gst_segment_init (&demux->in_segment, GST_FORMAT_UNDEFINED);
259 demux->state = GST_ASF_DEMUX_STATE_HEADER;
260 demux->seekable = FALSE;
261 demux->broadcast = FALSE;
262 demux->sidx_interval = 0;
263 demux->sidx_num_entries = 0;
264 g_free (demux->sidx_entries);
265 demux->sidx_entries = NULL;
267 demux->speed_packets = 1;
269 demux->asf_3D_mode = GST_ASF_3D_NONE;
272 GST_LOG_OBJECT (demux, "Restarting");
273 gst_segment_init (&demux->segment, GST_FORMAT_TIME);
274 demux->need_newsegment = TRUE;
275 demux->segment_seqnum = 0;
276 demux->segment_running = FALSE;
277 demux->keyunit_sync = FALSE;
278 demux->metadata = gst_caps_new_empty ();
279 demux->global_metadata = gst_structure_new_empty ("metadata");
280 demux->data_size = 0;
281 demux->data_offset = 0;
282 demux->index_offset = 0;
284 demux->base_offset = 0;
287 g_slist_free (demux->other_streams);
288 demux->other_streams = NULL;
292 gst_asf_demux_init (GstASFDemux * demux)
295 gst_pad_new_from_static_template (&gst_asf_demux_sink_template, "sink");
296 gst_pad_set_chain_function (demux->sinkpad,
297 GST_DEBUG_FUNCPTR (gst_asf_demux_chain));
298 gst_pad_set_event_function (demux->sinkpad,
299 GST_DEBUG_FUNCPTR (gst_asf_demux_sink_event));
300 gst_pad_set_activate_function (demux->sinkpad,
301 GST_DEBUG_FUNCPTR (gst_asf_demux_activate));
302 gst_pad_set_activatemode_function (demux->sinkpad,
303 GST_DEBUG_FUNCPTR (gst_asf_demux_activate_mode));
304 gst_element_add_pad (GST_ELEMENT (demux), demux->sinkpad);
306 /* set initial state */
307 gst_asf_demux_reset (demux, FALSE);
311 gst_asf_demux_activate (GstPad * sinkpad, GstObject * parent)
316 query = gst_query_new_scheduling ();
318 if (!gst_pad_peer_query (sinkpad, query)) {
319 gst_query_unref (query);
323 pull_mode = gst_query_has_scheduling_mode_with_flags (query,
324 GST_PAD_MODE_PULL, GST_SCHEDULING_FLAG_SEEKABLE);
325 gst_query_unref (query);
330 GST_DEBUG_OBJECT (sinkpad, "activating pull");
331 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PULL, TRUE);
335 GST_DEBUG_OBJECT (sinkpad, "activating push");
336 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PUSH, TRUE);
341 gst_asf_demux_activate_mode (GstPad * sinkpad, GstObject * parent,
342 GstPadMode mode, gboolean active)
347 demux = GST_ASF_DEMUX (parent);
350 case GST_PAD_MODE_PUSH:
351 demux->state = GST_ASF_DEMUX_STATE_HEADER;
352 demux->streaming = TRUE;
355 case GST_PAD_MODE_PULL:
357 demux->state = GST_ASF_DEMUX_STATE_HEADER;
358 demux->streaming = FALSE;
360 res = gst_pad_start_task (sinkpad, (GstTaskFunction) gst_asf_demux_loop,
363 res = gst_pad_stop_task (sinkpad);
374 gst_asf_demux_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
379 demux = GST_ASF_DEMUX (parent);
381 GST_LOG_OBJECT (demux, "handling %s event", GST_EVENT_TYPE_NAME (event));
382 switch (GST_EVENT_TYPE (event)) {
383 case GST_EVENT_SEGMENT:{
384 const GstSegment *segment;
386 gst_event_parse_segment (event, &segment);
388 if (segment->format == GST_FORMAT_BYTES) {
389 if (demux->packet_size && segment->start > demux->data_offset)
390 demux->packet = (segment->start - demux->data_offset) /
394 } else if (segment->format == GST_FORMAT_TIME) {
395 /* do not know packet position, not really a problem */
398 GST_WARNING_OBJECT (demux, "unsupported newsegment format, ignoring");
399 gst_event_unref (event);
403 /* record upstream segment for interpolation */
404 if (segment->format != demux->in_segment.format)
405 gst_segment_init (&demux->in_segment, GST_FORMAT_UNDEFINED);
406 gst_segment_copy_into (segment, &demux->in_segment);
408 /* in either case, clear some state and generate newsegment later on */
409 GST_OBJECT_LOCK (demux);
410 demux->segment_ts = GST_CLOCK_TIME_NONE;
411 demux->in_gap = GST_CLOCK_TIME_NONE;
412 demux->need_newsegment = TRUE;
413 demux->segment_seqnum = gst_event_get_seqnum (event);
414 gst_asf_demux_reset_stream_state_after_discont (demux);
415 GST_OBJECT_UNLOCK (demux);
417 gst_event_unref (event);
423 if (demux->state == GST_ASF_DEMUX_STATE_HEADER) {
424 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
425 (_("This stream contains no data.")),
426 ("got eos and didn't receive a complete header object"));
429 flow = gst_asf_demux_push_complete_payloads (demux, TRUE);
430 if (flow < GST_FLOW_EOS || flow == GST_FLOW_NOT_LINKED) {
431 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
432 (_("Internal data stream error.")),
433 ("streaming stopped, reason %s", gst_flow_get_name (flow)));
437 GST_OBJECT_LOCK (demux);
438 gst_adapter_clear (demux->adapter);
439 GST_OBJECT_UNLOCK (demux);
440 gst_asf_demux_send_event_unlocked (demux, event);
444 case GST_EVENT_FLUSH_STOP:
445 GST_OBJECT_LOCK (demux);
446 gst_asf_demux_reset_stream_state_after_discont (demux);
447 GST_OBJECT_UNLOCK (demux);
448 gst_asf_demux_send_event_unlocked (demux, event);
449 /* upon activation, latency is no longer introduced, e.g. after seek */
450 if (demux->activated_streams)
455 ret = gst_pad_event_default (pad, parent, event);
463 gst_asf_demux_seek_index_lookup (GstASFDemux * demux, guint * packet,
464 GstClockTime seek_time, GstClockTime * p_idx_time, guint * speed,
465 gboolean next, gboolean * eos)
467 GstClockTime idx_time;
473 if (G_UNLIKELY (demux->sidx_num_entries == 0 || demux->sidx_interval == 0))
476 idx = (guint) ((seek_time + demux->preroll) / demux->sidx_interval);
479 /* if we want the next keyframe, we have to go forward till we find
480 a different packet number */
482 if (idx >= demux->sidx_num_entries - 1) {
483 /* If we get here, we're asking for next keyframe after the last one. There isn't one. */
488 for (idx2 = idx + 1; idx2 < demux->sidx_num_entries; ++idx2) {
489 if (demux->sidx_entries[idx].packet != demux->sidx_entries[idx2].packet) {
496 if (G_UNLIKELY (idx >= demux->sidx_num_entries)) {
502 *packet = demux->sidx_entries[idx].packet;
504 *speed = demux->sidx_entries[idx].count;
506 /* so we get closer to the actual time of the packet ... actually, let's not
507 * do this, since we throw away superfluous payloads before the seek position
508 * anyway; this way, our key unit seek 'snap resolution' is a bit better
509 * (ie. same as index resolution) */
511 while (idx > 0 && demux->sidx_entries[idx-1] == demux->sidx_entries[idx])
515 idx_time = demux->sidx_interval * idx;
516 if (G_LIKELY (idx_time >= demux->preroll))
517 idx_time -= demux->preroll;
519 GST_DEBUG_OBJECT (demux, "%" GST_TIME_FORMAT " => packet %u at %"
520 GST_TIME_FORMAT, GST_TIME_ARGS (seek_time), *packet,
521 GST_TIME_ARGS (idx_time));
523 if (G_LIKELY (p_idx_time))
524 *p_idx_time = idx_time;
530 gst_asf_demux_reset_stream_state_after_discont (GstASFDemux * demux)
534 gst_adapter_clear (demux->adapter);
536 GST_DEBUG_OBJECT (demux, "reset stream state");
538 gst_flow_combiner_reset (demux->flowcombiner);
539 for (n = 0; n < demux->num_streams; n++) {
540 demux->stream[n].discont = TRUE;
541 demux->stream[n].first_buffer = TRUE;
543 while (demux->stream[n].payloads->len > 0) {
547 last = demux->stream[n].payloads->len - 1;
548 payload = &g_array_index (demux->stream[n].payloads, AsfPayload, last);
549 gst_buffer_replace (&payload->buf, NULL);
550 g_array_remove_index (demux->stream[n].payloads, last);
556 gst_asf_demux_mark_discont (GstASFDemux * demux)
560 GST_DEBUG_OBJECT (demux, "Mark stream discont");
562 for (n = 0; n < demux->num_streams; n++)
563 demux->stream[n].discont = TRUE;
566 /* do a seek in push based mode */
568 gst_asf_demux_handle_seek_push (GstASFDemux * demux, GstEvent * event)
573 GstSeekType cur_type, stop_type;
577 GstEvent *byte_event;
579 gst_event_parse_seek (event, &rate, &format, &flags, &cur_type, &cur,
582 stop_type = GST_SEEK_TYPE_NONE;
585 GST_DEBUG_OBJECT (demux, "seeking to %" GST_TIME_FORMAT, GST_TIME_ARGS (cur));
587 /* determine packet, by index or by estimation */
588 if (!gst_asf_demux_seek_index_lookup (demux, &packet, cur, NULL, NULL, FALSE,
591 (guint) gst_util_uint64_scale (demux->num_packets, cur,
595 if (packet > demux->num_packets) {
596 GST_DEBUG_OBJECT (demux, "could not determine packet to seek to, "
601 GST_DEBUG_OBJECT (demux, "seeking to packet %d", packet);
603 cur = demux->data_offset + ((guint64) packet * demux->packet_size);
605 GST_DEBUG_OBJECT (demux, "Pushing BYTE seek rate %g, "
606 "start %" G_GINT64_FORMAT ", stop %" G_GINT64_FORMAT, rate, cur, stop);
607 /* BYTE seek event */
608 byte_event = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags, cur_type,
609 cur, stop_type, stop);
610 gst_event_set_seqnum (byte_event, gst_event_get_seqnum (event));
611 res = gst_pad_push_event (demux->sinkpad, byte_event);
617 gst_asf_demux_handle_seek_event (GstASFDemux * demux, GstEvent * event)
619 GstClockTime idx_time;
622 GstSeekType cur_type, stop_type;
624 gboolean only_need_update;
625 gboolean accurate, after, before, next;
630 guint packet, speed_count = 1;
635 gst_event_parse_seek (event, &rate, &format, &flags, &cur_type, &cur,
638 if (G_UNLIKELY (format != GST_FORMAT_TIME)) {
639 GST_LOG_OBJECT (demux, "seeking is only supported in TIME format");
643 /* upstream might handle TIME seek, e.g. mms or rtsp, or not, e.g. http,
644 * so first try to let it handle the seek event. */
645 if (gst_pad_push_event (demux->sinkpad, gst_event_ref (event)))
648 if (G_UNLIKELY (demux->seekable == FALSE || demux->packet_size == 0 ||
649 demux->num_packets == 0 || demux->play_time == 0)) {
650 GST_LOG_OBJECT (demux, "stream is not seekable");
654 if (G_UNLIKELY (!demux->activated_streams)) {
655 GST_LOG_OBJECT (demux, "streams not yet activated, ignoring seek");
659 if (G_UNLIKELY (rate <= 0.0)) {
660 GST_LOG_OBJECT (demux, "backward playback is not supported yet");
664 seqnum = gst_event_get_seqnum (event);
665 flush = ((flags & GST_SEEK_FLAG_FLUSH) == GST_SEEK_FLAG_FLUSH);
666 accurate = ((flags & GST_SEEK_FLAG_ACCURATE) == GST_SEEK_FLAG_ACCURATE);
667 demux->keyunit_sync =
668 ((flags & GST_SEEK_FLAG_KEY_UNIT) == GST_SEEK_FLAG_KEY_UNIT);
669 after = ((flags & GST_SEEK_FLAG_SNAP_AFTER) == GST_SEEK_FLAG_SNAP_AFTER);
670 before = ((flags & GST_SEEK_FLAG_SNAP_BEFORE) == GST_SEEK_FLAG_SNAP_BEFORE);
671 next = after && !before;
673 if (G_UNLIKELY (demux->streaming)) {
674 /* support it safely needs more segment handling, e.g. closing etc */
676 GST_LOG_OBJECT (demux, "streaming; non-flushing seek not supported");
679 /* we can (re)construct the start later on, but not the end */
680 if (stop_type != GST_SEEK_TYPE_NONE &&
681 (stop_type != GST_SEEK_TYPE_SET || GST_CLOCK_TIME_IS_VALID (stop))) {
682 GST_LOG_OBJECT (demux, "streaming; end position must be NONE");
685 return gst_asf_demux_handle_seek_push (demux, event);
688 /* unlock the streaming thread */
689 if (G_LIKELY (flush)) {
690 fevent = gst_event_new_flush_start ();
692 gst_event_set_seqnum (fevent, seqnum);
693 gst_pad_push_event (demux->sinkpad, gst_event_ref (fevent));
694 gst_asf_demux_send_event_unlocked (demux, fevent);
696 gst_pad_pause_task (demux->sinkpad);
699 /* grab the stream lock so that streaming cannot continue, for
700 * non flushing seeks when the element is in PAUSED this could block
702 GST_PAD_STREAM_LOCK (demux->sinkpad);
704 /* we now can stop flushing, since we have the stream lock now */
705 fevent = gst_event_new_flush_stop (TRUE);
706 gst_event_set_seqnum (fevent, seqnum);
707 gst_pad_push_event (demux->sinkpad, gst_event_ref (fevent));
709 if (G_LIKELY (flush))
710 gst_asf_demux_send_event_unlocked (demux, fevent);
712 gst_event_unref (fevent);
714 /* operating on copy of segment until we know the seek worked */
715 segment = demux->segment;
717 if (G_UNLIKELY (demux->segment_running && !flush)) {
718 GstSegment newsegment;
721 /* create the segment event to close the current segment */
722 gst_segment_copy_into (&segment, &newsegment);
723 newseg = gst_event_new_segment (&newsegment);
724 gst_event_set_seqnum (newseg, seqnum);
726 gst_asf_demux_send_event_unlocked (demux, newseg);
729 gst_segment_do_seek (&segment, rate, format, flags, cur_type,
730 cur, stop_type, stop, &only_need_update);
732 GST_DEBUG_OBJECT (demux, "seeking to time %" GST_TIME_FORMAT ", segment: "
733 "%" GST_SEGMENT_FORMAT, GST_TIME_ARGS (segment.start), &segment);
735 if (cur_type != GST_SEEK_TYPE_SET)
736 seek_time = segment.start;
740 /* FIXME: should check the KEY_UNIT flag; need to adjust position to
741 * real start of data and segment_start to indexed time for key unit seek*/
742 if (G_UNLIKELY (!gst_asf_demux_seek_index_lookup (demux, &packet, seek_time,
743 &idx_time, &speed_count, next, &eos))) {
747 demux->packet = demux->num_packets;
751 /* First try to query our source to see if it can convert for us. This is
752 the case when our source is an mms stream, notice that in this case
753 gstmms will do a time based seek to get the byte offset, this is not a
754 problem as the seek to this offset needs to happen anway. */
755 if (gst_pad_peer_query_convert (demux->sinkpad, GST_FORMAT_TIME, seek_time,
756 GST_FORMAT_BYTES, &offset)) {
757 packet = (offset - demux->data_offset) / demux->packet_size;
758 GST_LOG_OBJECT (demux, "convert %" GST_TIME_FORMAT
759 " to bytes query result: %" G_GINT64_FORMAT ", data_ofset: %"
760 G_GINT64_FORMAT ", packet_size: %u," " resulting packet: %u\n",
761 GST_TIME_ARGS (seek_time), offset, demux->data_offset,
762 demux->packet_size, packet);
764 /* FIXME: For streams containing video, seek to an earlier position in
765 * the hope of hitting a keyframe and let the sinks throw away the stuff
766 * before the segment start. For audio-only this is unnecessary as every
768 if (flush && (accurate || (demux->keyunit_sync && !next))
769 && demux->num_video_streams > 0) {
770 seek_time -= 5 * GST_SECOND;
775 packet = (guint) gst_util_uint64_scale (demux->num_packets,
776 seek_time, demux->play_time);
778 if (packet > demux->num_packets)
779 packet = demux->num_packets;
782 if (G_LIKELY (demux->keyunit_sync)) {
783 GST_DEBUG_OBJECT (demux, "key unit seek, adjust seek_time = %"
784 GST_TIME_FORMAT " to index_time = %" GST_TIME_FORMAT,
785 GST_TIME_ARGS (seek_time), GST_TIME_ARGS (idx_time));
786 segment.start = idx_time;
787 segment.position = idx_time;
788 segment.time = idx_time;
792 GST_DEBUG_OBJECT (demux, "seeking to packet %u (%d)", packet, speed_count);
794 GST_OBJECT_LOCK (demux);
795 demux->segment = segment;
796 demux->packet = packet;
797 demux->need_newsegment = TRUE;
798 demux->segment_seqnum = seqnum;
799 demux->speed_packets = speed_count;
800 gst_asf_demux_reset_stream_state_after_discont (demux);
801 GST_OBJECT_UNLOCK (demux);
804 /* restart our task since it might have been stopped when we did the flush */
805 gst_pad_start_task (demux->sinkpad, (GstTaskFunction) gst_asf_demux_loop,
808 /* streaming can continue now */
809 GST_PAD_STREAM_UNLOCK (demux->sinkpad);
815 gst_asf_demux_handle_src_event (GstPad * pad, GstObject * parent,
821 demux = GST_ASF_DEMUX (parent);
823 switch (GST_EVENT_TYPE (event)) {
825 GST_LOG_OBJECT (pad, "seek event");
826 ret = gst_asf_demux_handle_seek_event (demux, event);
827 gst_event_unref (event);
830 case GST_EVENT_NAVIGATION:
831 /* just drop these two silently */
832 gst_event_unref (event);
836 GST_LOG_OBJECT (pad, "%s event", GST_EVENT_TYPE_NAME (event));
837 ret = gst_pad_event_default (pad, parent, event);
844 static inline guint32
845 gst_asf_demux_identify_guid (const ASFGuidHash * guids, ASFGuid * guid)
849 ret = gst_asf_identify_guid (guids, guid);
851 GST_LOG ("%s 0x%08x-0x%08x-0x%08x-0x%08x",
852 gst_asf_get_guid_nick (guids, ret),
853 guid->v1, guid->v2, guid->v3, guid->v4);
865 /* expect is true when the user is expeting an object,
866 * when false, it will give no warnings if the object
870 asf_demux_peek_object (GstASFDemux * demux, const guint8 * data,
871 guint data_len, AsfObject * object, gboolean expect)
875 if (data_len < ASF_OBJECT_HEADER_SIZE)
878 guid.v1 = GST_READ_UINT32_LE (data + 0);
879 guid.v2 = GST_READ_UINT32_LE (data + 4);
880 guid.v3 = GST_READ_UINT32_LE (data + 8);
881 guid.v4 = GST_READ_UINT32_LE (data + 12);
883 object->size = GST_READ_UINT64_LE (data + 16);
885 /* FIXME: make asf_demux_identify_object_guid() */
886 object->id = gst_asf_demux_identify_guid (asf_object_guids, &guid);
887 if (object->id == ASF_OBJ_UNDEFINED && expect) {
888 GST_WARNING_OBJECT (demux, "Unknown object %08x-%08x-%08x-%08x",
889 guid.v1, guid.v2, guid.v3, guid.v4);
896 gst_asf_demux_release_old_pads (GstASFDemux * demux)
898 GST_DEBUG_OBJECT (demux, "Releasing old pads");
900 while (demux->old_num_streams > 0) {
901 gst_pad_push_event (demux->old_stream[demux->old_num_streams - 1].pad,
902 gst_event_new_eos ());
903 gst_asf_demux_free_stream (demux,
904 &demux->old_stream[demux->old_num_streams - 1]);
905 --demux->old_num_streams;
907 memset (demux->old_stream, 0, sizeof (demux->old_stream));
908 demux->old_num_streams = 0;
912 gst_asf_demux_chain_headers (GstASFDemux * demux)
916 guint8 *header_data, *data = NULL;
917 const guint8 *cdata = NULL;
920 cdata = (guint8 *) gst_adapter_map (demux->adapter, ASF_OBJECT_HEADER_SIZE);
924 asf_demux_peek_object (demux, cdata, ASF_OBJECT_HEADER_SIZE, &obj, TRUE);
925 if (obj.id != ASF_OBJ_HEADER)
928 GST_LOG_OBJECT (demux, "header size = %u", (guint) obj.size);
930 /* + 50 for non-packet data at beginning of ASF_OBJ_DATA */
931 if (gst_adapter_available (demux->adapter) < obj.size + 50)
934 data = gst_adapter_take (demux->adapter, obj.size + 50);
937 header_size = obj.size;
938 flow = gst_asf_demux_process_object (demux, &header_data, &header_size);
939 if (flow != GST_FLOW_OK)
942 /* calculate where the packet data starts */
943 demux->data_offset = obj.size + 50;
945 /* now parse the beginning of the ASF_OBJ_DATA object */
946 if (!gst_asf_demux_parse_data_object_start (demux, data + obj.size))
949 if (demux->num_streams == 0)
958 GST_LOG_OBJECT (demux, "not enough data in adapter yet");
965 GST_ELEMENT_ERROR (demux, STREAM, WRONG_TYPE, (NULL),
966 ("This doesn't seem to be an ASF file"));
968 return GST_FLOW_ERROR;
973 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
974 ("header parsing failed, or no streams found, flow = %s",
975 gst_flow_get_name (flow)));
977 return GST_FLOW_ERROR;
982 gst_asf_demux_pull_data (GstASFDemux * demux, guint64 offset, guint size,
983 GstBuffer ** p_buf, GstFlowReturn * p_flow)
988 GST_LOG_OBJECT (demux, "pulling buffer at %" G_GUINT64_FORMAT "+%u",
991 flow = gst_pad_pull_range (demux->sinkpad, offset, size, p_buf);
993 if (G_LIKELY (p_flow))
996 if (G_UNLIKELY (flow != GST_FLOW_OK)) {
997 GST_DEBUG_OBJECT (demux, "flow %s pulling buffer at %" G_GUINT64_FORMAT
998 "+%u", gst_flow_get_name (flow), offset, size);
1003 g_assert (*p_buf != NULL);
1005 buffer_size = gst_buffer_get_size (*p_buf);
1006 if (G_UNLIKELY (buffer_size < size)) {
1007 GST_DEBUG_OBJECT (demux, "short read pulling buffer at %" G_GUINT64_FORMAT
1008 "+%u (got only %" G_GSIZE_FORMAT " bytes)", offset, size, buffer_size);
1009 gst_buffer_unref (*p_buf);
1010 if (G_LIKELY (p_flow))
1011 *p_flow = GST_FLOW_EOS;
1020 gst_asf_demux_pull_indices (GstASFDemux * demux)
1022 GstBuffer *buf = NULL;
1026 offset = demux->index_offset;
1028 if (G_UNLIKELY (offset == 0)) {
1029 GST_DEBUG_OBJECT (demux, "can't read indices, don't know index offset");
1033 while (gst_asf_demux_pull_data (demux, offset, 16 + 8, &buf, NULL)) {
1039 gst_buffer_map (buf, &map, GST_MAP_READ);
1040 g_assert (map.size >= 16 + 8);
1041 asf_demux_peek_object (demux, map.data, 16 + 8, &obj, TRUE);
1042 gst_buffer_unmap (buf, &map);
1043 gst_buffer_replace (&buf, NULL);
1045 /* check for sanity */
1046 if (G_UNLIKELY (obj.size > (5 * 1024 * 1024))) {
1047 GST_DEBUG_OBJECT (demux, "implausible index object size, bailing out");
1051 if (G_UNLIKELY (!gst_asf_demux_pull_data (demux, offset, obj.size, &buf,
1055 GST_LOG_OBJECT (demux, "index object at offset 0x%" G_GINT64_MODIFIER "X"
1056 ", size %u", offset, (guint) obj.size);
1058 offset += obj.size; /* increase before _process_object changes it */
1060 gst_buffer_map (buf, &map, GST_MAP_READ);
1061 g_assert (map.size >= obj.size);
1062 bufdata = (guint8 *) map.data;
1063 flow = gst_asf_demux_process_object (demux, &bufdata, &obj.size);
1064 gst_buffer_unmap (buf, &map);
1065 gst_buffer_replace (&buf, NULL);
1067 if (G_UNLIKELY (flow != GST_FLOW_OK))
1072 GST_DEBUG_OBJECT (demux, "read %u index objects", num_read);
1076 gst_asf_demux_parse_data_object_start (GstASFDemux * demux, guint8 * data)
1080 asf_demux_peek_object (demux, data, 50, &obj, TRUE);
1081 if (obj.id != ASF_OBJ_DATA) {
1082 GST_WARNING_OBJECT (demux, "headers not followed by a DATA object");
1086 demux->state = GST_ASF_DEMUX_STATE_DATA;
1088 if (!demux->broadcast && obj.size > 50) {
1089 demux->data_size = obj.size - 50;
1090 /* CHECKME: for at least one file this is off by +158 bytes?! */
1091 demux->index_offset = demux->data_offset + demux->data_size;
1093 demux->data_size = 0;
1094 demux->index_offset = 0;
1099 if (!demux->broadcast) {
1100 /* skip object header (24 bytes) and file GUID (16 bytes) */
1101 demux->num_packets = GST_READ_UINT64_LE (data + (16 + 8) + 16);
1103 demux->num_packets = 0;
1106 if (demux->num_packets == 0)
1107 demux->seekable = FALSE;
1109 /* fallback in the unlikely case that headers are inconsistent, can't hurt */
1110 if (demux->data_size == 0 && demux->num_packets > 0) {
1111 demux->data_size = demux->num_packets * demux->packet_size;
1112 demux->index_offset = demux->data_offset + demux->data_size;
1115 /* process pending stream objects and create pads for those */
1116 gst_asf_demux_process_queued_extended_stream_objects (demux);
1118 GST_INFO_OBJECT (demux, "Stream has %" G_GUINT64_FORMAT " packets, "
1119 "data_offset=%" G_GINT64_FORMAT ", data_size=%" G_GINT64_FORMAT
1120 ", index_offset=%" G_GUINT64_FORMAT, demux->num_packets,
1121 demux->data_offset, demux->data_size, demux->index_offset);
1127 gst_asf_demux_pull_headers (GstASFDemux * demux, GstFlowReturn * pflow)
1129 GstFlowReturn flow = GST_FLOW_OK;
1131 GstBuffer *buf = NULL;
1136 GST_LOG_OBJECT (demux, "reading headers");
1138 /* pull HEADER object header, so we know its size */
1139 if (!gst_asf_demux_pull_data (demux, demux->base_offset, 16 + 8, &buf, &flow))
1142 gst_buffer_map (buf, &map, GST_MAP_READ);
1143 g_assert (map.size >= 16 + 8);
1144 asf_demux_peek_object (demux, map.data, 16 + 8, &obj, TRUE);
1145 gst_buffer_unmap (buf, &map);
1146 gst_buffer_replace (&buf, NULL);
1148 if (obj.id != ASF_OBJ_HEADER)
1151 GST_LOG_OBJECT (demux, "header size = %u", (guint) obj.size);
1153 /* pull HEADER object */
1154 if (!gst_asf_demux_pull_data (demux, demux->base_offset, obj.size, &buf,
1158 size = obj.size; /* don't want obj.size changed */
1159 gst_buffer_map (buf, &map, GST_MAP_READ);
1160 g_assert (map.size >= size);
1161 bufdata = (guint8 *) map.data;
1162 flow = gst_asf_demux_process_object (demux, &bufdata, &size);
1163 gst_buffer_unmap (buf, &map);
1164 gst_buffer_replace (&buf, NULL);
1166 if (flow != GST_FLOW_OK) {
1167 GST_WARNING_OBJECT (demux, "process_object: %s", gst_flow_get_name (flow));
1171 /* calculate where the packet data starts */
1172 demux->data_offset = demux->base_offset + obj.size + 50;
1174 /* now pull beginning of DATA object before packet data */
1175 if (!gst_asf_demux_pull_data (demux, demux->base_offset + obj.size, 50, &buf,
1179 gst_buffer_map (buf, &map, GST_MAP_READ);
1180 g_assert (map.size >= size);
1181 bufdata = (guint8 *) map.data;
1182 if (!gst_asf_demux_parse_data_object_start (demux, bufdata))
1185 if (demux->num_streams == 0)
1188 gst_buffer_unmap (buf, &map);
1189 gst_buffer_replace (&buf, NULL);
1197 gst_buffer_unmap (buf, &map);
1198 gst_buffer_replace (&buf, NULL);
1200 GST_ELEMENT_ERROR (demux, STREAM, WRONG_TYPE, (NULL),
1201 ("This doesn't seem to be an ASF file"));
1202 *pflow = GST_FLOW_ERROR;
1207 flow = GST_FLOW_ERROR;
1208 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
1209 ("header parsing failed, or no streams found, flow = %s",
1210 gst_flow_get_name (flow)));
1215 gst_buffer_unmap (buf, &map);
1216 gst_buffer_replace (&buf, NULL);
1223 all_streams_prerolled (GstASFDemux * demux)
1225 GstClockTime preroll_time;
1226 guint i, num_no_data = 0;
1228 /* Allow at least 500ms of preroll_time */
1229 preroll_time = MAX (demux->preroll, 500 * GST_MSECOND);
1231 /* returns TRUE as long as there isn't a stream which (a) has data queued
1232 * and (b) the timestamp of last piece of data queued is < demux->preroll
1233 * AND there is at least one other stream with data queued */
1234 for (i = 0; i < demux->num_streams; ++i) {
1235 AsfPayload *last_payload = NULL;
1239 stream = &demux->stream[i];
1240 if (G_UNLIKELY (stream->payloads->len == 0)) {
1242 GST_LOG_OBJECT (stream->pad, "no data queued");
1246 /* find last payload with timestamp */
1247 for (last_idx = stream->payloads->len - 1;
1248 last_idx >= 0 && (last_payload == NULL
1249 || !GST_CLOCK_TIME_IS_VALID (last_payload->ts)); --last_idx) {
1250 last_payload = &g_array_index (stream->payloads, AsfPayload, last_idx);
1253 GST_LOG_OBJECT (stream->pad, "checking if %" GST_TIME_FORMAT " > %"
1254 GST_TIME_FORMAT, GST_TIME_ARGS (last_payload->ts),
1255 GST_TIME_ARGS (preroll_time));
1256 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (last_payload->ts)
1257 || last_payload->ts <= preroll_time)) {
1258 GST_LOG_OBJECT (stream->pad, "not beyond preroll point yet");
1263 if (G_UNLIKELY (num_no_data > 0))
1271 gst_asf_demux_have_mutually_exclusive_active_stream (GstASFDemux * demux,
1276 for (l = demux->mut_ex_streams; l != NULL; l = l->next) {
1279 /* check for each mutual exclusion group whether it affects this stream */
1280 for (mes = (guint8 *) l->data; mes != NULL && *mes != 0xff; ++mes) {
1281 if (*mes == stream->id) {
1282 /* we are in this group; let's check if we've already activated streams
1283 * that are in the same group (and hence mutually exclusive to this
1285 for (mes = (guint8 *) l->data; mes != NULL && *mes != 0xff; ++mes) {
1288 for (i = 0; i < demux->num_streams; ++i) {
1289 if (demux->stream[i].id == *mes && demux->stream[i].active) {
1290 GST_LOG_OBJECT (demux, "stream with ID %d is mutually exclusive "
1291 "to already active stream with ID %d", stream->id,
1292 demux->stream[i].id);
1297 /* we can only be in this group once, let's break out and move on to
1298 * the next mutual exclusion group */
1309 gst_asf_demux_check_segment_ts (GstASFDemux * demux, GstClockTime payload_ts)
1311 /* remember the first queued timestamp for the segment */
1312 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (demux->segment_ts) &&
1313 GST_CLOCK_TIME_IS_VALID (demux->first_ts))) {
1314 GST_DEBUG_OBJECT (demux, "segment ts: %" GST_TIME_FORMAT,
1315 GST_TIME_ARGS (demux->first_ts));
1316 demux->segment_ts = payload_ts;
1317 /* always note, but only determines segment when streaming */
1318 if (demux->streaming)
1319 gst_segment_do_seek (&demux->segment, demux->in_segment.rate,
1320 GST_FORMAT_TIME, (GstSeekFlags) demux->segment.flags,
1321 GST_SEEK_TYPE_SET, demux->segment_ts, GST_SEEK_TYPE_NONE, 0, NULL);
1326 gst_asf_demux_check_first_ts (GstASFDemux * demux, gboolean force)
1328 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (demux->first_ts))) {
1329 GstClockTime first_ts = GST_CLOCK_TIME_NONE;
1332 /* go trhough each stream, find smallest timestamp */
1333 for (i = 0; i < demux->num_streams; ++i) {
1336 GstClockTime stream_min_ts = GST_CLOCK_TIME_NONE;
1337 GstClockTime stream_min_ts2 = GST_CLOCK_TIME_NONE; /* second smallest timestamp */
1338 stream = &demux->stream[i];
1340 for (j = 0; j < stream->payloads->len; ++j) {
1341 AsfPayload *payload = &g_array_index (stream->payloads, AsfPayload, j);
1342 if (GST_CLOCK_TIME_IS_VALID (payload->ts) &&
1343 (!GST_CLOCK_TIME_IS_VALID (stream_min_ts)
1344 || stream_min_ts > payload->ts)) {
1345 stream_min_ts = payload->ts;
1347 if (GST_CLOCK_TIME_IS_VALID (payload->ts) &&
1348 payload->ts > stream_min_ts &&
1349 (!GST_CLOCK_TIME_IS_VALID (stream_min_ts2)
1350 || stream_min_ts2 > payload->ts)) {
1351 stream_min_ts2 = payload->ts;
1355 /* there are some DVR ms files where first packet has TS of 0 (instead of -1) while subsequent packets have
1356 regular (singificantly larger) timestamps. If we don't deal with it, we may end up with huge gap in timestamps
1357 which makes playback stuck. The 0 timestamp may also be valid though, if the second packet timestamp continues
1358 from it. I havent found a better way to distinguish between these two, except to set an arbitrary boundary
1359 and disregard the first 0 timestamp if the second timestamp is bigger than the boundary) */
1361 if (stream_min_ts == 0 && stream_min_ts2 == GST_CLOCK_TIME_NONE && !force) /* still waiting for the second timestamp */
1364 if (stream_min_ts == 0 && stream_min_ts2 > GST_SECOND) /* first timestamp is 0 and second is significantly larger, disregard the 0 */
1365 stream_min_ts = stream_min_ts2;
1367 /* if we don't have timestamp for this stream, wait for more data */
1368 if (!GST_CLOCK_TIME_IS_VALID (stream_min_ts) && !force)
1371 if (GST_CLOCK_TIME_IS_VALID (stream_min_ts) &&
1372 (!GST_CLOCK_TIME_IS_VALID (first_ts) || first_ts > stream_min_ts))
1373 first_ts = stream_min_ts;
1376 if (!GST_CLOCK_TIME_IS_VALID (first_ts)) /* can happen with force = TRUE */
1379 demux->first_ts = first_ts;
1381 /* update packets queued before we knew first timestamp */
1382 for (i = 0; i < demux->num_streams; ++i) {
1385 stream = &demux->stream[i];
1387 for (j = 0; j < stream->payloads->len; ++j) {
1388 AsfPayload *payload = &g_array_index (stream->payloads, AsfPayload, j);
1389 if (GST_CLOCK_TIME_IS_VALID (payload->ts)) {
1390 if (payload->ts > first_ts)
1391 payload->ts -= first_ts;
1399 gst_asf_demux_check_segment_ts (demux, 0);
1405 gst_asf_demux_update_caps_from_payload (GstASFDemux * demux, AsfStream * stream)
1407 /* try to determine whether the stream is AC-3 or MPEG; In dvr-ms the codecTag is unreliable
1408 and often set wrong, inspecting the data is the only way that seem to be working */
1409 GstTypeFindProbability prob = GST_TYPE_FIND_NONE;
1410 GstCaps *caps = NULL;
1412 GstAdapter *adapter = gst_adapter_new ();
1414 for (i = 0; i < stream->payloads->len && prob < GST_TYPE_FIND_LIKELY; ++i) {
1416 AsfPayload *payload;
1419 payload = &g_array_index (stream->payloads, AsfPayload, i);
1420 gst_adapter_push (adapter, gst_buffer_ref (payload->buf));
1421 len = gst_adapter_available (adapter);
1422 data = gst_adapter_map (adapter, len);
1426 #define MIN_LENGTH 128
1428 /* look for the sync points */
1430 if (len < MIN_LENGTH || /* give typefind something to work on */
1431 (data[0] == 0x0b && data[1] == 0x77) || /* AC-3 sync point */
1432 (data[0] == 0xFF && ((data[1] & 0xF0) >> 4) == 0xF)) /* MPEG sync point */
1438 gst_caps_take (&caps, gst_type_find_helper_for_data (GST_OBJECT (demux),
1441 if (prob < GST_TYPE_FIND_LIKELY) {
1444 if (len > MIN_LENGTH)
1445 /* this wasn't it, look for another sync point */
1449 gst_adapter_unmap (adapter);
1452 gst_object_unref (adapter);
1455 gst_caps_take (&stream->caps, caps);
1463 gst_asf_demux_check_activate_streams (GstASFDemux * demux, gboolean force)
1467 if (demux->activated_streams)
1470 if (G_UNLIKELY (!gst_asf_demux_check_first_ts (demux, force)))
1473 if (!all_streams_prerolled (demux) && !force) {
1474 GST_DEBUG_OBJECT (demux, "not all streams with data beyond preroll yet");
1478 for (i = 0; i < demux->num_streams; ++i) {
1479 AsfStream *stream = &demux->stream[i];
1481 if (stream->payloads->len > 0) {
1483 if (stream->inspect_payload && /* dvr-ms required payload inspection */
1484 !stream->active && /* do not inspect active streams (caps were already set) */
1485 !gst_asf_demux_update_caps_from_payload (demux, stream) && /* failed to determine caps */
1486 stream->payloads->len < 20) { /* if we couldn't determine the caps from 20 packets then just give up and use whatever was in codecTag */
1487 /* try to gather some more data */
1490 /* we don't check mutual exclusion stuff here; either we have data for
1491 * a stream, then we active it, or we don't, then we'll ignore it */
1492 GST_LOG_OBJECT (stream->pad, "is prerolled - activate!");
1493 gst_asf_demux_activate_stream (demux, stream);
1495 GST_LOG_OBJECT (stream->pad, "no data, ignoring stream");
1499 gst_asf_demux_release_old_pads (demux);
1501 demux->activated_streams = TRUE;
1502 GST_LOG_OBJECT (demux, "signalling no more pads");
1503 gst_element_no_more_pads (GST_ELEMENT (demux));
1507 /* returns the stream that has a complete payload with the lowest timestamp
1508 * queued, or NULL (we push things by timestamp because during the internal
1509 * prerolling we might accumulate more data then the external queues can take,
1510 * so we'd lock up if we pushed all accumulated data for stream N in one go) */
1512 gst_asf_demux_find_stream_with_complete_payload (GstASFDemux * demux)
1514 AsfPayload *best_payload = NULL;
1515 AsfStream *best_stream = NULL;
1518 for (i = 0; i < demux->num_streams; ++i) {
1522 stream = &demux->stream[i];
1524 /* Don't push any data until we have at least one payload that falls within
1525 * the current segment. This way we can remove out-of-segment payloads that
1526 * don't need to be decoded after a seek, sending only data from the
1527 * keyframe directly before our segment start */
1528 if (stream->payloads->len > 0) {
1529 AsfPayload *payload = NULL;
1532 /* find last payload with timestamp */
1533 for (last_idx = stream->payloads->len - 1;
1534 last_idx >= 0 && (payload == NULL
1535 || !GST_CLOCK_TIME_IS_VALID (payload->ts)); --last_idx) {
1536 payload = &g_array_index (stream->payloads, AsfPayload, last_idx);
1539 /* if this is first payload after seek we might need to update the segment */
1540 if (GST_CLOCK_TIME_IS_VALID (payload->ts))
1541 gst_asf_demux_check_segment_ts (demux, payload->ts);
1543 if (G_UNLIKELY (GST_CLOCK_TIME_IS_VALID (payload->ts) &&
1544 (payload->ts < demux->segment.start))) {
1545 if (G_UNLIKELY (demux->keyunit_sync && payload->keyframe)) {
1546 GST_DEBUG_OBJECT (stream->pad,
1547 "Found keyframe, updating segment start to %" GST_TIME_FORMAT,
1548 GST_TIME_ARGS (payload->ts));
1549 demux->segment.start = payload->ts;
1550 demux->segment.time = payload->ts;
1552 GST_DEBUG_OBJECT (stream->pad, "Last queued payload has timestamp %"
1553 GST_TIME_FORMAT " which is before our segment start %"
1554 GST_TIME_FORMAT ", not pushing yet", GST_TIME_ARGS (payload->ts),
1555 GST_TIME_ARGS (demux->segment.start));
1560 /* Now see if there's a complete payload queued for this stream */
1563 /* find first complete payload with timestamp */
1565 j < stream->payloads->len && (payload == NULL
1566 || !GST_CLOCK_TIME_IS_VALID (payload->ts)); ++j) {
1567 payload = &g_array_index (stream->payloads, AsfPayload, j);
1570 if (!gst_asf_payload_is_complete (payload))
1573 /* ... and whether its timestamp is lower than the current best */
1574 if (best_stream == NULL || best_payload->ts > payload->ts) {
1575 best_stream = stream;
1576 best_payload = payload;
1584 static GstFlowReturn
1585 gst_asf_demux_push_complete_payloads (GstASFDemux * demux, gboolean force)
1588 GstFlowReturn ret = GST_FLOW_OK;
1590 if (G_UNLIKELY (!demux->activated_streams)) {
1591 if (!gst_asf_demux_check_activate_streams (demux, force))
1593 /* streams are now activated */
1596 while ((stream = gst_asf_demux_find_stream_with_complete_payload (demux))) {
1597 AsfPayload *payload;
1598 GstClockTime timestamp = GST_CLOCK_TIME_NONE;
1599 GstClockTime duration = GST_CLOCK_TIME_NONE;
1601 /* wait until we had a chance to "lock on" some payload's timestamp */
1602 if (G_UNLIKELY (demux->need_newsegment
1603 && !GST_CLOCK_TIME_IS_VALID (demux->segment_ts)))
1606 payload = &g_array_index (stream->payloads, AsfPayload, 0);
1608 /* do we need to send a newsegment event */
1609 if ((G_UNLIKELY (demux->need_newsegment))) {
1610 GstEvent *segment_event;
1612 /* safe default if insufficient upstream info */
1613 if (!GST_CLOCK_TIME_IS_VALID (demux->in_gap))
1616 if (demux->segment.stop == GST_CLOCK_TIME_NONE &&
1617 demux->segment.duration > 0) {
1618 /* slight HACK; prevent clipping of last bit */
1619 demux->segment.stop = demux->segment.duration + demux->in_gap;
1622 /* FIXME : only if ACCURATE ! */
1623 if (G_LIKELY (demux->keyunit_sync
1624 && GST_CLOCK_TIME_IS_VALID (payload->ts))) {
1625 GST_DEBUG ("Adjusting newsegment start to %" GST_TIME_FORMAT,
1626 GST_TIME_ARGS (payload->ts));
1627 demux->segment.start = payload->ts;
1628 demux->segment.time = payload->ts;
1631 GST_DEBUG_OBJECT (demux, "sending new-segment event %" GST_SEGMENT_FORMAT,
1634 /* note: we fix up all timestamps to start from 0, so this should be ok */
1635 segment_event = gst_event_new_segment (&demux->segment);
1636 if (demux->segment_seqnum)
1637 gst_event_set_seqnum (segment_event, demux->segment_seqnum);
1638 gst_asf_demux_send_event_unlocked (demux, segment_event);
1640 /* now post any global tags we may have found */
1641 if (demux->taglist == NULL) {
1642 demux->taglist = gst_tag_list_new_empty ();
1643 gst_tag_list_set_scope (demux->taglist, GST_TAG_SCOPE_GLOBAL);
1646 gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
1647 GST_TAG_CONTAINER_FORMAT, "ASF", NULL);
1649 GST_DEBUG_OBJECT (demux, "global tags: %" GST_PTR_FORMAT, demux->taglist);
1650 gst_asf_demux_send_event_unlocked (demux,
1651 gst_event_new_tag (demux->taglist));
1652 demux->taglist = NULL;
1654 demux->need_newsegment = FALSE;
1655 demux->segment_seqnum = 0;
1656 demux->segment_running = TRUE;
1659 /* Do we have tags pending for this stream? */
1660 if (G_UNLIKELY (stream->pending_tags)) {
1661 GST_LOG_OBJECT (stream->pad, "%" GST_PTR_FORMAT, stream->pending_tags);
1662 gst_pad_push_event (stream->pad,
1663 gst_event_new_tag (stream->pending_tags));
1664 stream->pending_tags = NULL;
1667 /* We have the whole packet now so we should push the packet to
1668 * the src pad now. First though we should check if we need to do
1670 if (G_UNLIKELY (stream->span > 1)) {
1671 gst_asf_demux_descramble_buffer (demux, stream, &payload->buf);
1674 payload->buf = gst_buffer_make_writable (payload->buf);
1676 if (G_LIKELY (!payload->keyframe)) {
1677 GST_BUFFER_FLAG_SET (payload->buf, GST_BUFFER_FLAG_DELTA_UNIT);
1680 if (G_UNLIKELY (stream->discont)) {
1681 GST_DEBUG_OBJECT (stream->pad, "marking DISCONT on stream");
1682 GST_BUFFER_FLAG_SET (payload->buf, GST_BUFFER_FLAG_DISCONT);
1683 stream->discont = FALSE;
1686 if (G_UNLIKELY (stream->is_video && payload->par_x && payload->par_y &&
1687 (payload->par_x != stream->par_x) &&
1688 (payload->par_y != stream->par_y))) {
1689 GST_DEBUG ("Updating PAR (%d/%d => %d/%d)",
1690 stream->par_x, stream->par_y, payload->par_x, payload->par_y);
1691 stream->par_x = payload->par_x;
1692 stream->par_y = payload->par_y;
1693 stream->caps = gst_caps_make_writable (stream->caps);
1694 gst_caps_set_simple (stream->caps, "pixel-aspect-ratio",
1695 GST_TYPE_FRACTION, stream->par_x, stream->par_y, NULL);
1696 gst_pad_set_caps (stream->pad, stream->caps);
1699 if (G_UNLIKELY (stream->interlaced != payload->interlaced)) {
1700 GST_DEBUG ("Updating interlaced status (%d => %d)", stream->interlaced,
1701 payload->interlaced);
1702 stream->interlaced = payload->interlaced;
1703 stream->caps = gst_caps_make_writable (stream->caps);
1704 gst_caps_set_simple (stream->caps, "interlace-mode", G_TYPE_BOOLEAN,
1705 (stream->interlaced ? "mixed" : "progressive"), NULL);
1706 gst_pad_set_caps (stream->pad, stream->caps);
1709 /* (sort of) interpolate timestamps using upstream "frame of reference",
1710 * typically useful for live src, but might (unavoidably) mess with
1711 * position reporting if a live src is playing not so live content
1712 * (e.g. rtspsrc taking some time to fall back to tcp) */
1713 timestamp = payload->ts;
1714 if (GST_CLOCK_TIME_IS_VALID (timestamp)) {
1715 timestamp += demux->in_gap;
1717 /* Check if we're after the segment already, if so no need to push
1719 if (demux->segment.stop != -1 && timestamp > demux->segment.stop) {
1720 GST_DEBUG_OBJECT (stream->pad,
1721 "Payload after segment stop %" GST_TIME_FORMAT,
1722 GST_TIME_ARGS (demux->segment.stop));
1724 gst_flow_combiner_update_pad_flow (demux->flowcombiner, stream->pad,
1726 gst_buffer_unref (payload->buf);
1727 payload->buf = NULL;
1728 g_array_remove_index (stream->payloads, 0);
1729 /* Break out as soon as we have an issue */
1730 if (G_UNLIKELY (ret != GST_FLOW_OK))
1737 GST_BUFFER_PTS (payload->buf) = timestamp;
1739 if (payload->duration == GST_CLOCK_TIME_NONE
1740 && stream->ext_props.avg_time_per_frame != 0) {
1741 duration = stream->ext_props.avg_time_per_frame * 100;
1743 duration = payload->duration;
1745 GST_BUFFER_DURATION (payload->buf) = duration;
1747 /* FIXME: we should really set durations on buffers if we can */
1749 GST_LOG_OBJECT (stream->pad, "pushing buffer, %" GST_PTR_FORMAT,
1752 if (stream->active) {
1753 if (G_UNLIKELY (stream->first_buffer)) {
1754 if (stream->streamheader != NULL) {
1755 GST_DEBUG_OBJECT (stream->pad,
1756 "Pushing streamheader before first buffer");
1757 gst_pad_push (stream->pad, gst_buffer_ref (stream->streamheader));
1759 stream->first_buffer = FALSE;
1762 if (GST_CLOCK_TIME_IS_VALID (timestamp)
1763 && timestamp > demux->segment.position) {
1764 demux->segment.position = timestamp;
1765 if (GST_CLOCK_TIME_IS_VALID (duration))
1766 demux->segment.position += timestamp;
1769 ret = gst_pad_push (stream->pad, payload->buf);
1771 gst_flow_combiner_update_pad_flow (demux->flowcombiner, stream->pad,
1774 gst_buffer_unref (payload->buf);
1777 payload->buf = NULL;
1778 g_array_remove_index (stream->payloads, 0);
1780 /* Break out as soon as we have an issue */
1781 if (G_UNLIKELY (ret != GST_FLOW_OK))
1789 gst_asf_demux_check_buffer_is_header (GstASFDemux * demux, GstBuffer * buf)
1793 g_assert (buf != NULL);
1795 GST_LOG_OBJECT (demux, "Checking if buffer is a header");
1797 gst_buffer_map (buf, &map, GST_MAP_READ);
1799 /* we return false on buffer too small */
1800 if (map.size < ASF_OBJECT_HEADER_SIZE) {
1801 gst_buffer_unmap (buf, &map);
1805 /* check if it is a header */
1806 asf_demux_peek_object (demux, map.data, ASF_OBJECT_HEADER_SIZE, &obj, TRUE);
1807 gst_buffer_unmap (buf, &map);
1808 if (obj.id == ASF_OBJ_HEADER) {
1815 gst_asf_demux_check_chained_asf (GstASFDemux * demux)
1817 guint64 off = demux->data_offset + (demux->packet * demux->packet_size);
1818 GstFlowReturn ret = GST_FLOW_OK;
1819 GstBuffer *buf = NULL;
1820 gboolean header = FALSE;
1822 /* TODO maybe we should skip index objects after the data and look
1823 * further for a new header */
1824 if (gst_asf_demux_pull_data (demux, off, ASF_OBJECT_HEADER_SIZE, &buf, &ret)) {
1825 g_assert (buf != NULL);
1826 /* check if it is a header */
1827 if (gst_asf_demux_check_buffer_is_header (demux, buf)) {
1828 GST_DEBUG_OBJECT (demux, "new base offset: %" G_GUINT64_FORMAT, off);
1829 demux->base_offset = off;
1833 gst_buffer_unref (buf);
1840 gst_asf_demux_loop (GstASFDemux * demux)
1842 GstFlowReturn flow = GST_FLOW_OK;
1843 GstBuffer *buf = NULL;
1846 if (G_UNLIKELY (demux->state == GST_ASF_DEMUX_STATE_HEADER)) {
1847 if (!gst_asf_demux_pull_headers (demux, &flow)) {
1851 gst_asf_demux_pull_indices (demux);
1854 g_assert (demux->state == GST_ASF_DEMUX_STATE_DATA);
1856 if (G_UNLIKELY (demux->num_packets != 0
1857 && demux->packet >= demux->num_packets))
1860 GST_LOG_OBJECT (demux, "packet %u/%u", (guint) demux->packet + 1,
1861 (guint) demux->num_packets);
1863 off = demux->data_offset + (demux->packet * demux->packet_size);
1865 if (G_UNLIKELY (!gst_asf_demux_pull_data (demux, off,
1866 demux->packet_size * demux->speed_packets, &buf, &flow))) {
1867 GST_DEBUG_OBJECT (demux, "got flow %s", gst_flow_get_name (flow));
1868 if (flow == GST_FLOW_EOS) {
1870 } else if (flow == GST_FLOW_FLUSHING) {
1871 GST_DEBUG_OBJECT (demux, "Not fatal");
1878 if (G_LIKELY (demux->speed_packets == 1)) {
1879 GstAsfDemuxParsePacketError err;
1880 err = gst_asf_demux_parse_packet (demux, buf);
1881 if (G_UNLIKELY (err != GST_ASF_DEMUX_PARSE_PACKET_ERROR_NONE)) {
1882 /* when we don't know when the data object ends, we should check
1883 * for a chained asf */
1884 if (demux->num_packets == 0) {
1885 if (gst_asf_demux_check_buffer_is_header (demux, buf)) {
1886 GST_INFO_OBJECT (demux, "Chained asf found");
1887 demux->base_offset = off;
1888 gst_asf_demux_reset (demux, TRUE);
1889 gst_buffer_unref (buf);
1893 /* FIXME: We should tally up fatal errors and error out only
1894 * after a few broken packets in a row? */
1896 GST_INFO_OBJECT (demux, "Ignoring recoverable parse error");
1897 gst_buffer_unref (buf);
1902 flow = gst_asf_demux_push_complete_payloads (demux, FALSE);
1908 for (n = 0; n < demux->speed_packets; n++) {
1910 GstAsfDemuxParsePacketError err;
1913 gst_buffer_copy_region (buf, GST_BUFFER_COPY_ALL,
1914 n * demux->packet_size, demux->packet_size);
1915 err = gst_asf_demux_parse_packet (demux, sub);
1916 if (G_UNLIKELY (err != GST_ASF_DEMUX_PARSE_PACKET_ERROR_NONE)) {
1917 /* when we don't know when the data object ends, we should check
1918 * for a chained asf */
1919 if (demux->num_packets == 0) {
1920 if (gst_asf_demux_check_buffer_is_header (demux, sub)) {
1921 GST_INFO_OBJECT (demux, "Chained asf found");
1922 demux->base_offset = off + n * demux->packet_size;
1923 gst_asf_demux_reset (demux, TRUE);
1924 gst_buffer_unref (sub);
1925 gst_buffer_unref (buf);
1929 /* FIXME: We should tally up fatal errors and error out only
1930 * after a few broken packets in a row? */
1932 GST_INFO_OBJECT (demux, "Ignoring recoverable parse error");
1936 gst_buffer_unref (sub);
1938 if (err == GST_ASF_DEMUX_PARSE_PACKET_ERROR_NONE)
1939 flow = gst_asf_demux_push_complete_payloads (demux, FALSE);
1945 /* reset speed pull */
1946 demux->speed_packets = 1;
1949 gst_buffer_unref (buf);
1951 if (G_UNLIKELY ((demux->num_packets > 0
1952 && demux->packet >= demux->num_packets)
1953 || flow == GST_FLOW_EOS)) {
1954 GST_LOG_OBJECT (demux, "reached EOS");
1958 if (G_UNLIKELY (flow != GST_FLOW_OK)) {
1959 GST_DEBUG_OBJECT (demux, "pushing complete payloads failed");
1963 /* check if we're at the end of the configured segment */
1964 /* FIXME: check if segment end reached etc. */
1970 /* if we haven't activated our streams yet, this might be because we have
1971 * less data queued than required for preroll; force stream activation and
1972 * send any pending payloads before sending EOS */
1973 if (!demux->activated_streams)
1974 gst_asf_demux_push_complete_payloads (demux, TRUE);
1976 /* we want to push an eos or post a segment-done in any case */
1977 if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
1980 /* for segment playback we need to post when (in stream time)
1981 * we stopped, this is either stop (when set) or the duration. */
1982 if ((stop = demux->segment.stop) == -1)
1983 stop = demux->segment.duration;
1985 GST_INFO_OBJECT (demux, "Posting segment-done, at end of segment");
1986 gst_element_post_message (GST_ELEMENT_CAST (demux),
1987 gst_message_new_segment_done (GST_OBJECT (demux), GST_FORMAT_TIME,
1989 gst_asf_demux_send_event_unlocked (demux,
1990 gst_event_new_segment_done (GST_FORMAT_TIME, stop));
1991 } else if (flow != GST_FLOW_EOS) {
1992 /* check if we have a chained asf, in case, we don't eos yet */
1993 if (gst_asf_demux_check_chained_asf (demux)) {
1994 GST_INFO_OBJECT (demux, "Chained ASF starting");
1995 gst_asf_demux_reset (demux, TRUE);
2000 if (!(demux->segment.flags & GST_SEEK_FLAG_SEGMENT)) {
2001 /* normal playback, send EOS to all linked pads */
2002 GST_INFO_OBJECT (demux, "Sending EOS, at end of stream");
2003 gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
2005 /* ... and fall through to pause */
2009 GST_DEBUG_OBJECT (demux, "pausing task, flow return: %s",
2010 gst_flow_get_name (flow));
2011 demux->segment_running = FALSE;
2012 gst_pad_pause_task (demux->sinkpad);
2014 /* For the error cases */
2015 if (flow < GST_FLOW_EOS || flow == GST_FLOW_NOT_LINKED) {
2016 /* Post an error. Hopefully something else already has, but if not... */
2017 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
2018 (_("Internal data stream error.")),
2019 ("streaming stopped, reason %s", gst_flow_get_name (flow)));
2020 gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
2029 GST_DEBUG_OBJECT (demux, "Read failed, doh");
2030 flow = GST_FLOW_EOS;
2034 /* See FIXMEs above */
2037 gst_buffer_unref (buf);
2038 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
2039 ("Error parsing ASF packet %u", (guint) demux->packet));
2040 gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
2041 flow = GST_FLOW_ERROR;
2047 #define GST_ASF_DEMUX_CHECK_HEADER_YES 0
2048 #define GST_ASF_DEMUX_CHECK_HEADER_NO 1
2049 #define GST_ASF_DEMUX_CHECK_HEADER_NEED_DATA 2
2052 gst_asf_demux_check_header (GstASFDemux * demux)
2055 guint8 *cdata = (guint8 *) gst_adapter_map (demux->adapter,
2056 ASF_OBJECT_HEADER_SIZE);
2057 if (cdata == NULL) /* need more data */
2058 return GST_ASF_DEMUX_CHECK_HEADER_NEED_DATA;
2060 asf_demux_peek_object (demux, cdata, ASF_OBJECT_HEADER_SIZE, &obj, FALSE);
2061 if (obj.id != ASF_OBJ_HEADER) {
2062 return GST_ASF_DEMUX_CHECK_HEADER_NO;
2064 return GST_ASF_DEMUX_CHECK_HEADER_YES;
2068 static GstFlowReturn
2069 gst_asf_demux_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
2071 GstFlowReturn ret = GST_FLOW_OK;
2074 demux = GST_ASF_DEMUX (parent);
2076 GST_LOG_OBJECT (demux,
2077 "buffer: size=%" G_GSIZE_FORMAT ", offset=%" G_GINT64_FORMAT ", time=%"
2078 GST_TIME_FORMAT, gst_buffer_get_size (buf), GST_BUFFER_OFFSET (buf),
2079 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)));
2081 if (G_UNLIKELY (GST_BUFFER_IS_DISCONT (buf))) {
2082 GST_DEBUG_OBJECT (demux, "received DISCONT");
2083 gst_asf_demux_mark_discont (demux);
2086 if (G_UNLIKELY ((!GST_CLOCK_TIME_IS_VALID (demux->in_gap) &&
2087 GST_BUFFER_TIMESTAMP_IS_VALID (buf)))) {
2088 demux->in_gap = GST_BUFFER_TIMESTAMP (buf) - demux->in_segment.start;
2089 GST_DEBUG_OBJECT (demux, "upstream segment start %" GST_TIME_FORMAT
2090 ", interpolation gap: %" GST_TIME_FORMAT,
2091 GST_TIME_ARGS (demux->in_segment.start), GST_TIME_ARGS (demux->in_gap));
2094 gst_adapter_push (demux->adapter, buf);
2096 switch (demux->state) {
2097 case GST_ASF_DEMUX_STATE_INDEX:{
2098 gint result = gst_asf_demux_check_header (demux);
2099 if (result == GST_ASF_DEMUX_CHECK_HEADER_NEED_DATA) /* need more data */
2102 if (result == GST_ASF_DEMUX_CHECK_HEADER_NO) {
2103 /* we don't care about this, probably an index */
2104 /* TODO maybe would be smarter to skip all the indices
2105 * until we got a new header or EOS to decide */
2106 GST_LOG_OBJECT (demux, "Received index object, its EOS");
2109 GST_INFO_OBJECT (demux, "Chained asf starting");
2110 /* cleanup and get ready for a chained asf */
2111 gst_asf_demux_reset (demux, TRUE);
2115 case GST_ASF_DEMUX_STATE_HEADER:{
2116 ret = gst_asf_demux_chain_headers (demux);
2117 if (demux->state != GST_ASF_DEMUX_STATE_DATA)
2119 /* otherwise fall through */
2121 case GST_ASF_DEMUX_STATE_DATA:
2125 data_size = demux->packet_size;
2127 while (gst_adapter_available (demux->adapter) >= data_size) {
2129 GstAsfDemuxParsePacketError err;
2131 /* we don't know the length of the stream
2132 * check for a chained asf everytime */
2133 if (demux->num_packets == 0) {
2134 gint result = gst_asf_demux_check_header (demux);
2136 if (result == GST_ASF_DEMUX_CHECK_HEADER_YES) {
2137 GST_INFO_OBJECT (demux, "Chained asf starting");
2138 /* cleanup and get ready for a chained asf */
2139 gst_asf_demux_reset (demux, TRUE);
2142 } else if (G_UNLIKELY (demux->num_packets != 0 && demux->packet >= 0
2143 && demux->packet >= demux->num_packets)) {
2144 /* do not overshoot data section when streaming */
2148 buf = gst_adapter_take_buffer (demux->adapter, data_size);
2150 /* FIXME: We should tally up fatal errors and error out only
2151 * after a few broken packets in a row? */
2152 err = gst_asf_demux_parse_packet (demux, buf);
2154 gst_buffer_unref (buf);
2156 if (G_LIKELY (err == GST_ASF_DEMUX_PARSE_PACKET_ERROR_NONE))
2157 ret = gst_asf_demux_push_complete_payloads (demux, FALSE);
2159 GST_WARNING_OBJECT (demux, "Parse error");
2161 if (demux->packet >= 0)
2164 if (G_UNLIKELY (demux->num_packets != 0 && demux->packet >= 0
2165 && demux->packet >= demux->num_packets)) {
2166 demux->state = GST_ASF_DEMUX_STATE_INDEX;
2171 g_assert_not_reached ();
2175 if (ret != GST_FLOW_OK)
2176 GST_DEBUG_OBJECT (demux, "flow: %s", gst_flow_get_name (ret));
2182 GST_DEBUG_OBJECT (demux, "Handled last packet, setting EOS");
2188 static inline gboolean
2189 gst_asf_demux_skip_bytes (guint num_bytes, guint8 ** p_data, guint64 * p_size)
2191 if (*p_size < num_bytes)
2194 *p_data += num_bytes;
2195 *p_size -= num_bytes;
2199 static inline guint8
2200 gst_asf_demux_get_uint8 (guint8 ** p_data, guint64 * p_size)
2204 g_assert (*p_size >= 1);
2205 ret = GST_READ_UINT8 (*p_data);
2206 *p_data += sizeof (guint8);
2207 *p_size -= sizeof (guint8);
2211 static inline guint16
2212 gst_asf_demux_get_uint16 (guint8 ** p_data, guint64 * p_size)
2216 g_assert (*p_size >= 2);
2217 ret = GST_READ_UINT16_LE (*p_data);
2218 *p_data += sizeof (guint16);
2219 *p_size -= sizeof (guint16);
2223 static inline guint32
2224 gst_asf_demux_get_uint32 (guint8 ** p_data, guint64 * p_size)
2228 g_assert (*p_size >= 4);
2229 ret = GST_READ_UINT32_LE (*p_data);
2230 *p_data += sizeof (guint32);
2231 *p_size -= sizeof (guint32);
2235 static inline guint64
2236 gst_asf_demux_get_uint64 (guint8 ** p_data, guint64 * p_size)
2240 g_assert (*p_size >= 8);
2241 ret = GST_READ_UINT64_LE (*p_data);
2242 *p_data += sizeof (guint64);
2243 *p_size -= sizeof (guint64);
2248 gst_asf_demux_get_buffer (GstBuffer ** p_buf, guint num_bytes_to_read,
2249 guint8 ** p_data, guint64 * p_size)
2253 if (*p_size < num_bytes_to_read)
2256 *p_buf = gst_buffer_new_and_alloc (num_bytes_to_read);
2257 gst_buffer_fill (*p_buf, 0, *p_data, num_bytes_to_read);
2259 *p_data += num_bytes_to_read;
2260 *p_size -= num_bytes_to_read;
2266 gst_asf_demux_get_bytes (guint8 ** p_buf, guint num_bytes_to_read,
2267 guint8 ** p_data, guint64 * p_size)
2271 if (*p_size < num_bytes_to_read)
2274 *p_buf = g_memdup (*p_data, num_bytes_to_read);
2275 *p_data += num_bytes_to_read;
2276 *p_size -= num_bytes_to_read;
2281 gst_asf_demux_get_string (gchar ** p_str, guint16 * p_strlen,
2282 guint8 ** p_data, guint64 * p_size)
2292 s_length = gst_asf_demux_get_uint16 (p_data, p_size);
2295 *p_strlen = s_length;
2297 if (s_length == 0) {
2298 GST_WARNING ("zero-length string");
2299 *p_str = g_strdup ("");
2303 if (!gst_asf_demux_get_bytes (&s, s_length, p_data, p_size))
2306 g_assert (s != NULL);
2308 /* just because They don't exist doesn't
2309 * mean They are not out to get you ... */
2310 if (s[s_length - 1] != '\0') {
2311 s = g_realloc (s, s_length + 1);
2315 *p_str = (gchar *) s;
2321 gst_asf_demux_get_guid (ASFGuid * guid, guint8 ** p_data, guint64 * p_size)
2323 g_assert (*p_size >= 4 * sizeof (guint32));
2325 guid->v1 = gst_asf_demux_get_uint32 (p_data, p_size);
2326 guid->v2 = gst_asf_demux_get_uint32 (p_data, p_size);
2327 guid->v3 = gst_asf_demux_get_uint32 (p_data, p_size);
2328 guid->v4 = gst_asf_demux_get_uint32 (p_data, p_size);
2332 gst_asf_demux_get_stream_audio (asf_stream_audio * audio, guint8 ** p_data,
2335 if (*p_size < (2 + 2 + 4 + 4 + 2 + 2 + 2))
2338 /* WAVEFORMATEX Structure */
2339 audio->codec_tag = gst_asf_demux_get_uint16 (p_data, p_size);
2340 audio->channels = gst_asf_demux_get_uint16 (p_data, p_size);
2341 audio->sample_rate = gst_asf_demux_get_uint32 (p_data, p_size);
2342 audio->byte_rate = gst_asf_demux_get_uint32 (p_data, p_size);
2343 audio->block_align = gst_asf_demux_get_uint16 (p_data, p_size);
2344 audio->word_size = gst_asf_demux_get_uint16 (p_data, p_size);
2345 /* Codec specific data size */
2346 audio->size = gst_asf_demux_get_uint16 (p_data, p_size);
2351 gst_asf_demux_get_stream_video (asf_stream_video * video, guint8 ** p_data,
2354 if (*p_size < (4 + 4 + 1 + 2))
2357 video->width = gst_asf_demux_get_uint32 (p_data, p_size);
2358 video->height = gst_asf_demux_get_uint32 (p_data, p_size);
2359 video->unknown = gst_asf_demux_get_uint8 (p_data, p_size);
2360 video->size = gst_asf_demux_get_uint16 (p_data, p_size);
2365 gst_asf_demux_get_stream_video_format (asf_stream_video_format * fmt,
2366 guint8 ** p_data, guint64 * p_size)
2368 if (*p_size < (4 + 4 + 4 + 2 + 2 + 4 + 4 + 4 + 4 + 4 + 4))
2371 fmt->size = gst_asf_demux_get_uint32 (p_data, p_size);
2372 fmt->width = gst_asf_demux_get_uint32 (p_data, p_size);
2373 fmt->height = gst_asf_demux_get_uint32 (p_data, p_size);
2374 fmt->planes = gst_asf_demux_get_uint16 (p_data, p_size);
2375 fmt->depth = gst_asf_demux_get_uint16 (p_data, p_size);
2376 fmt->tag = gst_asf_demux_get_uint32 (p_data, p_size);
2377 fmt->image_size = gst_asf_demux_get_uint32 (p_data, p_size);
2378 fmt->xpels_meter = gst_asf_demux_get_uint32 (p_data, p_size);
2379 fmt->ypels_meter = gst_asf_demux_get_uint32 (p_data, p_size);
2380 fmt->num_colors = gst_asf_demux_get_uint32 (p_data, p_size);
2381 fmt->imp_colors = gst_asf_demux_get_uint32 (p_data, p_size);
2386 gst_asf_demux_get_stream (GstASFDemux * demux, guint16 id)
2390 for (i = 0; i < demux->num_streams; i++) {
2391 if (demux->stream[i].id == id)
2392 return &demux->stream[i];
2395 if (gst_asf_demux_is_unknown_stream (demux, id))
2396 GST_WARNING ("Segment found for undefined stream: (%d)", id);
2401 gst_asf_demux_setup_pad (GstASFDemux * demux, GstPad * src_pad,
2402 GstCaps * caps, guint16 id, gboolean is_video, GstBuffer * streamheader,
2407 gst_pad_use_fixed_caps (src_pad);
2408 gst_pad_set_caps (src_pad, caps);
2410 gst_pad_set_event_function (src_pad,
2411 GST_DEBUG_FUNCPTR (gst_asf_demux_handle_src_event));
2412 gst_pad_set_query_function (src_pad,
2413 GST_DEBUG_FUNCPTR (gst_asf_demux_handle_src_query));
2415 stream = &demux->stream[demux->num_streams];
2416 stream->caps = caps;
2417 stream->pad = src_pad;
2419 stream->fps_known = !is_video; /* bit hacky for audio */
2420 stream->is_video = is_video;
2421 stream->pending_tags = tags;
2422 stream->discont = TRUE;
2423 stream->first_buffer = TRUE;
2424 stream->streamheader = streamheader;
2425 if (stream->streamheader) {
2426 stream->streamheader = gst_buffer_make_writable (streamheader);
2427 GST_BUFFER_FLAG_SET (stream->streamheader, GST_BUFFER_FLAG_HEADER);
2432 st = gst_caps_get_structure (caps, 0);
2433 if (gst_structure_get_fraction (st, "pixel-aspect-ratio", &par_x, &par_y) &&
2434 par_x > 0 && par_y > 0) {
2435 GST_DEBUG ("PAR %d/%d", par_x, par_y);
2436 stream->par_x = par_x;
2437 stream->par_y = par_y;
2441 stream->payloads = g_array_new (FALSE, FALSE, sizeof (AsfPayload));
2443 GST_INFO ("Created pad %s for stream %u with caps %" GST_PTR_FORMAT,
2444 GST_PAD_NAME (src_pad), demux->num_streams, caps);
2446 ++demux->num_streams;
2448 stream->active = FALSE;
2454 gst_asf_demux_add_stream_headers_to_caps (GstASFDemux * demux,
2455 GstBuffer * buffer, GstStructure * structure)
2457 GValue arr_val = G_VALUE_INIT;
2458 GValue buf_val = G_VALUE_INIT;
2460 g_value_init (&arr_val, GST_TYPE_ARRAY);
2461 g_value_init (&buf_val, GST_TYPE_BUFFER);
2463 gst_value_set_buffer (&buf_val, buffer);
2464 gst_value_array_append_and_take_value (&arr_val, &buf_val);
2466 gst_structure_take_value (structure, "streamheader", &arr_val);
2470 gst_asf_demux_add_audio_stream (GstASFDemux * demux,
2471 asf_stream_audio * audio, guint16 id, guint8 ** p_data, guint64 * p_size)
2473 GstTagList *tags = NULL;
2474 GstBuffer *extradata = NULL;
2477 guint16 size_left = 0;
2478 gchar *codec_name = NULL;
2481 size_left = audio->size;
2483 /* Create the audio pad */
2484 name = g_strdup_printf ("audio_%u", demux->num_audio_streams);
2486 src_pad = gst_pad_new_from_static_template (&audio_src_template, name);
2489 /* Swallow up any left over data and set up the
2490 * standard properties from the header info */
2492 GST_INFO_OBJECT (demux, "Audio header contains %d bytes of "
2493 "codec specific data", size_left);
2495 g_assert (size_left <= *p_size);
2496 gst_asf_demux_get_buffer (&extradata, size_left, p_data, p_size);
2499 /* asf_stream_audio is the same as gst_riff_strf_auds, but with an
2500 * additional two bytes indicating extradata. */
2501 /* FIXME: Handle the channel reorder map here */
2502 caps = gst_riff_create_audio_caps (audio->codec_tag, NULL,
2503 (gst_riff_strf_auds *) audio, extradata, NULL, &codec_name, NULL);
2506 caps = gst_caps_new_simple ("audio/x-asf-unknown", "codec_id",
2507 G_TYPE_INT, (gint) audio->codec_tag, NULL);
2510 /* Informing about that audio format we just added */
2512 tags = gst_tag_list_new (GST_TAG_AUDIO_CODEC, codec_name, NULL);
2513 g_free (codec_name);
2517 gst_buffer_unref (extradata);
2519 GST_INFO ("Adding audio stream #%u, id %u codec %u (0x%04x), tags=%"
2520 GST_PTR_FORMAT, demux->num_audio_streams, id, audio->codec_tag,
2521 audio->codec_tag, tags);
2523 ++demux->num_audio_streams;
2525 return gst_asf_demux_setup_pad (demux, src_pad, caps, id, FALSE, NULL, tags);
2529 gst_asf_demux_add_video_stream (GstASFDemux * demux,
2530 asf_stream_video_format * video, guint16 id,
2531 guint8 ** p_data, guint64 * p_size)
2533 GstTagList *tags = NULL;
2534 GstStructure *caps_s;
2535 GstBuffer *extradata = NULL;
2540 gchar *codec_name = NULL;
2541 gint size_left = video->size - 40;
2542 GstBuffer *streamheader = NULL;
2543 guint par_w = 1, par_h = 1;
2545 /* Create the video pad */
2546 name = g_strdup_printf ("video_%u", demux->num_video_streams);
2547 src_pad = gst_pad_new_from_static_template (&video_src_template, name);
2550 /* Now try some gstreamer formatted MIME types (from gst_avi_demux_strf_vids) */
2552 GST_LOG ("Video header has %d bytes of codec specific data", size_left);
2553 g_assert (size_left <= *p_size);
2554 gst_asf_demux_get_buffer (&extradata, size_left, p_data, p_size);
2557 GST_DEBUG ("video codec %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (video->tag));
2559 /* yes, asf_stream_video_format and gst_riff_strf_vids are the same */
2560 caps = gst_riff_create_video_caps (video->tag, NULL,
2561 (gst_riff_strf_vids *) video, extradata, NULL, &codec_name);
2564 caps = gst_caps_new_simple ("video/x-asf-unknown", "fourcc",
2565 G_TYPE_UINT, video->tag, NULL);
2570 s = gst_asf_demux_get_metadata_for_stream (demux, id);
2571 if (gst_structure_get_int (s, "AspectRatioX", &ax) &&
2572 gst_structure_get_int (s, "AspectRatioY", &ay) && (ax > 0 && ay > 0)) {
2575 gst_caps_set_simple (caps, "pixel-aspect-ratio", GST_TYPE_FRACTION,
2579 /* retry with the global metadata */
2580 GST_DEBUG ("Retrying with global metadata %" GST_PTR_FORMAT,
2581 demux->global_metadata);
2582 s = demux->global_metadata;
2583 if (gst_structure_get_uint (s, "AspectRatioX", &ax) &&
2584 gst_structure_get_uint (s, "AspectRatioY", &ay)) {
2585 GST_DEBUG ("ax:%d, ay:%d", ax, ay);
2586 if (ax > 0 && ay > 0) {
2589 gst_caps_set_simple (caps, "pixel-aspect-ratio", GST_TYPE_FRACTION,
2594 s = gst_caps_get_structure (caps, 0);
2595 gst_structure_remove_field (s, "framerate");
2598 caps_s = gst_caps_get_structure (caps, 0);
2600 /* add format field with fourcc to WMV/VC1 caps to differentiate variants */
2601 if (gst_structure_has_name (caps_s, "video/x-wmv")) {
2602 str = g_strdup_printf ("%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (video->tag));
2603 gst_caps_set_simple (caps, "format", G_TYPE_STRING, str, NULL);
2606 /* check if h264 has codec_data (avc) or streamheaders (bytestream) */
2607 } else if (gst_structure_has_name (caps_s, "video/x-h264")) {
2608 const GValue *value = gst_structure_get_value (caps_s, "codec_data");
2610 GstBuffer *buf = gst_value_get_buffer (value);
2613 if (gst_buffer_map (buf, &mapinfo, GST_MAP_READ)) {
2614 if (mapinfo.size >= 4 && GST_READ_UINT32_BE (mapinfo.data) == 1) {
2615 /* this looks like a bytestream start */
2616 streamheader = gst_buffer_ref (buf);
2617 gst_asf_demux_add_stream_headers_to_caps (demux, buf, caps_s);
2618 gst_structure_remove_field (caps_s, "codec_data");
2621 gst_buffer_unmap (buf, &mapinfo);
2626 /* For a 3D video, set multiview information into the caps based on
2627 * what was detected during object parsing */
2628 if (demux->asf_3D_mode != GST_ASF_3D_NONE) {
2629 GstVideoMultiviewMode mv_mode = GST_VIDEO_MULTIVIEW_MODE_NONE;
2630 GstVideoMultiviewFlags mv_flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
2631 const gchar *mview_mode_str;
2633 switch (demux->asf_3D_mode) {
2634 case GST_ASF_3D_SIDE_BY_SIDE_HALF_LR:
2635 mv_mode = GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE;
2637 case GST_ASF_3D_SIDE_BY_SIDE_HALF_RL:
2638 mv_mode = GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE;
2639 mv_flags = GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST;
2641 case GST_ASF_3D_TOP_AND_BOTTOM_HALF_LR:
2642 mv_mode = GST_VIDEO_MULTIVIEW_MODE_TOP_BOTTOM;
2644 case GST_ASF_3D_TOP_AND_BOTTOM_HALF_RL:
2645 mv_mode = GST_VIDEO_MULTIVIEW_MODE_TOP_BOTTOM;
2646 mv_flags = GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST;
2648 case GST_ASF_3D_DUAL_STREAM:{
2649 gboolean is_right_view = FALSE;
2650 /* if Advanced_Mutual_Exclusion object exists, use it
2651 * to figure out which is the left view (lower ID) */
2652 if (demux->mut_ex_streams != NULL) {
2656 length = g_slist_length (demux->mut_ex_streams);
2658 for (i = 0; i < length; i++) {
2661 v_s_id = g_slist_nth_data (demux->mut_ex_streams, i);
2663 GST_DEBUG_OBJECT (demux,
2664 "has Mutual_Exclusion object. stream id in object is %d",
2665 GPOINTER_TO_INT (v_s_id));
2667 if (id > GPOINTER_TO_INT (v_s_id))
2668 is_right_view = TRUE;
2671 /* if the Advaced_Mutual_Exclusion object doesn't exist, assume the
2672 * first video stream encountered has the lower ID */
2673 if (demux->num_video_streams > 0) {
2674 /* This is not the first video stream, assuming right eye view */
2675 is_right_view = TRUE;
2679 mv_mode = GST_VIDEO_MULTIVIEW_MODE_RIGHT;
2681 mv_mode = GST_VIDEO_MULTIVIEW_MODE_LEFT;
2688 GST_INFO_OBJECT (demux,
2689 "stream_id %d, has multiview-mode %d flags 0x%x", id, mv_mode,
2692 mview_mode_str = gst_video_multiview_mode_to_caps_string (mv_mode);
2693 if (mview_mode_str != NULL) {
2694 if (gst_video_multiview_guess_half_aspect (mv_mode, video->width,
2695 video->height, par_w, par_h))
2696 mv_flags |= GST_VIDEO_MULTIVIEW_FLAGS_HALF_ASPECT;
2698 gst_caps_set_simple (caps,
2699 "multiview-mode", G_TYPE_STRING, mview_mode_str,
2700 "multiview-flags", GST_TYPE_VIDEO_MULTIVIEW_FLAGSET, mv_flags,
2701 GST_FLAG_SET_MASK_EXACT, NULL);
2706 tags = gst_tag_list_new (GST_TAG_VIDEO_CODEC, codec_name, NULL);
2707 g_free (codec_name);
2711 gst_buffer_unref (extradata);
2713 GST_INFO ("Adding video stream #%u, id %u, codec %"
2714 GST_FOURCC_FORMAT " (0x%08x)", demux->num_video_streams, id,
2715 GST_FOURCC_ARGS (video->tag), video->tag);
2717 ++demux->num_video_streams;
2719 return gst_asf_demux_setup_pad (demux, src_pad, caps, id, TRUE,
2720 streamheader, tags);
2724 gst_asf_demux_activate_stream (GstASFDemux * demux, AsfStream * stream)
2726 if (!stream->active) {
2730 GST_INFO_OBJECT (demux, "Activating stream %2u, pad %s, caps %"
2731 GST_PTR_FORMAT, stream->id, GST_PAD_NAME (stream->pad), stream->caps);
2732 gst_pad_set_active (stream->pad, TRUE);
2735 gst_pad_create_stream_id_printf (stream->pad, GST_ELEMENT_CAST (demux),
2736 "%03u", stream->id);
2739 gst_pad_get_sticky_event (demux->sinkpad, GST_EVENT_STREAM_START, 0);
2741 if (gst_event_parse_group_id (event, &demux->group_id))
2742 demux->have_group_id = TRUE;
2744 demux->have_group_id = FALSE;
2745 gst_event_unref (event);
2746 } else if (!demux->have_group_id) {
2747 demux->have_group_id = TRUE;
2748 demux->group_id = gst_util_group_id_next ();
2751 event = gst_event_new_stream_start (stream_id);
2752 if (demux->have_group_id)
2753 gst_event_set_group_id (event, demux->group_id);
2755 gst_pad_push_event (stream->pad, event);
2757 gst_pad_set_caps (stream->pad, stream->caps);
2759 gst_element_add_pad (GST_ELEMENT_CAST (demux), stream->pad);
2760 gst_flow_combiner_add_pad (demux->flowcombiner, stream->pad);
2761 stream->active = TRUE;
2766 gst_asf_demux_parse_stream_object (GstASFDemux * demux, guint8 * data,
2769 AsfCorrectionType correction_type;
2770 AsfStreamType stream_type;
2771 GstClockTime time_offset;
2772 gboolean is_encrypted G_GNUC_UNUSED;
2776 guint stream_specific_size;
2777 guint type_specific_size G_GNUC_UNUSED;
2778 guint unknown G_GNUC_UNUSED;
2779 gboolean inspect_payload = FALSE;
2780 AsfStream *stream = NULL;
2782 /* Get the rest of the header's header */
2783 if (size < (16 + 16 + 8 + 4 + 4 + 2 + 4))
2784 goto not_enough_data;
2786 gst_asf_demux_get_guid (&guid, &data, &size);
2787 stream_type = gst_asf_demux_identify_guid (asf_stream_guids, &guid);
2789 gst_asf_demux_get_guid (&guid, &data, &size);
2790 correction_type = gst_asf_demux_identify_guid (asf_correction_guids, &guid);
2792 time_offset = gst_asf_demux_get_uint64 (&data, &size) * 100;
2794 type_specific_size = gst_asf_demux_get_uint32 (&data, &size);
2795 stream_specific_size = gst_asf_demux_get_uint32 (&data, &size);
2797 flags = gst_asf_demux_get_uint16 (&data, &size);
2798 stream_id = flags & 0x7f;
2799 is_encrypted = ! !((flags & 0x8000) << 15);
2800 unknown = gst_asf_demux_get_uint32 (&data, &size);
2802 GST_DEBUG_OBJECT (demux, "Found stream %u, time_offset=%" GST_TIME_FORMAT,
2803 stream_id, GST_TIME_ARGS (time_offset));
2805 /* dvr-ms has audio stream declared in stream specific data */
2806 if (stream_type == ASF_STREAM_EXT_EMBED_HEADER) {
2807 AsfExtStreamType ext_stream_type;
2808 gst_asf_demux_get_guid (&guid, &data, &size);
2809 ext_stream_type = gst_asf_demux_identify_guid (asf_ext_stream_guids, &guid);
2811 if (ext_stream_type == ASF_EXT_STREAM_AUDIO) {
2812 inspect_payload = TRUE;
2814 gst_asf_demux_get_guid (&guid, &data, &size);
2815 gst_asf_demux_get_uint32 (&data, &size);
2816 gst_asf_demux_get_uint32 (&data, &size);
2817 gst_asf_demux_get_uint32 (&data, &size);
2818 gst_asf_demux_get_guid (&guid, &data, &size);
2819 gst_asf_demux_get_uint32 (&data, &size);
2820 stream_type = ASF_STREAM_AUDIO;
2824 switch (stream_type) {
2825 case ASF_STREAM_AUDIO:{
2826 asf_stream_audio audio_object;
2828 if (!gst_asf_demux_get_stream_audio (&audio_object, &data, &size))
2829 goto not_enough_data;
2831 GST_INFO ("Object is an audio stream with %u bytes of additional data",
2834 stream = gst_asf_demux_add_audio_stream (demux, &audio_object, stream_id,
2837 switch (correction_type) {
2838 case ASF_CORRECTION_ON:{
2839 guint span, packet_size, chunk_size, data_size, silence_data;
2841 GST_INFO ("Using error correction");
2843 if (size < (1 + 2 + 2 + 2 + 1))
2844 goto not_enough_data;
2846 span = gst_asf_demux_get_uint8 (&data, &size);
2847 packet_size = gst_asf_demux_get_uint16 (&data, &size);
2848 chunk_size = gst_asf_demux_get_uint16 (&data, &size);
2849 data_size = gst_asf_demux_get_uint16 (&data, &size);
2850 silence_data = gst_asf_demux_get_uint8 (&data, &size);
2852 stream->span = span;
2854 GST_DEBUG_OBJECT (demux, "Descrambling ps:%u cs:%u ds:%u s:%u sd:%u",
2855 packet_size, chunk_size, data_size, span, silence_data);
2857 if (stream->span > 1) {
2858 if (chunk_size == 0 || ((packet_size / chunk_size) <= 1)) {
2859 /* Disable descrambling */
2862 /* FIXME: this else branch was added for
2863 * weird_al_yankovic - the saga begins.asf */
2864 stream->ds_packet_size = packet_size;
2865 stream->ds_chunk_size = chunk_size;
2868 /* Descambling is enabled */
2869 stream->ds_packet_size = packet_size;
2870 stream->ds_chunk_size = chunk_size;
2873 /* Now skip the rest of the silence data */
2875 gst_bytestream_flush (demux->bs, data_size - 1);
2877 /* FIXME: CHECKME. And why -1? */
2878 if (data_size > 1) {
2879 if (!gst_asf_demux_skip_bytes (data_size - 1, &data, &size)) {
2880 goto not_enough_data;
2886 case ASF_CORRECTION_OFF:{
2887 GST_INFO ("Error correction off");
2888 if (!gst_asf_demux_skip_bytes (stream_specific_size, &data, &size))
2889 goto not_enough_data;
2893 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
2894 ("Audio stream using unknown error correction"));
2901 case ASF_STREAM_VIDEO:{
2902 asf_stream_video_format video_format_object;
2903 asf_stream_video video_object;
2906 if (!gst_asf_demux_get_stream_video (&video_object, &data, &size))
2907 goto not_enough_data;
2909 vsize = video_object.size - 40; /* Byte order gets offset by single byte */
2911 GST_INFO ("object is a video stream with %u bytes of "
2912 "additional data", vsize);
2914 if (!gst_asf_demux_get_stream_video_format (&video_format_object,
2916 goto not_enough_data;
2919 stream = gst_asf_demux_add_video_stream (demux, &video_format_object,
2920 stream_id, &data, &size);
2926 GST_WARNING_OBJECT (demux, "Unknown stream type for stream %u",
2928 demux->other_streams =
2929 g_slist_append (demux->other_streams, GINT_TO_POINTER (stream_id));
2934 stream->inspect_payload = inspect_payload;
2939 GST_WARNING_OBJECT (demux, "Unexpected end of data parsing stream object");
2940 /* we'll error out later if we found no streams */
2945 static const gchar *
2946 gst_asf_demux_get_gst_tag_from_tag_name (const gchar * name_utf8)
2950 const gchar *asf_name;
2951 const gchar *gst_name;
2954 "WM/Genre", GST_TAG_GENRE}, {
2955 "WM/AlbumTitle", GST_TAG_ALBUM}, {
2956 "WM/AlbumArtist", GST_TAG_ARTIST}, {
2957 "WM/Picture", GST_TAG_IMAGE}, {
2958 "WM/Track", GST_TAG_TRACK_NUMBER}, {
2959 "WM/TrackNumber", GST_TAG_TRACK_NUMBER}, {
2960 "WM/Year", GST_TAG_DATE_TIME}
2961 /* { "WM/Composer", GST_TAG_COMPOSER } */
2966 if (name_utf8 == NULL) {
2967 GST_WARNING ("Failed to convert name to UTF8, skipping");
2971 out = strlen (name_utf8);
2973 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
2974 if (strncmp (tags[i].asf_name, name_utf8, out) == 0) {
2975 GST_LOG ("map tagname '%s' -> '%s'", name_utf8, tags[i].gst_name);
2976 return tags[i].gst_name;
2983 /* gst_asf_demux_add_global_tags() takes ownership of taglist! */
2985 gst_asf_demux_add_global_tags (GstASFDemux * demux, GstTagList * taglist)
2989 GST_DEBUG_OBJECT (demux, "adding global tags: %" GST_PTR_FORMAT, taglist);
2991 if (taglist == NULL)
2994 if (gst_tag_list_is_empty (taglist)) {
2995 gst_tag_list_unref (taglist);
2999 t = gst_tag_list_merge (demux->taglist, taglist, GST_TAG_MERGE_APPEND);
3000 gst_tag_list_set_scope (t, GST_TAG_SCOPE_GLOBAL);
3002 gst_tag_list_unref (demux->taglist);
3003 gst_tag_list_unref (taglist);
3005 GST_LOG_OBJECT (demux, "global tags now: %" GST_PTR_FORMAT, demux->taglist);
3008 #define ASF_DEMUX_DATA_TYPE_UTF16LE_STRING 0
3009 #define ASF_DEMUX_DATA_TYPE_BYTE_ARRAY 1
3010 #define ASF_DEMUX_DATA_TYPE_BOOL 2
3011 #define ASF_DEMUX_DATA_TYPE_DWORD 3
3014 asf_demux_parse_picture_tag (GstTagList * tags, const guint8 * tag_data,
3018 const guint8 *img_data = NULL;
3019 guint32 img_data_len = 0;
3020 guint8 pic_type = 0;
3022 gst_byte_reader_init (&r, tag_data, tag_data_len);
3024 /* skip mime type string (we don't trust it and do our own typefinding),
3025 * and also skip the description string, since we don't use it */
3026 if (!gst_byte_reader_get_uint8 (&r, &pic_type) ||
3027 !gst_byte_reader_get_uint32_le (&r, &img_data_len) ||
3028 !gst_byte_reader_skip_string_utf16 (&r) ||
3029 !gst_byte_reader_skip_string_utf16 (&r) ||
3030 !gst_byte_reader_get_data (&r, img_data_len, &img_data)) {
3031 goto not_enough_data;
3035 if (!gst_tag_list_add_id3_image (tags, img_data, img_data_len, pic_type))
3036 GST_DEBUG ("failed to add image extracted from WM/Picture tag to taglist");
3042 GST_DEBUG ("Failed to read WM/Picture tag: not enough data");
3043 GST_MEMDUMP ("WM/Picture data", tag_data, tag_data_len);
3048 /* Extended Content Description Object */
3049 static GstFlowReturn
3050 gst_asf_demux_process_ext_content_desc (GstASFDemux * demux, guint8 * data,
3053 /* Other known (and unused) 'text/unicode' metadata available :
3056 * WM/MediaPrimaryClassID = {D1607DBC-E323-4BE2-86A1-48A42A28441E}
3057 * WMFSDKVersion = 9.00.00.2980
3058 * WMFSDKNeeded = 0.0.0.0000
3059 * WM/UniqueFileIdentifier = AMGa_id=R 15334;AMGp_id=P 5149;AMGt_id=T 2324984
3060 * WM/Publisher = 4AD
3062 * WM/ProviderRating = 8
3063 * WM/ProviderStyle = Rock (similar to WM/Genre)
3064 * WM/GenreID (similar to WM/Genre)
3065 * WM/TrackNumber (same as WM/Track but as a string)
3067 * Other known (and unused) 'non-text' metadata available :
3073 * We might want to read WM/TrackNumber and use atoi() if we don't have
3077 GstTagList *taglist;
3078 guint16 blockcount, i;
3079 gboolean content3D = FALSE;
3083 const gchar *interleave_name;
3084 GstASF3DMode interleaving_type;
3085 } stereoscopic_layout_map[] = {
3087 "SideBySideRF", GST_ASF_3D_SIDE_BY_SIDE_HALF_RL}, {
3088 "SideBySideLF", GST_ASF_3D_SIDE_BY_SIDE_HALF_LR}, {
3089 "OverUnderRT", GST_ASF_3D_TOP_AND_BOTTOM_HALF_RL}, {
3090 "OverUnderLT", GST_ASF_3D_TOP_AND_BOTTOM_HALF_LR}, {
3091 "DualStream", GST_ASF_3D_DUAL_STREAM}
3093 GST_INFO_OBJECT (demux, "object is an extended content description");
3095 taglist = gst_tag_list_new_empty ();
3097 /* Content Descriptor Count */
3099 goto not_enough_data;
3101 blockcount = gst_asf_demux_get_uint16 (&data, &size);
3103 for (i = 1; i <= blockcount; ++i) {
3104 const gchar *gst_tag_name;
3108 GValue tag_value = { 0, };
3111 gchar *name_utf8 = NULL;
3115 if (!gst_asf_demux_get_string (&name, &name_len, &data, &size))
3116 goto not_enough_data;
3120 goto not_enough_data;
3122 /* Descriptor Value Data Type */
3123 datatype = gst_asf_demux_get_uint16 (&data, &size);
3125 /* Descriptor Value (not really a string, but same thing reading-wise) */
3126 if (!gst_asf_demux_get_string (&value, &value_len, &data, &size)) {
3128 goto not_enough_data;
3132 g_convert (name, name_len, "UTF-8", "UTF-16LE", &in, &out, NULL);
3134 if (name_utf8 != NULL) {
3135 GST_DEBUG ("Found tag/metadata %s", name_utf8);
3137 gst_tag_name = gst_asf_demux_get_gst_tag_from_tag_name (name_utf8);
3138 GST_DEBUG ("gst_tag_name %s", GST_STR_NULL (gst_tag_name));
3141 case ASF_DEMUX_DATA_TYPE_UTF16LE_STRING:{
3144 value_utf8 = g_convert (value, value_len, "UTF-8", "UTF-16LE",
3147 /* get rid of tags with empty value */
3148 if (value_utf8 != NULL && *value_utf8 != '\0') {
3149 GST_DEBUG ("string value %s", value_utf8);
3151 value_utf8[out] = '\0';
3153 if (gst_tag_name != NULL) {
3154 if (strcmp (gst_tag_name, GST_TAG_DATE_TIME) == 0) {
3155 guint year = atoi (value_utf8);
3158 g_value_init (&tag_value, GST_TYPE_DATE_TIME);
3159 g_value_take_boxed (&tag_value, gst_date_time_new_y (year));
3161 } else if (strcmp (gst_tag_name, GST_TAG_GENRE) == 0) {
3162 guint id3v1_genre_id;
3163 const gchar *genre_str;
3165 if (sscanf (value_utf8, "(%u)", &id3v1_genre_id) == 1 &&
3166 ((genre_str = gst_tag_id3_genre_get (id3v1_genre_id)))) {
3167 GST_DEBUG ("Genre: %s -> %s", value_utf8, genre_str);
3168 g_free (value_utf8);
3169 value_utf8 = g_strdup (genre_str);
3174 /* convert tag from string to other type if required */
3175 tag_type = gst_tag_get_type (gst_tag_name);
3176 g_value_init (&tag_value, tag_type);
3177 if (!gst_value_deserialize (&tag_value, value_utf8)) {
3178 GValue from_val = { 0, };
3180 g_value_init (&from_val, G_TYPE_STRING);
3181 g_value_set_string (&from_val, value_utf8);
3182 if (!g_value_transform (&from_val, &tag_value)) {
3183 GST_WARNING_OBJECT (demux,
3184 "Could not transform string tag to " "%s tag type %s",
3185 gst_tag_name, g_type_name (tag_type));
3186 g_value_unset (&tag_value);
3188 g_value_unset (&from_val);
3193 GST_DEBUG ("Setting metadata");
3194 g_value_init (&tag_value, G_TYPE_STRING);
3195 g_value_set_string (&tag_value, value_utf8);
3196 /* If we found a stereoscopic marker, look for StereoscopicLayout
3200 if (strncmp ("StereoscopicLayout", name_utf8,
3201 strlen (name_utf8)) == 0) {
3202 for (i = 0; i < G_N_ELEMENTS (stereoscopic_layout_map); i++) {
3203 if (g_str_equal (stereoscopic_layout_map[i].interleave_name,
3205 demux->asf_3D_mode =
3206 stereoscopic_layout_map[i].interleaving_type;
3207 GST_INFO ("find interleave type %u", demux->asf_3D_mode);
3211 GST_INFO_OBJECT (demux, "3d type is %u", demux->asf_3D_mode);
3213 demux->asf_3D_mode = GST_ASF_3D_NONE;
3214 GST_INFO_OBJECT (demux, "None 3d type");
3217 } else if (value_utf8 == NULL) {
3218 GST_WARNING ("Failed to convert string value to UTF8, skipping");
3220 GST_DEBUG ("Skipping empty string value for %s",
3221 GST_STR_NULL (gst_tag_name));
3223 g_free (value_utf8);
3226 case ASF_DEMUX_DATA_TYPE_BYTE_ARRAY:{
3228 if (!g_str_equal (gst_tag_name, GST_TAG_IMAGE)) {
3229 GST_FIXME ("Unhandled byte array tag %s",
3230 GST_STR_NULL (gst_tag_name));
3233 asf_demux_parse_picture_tag (taglist, (guint8 *) value,
3239 case ASF_DEMUX_DATA_TYPE_DWORD:{
3240 guint uint_val = GST_READ_UINT32_LE (value);
3242 /* this is the track number */
3243 g_value_init (&tag_value, G_TYPE_UINT);
3245 /* WM/Track counts from 0 */
3246 if (!strcmp (name_utf8, "WM/Track"))
3249 g_value_set_uint (&tag_value, uint_val);
3253 case ASF_DEMUX_DATA_TYPE_BOOL:{
3254 gboolean bool_val = GST_READ_UINT32_LE (value);
3256 if (strncmp ("Stereoscopic", name_utf8, strlen (name_utf8)) == 0) {
3258 GST_INFO_OBJECT (demux, "This is 3D contents");
3261 GST_INFO_OBJECT (demux, "This is not 3D contenst");
3269 GST_DEBUG ("Skipping tag %s of type %d", gst_tag_name, datatype);
3274 if (G_IS_VALUE (&tag_value)) {
3276 GstTagMergeMode merge_mode = GST_TAG_MERGE_APPEND;
3278 /* WM/TrackNumber is more reliable than WM/Track, since the latter
3279 * is supposed to have a 0 base but is often wrongly written to start
3280 * from 1 as well, so prefer WM/TrackNumber when we have it: either
3281 * replace the value added earlier from WM/Track or put it first in
3282 * the list, so that it will get picked up by _get_uint() */
3283 if (strcmp (name_utf8, "WM/TrackNumber") == 0)
3284 merge_mode = GST_TAG_MERGE_REPLACE;
3286 gst_tag_list_add_values (taglist, merge_mode, gst_tag_name,
3289 GST_DEBUG ("Setting global metadata %s", name_utf8);
3290 gst_structure_set_value (demux->global_metadata, name_utf8,
3294 g_value_unset (&tag_value);
3303 gst_asf_demux_add_global_tags (demux, taglist);
3310 GST_WARNING ("Unexpected end of data parsing ext content desc object");
3311 gst_tag_list_unref (taglist);
3312 return GST_FLOW_OK; /* not really fatal */
3316 static GstStructure *
3317 gst_asf_demux_get_metadata_for_stream (GstASFDemux * demux, guint stream_num)
3322 g_snprintf (sname, sizeof (sname), "stream-%u", stream_num);
3324 for (i = 0; i < gst_caps_get_size (demux->metadata); ++i) {
3327 s = gst_caps_get_structure (demux->metadata, i);
3328 if (gst_structure_has_name (s, sname))
3332 gst_caps_append_structure (demux->metadata, gst_structure_new_empty (sname));
3334 /* try lookup again; demux->metadata took ownership of the structure, so we
3335 * can't really make any assumptions about what happened to it, so we can't
3336 * just return it directly after appending it */
3337 return gst_asf_demux_get_metadata_for_stream (demux, stream_num);
3340 static GstFlowReturn
3341 gst_asf_demux_process_metadata (GstASFDemux * demux, guint8 * data,
3344 guint16 blockcount, i;
3346 GST_INFO_OBJECT (demux, "object is a metadata object");
3348 /* Content Descriptor Count */
3350 goto not_enough_data;
3352 blockcount = gst_asf_demux_get_uint16 (&data, &size);
3354 for (i = 0; i < blockcount; ++i) {
3356 guint16 stream_num, name_len, data_type, lang_idx G_GNUC_UNUSED;
3357 guint32 data_len, ival;
3360 if (size < (2 + 2 + 2 + 2 + 4))
3361 goto not_enough_data;
3363 lang_idx = gst_asf_demux_get_uint16 (&data, &size);
3364 stream_num = gst_asf_demux_get_uint16 (&data, &size);
3365 name_len = gst_asf_demux_get_uint16 (&data, &size);
3366 data_type = gst_asf_demux_get_uint16 (&data, &size);
3367 data_len = gst_asf_demux_get_uint32 (&data, &size);
3369 if (size < name_len + data_len)
3370 goto not_enough_data;
3372 /* convert name to UTF-8 */
3373 name_utf8 = g_convert ((gchar *) data, name_len, "UTF-8", "UTF-16LE",
3375 gst_asf_demux_skip_bytes (name_len, &data, &size);
3377 if (name_utf8 == NULL) {
3378 GST_WARNING ("Failed to convert value name to UTF8, skipping");
3379 gst_asf_demux_skip_bytes (data_len, &data, &size);
3383 if (data_type != ASF_DEMUX_DATA_TYPE_DWORD) {
3384 gst_asf_demux_skip_bytes (data_len, &data, &size);
3392 goto not_enough_data;
3395 ival = gst_asf_demux_get_uint32 (&data, &size);
3397 /* skip anything else there may be, just in case */
3398 gst_asf_demux_skip_bytes (data_len - 4, &data, &size);
3400 s = gst_asf_demux_get_metadata_for_stream (demux, stream_num);
3401 gst_structure_set (s, name_utf8, G_TYPE_INT, ival, NULL);
3405 GST_INFO_OBJECT (demux, "metadata = %" GST_PTR_FORMAT, demux->metadata);
3411 GST_WARNING ("Unexpected end of data parsing metadata object");
3412 return GST_FLOW_OK; /* not really fatal */
3416 static GstFlowReturn
3417 gst_asf_demux_process_header (GstASFDemux * demux, guint8 * data, guint64 size)
3419 GstFlowReturn ret = GST_FLOW_OK;
3420 guint32 i, num_objects;
3421 guint8 unknown G_GNUC_UNUSED;
3423 /* Get the rest of the header's header */
3424 if (size < (4 + 1 + 1))
3425 goto not_enough_data;
3427 num_objects = gst_asf_demux_get_uint32 (&data, &size);
3428 unknown = gst_asf_demux_get_uint8 (&data, &size);
3429 unknown = gst_asf_demux_get_uint8 (&data, &size);
3431 GST_INFO_OBJECT (demux, "object is a header with %u parts", num_objects);
3433 /* Loop through the header's objects, processing those */
3434 for (i = 0; i < num_objects; ++i) {
3435 GST_INFO_OBJECT (demux, "reading header part %u", i);
3436 ret = gst_asf_demux_process_object (demux, &data, &size);
3437 if (ret != GST_FLOW_OK) {
3438 GST_WARNING ("process_object returned %s", gst_asf_get_flow_name (ret));
3447 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3448 ("short read parsing HEADER object"));
3449 return GST_FLOW_ERROR;
3453 static GstFlowReturn
3454 gst_asf_demux_process_file (GstASFDemux * demux, guint8 * data, guint64 size)
3456 guint64 creation_time G_GNUC_UNUSED;
3457 guint64 file_size G_GNUC_UNUSED;
3458 guint64 send_time G_GNUC_UNUSED;
3459 guint64 packets_count, play_time, preroll;
3460 guint32 flags, min_pktsize, max_pktsize, min_bitrate G_GNUC_UNUSED;
3462 if (size < (16 + 8 + 8 + 8 + 8 + 8 + 8 + 4 + 4 + 4 + 4))
3463 goto not_enough_data;
3465 gst_asf_demux_skip_bytes (16, &data, &size); /* skip GUID */
3466 file_size = gst_asf_demux_get_uint64 (&data, &size);
3467 creation_time = gst_asf_demux_get_uint64 (&data, &size);
3468 packets_count = gst_asf_demux_get_uint64 (&data, &size);
3469 play_time = gst_asf_demux_get_uint64 (&data, &size);
3470 send_time = gst_asf_demux_get_uint64 (&data, &size);
3471 preroll = gst_asf_demux_get_uint64 (&data, &size);
3472 flags = gst_asf_demux_get_uint32 (&data, &size);
3473 min_pktsize = gst_asf_demux_get_uint32 (&data, &size);
3474 max_pktsize = gst_asf_demux_get_uint32 (&data, &size);
3475 min_bitrate = gst_asf_demux_get_uint32 (&data, &size);
3477 demux->broadcast = ! !(flags & 0x01);
3478 demux->seekable = ! !(flags & 0x02);
3480 GST_DEBUG_OBJECT (demux, "min_pktsize = %u", min_pktsize);
3481 GST_DEBUG_OBJECT (demux, "flags::broadcast = %d", demux->broadcast);
3482 GST_DEBUG_OBJECT (demux, "flags::seekable = %d", demux->seekable);
3484 if (demux->broadcast) {
3485 /* these fields are invalid if the broadcast flag is set */
3490 if (min_pktsize != max_pktsize)
3491 goto non_fixed_packet_size;
3493 demux->packet_size = max_pktsize;
3495 /* FIXME: do we need send_time as well? what is it? */
3496 if ((play_time * 100) >= (preroll * GST_MSECOND))
3497 demux->play_time = (play_time * 100) - (preroll * GST_MSECOND);
3499 demux->play_time = 0;
3501 demux->preroll = preroll * GST_MSECOND;
3503 /* initial latency */
3504 demux->latency = demux->preroll;
3506 if (demux->play_time == 0)
3507 demux->seekable = FALSE;
3509 GST_DEBUG_OBJECT (demux, "play_time %" GST_TIME_FORMAT,
3510 GST_TIME_ARGS (demux->play_time));
3511 GST_DEBUG_OBJECT (demux, "preroll %" GST_TIME_FORMAT,
3512 GST_TIME_ARGS (demux->preroll));
3514 if (demux->play_time > 0) {
3515 demux->segment.duration = demux->play_time;
3518 GST_INFO ("object is a file with %" G_GUINT64_FORMAT " data packets",
3520 GST_INFO ("preroll = %" G_GUINT64_FORMAT, demux->preroll);
3525 non_fixed_packet_size:
3527 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3528 ("packet size must be fixed"));
3529 return GST_FLOW_ERROR;
3533 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3534 ("short read parsing FILE object"));
3535 return GST_FLOW_ERROR;
3539 /* Content Description Object */
3540 static GstFlowReturn
3541 gst_asf_demux_process_comment (GstASFDemux * demux, guint8 * data, guint64 size)
3545 const gchar *gst_tag;
3550 GST_TAG_TITLE, 0, NULL}, {
3551 GST_TAG_ARTIST, 0, NULL}, {
3552 GST_TAG_COPYRIGHT, 0, NULL}, {
3553 GST_TAG_DESCRIPTION, 0, NULL}, {
3554 GST_TAG_COMMENT, 0, NULL}
3556 GstTagList *taglist;
3557 GValue value = { 0 };
3561 GST_INFO_OBJECT (demux, "object is a comment");
3563 if (size < (2 + 2 + 2 + 2 + 2))
3564 goto not_enough_data;
3566 tags[0].val_length = gst_asf_demux_get_uint16 (&data, &size);
3567 tags[1].val_length = gst_asf_demux_get_uint16 (&data, &size);
3568 tags[2].val_length = gst_asf_demux_get_uint16 (&data, &size);
3569 tags[3].val_length = gst_asf_demux_get_uint16 (&data, &size);
3570 tags[4].val_length = gst_asf_demux_get_uint16 (&data, &size);
3572 GST_DEBUG_OBJECT (demux, "Comment lengths: title=%d author=%d copyright=%d "
3573 "description=%d rating=%d", tags[0].val_length, tags[1].val_length,
3574 tags[2].val_length, tags[3].val_length, tags[4].val_length);
3576 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
3577 if (size < tags[i].val_length)
3578 goto not_enough_data;
3580 /* might be just '/0', '/0'... */
3581 if (tags[i].val_length > 2 && tags[i].val_length % 2 == 0) {
3582 /* convert to UTF-8 */
3583 tags[i].val_utf8 = g_convert ((gchar *) data, tags[i].val_length,
3584 "UTF-8", "UTF-16LE", &in, &out, NULL);
3586 gst_asf_demux_skip_bytes (tags[i].val_length, &data, &size);
3589 /* parse metadata into taglist */
3590 taglist = gst_tag_list_new_empty ();
3591 g_value_init (&value, G_TYPE_STRING);
3592 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
3593 if (tags[i].val_utf8 && strlen (tags[i].val_utf8) > 0 && tags[i].gst_tag) {
3594 g_value_set_string (&value, tags[i].val_utf8);
3595 gst_tag_list_add_values (taglist, GST_TAG_MERGE_APPEND,
3596 tags[i].gst_tag, &value, NULL);
3599 g_value_unset (&value);
3601 gst_asf_demux_add_global_tags (demux, taglist);
3603 for (i = 0; i < G_N_ELEMENTS (tags); ++i)
3604 g_free (tags[i].val_utf8);
3610 GST_WARNING_OBJECT (demux, "unexpectedly short of data while processing "
3611 "comment tag section %d, skipping comment object", i);
3612 for (i = 0; i < G_N_ELEMENTS (tags); i++)
3613 g_free (tags[i].val_utf8);
3614 return GST_FLOW_OK; /* not really fatal */
3618 static GstFlowReturn
3619 gst_asf_demux_process_bitrate_props_object (GstASFDemux * demux, guint8 * data,
3622 guint16 num_streams, i;
3626 goto not_enough_data;
3628 num_streams = gst_asf_demux_get_uint16 (&data, &size);
3630 GST_INFO ("object is a bitrate properties object with %u streams",
3633 if (size < (num_streams * (2 + 4)))
3634 goto not_enough_data;
3636 for (i = 0; i < num_streams; ++i) {
3640 stream_id = gst_asf_demux_get_uint16 (&data, &size);
3641 bitrate = gst_asf_demux_get_uint32 (&data, &size);
3643 if (stream_id < GST_ASF_DEMUX_NUM_STREAM_IDS) {
3644 GST_DEBUG_OBJECT (demux, "bitrate of stream %u = %u", stream_id, bitrate);
3645 stream = gst_asf_demux_get_stream (demux, stream_id);
3647 if (stream->pending_tags == NULL) {
3648 stream->pending_tags =
3649 gst_tag_list_new (GST_TAG_BITRATE, bitrate, NULL);
3652 GST_WARNING_OBJECT (demux, "Stream id %u wasn't found", stream_id);
3655 GST_WARNING ("stream id %u is too large", stream_id);
3663 GST_WARNING_OBJECT (demux, "short read parsing bitrate props object!");
3664 return GST_FLOW_OK; /* not really fatal */
3668 static GstFlowReturn
3669 gst_asf_demux_process_header_ext (GstASFDemux * demux, guint8 * data,
3672 GstFlowReturn ret = GST_FLOW_OK;
3675 /* Get the rest of the header's header */
3676 if (size < (16 + 2 + 4))
3677 goto not_enough_data;
3679 /* skip GUID and two other bytes */
3680 gst_asf_demux_skip_bytes (16 + 2, &data, &size);
3681 hdr_size = gst_asf_demux_get_uint32 (&data, &size);
3683 GST_INFO ("extended header object with a size of %u bytes", (guint) size);
3685 /* FIXME: does data_size include the rest of the header that we have read? */
3686 if (hdr_size > size)
3687 goto not_enough_data;
3689 while (hdr_size > 0) {
3690 ret = gst_asf_demux_process_object (demux, &data, &hdr_size);
3691 if (ret != GST_FLOW_OK)
3699 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3700 ("short read parsing extended header object"));
3701 return GST_FLOW_ERROR;
3705 static GstFlowReturn
3706 gst_asf_demux_process_language_list (GstASFDemux * demux, guint8 * data,
3712 goto not_enough_data;
3714 if (demux->languages) {
3715 GST_WARNING ("More than one LANGUAGE_LIST object in stream");
3716 g_strfreev (demux->languages);
3717 demux->languages = NULL;
3718 demux->num_languages = 0;
3721 demux->num_languages = gst_asf_demux_get_uint16 (&data, &size);
3722 GST_LOG ("%u languages:", demux->num_languages);
3724 demux->languages = g_new0 (gchar *, demux->num_languages + 1);
3725 for (i = 0; i < demux->num_languages; ++i) {
3726 guint8 len, *lang_data = NULL;
3729 goto not_enough_data;
3730 len = gst_asf_demux_get_uint8 (&data, &size);
3731 if (gst_asf_demux_get_bytes (&lang_data, len, &data, &size)) {
3734 utf8 = g_convert ((gchar *) lang_data, len, "UTF-8", "UTF-16LE", NULL,
3737 /* truncate "en-us" etc. to just "en" */
3738 if (utf8 && strlen (utf8) >= 5 && (utf8[2] == '-' || utf8[2] == '_')) {
3741 GST_DEBUG ("[%u] %s", i, GST_STR_NULL (utf8));
3742 demux->languages[i] = utf8;
3745 goto not_enough_data;
3753 GST_WARNING_OBJECT (demux, "short read parsing language list object!");
3754 g_free (demux->languages);
3755 demux->languages = NULL;
3756 return GST_FLOW_OK; /* not fatal */
3760 static GstFlowReturn
3761 gst_asf_demux_process_simple_index (GstASFDemux * demux, guint8 * data,
3764 GstClockTime interval;
3767 if (size < (16 + 8 + 4 + 4))
3768 goto not_enough_data;
3771 gst_asf_demux_skip_bytes (16, &data, &size);
3772 interval = gst_asf_demux_get_uint64 (&data, &size) * (GstClockTime) 100;
3773 gst_asf_demux_skip_bytes (4, &data, &size);
3774 count = gst_asf_demux_get_uint32 (&data, &size);
3776 demux->sidx_interval = interval;
3777 demux->sidx_num_entries = count;
3778 g_free (demux->sidx_entries);
3779 demux->sidx_entries = g_new0 (AsfSimpleIndexEntry, count);
3781 for (i = 0; i < count; ++i) {
3782 if (G_UNLIKELY (size < 6)) {
3783 /* adjust for broken files, to avoid having entries at the end
3784 * of the parsed index that point to time=0. Resulting in seeking to
3785 * the end of the file leading back to the beginning */
3786 demux->sidx_num_entries -= (count - i);
3789 demux->sidx_entries[i].packet = gst_asf_demux_get_uint32 (&data, &size);
3790 demux->sidx_entries[i].count = gst_asf_demux_get_uint16 (&data, &size);
3791 GST_LOG_OBJECT (demux, "%" GST_TIME_FORMAT " = packet %4u count : %2d",
3792 GST_TIME_ARGS (i * interval), demux->sidx_entries[i].packet,
3793 demux->sidx_entries[i].count);
3796 GST_DEBUG_OBJECT (demux, "simple index object with 0 entries");
3803 GST_WARNING_OBJECT (demux, "short read parsing simple index object!");
3804 return GST_FLOW_OK; /* not fatal */
3808 static GstFlowReturn
3809 gst_asf_demux_process_advanced_mutual_exclusion (GstASFDemux * demux,
3810 guint8 * data, guint64 size)
3815 if (size < 16 + 2 + (2 * 2))
3816 goto not_enough_data;
3818 gst_asf_demux_get_guid (&guid, &data, &size);
3819 num = gst_asf_demux_get_uint16 (&data, &size);
3822 GST_WARNING_OBJECT (demux, "nonsensical mutually exclusive streams count");
3826 if (size < (num * sizeof (guint16)))
3827 goto not_enough_data;
3829 /* read mutually exclusive stream numbers */
3830 for (i = 0; i < num; ++i) {
3832 mes = gst_asf_demux_get_uint16 (&data, &size) & 0x7f;
3833 GST_LOG_OBJECT (demux, "mutually exclusive: stream %d", mes);
3835 demux->mut_ex_streams =
3836 g_slist_append (demux->mut_ex_streams, GINT_TO_POINTER (mes));
3845 GST_WARNING_OBJECT (demux, "short read parsing advanced mutual exclusion");
3846 return GST_FLOW_OK; /* not absolutely fatal */
3851 gst_asf_demux_is_unknown_stream (GstASFDemux * demux, guint stream_num)
3853 return g_slist_find (demux->other_streams,
3854 GINT_TO_POINTER (stream_num)) == NULL;
3857 static GstFlowReturn
3858 gst_asf_demux_process_ext_stream_props (GstASFDemux * demux, guint8 * data,
3861 AsfStreamExtProps esp;
3862 AsfStream *stream = NULL;
3863 AsfObject stream_obj;
3864 guint16 stream_name_count;
3865 guint16 num_payload_ext;
3867 guint8 *stream_obj_data = NULL;
3870 guint i, stream_num;
3873 obj_size = (guint) size;
3876 goto not_enough_data;
3879 esp.start_time = gst_asf_demux_get_uint64 (&data, &size) * GST_MSECOND;
3880 esp.end_time = gst_asf_demux_get_uint64 (&data, &size) * GST_MSECOND;
3881 esp.data_bitrate = gst_asf_demux_get_uint32 (&data, &size);
3882 esp.buffer_size = gst_asf_demux_get_uint32 (&data, &size);
3883 esp.intial_buf_fullness = gst_asf_demux_get_uint32 (&data, &size);
3884 esp.data_bitrate2 = gst_asf_demux_get_uint32 (&data, &size);
3885 esp.buffer_size2 = gst_asf_demux_get_uint32 (&data, &size);
3886 esp.intial_buf_fullness2 = gst_asf_demux_get_uint32 (&data, &size);
3887 esp.max_obj_size = gst_asf_demux_get_uint32 (&data, &size);
3888 esp.flags = gst_asf_demux_get_uint32 (&data, &size);
3889 stream_num = gst_asf_demux_get_uint16 (&data, &size);
3890 esp.lang_idx = gst_asf_demux_get_uint16 (&data, &size);
3891 esp.avg_time_per_frame = gst_asf_demux_get_uint64 (&data, &size);
3892 stream_name_count = gst_asf_demux_get_uint16 (&data, &size);
3893 num_payload_ext = gst_asf_demux_get_uint16 (&data, &size);
3895 GST_INFO ("start_time = %" GST_TIME_FORMAT,
3896 GST_TIME_ARGS (esp.start_time));
3897 GST_INFO ("end_time = %" GST_TIME_FORMAT,
3898 GST_TIME_ARGS (esp.end_time));
3899 GST_INFO ("flags = %08x", esp.flags);
3900 GST_INFO ("average time per frame = %" GST_TIME_FORMAT,
3901 GST_TIME_ARGS (esp.avg_time_per_frame * 100));
3902 GST_INFO ("stream number = %u", stream_num);
3903 GST_INFO ("stream language ID idx = %u (%s)", esp.lang_idx,
3904 (esp.lang_idx < demux->num_languages) ?
3905 GST_STR_NULL (demux->languages[esp.lang_idx]) : "??");
3906 GST_INFO ("stream name count = %u", stream_name_count);
3908 /* read stream names */
3909 for (i = 0; i < stream_name_count; ++i) {
3910 guint16 stream_lang_idx G_GNUC_UNUSED;
3911 gchar *stream_name = NULL;
3914 goto not_enough_data;
3915 stream_lang_idx = gst_asf_demux_get_uint16 (&data, &size);
3916 if (!gst_asf_demux_get_string (&stream_name, NULL, &data, &size))
3917 goto not_enough_data;
3918 GST_INFO ("stream name %d: %s", i, GST_STR_NULL (stream_name));
3919 g_free (stream_name); /* TODO: store names in struct */
3922 /* read payload extension systems stuff */
3923 GST_LOG ("payload extension systems count = %u", num_payload_ext);
3925 if (num_payload_ext > 0)
3926 esp.payload_extensions = g_new0 (AsfPayloadExtension, num_payload_ext + 1);
3928 esp.payload_extensions = NULL;
3930 for (i = 0; i < num_payload_ext; ++i) {
3931 AsfPayloadExtension ext;
3933 guint32 sys_info_len;
3935 if (size < 16 + 2 + 4)
3936 goto not_enough_data;
3938 gst_asf_demux_get_guid (&ext_guid, &data, &size);
3939 ext.id = gst_asf_demux_identify_guid (asf_payload_ext_guids, &ext_guid);
3940 ext.len = gst_asf_demux_get_uint16 (&data, &size);
3942 sys_info_len = gst_asf_demux_get_uint32 (&data, &size);
3943 GST_LOG ("payload systems info len = %u", sys_info_len);
3944 if (!gst_asf_demux_skip_bytes (sys_info_len, &data, &size))
3945 goto not_enough_data;
3947 esp.payload_extensions[i] = ext;
3950 GST_LOG ("bytes read: %u/%u", (guint) (data - data_start), obj_size);
3952 /* there might be an optional STREAM_INFO object here now; if not, we
3953 * should have parsed the corresponding stream info object already (since
3954 * we are parsing the extended stream properties objects delayed) */
3956 stream = gst_asf_demux_get_stream (demux, stream_num);
3960 /* get size of the stream object */
3961 if (!asf_demux_peek_object (demux, data, size, &stream_obj, TRUE))
3962 goto not_enough_data;
3964 if (stream_obj.id != ASF_OBJ_STREAM)
3965 goto expected_stream_object;
3967 if (stream_obj.size < ASF_OBJECT_HEADER_SIZE ||
3968 stream_obj.size > (10 * 1024 * 1024))
3969 goto not_enough_data;
3971 gst_asf_demux_skip_bytes (ASF_OBJECT_HEADER_SIZE, &data, &size);
3973 /* process this stream object later after all the other 'normal' ones
3974 * have been processed (since the others are more important/non-hidden) */
3975 len = stream_obj.size - ASF_OBJECT_HEADER_SIZE;
3976 if (!gst_asf_demux_get_bytes (&stream_obj_data, len, &data, &size))
3977 goto not_enough_data;
3979 /* parse stream object */
3980 stream = gst_asf_demux_parse_stream_object (demux, stream_obj_data, len);
3981 g_free (stream_obj_data);
3986 stream->ext_props = esp;
3988 /* try to set the framerate */
3989 if (stream->is_video && stream->caps) {
3990 GValue framerate = { 0 };
3994 g_value_init (&framerate, GST_TYPE_FRACTION);
3996 num = GST_SECOND / 100;
3997 denom = esp.avg_time_per_frame;
3999 /* avoid division by 0, assume 25/1 framerate */
4000 denom = GST_SECOND / 2500;
4003 gst_value_set_fraction (&framerate, num, denom);
4005 stream->caps = gst_caps_make_writable (stream->caps);
4006 s = gst_caps_get_structure (stream->caps, 0);
4007 gst_structure_set_value (s, "framerate", &framerate);
4008 g_value_unset (&framerate);
4009 GST_DEBUG_OBJECT (demux, "setting framerate of %d/%d = %f",
4010 num, denom, ((gdouble) num) / denom);
4013 /* add language info now if we have it */
4014 if (stream->ext_props.lang_idx < demux->num_languages) {
4015 if (stream->pending_tags == NULL)
4016 stream->pending_tags = gst_tag_list_new_empty ();
4017 GST_LOG_OBJECT (demux, "stream %u has language '%s'", stream->id,
4018 demux->languages[stream->ext_props.lang_idx]);
4019 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_APPEND,
4020 GST_TAG_LANGUAGE_CODE, demux->languages[stream->ext_props.lang_idx],
4023 } else if (gst_asf_demux_is_unknown_stream (demux, stream_num)) {
4024 GST_WARNING_OBJECT (demux, "Ext. stream properties for unknown stream");
4032 GST_WARNING_OBJECT (demux, "short read parsing ext stream props object!");
4033 return GST_FLOW_OK; /* not absolutely fatal */
4035 expected_stream_object:
4037 GST_WARNING_OBJECT (demux, "error parsing extended stream properties "
4038 "object: expected embedded stream object, but got %s object instead!",
4039 gst_asf_get_guid_nick (asf_object_guids, stream_obj.id));
4040 return GST_FLOW_OK; /* not absolutely fatal */
4044 static const gchar *
4045 gst_asf_demux_push_obj (GstASFDemux * demux, guint32 obj_id)
4049 nick = gst_asf_get_guid_nick (asf_object_guids, obj_id);
4050 if (g_str_has_prefix (nick, "ASF_OBJ_"))
4051 nick += strlen ("ASF_OBJ_");
4053 if (demux->objpath == NULL) {
4054 demux->objpath = g_strdup (nick);
4058 newpath = g_strdup_printf ("%s/%s", demux->objpath, nick);
4059 g_free (demux->objpath);
4060 demux->objpath = newpath;
4063 return (const gchar *) demux->objpath;
4067 gst_asf_demux_pop_obj (GstASFDemux * demux)
4071 if ((s = g_strrstr (demux->objpath, "/"))) {
4074 g_free (demux->objpath);
4075 demux->objpath = NULL;
4080 gst_asf_demux_process_queued_extended_stream_objects (GstASFDemux * demux)
4085 /* Parse the queued extended stream property objects and add the info
4086 * to the existing streams or add the new embedded streams, but without
4087 * activating them yet */
4088 GST_LOG_OBJECT (demux, "%u queued extended stream properties objects",
4089 g_slist_length (demux->ext_stream_props));
4091 for (l = demux->ext_stream_props, i = 0; l != NULL; l = l->next, ++i) {
4092 GstBuffer *buf = GST_BUFFER (l->data);
4095 gst_buffer_map (buf, &map, GST_MAP_READ);
4097 GST_LOG_OBJECT (demux, "parsing ext. stream properties object #%u", i);
4098 gst_asf_demux_process_ext_stream_props (demux, map.data, map.size);
4099 gst_buffer_unmap (buf, &map);
4100 gst_buffer_unref (buf);
4102 g_slist_free (demux->ext_stream_props);
4103 demux->ext_stream_props = NULL;
4108 gst_asf_demux_activate_ext_props_streams (GstASFDemux * demux)
4112 for (i = 0; i < demux->num_streams; ++i) {
4117 stream = &demux->stream[i];
4119 GST_LOG_OBJECT (demux, "checking stream %2u", stream->id);
4121 if (stream->active) {
4122 GST_LOG_OBJECT (demux, "stream %2u is already activated", stream->id);
4127 for (x = demux->mut_ex_streams; x != NULL; x = x->next) {
4130 /* check for each mutual exclusion whether it affects this stream */
4131 for (mes = (guint8 *) x->data; mes != NULL && *mes != 0xff; ++mes) {
4132 if (*mes == stream->id) {
4133 /* if yes, check if we've already added streams that are mutually
4134 * exclusive with the stream we're about to add */
4135 for (mes = (guint8 *) x->data; mes != NULL && *mes != 0xff; ++mes) {
4136 for (j = 0; j < demux->num_streams; ++j) {
4137 /* if the broadcast flag is set, assume the hidden streams aren't
4138 * actually streamed and hide them (or playbin won't work right),
4139 * otherwise assume their data is available */
4140 if (demux->stream[j].id == *mes && demux->broadcast) {
4142 GST_LOG_OBJECT (demux, "broadcast stream ID %d to be added is "
4143 "mutually exclusive with already existing stream ID %d, "
4144 "hiding stream", stream->id, demux->stream[j].id);
4156 /* FIXME: we should do stream activation based on preroll data in
4157 * streaming mode too */
4158 if (demux->streaming && !is_hidden)
4159 gst_asf_demux_activate_stream (demux, stream);
4164 static GstFlowReturn
4165 gst_asf_demux_process_object (GstASFDemux * demux, guint8 ** p_data,
4168 GstFlowReturn ret = GST_FLOW_OK;
4170 guint64 obj_data_size;
4172 if (*p_size < ASF_OBJECT_HEADER_SIZE)
4173 return ASF_FLOW_NEED_MORE_DATA;
4175 asf_demux_peek_object (demux, *p_data, ASF_OBJECT_HEADER_SIZE, &obj, TRUE);
4176 gst_asf_demux_skip_bytes (ASF_OBJECT_HEADER_SIZE, p_data, p_size);
4178 obj_data_size = obj.size - ASF_OBJECT_HEADER_SIZE;
4180 if (*p_size < obj_data_size)
4181 return ASF_FLOW_NEED_MORE_DATA;
4183 gst_asf_demux_push_obj (demux, obj.id);
4185 GST_INFO ("%s: size %" G_GUINT64_FORMAT, demux->objpath, obj.size);
4188 case ASF_OBJ_STREAM:
4189 gst_asf_demux_parse_stream_object (demux, *p_data, obj_data_size);
4193 ret = gst_asf_demux_process_file (demux, *p_data, obj_data_size);
4195 case ASF_OBJ_HEADER:
4196 ret = gst_asf_demux_process_header (demux, *p_data, obj_data_size);
4198 case ASF_OBJ_COMMENT:
4199 ret = gst_asf_demux_process_comment (demux, *p_data, obj_data_size);
4202 ret = gst_asf_demux_process_header_ext (demux, *p_data, obj_data_size);
4204 case ASF_OBJ_BITRATE_PROPS:
4206 gst_asf_demux_process_bitrate_props_object (demux, *p_data,
4209 case ASF_OBJ_EXT_CONTENT_DESC:
4211 gst_asf_demux_process_ext_content_desc (demux, *p_data,
4214 case ASF_OBJ_METADATA_OBJECT:
4215 ret = gst_asf_demux_process_metadata (demux, *p_data, obj_data_size);
4217 case ASF_OBJ_EXTENDED_STREAM_PROPS:{
4220 /* process these later, we might not have parsed the corresponding
4221 * stream object yet */
4222 GST_LOG ("%s: queued for later parsing", demux->objpath);
4223 buf = gst_buffer_new_and_alloc (obj_data_size);
4224 gst_buffer_fill (buf, 0, *p_data, obj_data_size);
4225 demux->ext_stream_props = g_slist_append (demux->ext_stream_props, buf);
4229 case ASF_OBJ_LANGUAGE_LIST:
4230 ret = gst_asf_demux_process_language_list (demux, *p_data, obj_data_size);
4232 case ASF_OBJ_ADVANCED_MUTUAL_EXCLUSION:
4233 ret = gst_asf_demux_process_advanced_mutual_exclusion (demux, *p_data,
4236 case ASF_OBJ_SIMPLE_INDEX:
4237 ret = gst_asf_demux_process_simple_index (demux, *p_data, obj_data_size);
4239 case ASF_OBJ_CONTENT_ENCRYPTION:
4240 case ASF_OBJ_EXT_CONTENT_ENCRYPTION:
4241 case ASF_OBJ_DIGITAL_SIGNATURE_OBJECT:
4242 case ASF_OBJ_UNKNOWN_ENCRYPTION_OBJECT:
4243 goto error_encrypted;
4244 case ASF_OBJ_CONCEAL_NONE:
4246 case ASF_OBJ_UNDEFINED:
4247 case ASF_OBJ_CODEC_COMMENT:
4249 case ASF_OBJ_PADDING:
4250 case ASF_OBJ_BITRATE_MUTEX:
4251 case ASF_OBJ_COMPATIBILITY:
4252 case ASF_OBJ_INDEX_PLACEHOLDER:
4253 case ASF_OBJ_INDEX_PARAMETERS:
4254 case ASF_OBJ_STREAM_PRIORITIZATION:
4255 case ASF_OBJ_SCRIPT_COMMAND:
4256 case ASF_OBJ_METADATA_LIBRARY_OBJECT:
4258 /* Unknown/unhandled object, skip it and hope for the best */
4259 GST_INFO ("%s: skipping object", demux->objpath);
4264 /* this can't fail, we checked the number of bytes available before */
4265 gst_asf_demux_skip_bytes (obj_data_size, p_data, p_size);
4267 GST_LOG ("%s: ret = %s", demux->objpath, gst_asf_get_flow_name (ret));
4269 gst_asf_demux_pop_obj (demux);
4276 GST_ELEMENT_ERROR (demux, STREAM, DECRYPT, (NULL), (NULL));
4277 return GST_FLOW_ERROR;
4282 gst_asf_demux_descramble_buffer (GstASFDemux * demux, AsfStream * stream,
4283 GstBuffer ** p_buffer)
4285 GstBuffer *descrambled_buffer;
4286 GstBuffer *scrambled_buffer;
4287 GstBuffer *sub_buffer;
4294 /* descrambled_buffer is initialised in the first iteration */
4295 descrambled_buffer = NULL;
4296 scrambled_buffer = *p_buffer;
4298 if (gst_buffer_get_size (scrambled_buffer) <
4299 stream->ds_packet_size * stream->span)
4302 for (offset = 0; offset < gst_buffer_get_size (scrambled_buffer);
4303 offset += stream->ds_chunk_size) {
4304 off = offset / stream->ds_chunk_size;
4305 row = off / stream->span;
4306 col = off % stream->span;
4307 idx = row + col * stream->ds_packet_size / stream->ds_chunk_size;
4308 GST_DEBUG ("idx=%u, row=%u, col=%u, off=%u, ds_chunk_size=%u", idx, row,
4309 col, off, stream->ds_chunk_size);
4310 GST_DEBUG ("scrambled buffer size=%" G_GSIZE_FORMAT
4311 ", span=%u, packet_size=%u", gst_buffer_get_size (scrambled_buffer),
4312 stream->span, stream->ds_packet_size);
4313 GST_DEBUG ("gst_buffer_get_size (scrambled_buffer) = %" G_GSIZE_FORMAT,
4314 gst_buffer_get_size (scrambled_buffer));
4316 gst_buffer_copy_region (scrambled_buffer, GST_BUFFER_COPY_MEMORY,
4317 idx * stream->ds_chunk_size, stream->ds_chunk_size);
4319 descrambled_buffer = sub_buffer;
4321 descrambled_buffer = gst_buffer_append (descrambled_buffer, sub_buffer);
4325 GST_BUFFER_TIMESTAMP (descrambled_buffer) =
4326 GST_BUFFER_TIMESTAMP (scrambled_buffer);
4327 GST_BUFFER_DURATION (descrambled_buffer) =
4328 GST_BUFFER_DURATION (scrambled_buffer);
4329 GST_BUFFER_OFFSET (descrambled_buffer) = GST_BUFFER_OFFSET (scrambled_buffer);
4330 GST_BUFFER_OFFSET_END (descrambled_buffer) =
4331 GST_BUFFER_OFFSET_END (scrambled_buffer);
4333 /* FIXME/CHECK: do we need to transfer buffer flags here too? */
4335 gst_buffer_unref (scrambled_buffer);
4336 *p_buffer = descrambled_buffer;
4340 gst_asf_demux_element_send_event (GstElement * element, GstEvent * event)
4342 GstASFDemux *demux = GST_ASF_DEMUX (element);
4345 GST_DEBUG ("handling element event of type %s", GST_EVENT_TYPE_NAME (event));
4347 for (i = 0; i < demux->num_streams; ++i) {
4348 gst_event_ref (event);
4349 if (gst_asf_demux_handle_src_event (demux->stream[i].pad,
4350 GST_OBJECT_CAST (element), event)) {
4351 gst_event_unref (event);
4356 gst_event_unref (event);
4360 /* takes ownership of the passed event */
4362 gst_asf_demux_send_event_unlocked (GstASFDemux * demux, GstEvent * event)
4364 gboolean ret = TRUE;
4367 GST_DEBUG_OBJECT (demux, "sending %s event to all source pads",
4368 GST_EVENT_TYPE_NAME (event));
4370 for (i = 0; i < demux->num_streams; ++i) {
4371 gst_event_ref (event);
4372 ret &= gst_pad_push_event (demux->stream[i].pad, event);
4374 gst_event_unref (event);
4379 gst_asf_demux_handle_src_query (GstPad * pad, GstObject * parent,
4383 gboolean res = FALSE;
4385 demux = GST_ASF_DEMUX (parent);
4387 GST_DEBUG ("handling %s query",
4388 gst_query_type_get_name (GST_QUERY_TYPE (query)));
4390 switch (GST_QUERY_TYPE (query)) {
4391 case GST_QUERY_DURATION:
4395 gst_query_parse_duration (query, &format, NULL);
4397 if (format != GST_FORMAT_TIME) {
4398 GST_LOG ("only support duration queries in TIME format");
4402 res = gst_pad_query_default (pad, parent, query);
4404 GST_OBJECT_LOCK (demux);
4406 if (demux->segment.duration != GST_CLOCK_TIME_NONE) {
4407 GST_LOG ("returning duration: %" GST_TIME_FORMAT,
4408 GST_TIME_ARGS (demux->segment.duration));
4410 gst_query_set_duration (query, GST_FORMAT_TIME,
4411 demux->segment.duration);
4415 GST_LOG ("duration not known yet");
4418 GST_OBJECT_UNLOCK (demux);
4423 case GST_QUERY_POSITION:{
4426 gst_query_parse_position (query, &format, NULL);
4428 if (format != GST_FORMAT_TIME) {
4429 GST_LOG ("only support position queries in TIME format");
4433 GST_OBJECT_LOCK (demux);
4435 if (demux->segment.position != GST_CLOCK_TIME_NONE) {
4436 GST_LOG ("returning position: %" GST_TIME_FORMAT,
4437 GST_TIME_ARGS (demux->segment.position));
4439 gst_query_set_position (query, GST_FORMAT_TIME,
4440 demux->segment.position);
4444 GST_LOG ("position not known yet");
4447 GST_OBJECT_UNLOCK (demux);
4451 case GST_QUERY_SEEKING:{
4454 gst_query_parse_seeking (query, &format, NULL, NULL, NULL);
4455 if (format == GST_FORMAT_TIME) {
4458 GST_OBJECT_LOCK (demux);
4459 duration = demux->segment.duration;
4460 GST_OBJECT_UNLOCK (demux);
4462 if (!demux->streaming || !demux->seekable) {
4463 gst_query_set_seeking (query, GST_FORMAT_TIME, demux->seekable, 0,
4470 /* try upstream first in TIME */
4471 res = gst_pad_query_default (pad, parent, query);
4473 gst_query_parse_seeking (query, &fmt, &seekable, NULL, NULL);
4474 GST_LOG_OBJECT (demux, "upstream %s seekable %d",
4475 GST_STR_NULL (gst_format_get_name (fmt)), seekable);
4476 /* if no luck, maybe in BYTES */
4477 if (!seekable || fmt != GST_FORMAT_TIME) {
4480 q = gst_query_new_seeking (GST_FORMAT_BYTES);
4481 if ((res = gst_pad_peer_query (demux->sinkpad, q))) {
4482 gst_query_parse_seeking (q, &fmt, &seekable, NULL, NULL);
4483 GST_LOG_OBJECT (demux, "upstream %s seekable %d",
4484 GST_STR_NULL (gst_format_get_name (fmt)), seekable);
4485 if (fmt != GST_FORMAT_BYTES)
4488 gst_query_unref (q);
4489 gst_query_set_seeking (query, GST_FORMAT_TIME, seekable, 0,
4495 GST_LOG_OBJECT (demux, "only support seeking in TIME format");
4499 case GST_QUERY_LATENCY:
4502 GstClockTime min, max;
4504 /* preroll delay does not matter in non-live pipeline,
4505 * but we might end up in a live (rtsp) one ... */
4508 res = gst_pad_query_default (pad, parent, query);
4512 gst_query_parse_latency (query, &live, &min, &max);
4514 GST_DEBUG_OBJECT (demux, "Peer latency: live %d, min %"
4515 GST_TIME_FORMAT " max %" GST_TIME_FORMAT, live,
4516 GST_TIME_ARGS (min), GST_TIME_ARGS (max));
4518 GST_OBJECT_LOCK (demux);
4519 min += demux->latency;
4521 max += demux->latency;
4522 GST_OBJECT_UNLOCK (demux);
4524 gst_query_set_latency (query, live, min, max);
4527 case GST_QUERY_SEGMENT:
4532 format = demux->segment.format;
4535 gst_segment_to_stream_time (&demux->segment, format,
4536 demux->segment.start);
4537 if ((stop = demux->segment.stop) == -1)
4538 stop = demux->segment.duration;
4540 stop = gst_segment_to_stream_time (&demux->segment, format, stop);
4542 gst_query_set_segment (query, demux->segment.rate, format, start, stop);
4547 res = gst_pad_query_default (pad, parent, query);
4554 static GstStateChangeReturn
4555 gst_asf_demux_change_state (GstElement * element, GstStateChange transition)
4557 GstASFDemux *demux = GST_ASF_DEMUX (element);
4558 GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
4560 switch (transition) {
4561 case GST_STATE_CHANGE_NULL_TO_READY:{
4562 gst_segment_init (&demux->segment, GST_FORMAT_TIME);
4563 demux->need_newsegment = TRUE;
4564 demux->segment_running = FALSE;
4565 demux->keyunit_sync = FALSE;
4566 demux->adapter = gst_adapter_new ();
4567 demux->metadata = gst_caps_new_empty ();
4568 demux->global_metadata = gst_structure_new_empty ("metadata");
4569 demux->data_size = 0;
4570 demux->data_offset = 0;
4571 demux->index_offset = 0;
4572 demux->base_offset = 0;
4573 demux->flowcombiner = gst_flow_combiner_new ();
4580 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
4581 if (ret == GST_STATE_CHANGE_FAILURE)
4584 switch (transition) {
4585 case GST_STATE_CHANGE_PAUSED_TO_READY:
4586 gst_asf_demux_reset (demux, FALSE);
4589 case GST_STATE_CHANGE_READY_TO_NULL:
4590 gst_asf_demux_reset (demux, FALSE);
4591 gst_flow_combiner_free (demux->flowcombiner);
4592 demux->flowcombiner = NULL;