1 /* GStreamer ASF/WMV/WMA demuxer
2 * Copyright (C) 1999 Erik Walthinsen <omega@cse.ogi.edu>
3 * Copyright (C) 2006-2009 Tim-Philipp Müller <tim centricular net>
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
15 * You should have received a copy of the GNU Library General Public
16 * License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
24 * stop if at end of segment if != end of file, ie. demux->segment.stop
26 * - fix packet parsing:
27 * there's something wrong with timestamps for packets with keyframes,
35 #include <gst/gstutils.h>
36 #include <gst/base/gstbytereader.h>
37 #include <gst/base/gsttypefindhelper.h>
38 #include <gst/riff/riff-media.h>
39 #include <gst/tag/tag.h>
40 #include <gst/gst-i18n-plugin.h>
41 #include <gst/video/video.h>
46 #include "gstasfdemux.h"
47 #include "asfheaders.h"
48 #include "asfpacket.h"
50 static GstStaticPadTemplate gst_asf_demux_sink_template =
51 GST_STATIC_PAD_TEMPLATE ("sink",
54 GST_STATIC_CAPS ("video/x-ms-asf")
57 static GstStaticPadTemplate audio_src_template =
58 GST_STATIC_PAD_TEMPLATE ("audio_%u",
63 static GstStaticPadTemplate video_src_template =
64 GST_STATIC_PAD_TEMPLATE ("video_%u",
69 /* size of an ASF object header, ie. GUID (16 bytes) + object size (8 bytes) */
70 #define ASF_OBJECT_HEADER_SIZE (16+8)
72 /* FIXME: get rid of this */
73 /* abuse this GstFlowReturn enum for internal usage */
74 #define ASF_FLOW_NEED_MORE_DATA 99
76 #define gst_asf_get_flow_name(flow) \
77 (flow == ASF_FLOW_NEED_MORE_DATA) ? \
78 "need-more-data" : gst_flow_get_name (flow)
80 GST_DEBUG_CATEGORY (asfdemux_dbg);
82 static GstStateChangeReturn gst_asf_demux_change_state (GstElement * element,
83 GstStateChange transition);
84 static gboolean gst_asf_demux_element_send_event (GstElement * element,
86 static gboolean gst_asf_demux_send_event_unlocked (GstASFDemux * demux,
88 static gboolean gst_asf_demux_handle_src_query (GstPad * pad,
89 GstObject * parent, GstQuery * query);
90 static GstFlowReturn gst_asf_demux_chain (GstPad * pad, GstObject * parent,
92 static gboolean gst_asf_demux_sink_event (GstPad * pad, GstObject * parent,
94 static GstFlowReturn gst_asf_demux_process_object (GstASFDemux * demux,
95 guint8 ** p_data, guint64 * p_size);
96 static gboolean gst_asf_demux_activate (GstPad * sinkpad, GstObject * parent);
97 static gboolean gst_asf_demux_activate_mode (GstPad * sinkpad,
98 GstObject * parent, GstPadMode mode, gboolean active);
99 static void gst_asf_demux_loop (GstASFDemux * demux);
101 gst_asf_demux_process_queued_extended_stream_objects (GstASFDemux * demux);
102 static gboolean gst_asf_demux_pull_headers (GstASFDemux * demux,
103 GstFlowReturn * pflow);
104 static void gst_asf_demux_pull_indices (GstASFDemux * demux);
105 static void gst_asf_demux_reset_stream_state_after_discont (GstASFDemux * asf);
107 gst_asf_demux_parse_data_object_start (GstASFDemux * demux, guint8 * data);
108 static void gst_asf_demux_descramble_buffer (GstASFDemux * demux,
109 AsfStream * stream, GstBuffer ** p_buffer);
110 static void gst_asf_demux_activate_stream (GstASFDemux * demux,
112 static GstStructure *gst_asf_demux_get_metadata_for_stream (GstASFDemux * d,
114 static GstFlowReturn gst_asf_demux_push_complete_payloads (GstASFDemux * demux,
117 #define gst_asf_demux_parent_class parent_class
118 G_DEFINE_TYPE (GstASFDemux, gst_asf_demux, GST_TYPE_ELEMENT);
121 gst_asf_demux_class_init (GstASFDemuxClass * klass)
123 GstElementClass *gstelement_class;
125 gstelement_class = (GstElementClass *) klass;
127 gst_element_class_set_static_metadata (gstelement_class, "ASF Demuxer",
129 "Demultiplexes ASF Streams", "Owen Fraser-Green <owen@discobabe.net>");
131 gst_element_class_add_static_pad_template (gstelement_class,
132 &audio_src_template);
133 gst_element_class_add_static_pad_template (gstelement_class,
134 &video_src_template);
135 gst_element_class_add_static_pad_template (gstelement_class,
136 &gst_asf_demux_sink_template);
138 gstelement_class->change_state =
139 GST_DEBUG_FUNCPTR (gst_asf_demux_change_state);
140 gstelement_class->send_event =
141 GST_DEBUG_FUNCPTR (gst_asf_demux_element_send_event);
145 gst_asf_demux_free_stream (GstASFDemux * demux, AsfStream * stream)
147 gst_caps_replace (&stream->caps, NULL);
148 if (stream->pending_tags) {
149 gst_tag_list_unref (stream->pending_tags);
150 stream->pending_tags = NULL;
152 if (stream->streamheader) {
153 gst_buffer_unref (stream->streamheader);
154 stream->streamheader = NULL;
157 if (stream->active) {
158 gst_element_remove_pad (GST_ELEMENT_CAST (demux), stream->pad);
159 gst_flow_combiner_remove_pad (demux->flowcombiner, stream->pad);
161 gst_object_unref (stream->pad);
165 if (stream->payloads) {
166 while (stream->payloads->len > 0) {
170 last = stream->payloads->len - 1;
171 payload = &g_array_index (stream->payloads, AsfPayload, last);
172 gst_buffer_replace (&payload->buf, NULL);
173 g_array_remove_index (stream->payloads, last);
175 g_array_free (stream->payloads, TRUE);
176 stream->payloads = NULL;
179 if (stream->payloads_rev) {
180 while (stream->payloads_rev->len > 0) {
184 last = stream->payloads_rev->len - 1;
185 payload = &g_array_index (stream->payloads_rev, AsfPayload, last);
186 gst_buffer_replace (&payload->buf, NULL);
187 g_array_remove_index (stream->payloads_rev, last);
189 g_array_free (stream->payloads_rev, TRUE);
190 stream->payloads_rev = NULL;
193 if (stream->ext_props.valid) {
194 g_free (stream->ext_props.payload_extensions);
195 stream->ext_props.payload_extensions = NULL;
200 gst_asf_demux_reset (GstASFDemux * demux, gboolean chain_reset)
202 GST_LOG_OBJECT (demux, "resetting");
204 gst_segment_init (&demux->segment, GST_FORMAT_UNDEFINED);
205 demux->segment_running = FALSE;
206 if (demux->adapter && !chain_reset) {
207 gst_adapter_clear (demux->adapter);
208 g_object_unref (demux->adapter);
209 demux->adapter = NULL;
211 if (demux->taglist) {
212 gst_tag_list_unref (demux->taglist);
213 demux->taglist = NULL;
215 if (demux->metadata) {
216 gst_caps_unref (demux->metadata);
217 demux->metadata = NULL;
219 if (demux->global_metadata) {
220 gst_structure_free (demux->global_metadata);
221 demux->global_metadata = NULL;
223 if (demux->mut_ex_streams) {
224 g_slist_free (demux->mut_ex_streams);
225 demux->mut_ex_streams = NULL;
228 demux->state = GST_ASF_DEMUX_STATE_HEADER;
229 g_free (demux->objpath);
230 demux->objpath = NULL;
231 g_strfreev (demux->languages);
232 demux->languages = NULL;
233 demux->num_languages = 0;
234 g_slist_foreach (demux->ext_stream_props, (GFunc) gst_mini_object_unref,
236 g_slist_free (demux->ext_stream_props);
237 demux->ext_stream_props = NULL;
239 while (demux->old_num_streams > 0) {
240 gst_asf_demux_free_stream (demux,
241 &demux->old_stream[demux->old_num_streams - 1]);
242 --demux->old_num_streams;
244 memset (demux->old_stream, 0, sizeof (demux->old_stream));
245 demux->old_num_streams = 0;
247 /* when resetting for a new chained asf, we don't want to remove the pads
248 * before adding the new ones */
250 memcpy (demux->old_stream, demux->stream, sizeof (demux->stream));
251 demux->old_num_streams = demux->num_streams;
252 demux->num_streams = 0;
255 while (demux->num_streams > 0) {
256 gst_asf_demux_free_stream (demux, &demux->stream[demux->num_streams - 1]);
257 --demux->num_streams;
259 memset (demux->stream, 0, sizeof (demux->stream));
261 /* do not remove those for not adding pads with same name */
262 demux->num_audio_streams = 0;
263 demux->num_video_streams = 0;
264 demux->have_group_id = FALSE;
265 demux->group_id = G_MAXUINT;
267 demux->num_streams = 0;
268 demux->activated_streams = FALSE;
269 demux->first_ts = GST_CLOCK_TIME_NONE;
270 demux->segment_ts = GST_CLOCK_TIME_NONE;
273 gst_segment_init (&demux->in_segment, GST_FORMAT_UNDEFINED);
274 demux->state = GST_ASF_DEMUX_STATE_HEADER;
275 demux->seekable = FALSE;
276 demux->broadcast = FALSE;
277 demux->sidx_interval = 0;
278 demux->sidx_num_entries = 0;
279 g_free (demux->sidx_entries);
280 demux->sidx_entries = NULL;
282 demux->speed_packets = 1;
284 demux->asf_3D_mode = GST_ASF_3D_NONE;
287 GST_LOG_OBJECT (demux, "Restarting");
288 gst_segment_init (&demux->segment, GST_FORMAT_TIME);
289 demux->need_newsegment = TRUE;
290 demux->segment_seqnum = 0;
291 demux->segment_running = FALSE;
292 demux->keyunit_sync = FALSE;
293 demux->accurate = FALSE;
294 demux->metadata = gst_caps_new_empty ();
295 demux->global_metadata = gst_structure_new_empty ("metadata");
296 demux->data_size = 0;
297 demux->data_offset = 0;
298 demux->index_offset = 0;
300 demux->base_offset = 0;
303 g_slist_free (demux->other_streams);
304 demux->other_streams = NULL;
308 gst_asf_demux_init (GstASFDemux * demux)
311 gst_pad_new_from_static_template (&gst_asf_demux_sink_template, "sink");
312 gst_pad_set_chain_function (demux->sinkpad,
313 GST_DEBUG_FUNCPTR (gst_asf_demux_chain));
314 gst_pad_set_event_function (demux->sinkpad,
315 GST_DEBUG_FUNCPTR (gst_asf_demux_sink_event));
316 gst_pad_set_activate_function (demux->sinkpad,
317 GST_DEBUG_FUNCPTR (gst_asf_demux_activate));
318 gst_pad_set_activatemode_function (demux->sinkpad,
319 GST_DEBUG_FUNCPTR (gst_asf_demux_activate_mode));
320 gst_element_add_pad (GST_ELEMENT (demux), demux->sinkpad);
322 /* set initial state */
323 gst_asf_demux_reset (demux, FALSE);
327 gst_asf_demux_activate (GstPad * sinkpad, GstObject * parent)
332 query = gst_query_new_scheduling ();
334 if (!gst_pad_peer_query (sinkpad, query)) {
335 gst_query_unref (query);
339 pull_mode = gst_query_has_scheduling_mode_with_flags (query,
340 GST_PAD_MODE_PULL, GST_SCHEDULING_FLAG_SEEKABLE);
341 gst_query_unref (query);
346 GST_DEBUG_OBJECT (sinkpad, "activating pull");
347 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PULL, TRUE);
351 GST_DEBUG_OBJECT (sinkpad, "activating push");
352 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PUSH, TRUE);
357 gst_asf_demux_activate_mode (GstPad * sinkpad, GstObject * parent,
358 GstPadMode mode, gboolean active)
363 demux = GST_ASF_DEMUX (parent);
366 case GST_PAD_MODE_PUSH:
367 demux->state = GST_ASF_DEMUX_STATE_HEADER;
368 demux->streaming = TRUE;
371 case GST_PAD_MODE_PULL:
373 demux->state = GST_ASF_DEMUX_STATE_HEADER;
374 demux->streaming = FALSE;
376 res = gst_pad_start_task (sinkpad, (GstTaskFunction) gst_asf_demux_loop,
379 res = gst_pad_stop_task (sinkpad);
390 gst_asf_demux_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
395 demux = GST_ASF_DEMUX (parent);
397 GST_LOG_OBJECT (demux, "handling %s event", GST_EVENT_TYPE_NAME (event));
398 switch (GST_EVENT_TYPE (event)) {
399 case GST_EVENT_SEGMENT:{
400 const GstSegment *segment;
402 gst_event_parse_segment (event, &segment);
404 if (segment->format == GST_FORMAT_BYTES) {
405 if (demux->packet_size && segment->start > demux->data_offset)
406 demux->packet = (segment->start - demux->data_offset) /
410 } else if (segment->format == GST_FORMAT_TIME) {
411 /* do not know packet position, not really a problem */
414 GST_WARNING_OBJECT (demux, "unsupported newsegment format, ignoring");
415 gst_event_unref (event);
419 /* record upstream segment for interpolation */
420 if (segment->format != demux->in_segment.format)
421 gst_segment_init (&demux->in_segment, GST_FORMAT_UNDEFINED);
422 gst_segment_copy_into (segment, &demux->in_segment);
424 /* in either case, clear some state and generate newsegment later on */
425 GST_OBJECT_LOCK (demux);
426 demux->segment_ts = GST_CLOCK_TIME_NONE;
427 demux->in_gap = GST_CLOCK_TIME_NONE;
428 demux->need_newsegment = TRUE;
429 demux->segment_seqnum = gst_event_get_seqnum (event);
430 gst_asf_demux_reset_stream_state_after_discont (demux);
431 /* if we seek back after reaching EOS, go back to packet reading state */
432 if (demux->data_offset > 0 && segment->start >= demux->data_offset
433 && demux->state == GST_ASF_DEMUX_STATE_INDEX) {
434 demux->state = GST_ASF_DEMUX_STATE_DATA;
436 GST_OBJECT_UNLOCK (demux);
438 gst_event_unref (event);
444 if (demux->state == GST_ASF_DEMUX_STATE_HEADER) {
445 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
446 (_("This stream contains no data.")),
447 ("got eos and didn't receive a complete header object"));
450 flow = gst_asf_demux_push_complete_payloads (demux, TRUE);
451 if (!demux->activated_streams) {
452 /* If we still haven't got activated streams, the file is most likely corrupt */
453 GST_ELEMENT_ERROR (demux, STREAM, WRONG_TYPE,
454 (_("This stream contains no data.")),
455 ("got eos and didn't receive a complete header object"));
458 if (flow < GST_FLOW_EOS || flow == GST_FLOW_NOT_LINKED) {
459 GST_ELEMENT_FLOW_ERROR (demux, flow);
463 GST_OBJECT_LOCK (demux);
464 gst_adapter_clear (demux->adapter);
465 GST_OBJECT_UNLOCK (demux);
466 gst_asf_demux_send_event_unlocked (demux, event);
470 case GST_EVENT_FLUSH_STOP:
471 GST_OBJECT_LOCK (demux);
472 gst_asf_demux_reset_stream_state_after_discont (demux);
473 GST_OBJECT_UNLOCK (demux);
474 gst_asf_demux_send_event_unlocked (demux, event);
475 /* upon activation, latency is no longer introduced, e.g. after seek */
476 if (demux->activated_streams)
481 ret = gst_pad_event_default (pad, parent, event);
489 gst_asf_demux_seek_index_lookup (GstASFDemux * demux, guint * packet,
490 GstClockTime seek_time, GstClockTime * p_idx_time, guint * speed,
491 gboolean next, gboolean * eos)
493 GstClockTime idx_time;
499 if (G_UNLIKELY (demux->sidx_num_entries == 0 || demux->sidx_interval == 0))
502 idx = (guint) ((seek_time + demux->preroll) / demux->sidx_interval);
505 /* if we want the next keyframe, we have to go forward till we find
506 a different packet number */
508 if (idx >= demux->sidx_num_entries - 1) {
509 /* If we get here, we're asking for next keyframe after the last one. There isn't one. */
514 for (idx2 = idx + 1; idx2 < demux->sidx_num_entries; ++idx2) {
515 if (demux->sidx_entries[idx].packet != demux->sidx_entries[idx2].packet) {
522 if (G_UNLIKELY (idx >= demux->sidx_num_entries)) {
528 *packet = demux->sidx_entries[idx].packet;
530 *speed = demux->sidx_entries[idx].count;
532 /* so we get closer to the actual time of the packet ... actually, let's not
533 * do this, since we throw away superfluous payloads before the seek position
534 * anyway; this way, our key unit seek 'snap resolution' is a bit better
535 * (ie. same as index resolution) */
537 while (idx > 0 && demux->sidx_entries[idx-1] == demux->sidx_entries[idx])
541 idx_time = demux->sidx_interval * idx;
542 if (G_LIKELY (idx_time >= demux->preroll))
543 idx_time -= demux->preroll;
545 GST_DEBUG_OBJECT (demux, "%" GST_TIME_FORMAT " => packet %u at %"
546 GST_TIME_FORMAT, GST_TIME_ARGS (seek_time), *packet,
547 GST_TIME_ARGS (idx_time));
549 if (G_LIKELY (p_idx_time))
550 *p_idx_time = idx_time;
556 gst_asf_demux_reset_stream_state_after_discont (GstASFDemux * demux)
560 gst_adapter_clear (demux->adapter);
562 GST_DEBUG_OBJECT (demux, "reset stream state");
564 gst_flow_combiner_reset (demux->flowcombiner);
565 for (n = 0; n < demux->num_streams; n++) {
566 demux->stream[n].discont = TRUE;
567 demux->stream[n].first_buffer = TRUE;
569 while (demux->stream[n].payloads->len > 0) {
573 last = demux->stream[n].payloads->len - 1;
574 payload = &g_array_index (demux->stream[n].payloads, AsfPayload, last);
575 gst_buffer_replace (&payload->buf, NULL);
576 g_array_remove_index (demux->stream[n].payloads, last);
582 gst_asf_demux_mark_discont (GstASFDemux * demux)
586 GST_DEBUG_OBJECT (demux, "Mark stream discont");
588 for (n = 0; n < demux->num_streams; n++)
589 demux->stream[n].discont = TRUE;
592 /* do a seek in push based mode */
594 gst_asf_demux_handle_seek_push (GstASFDemux * demux, GstEvent * event)
599 GstSeekType cur_type, stop_type;
603 GstEvent *byte_event;
605 gst_event_parse_seek (event, &rate, &format, &flags, &cur_type, &cur,
608 stop_type = GST_SEEK_TYPE_NONE;
611 GST_DEBUG_OBJECT (demux, "seeking to %" GST_TIME_FORMAT, GST_TIME_ARGS (cur));
613 /* determine packet, by index or by estimation */
614 if (!gst_asf_demux_seek_index_lookup (demux, &packet, cur, NULL, NULL, FALSE,
617 (guint) gst_util_uint64_scale (demux->num_packets, cur,
621 if (packet > demux->num_packets) {
622 GST_DEBUG_OBJECT (demux, "could not determine packet to seek to, "
627 GST_DEBUG_OBJECT (demux, "seeking to packet %d", packet);
629 cur = demux->data_offset + ((guint64) packet * demux->packet_size);
631 GST_DEBUG_OBJECT (demux, "Pushing BYTE seek rate %g, "
632 "start %" G_GINT64_FORMAT ", stop %" G_GINT64_FORMAT, rate, cur, stop);
633 /* BYTE seek event */
634 byte_event = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags, cur_type,
635 cur, stop_type, stop);
636 gst_event_set_seqnum (byte_event, gst_event_get_seqnum (event));
637 res = gst_pad_push_event (demux->sinkpad, byte_event);
643 gst_asf_demux_handle_seek_event (GstASFDemux * demux, GstEvent * event)
645 GstClockTime idx_time;
648 GstSeekType cur_type, stop_type;
650 gboolean only_need_update;
651 gboolean after, before, next;
656 guint packet, speed_count = 1;
662 gst_event_parse_seek (event, &rate, &format, &flags, &cur_type, &cur,
665 if (G_UNLIKELY (format != GST_FORMAT_TIME)) {
666 GST_LOG_OBJECT (demux, "seeking is only supported in TIME format");
670 /* upstream might handle TIME seek, e.g. mms or rtsp, or not, e.g. http,
671 * so first try to let it handle the seek event. */
672 if (gst_pad_push_event (demux->sinkpad, gst_event_ref (event)))
675 if (G_UNLIKELY (demux->seekable == FALSE || demux->packet_size == 0 ||
676 demux->num_packets == 0 || demux->play_time == 0)) {
677 GST_LOG_OBJECT (demux, "stream is not seekable");
681 if (G_UNLIKELY (!demux->activated_streams)) {
682 GST_LOG_OBJECT (demux, "streams not yet activated, ignoring seek");
686 if (G_UNLIKELY (rate <= 0.0)) {
687 GST_LOG_OBJECT (demux, "backward playback");
688 demux->seek_to_cur_pos = TRUE;
689 for (i = 0; i < demux->num_streams; i++) {
690 demux->stream[i].reverse_kf_ready = FALSE;
694 seqnum = gst_event_get_seqnum (event);
695 flush = ((flags & GST_SEEK_FLAG_FLUSH) == GST_SEEK_FLAG_FLUSH);
697 ((flags & GST_SEEK_FLAG_ACCURATE) == GST_SEEK_FLAG_ACCURATE);
698 demux->keyunit_sync =
699 ((flags & GST_SEEK_FLAG_KEY_UNIT) == GST_SEEK_FLAG_KEY_UNIT);
700 after = ((flags & GST_SEEK_FLAG_SNAP_AFTER) == GST_SEEK_FLAG_SNAP_AFTER);
701 before = ((flags & GST_SEEK_FLAG_SNAP_BEFORE) == GST_SEEK_FLAG_SNAP_BEFORE);
702 next = after && !before;
704 if (G_UNLIKELY (demux->streaming)) {
705 /* support it safely needs more segment handling, e.g. closing etc */
707 GST_LOG_OBJECT (demux, "streaming; non-flushing seek not supported");
710 /* we can (re)construct the start later on, but not the end */
711 if (stop_type != GST_SEEK_TYPE_NONE &&
712 (stop_type != GST_SEEK_TYPE_SET || GST_CLOCK_TIME_IS_VALID (stop))) {
713 GST_LOG_OBJECT (demux, "streaming; end position must be NONE");
716 return gst_asf_demux_handle_seek_push (demux, event);
719 /* unlock the streaming thread */
720 if (G_LIKELY (flush)) {
721 fevent = gst_event_new_flush_start ();
723 gst_event_set_seqnum (fevent, seqnum);
724 gst_pad_push_event (demux->sinkpad, gst_event_ref (fevent));
725 gst_asf_demux_send_event_unlocked (demux, fevent);
727 gst_pad_pause_task (demux->sinkpad);
730 /* grab the stream lock so that streaming cannot continue, for
731 * non flushing seeks when the element is in PAUSED this could block
733 GST_PAD_STREAM_LOCK (demux->sinkpad);
735 /* we now can stop flushing, since we have the stream lock now */
736 fevent = gst_event_new_flush_stop (TRUE);
737 gst_event_set_seqnum (fevent, seqnum);
738 gst_pad_push_event (demux->sinkpad, gst_event_ref (fevent));
740 if (G_LIKELY (flush))
741 gst_asf_demux_send_event_unlocked (demux, fevent);
743 gst_event_unref (fevent);
745 /* operating on copy of segment until we know the seek worked */
746 segment = demux->segment;
748 if (G_UNLIKELY (demux->segment_running && !flush)) {
749 GstSegment newsegment;
752 /* create the segment event to close the current segment */
753 gst_segment_copy_into (&segment, &newsegment);
754 newseg = gst_event_new_segment (&newsegment);
755 gst_event_set_seqnum (newseg, seqnum);
757 gst_asf_demux_send_event_unlocked (demux, newseg);
760 gst_segment_do_seek (&segment, rate, format, flags, cur_type,
761 cur, stop_type, stop, &only_need_update);
763 GST_DEBUG_OBJECT (demux, "seeking to time %" GST_TIME_FORMAT ", segment: "
764 "%" GST_SEGMENT_FORMAT, GST_TIME_ARGS (segment.start), &segment);
766 if (cur_type != GST_SEEK_TYPE_SET)
767 seek_time = segment.start;
771 /* FIXME: should check the KEY_UNIT flag; need to adjust position to
772 * real start of data and segment_start to indexed time for key unit seek*/
773 if (G_UNLIKELY (!gst_asf_demux_seek_index_lookup (demux, &packet, seek_time,
774 &idx_time, &speed_count, next, &eos))) {
778 demux->packet = demux->num_packets;
782 /* First try to query our source to see if it can convert for us. This is
783 the case when our source is an mms stream, notice that in this case
784 gstmms will do a time based seek to get the byte offset, this is not a
785 problem as the seek to this offset needs to happen anway. */
786 if (gst_pad_peer_query_convert (demux->sinkpad, GST_FORMAT_TIME, seek_time,
787 GST_FORMAT_BYTES, &offset)) {
788 packet = (offset - demux->data_offset) / demux->packet_size;
789 GST_LOG_OBJECT (demux, "convert %" GST_TIME_FORMAT
790 " to bytes query result: %" G_GINT64_FORMAT ", data_ofset: %"
791 G_GINT64_FORMAT ", packet_size: %u," " resulting packet: %u\n",
792 GST_TIME_ARGS (seek_time), offset, demux->data_offset,
793 demux->packet_size, packet);
795 /* FIXME: For streams containing video, seek to an earlier position in
796 * the hope of hitting a keyframe and let the sinks throw away the stuff
797 * before the segment start. For audio-only this is unnecessary as every
799 if (flush && (demux->accurate || (demux->keyunit_sync && !next))
800 && demux->num_video_streams > 0) {
801 seek_time -= 5 * GST_SECOND;
806 packet = (guint) gst_util_uint64_scale (demux->num_packets,
807 seek_time, demux->play_time);
809 if (packet > demux->num_packets)
810 packet = demux->num_packets;
813 if (G_LIKELY (demux->keyunit_sync && !demux->accurate)) {
814 GST_DEBUG_OBJECT (demux, "key unit seek, adjust seek_time = %"
815 GST_TIME_FORMAT " to index_time = %" GST_TIME_FORMAT,
816 GST_TIME_ARGS (seek_time), GST_TIME_ARGS (idx_time));
817 segment.start = idx_time;
818 segment.position = idx_time;
819 segment.time = idx_time;
823 GST_DEBUG_OBJECT (demux, "seeking to packet %u (%d)", packet, speed_count);
825 GST_OBJECT_LOCK (demux);
826 demux->segment = segment;
827 if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment)) {
828 demux->packet = (gint64) gst_util_uint64_scale (demux->num_packets,
829 stop, demux->play_time);
831 demux->packet = packet;
834 demux->need_newsegment = TRUE;
835 demux->segment_seqnum = seqnum;
836 demux->speed_packets =
837 GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment) ? 1 : speed_count;
838 gst_asf_demux_reset_stream_state_after_discont (demux);
839 GST_OBJECT_UNLOCK (demux);
842 /* restart our task since it might have been stopped when we did the flush */
843 gst_pad_start_task (demux->sinkpad, (GstTaskFunction) gst_asf_demux_loop,
846 /* streaming can continue now */
847 GST_PAD_STREAM_UNLOCK (demux->sinkpad);
853 gst_asf_demux_handle_src_event (GstPad * pad, GstObject * parent,
859 demux = GST_ASF_DEMUX (parent);
861 switch (GST_EVENT_TYPE (event)) {
863 GST_LOG_OBJECT (pad, "seek event");
864 ret = gst_asf_demux_handle_seek_event (demux, event);
865 gst_event_unref (event);
868 case GST_EVENT_NAVIGATION:
869 /* just drop these two silently */
870 gst_event_unref (event);
874 GST_LOG_OBJECT (pad, "%s event", GST_EVENT_TYPE_NAME (event));
875 ret = gst_pad_event_default (pad, parent, event);
882 static inline guint32
883 gst_asf_demux_identify_guid (const ASFGuidHash * guids, ASFGuid * guid)
887 ret = gst_asf_identify_guid (guids, guid);
889 GST_LOG ("%s 0x%08x-0x%08x-0x%08x-0x%08x",
890 gst_asf_get_guid_nick (guids, ret),
891 guid->v1, guid->v2, guid->v3, guid->v4);
903 /* expect is true when the user is expeting an object,
904 * when false, it will give no warnings if the object
908 asf_demux_peek_object (GstASFDemux * demux, const guint8 * data,
909 guint data_len, AsfObject * object, gboolean expect)
913 if (data_len < ASF_OBJECT_HEADER_SIZE)
916 guid.v1 = GST_READ_UINT32_LE (data + 0);
917 guid.v2 = GST_READ_UINT32_LE (data + 4);
918 guid.v3 = GST_READ_UINT32_LE (data + 8);
919 guid.v4 = GST_READ_UINT32_LE (data + 12);
921 object->size = GST_READ_UINT64_LE (data + 16);
923 /* FIXME: make asf_demux_identify_object_guid() */
924 object->id = gst_asf_demux_identify_guid (asf_object_guids, &guid);
925 if (object->id == ASF_OBJ_UNDEFINED && expect) {
926 GST_WARNING_OBJECT (demux, "Unknown object %08x-%08x-%08x-%08x",
927 guid.v1, guid.v2, guid.v3, guid.v4);
934 gst_asf_demux_release_old_pads (GstASFDemux * demux)
936 GST_DEBUG_OBJECT (demux, "Releasing old pads");
938 while (demux->old_num_streams > 0) {
939 gst_pad_push_event (demux->old_stream[demux->old_num_streams - 1].pad,
940 gst_event_new_eos ());
941 gst_asf_demux_free_stream (demux,
942 &demux->old_stream[demux->old_num_streams - 1]);
943 --demux->old_num_streams;
945 memset (demux->old_stream, 0, sizeof (demux->old_stream));
946 demux->old_num_streams = 0;
950 gst_asf_demux_chain_headers (GstASFDemux * demux)
954 guint8 *header_data, *data = NULL;
955 const guint8 *cdata = NULL;
958 cdata = (guint8 *) gst_adapter_map (demux->adapter, ASF_OBJECT_HEADER_SIZE);
962 asf_demux_peek_object (demux, cdata, ASF_OBJECT_HEADER_SIZE, &obj, TRUE);
963 if (obj.id != ASF_OBJ_HEADER)
966 GST_LOG_OBJECT (demux, "header size = %u", (guint) obj.size);
968 /* + 50 for non-packet data at beginning of ASF_OBJ_DATA */
969 if (gst_adapter_available (demux->adapter) < obj.size + 50)
972 data = gst_adapter_take (demux->adapter, obj.size + 50);
975 header_size = obj.size;
976 flow = gst_asf_demux_process_object (demux, &header_data, &header_size);
977 if (flow != GST_FLOW_OK)
980 /* calculate where the packet data starts */
981 demux->data_offset = obj.size + 50;
983 /* now parse the beginning of the ASF_OBJ_DATA object */
984 if (!gst_asf_demux_parse_data_object_start (demux, data + obj.size))
987 if (demux->num_streams == 0)
996 GST_LOG_OBJECT (demux, "not enough data in adapter yet");
1003 GST_ELEMENT_ERROR (demux, STREAM, WRONG_TYPE, (NULL),
1004 ("This doesn't seem to be an ASF file"));
1006 return GST_FLOW_ERROR;
1011 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
1012 ("header parsing failed, or no streams found, flow = %s",
1013 gst_flow_get_name (flow)));
1015 return GST_FLOW_ERROR;
1020 gst_asf_demux_pull_data (GstASFDemux * demux, guint64 offset, guint size,
1021 GstBuffer ** p_buf, GstFlowReturn * p_flow)
1026 GST_LOG_OBJECT (demux, "pulling buffer at %" G_GUINT64_FORMAT "+%u",
1029 flow = gst_pad_pull_range (demux->sinkpad, offset, size, p_buf);
1031 if (G_LIKELY (p_flow))
1034 if (G_UNLIKELY (flow != GST_FLOW_OK)) {
1035 GST_DEBUG_OBJECT (demux, "flow %s pulling buffer at %" G_GUINT64_FORMAT
1036 "+%u", gst_flow_get_name (flow), offset, size);
1041 g_assert (*p_buf != NULL);
1043 buffer_size = gst_buffer_get_size (*p_buf);
1044 if (G_UNLIKELY (buffer_size < size)) {
1045 GST_DEBUG_OBJECT (demux, "short read pulling buffer at %" G_GUINT64_FORMAT
1046 "+%u (got only %" G_GSIZE_FORMAT " bytes)", offset, size, buffer_size);
1047 gst_buffer_unref (*p_buf);
1048 if (G_LIKELY (p_flow))
1049 *p_flow = GST_FLOW_EOS;
1058 gst_asf_demux_pull_indices (GstASFDemux * demux)
1060 GstBuffer *buf = NULL;
1064 offset = demux->index_offset;
1066 if (G_UNLIKELY (offset == 0)) {
1067 GST_DEBUG_OBJECT (demux, "can't read indices, don't know index offset");
1071 while (gst_asf_demux_pull_data (demux, offset, 16 + 8, &buf, NULL)) {
1077 gst_buffer_map (buf, &map, GST_MAP_READ);
1078 g_assert (map.size >= 16 + 8);
1079 asf_demux_peek_object (demux, map.data, 16 + 8, &obj, TRUE);
1080 gst_buffer_unmap (buf, &map);
1081 gst_buffer_replace (&buf, NULL);
1083 /* check for sanity */
1084 if (G_UNLIKELY (obj.size > (5 * 1024 * 1024))) {
1085 GST_DEBUG_OBJECT (demux, "implausible index object size, bailing out");
1089 if (G_UNLIKELY (!gst_asf_demux_pull_data (demux, offset, obj.size, &buf,
1093 GST_LOG_OBJECT (demux, "index object at offset 0x%" G_GINT64_MODIFIER "X"
1094 ", size %u", offset, (guint) obj.size);
1096 offset += obj.size; /* increase before _process_object changes it */
1098 gst_buffer_map (buf, &map, GST_MAP_READ);
1099 g_assert (map.size >= obj.size);
1100 bufdata = (guint8 *) map.data;
1101 flow = gst_asf_demux_process_object (demux, &bufdata, &obj.size);
1102 gst_buffer_unmap (buf, &map);
1103 gst_buffer_replace (&buf, NULL);
1105 if (G_UNLIKELY (flow != GST_FLOW_OK))
1110 GST_DEBUG_OBJECT (demux, "read %u index objects", num_read);
1114 gst_asf_demux_parse_data_object_start (GstASFDemux * demux, guint8 * data)
1118 asf_demux_peek_object (demux, data, 50, &obj, TRUE);
1119 if (obj.id != ASF_OBJ_DATA) {
1120 GST_WARNING_OBJECT (demux, "headers not followed by a DATA object");
1124 demux->state = GST_ASF_DEMUX_STATE_DATA;
1126 if (!demux->broadcast && obj.size > 50) {
1127 demux->data_size = obj.size - 50;
1128 /* CHECKME: for at least one file this is off by +158 bytes?! */
1129 demux->index_offset = demux->data_offset + demux->data_size;
1131 demux->data_size = 0;
1132 demux->index_offset = 0;
1137 if (!demux->broadcast) {
1138 /* skip object header (24 bytes) and file GUID (16 bytes) */
1139 demux->num_packets = GST_READ_UINT64_LE (data + (16 + 8) + 16);
1141 demux->num_packets = 0;
1144 if (demux->num_packets == 0)
1145 demux->seekable = FALSE;
1147 /* fallback in the unlikely case that headers are inconsistent, can't hurt */
1148 if (demux->data_size == 0 && demux->num_packets > 0) {
1149 demux->data_size = demux->num_packets * demux->packet_size;
1150 demux->index_offset = demux->data_offset + demux->data_size;
1153 /* process pending stream objects and create pads for those */
1154 gst_asf_demux_process_queued_extended_stream_objects (demux);
1156 GST_INFO_OBJECT (demux, "Stream has %" G_GUINT64_FORMAT " packets, "
1157 "data_offset=%" G_GINT64_FORMAT ", data_size=%" G_GINT64_FORMAT
1158 ", index_offset=%" G_GUINT64_FORMAT, demux->num_packets,
1159 demux->data_offset, demux->data_size, demux->index_offset);
1165 gst_asf_demux_pull_headers (GstASFDemux * demux, GstFlowReturn * pflow)
1167 GstFlowReturn flow = GST_FLOW_OK;
1169 GstBuffer *buf = NULL;
1174 GST_LOG_OBJECT (demux, "reading headers");
1176 /* pull HEADER object header, so we know its size */
1177 if (!gst_asf_demux_pull_data (demux, demux->base_offset, 16 + 8, &buf, &flow))
1180 gst_buffer_map (buf, &map, GST_MAP_READ);
1181 g_assert (map.size >= 16 + 8);
1182 asf_demux_peek_object (demux, map.data, 16 + 8, &obj, TRUE);
1183 gst_buffer_unmap (buf, &map);
1184 gst_buffer_replace (&buf, NULL);
1186 if (obj.id != ASF_OBJ_HEADER)
1189 GST_LOG_OBJECT (demux, "header size = %u", (guint) obj.size);
1191 /* pull HEADER object */
1192 if (!gst_asf_demux_pull_data (demux, demux->base_offset, obj.size, &buf,
1196 size = obj.size; /* don't want obj.size changed */
1197 gst_buffer_map (buf, &map, GST_MAP_READ);
1198 g_assert (map.size >= size);
1199 bufdata = (guint8 *) map.data;
1200 flow = gst_asf_demux_process_object (demux, &bufdata, &size);
1201 gst_buffer_unmap (buf, &map);
1202 gst_buffer_replace (&buf, NULL);
1204 if (flow != GST_FLOW_OK) {
1205 GST_WARNING_OBJECT (demux, "process_object: %s", gst_flow_get_name (flow));
1209 /* calculate where the packet data starts */
1210 demux->data_offset = demux->base_offset + obj.size + 50;
1212 /* now pull beginning of DATA object before packet data */
1213 if (!gst_asf_demux_pull_data (demux, demux->base_offset + obj.size, 50, &buf,
1217 gst_buffer_map (buf, &map, GST_MAP_READ);
1218 g_assert (map.size >= size);
1219 bufdata = (guint8 *) map.data;
1220 if (!gst_asf_demux_parse_data_object_start (demux, bufdata))
1223 if (demux->num_streams == 0)
1226 gst_buffer_unmap (buf, &map);
1227 gst_buffer_replace (&buf, NULL);
1235 gst_buffer_unmap (buf, &map);
1236 gst_buffer_replace (&buf, NULL);
1238 GST_ELEMENT_ERROR (demux, STREAM, WRONG_TYPE, (NULL),
1239 ("This doesn't seem to be an ASF file"));
1240 *pflow = GST_FLOW_ERROR;
1245 flow = GST_FLOW_ERROR;
1246 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
1247 ("header parsing failed, or no streams found, flow = %s",
1248 gst_flow_get_name (flow)));
1253 gst_buffer_unmap (buf, &map);
1254 gst_buffer_replace (&buf, NULL);
1255 if (flow == ASF_FLOW_NEED_MORE_DATA)
1256 flow = GST_FLOW_ERROR;
1263 all_streams_prerolled (GstASFDemux * demux)
1265 GstClockTime preroll_time;
1266 guint i, num_no_data = 0;
1268 /* Allow at least 500ms of preroll_time */
1269 preroll_time = MAX (demux->preroll, 500 * GST_MSECOND);
1271 /* returns TRUE as long as there isn't a stream which (a) has data queued
1272 * and (b) the timestamp of last piece of data queued is < demux->preroll
1273 * AND there is at least one other stream with data queued */
1274 for (i = 0; i < demux->num_streams; ++i) {
1275 AsfPayload *last_payload = NULL;
1279 stream = &demux->stream[i];
1280 if (G_UNLIKELY (stream->payloads->len == 0)) {
1282 GST_LOG_OBJECT (stream->pad, "no data queued");
1286 /* find last payload with timestamp */
1287 for (last_idx = stream->payloads->len - 1;
1288 last_idx >= 0 && (last_payload == NULL
1289 || !GST_CLOCK_TIME_IS_VALID (last_payload->ts)); --last_idx) {
1290 last_payload = &g_array_index (stream->payloads, AsfPayload, last_idx);
1293 GST_LOG_OBJECT (stream->pad, "checking if %" GST_TIME_FORMAT " > %"
1294 GST_TIME_FORMAT, GST_TIME_ARGS (last_payload->ts),
1295 GST_TIME_ARGS (preroll_time));
1296 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (last_payload->ts)
1297 || last_payload->ts <= preroll_time)) {
1298 GST_LOG_OBJECT (stream->pad, "not beyond preroll point yet");
1303 if (G_UNLIKELY (num_no_data > 0))
1311 gst_asf_demux_have_mutually_exclusive_active_stream (GstASFDemux * demux,
1316 for (l = demux->mut_ex_streams; l != NULL; l = l->next) {
1319 /* check for each mutual exclusion group whether it affects this stream */
1320 for (mes = (guint8 *) l->data; mes != NULL && *mes != 0xff; ++mes) {
1321 if (*mes == stream->id) {
1322 /* we are in this group; let's check if we've already activated streams
1323 * that are in the same group (and hence mutually exclusive to this
1325 for (mes = (guint8 *) l->data; mes != NULL && *mes != 0xff; ++mes) {
1328 for (i = 0; i < demux->num_streams; ++i) {
1329 if (demux->stream[i].id == *mes && demux->stream[i].active) {
1330 GST_LOG_OBJECT (demux, "stream with ID %d is mutually exclusive "
1331 "to already active stream with ID %d", stream->id,
1332 demux->stream[i].id);
1337 /* we can only be in this group once, let's break out and move on to
1338 * the next mutual exclusion group */
1349 gst_asf_demux_check_segment_ts (GstASFDemux * demux, GstClockTime payload_ts)
1351 /* remember the first queued timestamp for the segment */
1352 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (demux->segment_ts) &&
1353 GST_CLOCK_TIME_IS_VALID (demux->first_ts))) {
1354 GST_DEBUG_OBJECT (demux, "segment ts: %" GST_TIME_FORMAT,
1355 GST_TIME_ARGS (demux->first_ts));
1356 demux->segment_ts = payload_ts;
1357 /* always note, but only determines segment when streaming */
1358 if (demux->streaming)
1359 gst_segment_do_seek (&demux->segment, demux->in_segment.rate,
1360 GST_FORMAT_TIME, (GstSeekFlags) demux->segment.flags,
1361 GST_SEEK_TYPE_SET, demux->segment_ts, GST_SEEK_TYPE_NONE, 0, NULL);
1366 gst_asf_demux_check_first_ts (GstASFDemux * demux, gboolean force)
1368 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (demux->first_ts))) {
1369 GstClockTime first_ts = GST_CLOCK_TIME_NONE;
1372 /* go trhough each stream, find smallest timestamp */
1373 for (i = 0; i < demux->num_streams; ++i) {
1376 GstClockTime stream_min_ts = GST_CLOCK_TIME_NONE;
1377 GstClockTime stream_min_ts2 = GST_CLOCK_TIME_NONE; /* second smallest timestamp */
1378 stream = &demux->stream[i];
1380 for (j = 0; j < stream->payloads->len; ++j) {
1381 AsfPayload *payload = &g_array_index (stream->payloads, AsfPayload, j);
1382 if (GST_CLOCK_TIME_IS_VALID (payload->ts) &&
1383 (!GST_CLOCK_TIME_IS_VALID (stream_min_ts)
1384 || stream_min_ts > payload->ts)) {
1385 stream_min_ts = payload->ts;
1387 if (GST_CLOCK_TIME_IS_VALID (payload->ts) &&
1388 payload->ts > stream_min_ts &&
1389 (!GST_CLOCK_TIME_IS_VALID (stream_min_ts2)
1390 || stream_min_ts2 > payload->ts)) {
1391 stream_min_ts2 = payload->ts;
1395 /* there are some DVR ms files where first packet has TS of 0 (instead of -1) while subsequent packets have
1396 regular (singificantly larger) timestamps. If we don't deal with it, we may end up with huge gap in timestamps
1397 which makes playback stuck. The 0 timestamp may also be valid though, if the second packet timestamp continues
1398 from it. I havent found a better way to distinguish between these two, except to set an arbitrary boundary
1399 and disregard the first 0 timestamp if the second timestamp is bigger than the boundary) */
1401 if (stream_min_ts == 0 && stream_min_ts2 == GST_CLOCK_TIME_NONE && !force) /* still waiting for the second timestamp */
1404 if (stream_min_ts == 0 && stream_min_ts2 > GST_SECOND) /* first timestamp is 0 and second is significantly larger, disregard the 0 */
1405 stream_min_ts = stream_min_ts2;
1407 /* if we don't have timestamp for this stream, wait for more data */
1408 if (!GST_CLOCK_TIME_IS_VALID (stream_min_ts) && !force)
1411 if (GST_CLOCK_TIME_IS_VALID (stream_min_ts) &&
1412 (!GST_CLOCK_TIME_IS_VALID (first_ts) || first_ts > stream_min_ts))
1413 first_ts = stream_min_ts;
1416 if (!GST_CLOCK_TIME_IS_VALID (first_ts)) /* can happen with force = TRUE */
1419 demux->first_ts = first_ts;
1421 /* update packets queued before we knew first timestamp */
1422 for (i = 0; i < demux->num_streams; ++i) {
1425 stream = &demux->stream[i];
1427 for (j = 0; j < stream->payloads->len; ++j) {
1428 AsfPayload *payload = &g_array_index (stream->payloads, AsfPayload, j);
1429 if (GST_CLOCK_TIME_IS_VALID (payload->ts)) {
1430 if (payload->ts > first_ts)
1431 payload->ts -= first_ts;
1439 gst_asf_demux_check_segment_ts (demux, 0);
1445 gst_asf_demux_update_caps_from_payload (GstASFDemux * demux, AsfStream * stream)
1447 /* try to determine whether the stream is AC-3 or MPEG; In dvr-ms the codecTag is unreliable
1448 and often set wrong, inspecting the data is the only way that seem to be working */
1449 GstTypeFindProbability prob = GST_TYPE_FIND_NONE;
1450 GstCaps *caps = NULL;
1452 GstAdapter *adapter = gst_adapter_new ();
1454 for (i = 0; i < stream->payloads->len && prob < GST_TYPE_FIND_LIKELY; ++i) {
1456 AsfPayload *payload;
1459 payload = &g_array_index (stream->payloads, AsfPayload, i);
1460 gst_adapter_push (adapter, gst_buffer_ref (payload->buf));
1461 len = gst_adapter_available (adapter);
1462 data = gst_adapter_map (adapter, len);
1466 #define MIN_LENGTH 128
1468 /* look for the sync points */
1470 if (len < MIN_LENGTH || /* give typefind something to work on */
1471 (data[0] == 0x0b && data[1] == 0x77) || /* AC-3 sync point */
1472 (data[0] == 0xFF && ((data[1] & 0xF0) >> 4) == 0xF)) /* MPEG sync point */
1478 gst_caps_take (&caps, gst_type_find_helper_for_data (GST_OBJECT (demux),
1481 if (prob < GST_TYPE_FIND_LIKELY) {
1484 if (len > MIN_LENGTH)
1485 /* this wasn't it, look for another sync point */
1489 gst_adapter_unmap (adapter);
1492 gst_object_unref (adapter);
1495 gst_caps_take (&stream->caps, caps);
1503 gst_asf_demux_check_activate_streams (GstASFDemux * demux, gboolean force)
1505 guint i, actual_streams = 0;
1507 if (demux->activated_streams)
1510 if (G_UNLIKELY (!gst_asf_demux_check_first_ts (demux, force)))
1513 if (!all_streams_prerolled (demux) && !force) {
1514 GST_DEBUG_OBJECT (demux, "not all streams with data beyond preroll yet");
1518 for (i = 0; i < demux->num_streams; ++i) {
1519 AsfStream *stream = &demux->stream[i];
1521 if (stream->payloads->len > 0) {
1523 if (stream->inspect_payload && /* dvr-ms required payload inspection */
1524 !stream->active && /* do not inspect active streams (caps were already set) */
1525 !gst_asf_demux_update_caps_from_payload (demux, stream) && /* failed to determine caps */
1526 stream->payloads->len < 20) { /* if we couldn't determine the caps from 20 packets then just give up and use whatever was in codecTag */
1527 /* try to gather some more data */
1530 /* we don't check mutual exclusion stuff here; either we have data for
1531 * a stream, then we active it, or we don't, then we'll ignore it */
1532 GST_LOG_OBJECT (stream->pad, "is prerolled - activate!");
1533 gst_asf_demux_activate_stream (demux, stream);
1534 actual_streams += 1;
1536 GST_LOG_OBJECT (stream->pad, "no data, ignoring stream");
1540 if (actual_streams == 0) {
1541 /* We don't have any streams activated ! */
1542 GST_ERROR_OBJECT (demux, "No streams activated!");
1546 gst_asf_demux_release_old_pads (demux);
1548 demux->activated_streams = TRUE;
1549 GST_LOG_OBJECT (demux, "signalling no more pads");
1550 gst_element_no_more_pads (GST_ELEMENT (demux));
1554 /* returns the stream that has a complete payload with the lowest timestamp
1555 * queued, or NULL (we push things by timestamp because during the internal
1556 * prerolling we might accumulate more data then the external queues can take,
1557 * so we'd lock up if we pushed all accumulated data for stream N in one go) */
1559 gst_asf_demux_find_stream_with_complete_payload (GstASFDemux * demux)
1561 AsfPayload *best_payload = NULL;
1562 AsfStream *best_stream = NULL;
1565 for (i = 0; i < demux->num_streams; ++i) {
1569 stream = &demux->stream[i];
1571 /* Don't push any data until we have at least one payload that falls within
1572 * the current segment. This way we can remove out-of-segment payloads that
1573 * don't need to be decoded after a seek, sending only data from the
1574 * keyframe directly before our segment start */
1575 if (stream->payloads->len > 0) {
1576 AsfPayload *payload = NULL;
1579 if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment)) {
1580 /* Reverse playback */
1582 if (stream->is_video) {
1583 /* We have to push payloads from KF to the first frame we accumulated (reverse order) */
1584 if (stream->reverse_kf_ready) {
1586 &g_array_index (stream->payloads, AsfPayload, stream->kf_pos);
1587 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (payload->ts))) {
1588 /* TODO : remove payload from the list? */
1595 /* find first complete payload with timestamp */
1596 for (j = stream->payloads->len - 1;
1597 j >= 0 && (payload == NULL
1598 || !GST_CLOCK_TIME_IS_VALID (payload->ts)); --j) {
1599 payload = &g_array_index (stream->payloads, AsfPayload, j);
1602 /* If there's a complete payload queued for this stream */
1603 if (!gst_asf_payload_is_complete (payload))
1609 /* find last payload with timestamp */
1610 for (last_idx = stream->payloads->len - 1;
1611 last_idx >= 0 && (payload == NULL
1612 || !GST_CLOCK_TIME_IS_VALID (payload->ts)); --last_idx) {
1613 payload = &g_array_index (stream->payloads, AsfPayload, last_idx);
1616 /* if this is first payload after seek we might need to update the segment */
1617 if (GST_CLOCK_TIME_IS_VALID (payload->ts))
1618 gst_asf_demux_check_segment_ts (demux, payload->ts);
1620 if (G_UNLIKELY (GST_CLOCK_TIME_IS_VALID (payload->ts) &&
1621 (payload->ts < demux->segment.start))) {
1622 if (G_UNLIKELY ((!demux->keyunit_sync) && (!demux->accurate)
1623 && payload->keyframe)) {
1624 GST_DEBUG_OBJECT (stream->pad,
1625 "Found keyframe, updating segment start to %" GST_TIME_FORMAT,
1626 GST_TIME_ARGS (payload->ts));
1627 demux->segment.start = payload->ts;
1628 demux->segment.time = payload->ts;
1630 GST_DEBUG_OBJECT (stream->pad, "Last queued payload has timestamp %"
1631 GST_TIME_FORMAT " which is before our segment start %"
1632 GST_TIME_FORMAT ", not pushing yet",
1633 GST_TIME_ARGS (payload->ts),
1634 GST_TIME_ARGS (demux->segment.start));
1639 /* find first complete payload with timestamp */
1641 j < stream->payloads->len && (payload == NULL
1642 || !GST_CLOCK_TIME_IS_VALID (payload->ts)); ++j) {
1643 payload = &g_array_index (stream->payloads, AsfPayload, j);
1646 /* Now see if there's a complete payload queued for this stream */
1647 if (!gst_asf_payload_is_complete (payload))
1651 /* ... and whether its timestamp is lower than the current best */
1652 if (best_stream == NULL || best_payload->ts > payload->ts) {
1653 best_stream = stream;
1654 best_payload = payload;
1662 static GstFlowReturn
1663 gst_asf_demux_push_complete_payloads (GstASFDemux * demux, gboolean force)
1666 GstFlowReturn ret = GST_FLOW_OK;
1668 if (G_UNLIKELY (!demux->activated_streams)) {
1669 if (!gst_asf_demux_check_activate_streams (demux, force))
1671 /* streams are now activated */
1674 while ((stream = gst_asf_demux_find_stream_with_complete_payload (demux))) {
1675 AsfPayload *payload;
1676 GstClockTime timestamp = GST_CLOCK_TIME_NONE;
1677 GstClockTime duration = GST_CLOCK_TIME_NONE;
1679 /* wait until we had a chance to "lock on" some payload's timestamp */
1680 if (G_UNLIKELY (demux->need_newsegment
1681 && !GST_CLOCK_TIME_IS_VALID (demux->segment_ts)))
1684 if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment) && stream->is_video
1685 && stream->payloads->len) {
1686 payload = &g_array_index (stream->payloads, AsfPayload, stream->kf_pos);
1688 payload = &g_array_index (stream->payloads, AsfPayload, 0);
1691 /* do we need to send a newsegment event */
1692 if ((G_UNLIKELY (demux->need_newsegment))) {
1693 GstEvent *segment_event;
1695 /* safe default if insufficient upstream info */
1696 if (!GST_CLOCK_TIME_IS_VALID (demux->in_gap))
1699 if (demux->segment.stop == GST_CLOCK_TIME_NONE &&
1700 demux->segment.duration > 0) {
1701 /* slight HACK; prevent clipping of last bit */
1702 demux->segment.stop = demux->segment.duration + demux->in_gap;
1705 /* FIXME : only if ACCURATE ! */
1706 if (G_LIKELY (!demux->keyunit_sync && !demux->accurate
1707 && (GST_CLOCK_TIME_IS_VALID (payload->ts)))
1708 && !GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment)) {
1709 GST_DEBUG ("Adjusting newsegment start to %" GST_TIME_FORMAT,
1710 GST_TIME_ARGS (payload->ts));
1711 demux->segment.start = payload->ts;
1712 demux->segment.time = payload->ts;
1715 GST_DEBUG_OBJECT (demux, "sending new-segment event %" GST_SEGMENT_FORMAT,
1718 /* note: we fix up all timestamps to start from 0, so this should be ok */
1719 segment_event = gst_event_new_segment (&demux->segment);
1720 if (demux->segment_seqnum)
1721 gst_event_set_seqnum (segment_event, demux->segment_seqnum);
1722 gst_asf_demux_send_event_unlocked (demux, segment_event);
1724 /* now post any global tags we may have found */
1725 if (demux->taglist == NULL) {
1726 demux->taglist = gst_tag_list_new_empty ();
1727 gst_tag_list_set_scope (demux->taglist, GST_TAG_SCOPE_GLOBAL);
1730 gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
1731 GST_TAG_CONTAINER_FORMAT, "ASF", NULL);
1733 GST_DEBUG_OBJECT (demux, "global tags: %" GST_PTR_FORMAT, demux->taglist);
1734 gst_asf_demux_send_event_unlocked (demux,
1735 gst_event_new_tag (demux->taglist));
1736 demux->taglist = NULL;
1738 demux->need_newsegment = FALSE;
1739 demux->segment_seqnum = 0;
1740 demux->segment_running = TRUE;
1743 /* Do we have tags pending for this stream? */
1744 if (G_UNLIKELY (stream->pending_tags)) {
1745 GST_LOG_OBJECT (stream->pad, "%" GST_PTR_FORMAT, stream->pending_tags);
1746 gst_pad_push_event (stream->pad,
1747 gst_event_new_tag (stream->pending_tags));
1748 stream->pending_tags = NULL;
1751 /* We have the whole packet now so we should push the packet to
1752 * the src pad now. First though we should check if we need to do
1754 if (G_UNLIKELY (stream->span > 1)) {
1755 gst_asf_demux_descramble_buffer (demux, stream, &payload->buf);
1758 payload->buf = gst_buffer_make_writable (payload->buf);
1760 if (G_LIKELY (!payload->keyframe)) {
1761 GST_BUFFER_FLAG_SET (payload->buf, GST_BUFFER_FLAG_DELTA_UNIT);
1764 if (G_UNLIKELY (stream->discont)) {
1765 GST_DEBUG_OBJECT (stream->pad, "marking DISCONT on stream");
1766 GST_BUFFER_FLAG_SET (payload->buf, GST_BUFFER_FLAG_DISCONT);
1767 stream->discont = FALSE;
1770 if (G_UNLIKELY (stream->is_video && payload->par_x && payload->par_y &&
1771 (payload->par_x != stream->par_x) &&
1772 (payload->par_y != stream->par_y))) {
1773 GST_DEBUG ("Updating PAR (%d/%d => %d/%d)",
1774 stream->par_x, stream->par_y, payload->par_x, payload->par_y);
1775 stream->par_x = payload->par_x;
1776 stream->par_y = payload->par_y;
1777 stream->caps = gst_caps_make_writable (stream->caps);
1778 gst_caps_set_simple (stream->caps, "pixel-aspect-ratio",
1779 GST_TYPE_FRACTION, stream->par_x, stream->par_y, NULL);
1780 gst_pad_set_caps (stream->pad, stream->caps);
1783 if (G_UNLIKELY (stream->interlaced != payload->interlaced)) {
1784 GST_DEBUG ("Updating interlaced status (%d => %d)", stream->interlaced,
1785 payload->interlaced);
1786 stream->interlaced = payload->interlaced;
1787 stream->caps = gst_caps_make_writable (stream->caps);
1788 gst_caps_set_simple (stream->caps, "interlace-mode", G_TYPE_BOOLEAN,
1789 (stream->interlaced ? "mixed" : "progressive"), NULL);
1790 gst_pad_set_caps (stream->pad, stream->caps);
1793 /* (sort of) interpolate timestamps using upstream "frame of reference",
1794 * typically useful for live src, but might (unavoidably) mess with
1795 * position reporting if a live src is playing not so live content
1796 * (e.g. rtspsrc taking some time to fall back to tcp) */
1797 timestamp = payload->ts;
1798 if (GST_CLOCK_TIME_IS_VALID (timestamp)
1799 && !GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment)) {
1800 timestamp += demux->in_gap;
1802 /* Check if we're after the segment already, if so no need to push
1804 if (demux->segment.stop != -1 && timestamp > demux->segment.stop) {
1805 GST_DEBUG_OBJECT (stream->pad,
1806 "Payload after segment stop %" GST_TIME_FORMAT,
1807 GST_TIME_ARGS (demux->segment.stop));
1809 gst_flow_combiner_update_pad_flow (demux->flowcombiner, stream->pad,
1811 gst_buffer_unref (payload->buf);
1812 payload->buf = NULL;
1813 g_array_remove_index (stream->payloads, 0);
1814 /* Break out as soon as we have an issue */
1815 if (G_UNLIKELY (ret != GST_FLOW_OK))
1822 GST_BUFFER_PTS (payload->buf) = timestamp;
1824 if (payload->duration == GST_CLOCK_TIME_NONE
1825 && stream->ext_props.avg_time_per_frame != 0) {
1826 duration = stream->ext_props.avg_time_per_frame * 100;
1828 duration = payload->duration;
1830 GST_BUFFER_DURATION (payload->buf) = duration;
1832 /* FIXME: we should really set durations on buffers if we can */
1834 GST_LOG_OBJECT (stream->pad, "pushing buffer, %" GST_PTR_FORMAT,
1837 if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment) && stream->is_video) {
1838 if (stream->reverse_kf_ready == TRUE && stream->kf_pos == 0) {
1839 GST_BUFFER_FLAG_SET (payload->buf, GST_BUFFER_FLAG_DISCONT);
1841 } else if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment)) {
1842 GST_BUFFER_FLAG_SET (payload->buf, GST_BUFFER_FLAG_DISCONT);
1846 if (stream->active) {
1847 if (G_UNLIKELY (stream->first_buffer)) {
1848 if (stream->streamheader != NULL) {
1849 GST_DEBUG_OBJECT (stream->pad,
1850 "Pushing streamheader before first buffer");
1851 gst_pad_push (stream->pad, gst_buffer_ref (stream->streamheader));
1853 stream->first_buffer = FALSE;
1856 if (GST_CLOCK_TIME_IS_VALID (timestamp)
1857 && timestamp > demux->segment.position) {
1858 demux->segment.position = timestamp;
1859 if (GST_CLOCK_TIME_IS_VALID (duration))
1860 demux->segment.position += timestamp;
1863 ret = gst_pad_push (stream->pad, payload->buf);
1865 gst_flow_combiner_update_pad_flow (demux->flowcombiner, stream->pad,
1868 gst_buffer_unref (payload->buf);
1871 payload->buf = NULL;
1872 if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment) && stream->is_video
1873 && stream->reverse_kf_ready) {
1874 g_array_remove_index (stream->payloads, stream->kf_pos);
1877 if (stream->reverse_kf_ready == TRUE && stream->kf_pos < 0) {
1879 stream->reverse_kf_ready = FALSE;
1882 g_array_remove_index (stream->payloads, 0);
1885 /* Break out as soon as we have an issue */
1886 if (G_UNLIKELY (ret != GST_FLOW_OK))
1894 gst_asf_demux_check_buffer_is_header (GstASFDemux * demux, GstBuffer * buf)
1898 g_assert (buf != NULL);
1900 GST_LOG_OBJECT (demux, "Checking if buffer is a header");
1902 gst_buffer_map (buf, &map, GST_MAP_READ);
1904 /* we return false on buffer too small */
1905 if (map.size < ASF_OBJECT_HEADER_SIZE) {
1906 gst_buffer_unmap (buf, &map);
1910 /* check if it is a header */
1911 asf_demux_peek_object (demux, map.data, ASF_OBJECT_HEADER_SIZE, &obj, TRUE);
1912 gst_buffer_unmap (buf, &map);
1913 if (obj.id == ASF_OBJ_HEADER) {
1920 gst_asf_demux_check_chained_asf (GstASFDemux * demux)
1922 guint64 off = demux->data_offset + (demux->packet * demux->packet_size);
1923 GstFlowReturn ret = GST_FLOW_OK;
1924 GstBuffer *buf = NULL;
1925 gboolean header = FALSE;
1927 /* TODO maybe we should skip index objects after the data and look
1928 * further for a new header */
1929 if (gst_asf_demux_pull_data (demux, off, ASF_OBJECT_HEADER_SIZE, &buf, &ret)) {
1930 g_assert (buf != NULL);
1931 /* check if it is a header */
1932 if (gst_asf_demux_check_buffer_is_header (demux, buf)) {
1933 GST_DEBUG_OBJECT (demux, "new base offset: %" G_GUINT64_FORMAT, off);
1934 demux->base_offset = off;
1938 gst_buffer_unref (buf);
1945 gst_asf_demux_loop (GstASFDemux * demux)
1947 GstFlowReturn flow = GST_FLOW_OK;
1948 GstBuffer *buf = NULL;
1951 if (G_UNLIKELY (demux->state == GST_ASF_DEMUX_STATE_HEADER)) {
1952 if (!gst_asf_demux_pull_headers (demux, &flow)) {
1956 gst_asf_demux_pull_indices (demux);
1959 g_assert (demux->state == GST_ASF_DEMUX_STATE_DATA);
1961 if (G_UNLIKELY (demux->num_packets != 0
1962 && demux->packet >= demux->num_packets))
1965 GST_LOG_OBJECT (demux, "packet %u/%u", (guint) demux->packet + 1,
1966 (guint) demux->num_packets);
1968 off = demux->data_offset + (demux->packet * demux->packet_size);
1970 if (G_UNLIKELY (!gst_asf_demux_pull_data (demux, off,
1971 demux->packet_size * demux->speed_packets, &buf, &flow))) {
1972 GST_DEBUG_OBJECT (demux, "got flow %s", gst_flow_get_name (flow));
1973 if (flow == GST_FLOW_EOS) {
1975 } else if (flow == GST_FLOW_FLUSHING) {
1976 GST_DEBUG_OBJECT (demux, "Not fatal");
1983 if (G_LIKELY (demux->speed_packets == 1)) {
1984 GstAsfDemuxParsePacketError err;
1985 err = gst_asf_demux_parse_packet (demux, buf);
1986 if (G_UNLIKELY (err != GST_ASF_DEMUX_PARSE_PACKET_ERROR_NONE)) {
1987 /* when we don't know when the data object ends, we should check
1988 * for a chained asf */
1989 if (demux->num_packets == 0) {
1990 if (gst_asf_demux_check_buffer_is_header (demux, buf)) {
1991 GST_INFO_OBJECT (demux, "Chained asf found");
1992 demux->base_offset = off;
1993 gst_asf_demux_reset (demux, TRUE);
1994 gst_buffer_unref (buf);
1998 /* FIXME: We should tally up fatal errors and error out only
1999 * after a few broken packets in a row? */
2001 GST_INFO_OBJECT (demux, "Ignoring recoverable parse error");
2002 gst_buffer_unref (buf);
2004 if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment)
2005 && !demux->seek_to_cur_pos) {
2007 if (demux->packet < 0) {
2017 flow = gst_asf_demux_push_complete_payloads (demux, FALSE);
2019 if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment)
2020 && !demux->seek_to_cur_pos) {
2022 if (demux->packet < 0) {
2031 for (n = 0; n < demux->speed_packets; n++) {
2033 GstAsfDemuxParsePacketError err;
2036 gst_buffer_copy_region (buf, GST_BUFFER_COPY_ALL,
2037 n * demux->packet_size, demux->packet_size);
2038 err = gst_asf_demux_parse_packet (demux, sub);
2039 if (G_UNLIKELY (err != GST_ASF_DEMUX_PARSE_PACKET_ERROR_NONE)) {
2040 /* when we don't know when the data object ends, we should check
2041 * for a chained asf */
2042 if (demux->num_packets == 0) {
2043 if (gst_asf_demux_check_buffer_is_header (demux, sub)) {
2044 GST_INFO_OBJECT (demux, "Chained asf found");
2045 demux->base_offset = off + n * demux->packet_size;
2046 gst_asf_demux_reset (demux, TRUE);
2047 gst_buffer_unref (sub);
2048 gst_buffer_unref (buf);
2052 /* FIXME: We should tally up fatal errors and error out only
2053 * after a few broken packets in a row? */
2055 GST_INFO_OBJECT (demux, "Ignoring recoverable parse error");
2059 gst_buffer_unref (sub);
2061 if (err == GST_ASF_DEMUX_PARSE_PACKET_ERROR_NONE)
2062 flow = gst_asf_demux_push_complete_payloads (demux, FALSE);
2068 /* reset speed pull */
2069 demux->speed_packets = 1;
2072 gst_buffer_unref (buf);
2074 if (G_UNLIKELY ((demux->num_packets > 0
2075 && demux->packet >= demux->num_packets)
2076 || flow == GST_FLOW_EOS)) {
2077 GST_LOG_OBJECT (demux, "reached EOS");
2081 if (G_UNLIKELY (flow != GST_FLOW_OK)) {
2082 GST_DEBUG_OBJECT (demux, "pushing complete payloads failed");
2086 /* check if we're at the end of the configured segment */
2087 /* FIXME: check if segment end reached etc. */
2093 /* if we haven't activated our streams yet, this might be because we have
2094 * less data queued than required for preroll; force stream activation and
2095 * send any pending payloads before sending EOS */
2096 if (!demux->activated_streams)
2097 flow = gst_asf_demux_push_complete_payloads (demux, TRUE);
2099 /* we want to push an eos or post a segment-done in any case */
2100 if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
2103 /* for segment playback we need to post when (in stream time)
2104 * we stopped, this is either stop (when set) or the duration. */
2105 if ((stop = demux->segment.stop) == -1)
2106 stop = demux->segment.duration;
2108 GST_INFO_OBJECT (demux, "Posting segment-done, at end of segment");
2109 gst_element_post_message (GST_ELEMENT_CAST (demux),
2110 gst_message_new_segment_done (GST_OBJECT (demux), GST_FORMAT_TIME,
2112 gst_asf_demux_send_event_unlocked (demux,
2113 gst_event_new_segment_done (GST_FORMAT_TIME, stop));
2114 } else if (flow != GST_FLOW_EOS) {
2115 /* check if we have a chained asf, in case, we don't eos yet */
2116 if (gst_asf_demux_check_chained_asf (demux)) {
2117 GST_INFO_OBJECT (demux, "Chained ASF starting");
2118 gst_asf_demux_reset (demux, TRUE);
2123 if (!(demux->segment.flags & GST_SEEK_FLAG_SEGMENT)) {
2124 if (demux->activated_streams) {
2125 /* normal playback, send EOS to all linked pads */
2126 GST_INFO_OBJECT (demux, "Sending EOS, at end of stream");
2127 gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
2129 GST_WARNING_OBJECT (demux, "EOS without exposed streams");
2130 flow = GST_FLOW_EOS;
2133 /* ... and fall through to pause */
2137 GST_DEBUG_OBJECT (demux, "pausing task, flow return: %s",
2138 gst_flow_get_name (flow));
2139 demux->segment_running = FALSE;
2140 gst_pad_pause_task (demux->sinkpad);
2142 /* For the error cases */
2143 if (flow == GST_FLOW_EOS && !demux->activated_streams) {
2144 GST_ELEMENT_ERROR (demux, STREAM, WRONG_TYPE, (NULL),
2145 ("This doesn't seem to be an ASF file"));
2146 } else if (flow < GST_FLOW_EOS || flow == GST_FLOW_NOT_LINKED) {
2147 /* Post an error. Hopefully something else already has, but if not... */
2148 GST_ELEMENT_FLOW_ERROR (demux, flow);
2149 gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
2158 GST_DEBUG_OBJECT (demux, "Read failed, doh");
2159 flow = GST_FLOW_EOS;
2163 /* See FIXMEs above */
2166 gst_buffer_unref (buf);
2167 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
2168 ("Error parsing ASF packet %u", (guint) demux->packet));
2169 gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
2170 flow = GST_FLOW_ERROR;
2176 #define GST_ASF_DEMUX_CHECK_HEADER_YES 0
2177 #define GST_ASF_DEMUX_CHECK_HEADER_NO 1
2178 #define GST_ASF_DEMUX_CHECK_HEADER_NEED_DATA 2
2181 gst_asf_demux_check_header (GstASFDemux * demux)
2184 guint8 *cdata = (guint8 *) gst_adapter_map (demux->adapter,
2185 ASF_OBJECT_HEADER_SIZE);
2186 if (cdata == NULL) /* need more data */
2187 return GST_ASF_DEMUX_CHECK_HEADER_NEED_DATA;
2189 asf_demux_peek_object (demux, cdata, ASF_OBJECT_HEADER_SIZE, &obj, FALSE);
2190 if (obj.id != ASF_OBJ_HEADER) {
2191 return GST_ASF_DEMUX_CHECK_HEADER_NO;
2193 return GST_ASF_DEMUX_CHECK_HEADER_YES;
2197 static GstFlowReturn
2198 gst_asf_demux_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
2200 GstFlowReturn ret = GST_FLOW_OK;
2203 demux = GST_ASF_DEMUX (parent);
2205 GST_LOG_OBJECT (demux,
2206 "buffer: size=%" G_GSIZE_FORMAT ", offset=%" G_GINT64_FORMAT ", time=%"
2207 GST_TIME_FORMAT, gst_buffer_get_size (buf), GST_BUFFER_OFFSET (buf),
2208 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)));
2210 if (G_UNLIKELY (GST_BUFFER_IS_DISCONT (buf))) {
2211 GST_DEBUG_OBJECT (demux, "received DISCONT");
2212 gst_asf_demux_mark_discont (demux);
2215 if (G_UNLIKELY ((!GST_CLOCK_TIME_IS_VALID (demux->in_gap) &&
2216 GST_BUFFER_TIMESTAMP_IS_VALID (buf)))) {
2217 demux->in_gap = GST_BUFFER_TIMESTAMP (buf) - demux->in_segment.start;
2218 GST_DEBUG_OBJECT (demux, "upstream segment start %" GST_TIME_FORMAT
2219 ", interpolation gap: %" GST_TIME_FORMAT,
2220 GST_TIME_ARGS (demux->in_segment.start), GST_TIME_ARGS (demux->in_gap));
2223 gst_adapter_push (demux->adapter, buf);
2225 switch (demux->state) {
2226 case GST_ASF_DEMUX_STATE_INDEX:{
2227 gint result = gst_asf_demux_check_header (demux);
2228 if (result == GST_ASF_DEMUX_CHECK_HEADER_NEED_DATA) /* need more data */
2231 if (result == GST_ASF_DEMUX_CHECK_HEADER_NO) {
2232 /* we don't care about this, probably an index */
2233 /* TODO maybe would be smarter to skip all the indices
2234 * until we got a new header or EOS to decide */
2235 GST_LOG_OBJECT (demux, "Received index object, its EOS");
2238 GST_INFO_OBJECT (demux, "Chained asf starting");
2239 /* cleanup and get ready for a chained asf */
2240 gst_asf_demux_reset (demux, TRUE);
2244 case GST_ASF_DEMUX_STATE_HEADER:{
2245 ret = gst_asf_demux_chain_headers (demux);
2246 if (demux->state != GST_ASF_DEMUX_STATE_DATA)
2248 /* otherwise fall through */
2250 case GST_ASF_DEMUX_STATE_DATA:
2254 data_size = demux->packet_size;
2256 while (gst_adapter_available (demux->adapter) >= data_size) {
2258 GstAsfDemuxParsePacketError err;
2260 /* we don't know the length of the stream
2261 * check for a chained asf everytime */
2262 if (demux->num_packets == 0) {
2263 gint result = gst_asf_demux_check_header (demux);
2265 if (result == GST_ASF_DEMUX_CHECK_HEADER_YES) {
2266 GST_INFO_OBJECT (demux, "Chained asf starting");
2267 /* cleanup and get ready for a chained asf */
2268 gst_asf_demux_reset (demux, TRUE);
2271 } else if (G_UNLIKELY (demux->num_packets != 0 && demux->packet >= 0
2272 && demux->packet >= demux->num_packets)) {
2273 /* do not overshoot data section when streaming */
2277 buf = gst_adapter_take_buffer (demux->adapter, data_size);
2279 /* FIXME: We should tally up fatal errors and error out only
2280 * after a few broken packets in a row? */
2281 err = gst_asf_demux_parse_packet (demux, buf);
2283 gst_buffer_unref (buf);
2285 if (G_LIKELY (err == GST_ASF_DEMUX_PARSE_PACKET_ERROR_NONE))
2286 ret = gst_asf_demux_push_complete_payloads (demux, FALSE);
2288 GST_WARNING_OBJECT (demux, "Parse error");
2290 if (demux->packet >= 0)
2293 if (G_UNLIKELY (demux->num_packets != 0 && demux->packet >= 0
2294 && demux->packet >= demux->num_packets)) {
2295 demux->state = GST_ASF_DEMUX_STATE_INDEX;
2300 g_assert_not_reached ();
2304 if (ret != GST_FLOW_OK)
2305 GST_DEBUG_OBJECT (demux, "flow: %s", gst_flow_get_name (ret));
2311 GST_DEBUG_OBJECT (demux, "Handled last packet, setting EOS");
2317 static inline gboolean
2318 gst_asf_demux_skip_bytes (guint num_bytes, guint8 ** p_data, guint64 * p_size)
2320 if (*p_size < num_bytes)
2323 *p_data += num_bytes;
2324 *p_size -= num_bytes;
2328 static inline guint8
2329 gst_asf_demux_get_uint8 (guint8 ** p_data, guint64 * p_size)
2333 g_assert (*p_size >= 1);
2334 ret = GST_READ_UINT8 (*p_data);
2335 *p_data += sizeof (guint8);
2336 *p_size -= sizeof (guint8);
2340 static inline guint16
2341 gst_asf_demux_get_uint16 (guint8 ** p_data, guint64 * p_size)
2345 g_assert (*p_size >= 2);
2346 ret = GST_READ_UINT16_LE (*p_data);
2347 *p_data += sizeof (guint16);
2348 *p_size -= sizeof (guint16);
2352 static inline guint32
2353 gst_asf_demux_get_uint32 (guint8 ** p_data, guint64 * p_size)
2357 g_assert (*p_size >= 4);
2358 ret = GST_READ_UINT32_LE (*p_data);
2359 *p_data += sizeof (guint32);
2360 *p_size -= sizeof (guint32);
2364 static inline guint64
2365 gst_asf_demux_get_uint64 (guint8 ** p_data, guint64 * p_size)
2369 g_assert (*p_size >= 8);
2370 ret = GST_READ_UINT64_LE (*p_data);
2371 *p_data += sizeof (guint64);
2372 *p_size -= sizeof (guint64);
2377 gst_asf_demux_get_buffer (GstBuffer ** p_buf, guint num_bytes_to_read,
2378 guint8 ** p_data, guint64 * p_size)
2382 if (*p_size < num_bytes_to_read)
2385 *p_buf = gst_buffer_new_and_alloc (num_bytes_to_read);
2386 gst_buffer_fill (*p_buf, 0, *p_data, num_bytes_to_read);
2388 *p_data += num_bytes_to_read;
2389 *p_size -= num_bytes_to_read;
2395 gst_asf_demux_get_bytes (guint8 ** p_buf, guint num_bytes_to_read,
2396 guint8 ** p_data, guint64 * p_size)
2400 if (*p_size < num_bytes_to_read)
2403 *p_buf = g_memdup (*p_data, num_bytes_to_read);
2404 *p_data += num_bytes_to_read;
2405 *p_size -= num_bytes_to_read;
2410 gst_asf_demux_get_string (gchar ** p_str, guint16 * p_strlen,
2411 guint8 ** p_data, guint64 * p_size)
2421 s_length = gst_asf_demux_get_uint16 (p_data, p_size);
2424 *p_strlen = s_length;
2426 if (s_length == 0) {
2427 GST_WARNING ("zero-length string");
2428 *p_str = g_strdup ("");
2432 if (!gst_asf_demux_get_bytes (&s, s_length, p_data, p_size))
2435 g_assert (s != NULL);
2437 /* just because They don't exist doesn't
2438 * mean They are not out to get you ... */
2439 if (s[s_length - 1] != '\0') {
2440 s = g_realloc (s, s_length + 1);
2444 *p_str = (gchar *) s;
2450 gst_asf_demux_get_guid (ASFGuid * guid, guint8 ** p_data, guint64 * p_size)
2452 g_assert (*p_size >= 4 * sizeof (guint32));
2454 guid->v1 = gst_asf_demux_get_uint32 (p_data, p_size);
2455 guid->v2 = gst_asf_demux_get_uint32 (p_data, p_size);
2456 guid->v3 = gst_asf_demux_get_uint32 (p_data, p_size);
2457 guid->v4 = gst_asf_demux_get_uint32 (p_data, p_size);
2461 gst_asf_demux_get_stream_audio (asf_stream_audio * audio, guint8 ** p_data,
2464 if (*p_size < (2 + 2 + 4 + 4 + 2 + 2 + 2))
2467 /* WAVEFORMATEX Structure */
2468 audio->codec_tag = gst_asf_demux_get_uint16 (p_data, p_size);
2469 audio->channels = gst_asf_demux_get_uint16 (p_data, p_size);
2470 audio->sample_rate = gst_asf_demux_get_uint32 (p_data, p_size);
2471 audio->byte_rate = gst_asf_demux_get_uint32 (p_data, p_size);
2472 audio->block_align = gst_asf_demux_get_uint16 (p_data, p_size);
2473 audio->word_size = gst_asf_demux_get_uint16 (p_data, p_size);
2474 /* Codec specific data size */
2475 audio->size = gst_asf_demux_get_uint16 (p_data, p_size);
2480 gst_asf_demux_get_stream_video (asf_stream_video * video, guint8 ** p_data,
2483 if (*p_size < (4 + 4 + 1 + 2))
2486 video->width = gst_asf_demux_get_uint32 (p_data, p_size);
2487 video->height = gst_asf_demux_get_uint32 (p_data, p_size);
2488 video->unknown = gst_asf_demux_get_uint8 (p_data, p_size);
2489 video->size = gst_asf_demux_get_uint16 (p_data, p_size);
2494 gst_asf_demux_get_stream_video_format (asf_stream_video_format * fmt,
2495 guint8 ** p_data, guint64 * p_size)
2497 if (*p_size < (4 + 4 + 4 + 2 + 2 + 4 + 4 + 4 + 4 + 4 + 4))
2500 fmt->size = gst_asf_demux_get_uint32 (p_data, p_size);
2501 fmt->width = gst_asf_demux_get_uint32 (p_data, p_size);
2502 fmt->height = gst_asf_demux_get_uint32 (p_data, p_size);
2503 fmt->planes = gst_asf_demux_get_uint16 (p_data, p_size);
2504 fmt->depth = gst_asf_demux_get_uint16 (p_data, p_size);
2505 fmt->tag = gst_asf_demux_get_uint32 (p_data, p_size);
2506 fmt->image_size = gst_asf_demux_get_uint32 (p_data, p_size);
2507 fmt->xpels_meter = gst_asf_demux_get_uint32 (p_data, p_size);
2508 fmt->ypels_meter = gst_asf_demux_get_uint32 (p_data, p_size);
2509 fmt->num_colors = gst_asf_demux_get_uint32 (p_data, p_size);
2510 fmt->imp_colors = gst_asf_demux_get_uint32 (p_data, p_size);
2515 gst_asf_demux_get_stream (GstASFDemux * demux, guint16 id)
2519 for (i = 0; i < demux->num_streams; i++) {
2520 if (demux->stream[i].id == id)
2521 return &demux->stream[i];
2524 if (gst_asf_demux_is_unknown_stream (demux, id))
2525 GST_WARNING ("Segment found for undefined stream: (%d)", id);
2530 gst_asf_demux_setup_pad (GstASFDemux * demux, GstPad * src_pad,
2531 GstCaps * caps, guint16 id, gboolean is_video, GstBuffer * streamheader,
2536 gst_pad_use_fixed_caps (src_pad);
2537 gst_pad_set_caps (src_pad, caps);
2539 gst_pad_set_event_function (src_pad,
2540 GST_DEBUG_FUNCPTR (gst_asf_demux_handle_src_event));
2541 gst_pad_set_query_function (src_pad,
2542 GST_DEBUG_FUNCPTR (gst_asf_demux_handle_src_query));
2544 stream = &demux->stream[demux->num_streams];
2545 stream->caps = caps;
2546 stream->pad = src_pad;
2548 stream->fps_known = !is_video; /* bit hacky for audio */
2549 stream->is_video = is_video;
2550 stream->pending_tags = tags;
2551 stream->discont = TRUE;
2552 stream->first_buffer = TRUE;
2553 stream->streamheader = streamheader;
2554 if (stream->streamheader) {
2555 stream->streamheader = gst_buffer_make_writable (streamheader);
2556 GST_BUFFER_FLAG_SET (stream->streamheader, GST_BUFFER_FLAG_HEADER);
2561 st = gst_caps_get_structure (caps, 0);
2562 if (gst_structure_get_fraction (st, "pixel-aspect-ratio", &par_x, &par_y) &&
2563 par_x > 0 && par_y > 0) {
2564 GST_DEBUG ("PAR %d/%d", par_x, par_y);
2565 stream->par_x = par_x;
2566 stream->par_y = par_y;
2570 stream->payloads = g_array_new (FALSE, FALSE, sizeof (AsfPayload));
2572 /* TODO: create this array during reverse play? */
2573 stream->payloads_rev = g_array_new (FALSE, FALSE, sizeof (AsfPayload));
2575 GST_INFO ("Created pad %s for stream %u with caps %" GST_PTR_FORMAT,
2576 GST_PAD_NAME (src_pad), demux->num_streams, caps);
2578 ++demux->num_streams;
2580 stream->active = FALSE;
2586 gst_asf_demux_add_stream_headers_to_caps (GstASFDemux * demux,
2587 GstBuffer * buffer, GstStructure * structure)
2589 GValue arr_val = G_VALUE_INIT;
2590 GValue buf_val = G_VALUE_INIT;
2592 g_value_init (&arr_val, GST_TYPE_ARRAY);
2593 g_value_init (&buf_val, GST_TYPE_BUFFER);
2595 gst_value_set_buffer (&buf_val, buffer);
2596 gst_value_array_append_and_take_value (&arr_val, &buf_val);
2598 gst_structure_take_value (structure, "streamheader", &arr_val);
2602 gst_asf_demux_add_audio_stream (GstASFDemux * demux,
2603 asf_stream_audio * audio, guint16 id, guint8 ** p_data, guint64 * p_size)
2605 GstTagList *tags = NULL;
2606 GstBuffer *extradata = NULL;
2609 guint16 size_left = 0;
2610 gchar *codec_name = NULL;
2613 size_left = audio->size;
2615 /* Create the audio pad */
2616 name = g_strdup_printf ("audio_%u", demux->num_audio_streams);
2618 src_pad = gst_pad_new_from_static_template (&audio_src_template, name);
2621 /* Swallow up any left over data and set up the
2622 * standard properties from the header info */
2624 GST_INFO_OBJECT (demux, "Audio header contains %d bytes of "
2625 "codec specific data", size_left);
2627 g_assert (size_left <= *p_size);
2628 gst_asf_demux_get_buffer (&extradata, size_left, p_data, p_size);
2631 /* asf_stream_audio is the same as gst_riff_strf_auds, but with an
2632 * additional two bytes indicating extradata. */
2633 /* FIXME: Handle the channel reorder map here */
2634 caps = gst_riff_create_audio_caps (audio->codec_tag, NULL,
2635 (gst_riff_strf_auds *) audio, extradata, NULL, &codec_name, NULL);
2638 caps = gst_caps_new_simple ("audio/x-asf-unknown", "codec_id",
2639 G_TYPE_INT, (gint) audio->codec_tag, NULL);
2642 /* Informing about that audio format we just added */
2644 tags = gst_tag_list_new (GST_TAG_AUDIO_CODEC, codec_name, NULL);
2645 g_free (codec_name);
2648 if (audio->byte_rate > 0) {
2649 /* Some ASF files have no bitrate props object (often seen with
2650 * ASF files that contain raw audio data). Example files can
2651 * be generated with FFmpeg (tested with v2.8.6), like this:
2653 * ffmpeg -i sine-wave.wav -c:a pcm_alaw file.asf
2655 * In this case, if audio->byte_rate is nonzero, use that as
2658 guint bitrate = audio->byte_rate * 8;
2661 tags = gst_tag_list_new_empty ();
2663 /* Add bitrate, but only if there is none set already, since
2664 * this is just a fallback in case there is no bitrate tag
2665 * already present */
2666 gst_tag_list_add (tags, GST_TAG_MERGE_KEEP, GST_TAG_BITRATE, bitrate, NULL);
2670 gst_buffer_unref (extradata);
2672 GST_INFO ("Adding audio stream #%u, id %u codec %u (0x%04x), tags=%"
2673 GST_PTR_FORMAT, demux->num_audio_streams, id, audio->codec_tag,
2674 audio->codec_tag, tags);
2676 ++demux->num_audio_streams;
2678 return gst_asf_demux_setup_pad (demux, src_pad, caps, id, FALSE, NULL, tags);
2682 gst_asf_demux_add_video_stream (GstASFDemux * demux,
2683 asf_stream_video_format * video, guint16 id,
2684 guint8 ** p_data, guint64 * p_size)
2686 GstTagList *tags = NULL;
2687 GstStructure *caps_s;
2688 GstBuffer *extradata = NULL;
2693 gchar *codec_name = NULL;
2694 gint size_left = video->size - 40;
2695 GstBuffer *streamheader = NULL;
2696 guint par_w = 1, par_h = 1;
2698 /* Create the video pad */
2699 name = g_strdup_printf ("video_%u", demux->num_video_streams);
2700 src_pad = gst_pad_new_from_static_template (&video_src_template, name);
2703 /* Now try some gstreamer formatted MIME types (from gst_avi_demux_strf_vids) */
2705 GST_LOG ("Video header has %d bytes of codec specific data", size_left);
2706 g_assert (size_left <= *p_size);
2707 gst_asf_demux_get_buffer (&extradata, size_left, p_data, p_size);
2710 GST_DEBUG ("video codec %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (video->tag));
2712 /* yes, asf_stream_video_format and gst_riff_strf_vids are the same */
2713 caps = gst_riff_create_video_caps (video->tag, NULL,
2714 (gst_riff_strf_vids *) video, extradata, NULL, &codec_name);
2717 caps = gst_caps_new_simple ("video/x-asf-unknown", "fourcc",
2718 G_TYPE_UINT, video->tag, NULL);
2723 s = gst_asf_demux_get_metadata_for_stream (demux, id);
2724 if (gst_structure_get_int (s, "AspectRatioX", &ax) &&
2725 gst_structure_get_int (s, "AspectRatioY", &ay) && (ax > 0 && ay > 0)) {
2728 gst_caps_set_simple (caps, "pixel-aspect-ratio", GST_TYPE_FRACTION,
2732 /* retry with the global metadata */
2733 GST_DEBUG ("Retrying with global metadata %" GST_PTR_FORMAT,
2734 demux->global_metadata);
2735 s = demux->global_metadata;
2736 if (gst_structure_get_uint (s, "AspectRatioX", &ax) &&
2737 gst_structure_get_uint (s, "AspectRatioY", &ay)) {
2738 GST_DEBUG ("ax:%d, ay:%d", ax, ay);
2739 if (ax > 0 && ay > 0) {
2742 gst_caps_set_simple (caps, "pixel-aspect-ratio", GST_TYPE_FRACTION,
2747 s = gst_caps_get_structure (caps, 0);
2748 gst_structure_remove_field (s, "framerate");
2751 caps_s = gst_caps_get_structure (caps, 0);
2753 /* add format field with fourcc to WMV/VC1 caps to differentiate variants */
2754 if (gst_structure_has_name (caps_s, "video/x-wmv")) {
2755 str = g_strdup_printf ("%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (video->tag));
2756 gst_caps_set_simple (caps, "format", G_TYPE_STRING, str, NULL);
2759 /* check if h264 has codec_data (avc) or streamheaders (bytestream) */
2760 } else if (gst_structure_has_name (caps_s, "video/x-h264")) {
2761 const GValue *value = gst_structure_get_value (caps_s, "codec_data");
2763 GstBuffer *buf = gst_value_get_buffer (value);
2766 if (gst_buffer_map (buf, &mapinfo, GST_MAP_READ)) {
2767 if (mapinfo.size >= 4 && GST_READ_UINT32_BE (mapinfo.data) == 1) {
2768 /* this looks like a bytestream start */
2769 streamheader = gst_buffer_ref (buf);
2770 gst_asf_demux_add_stream_headers_to_caps (demux, buf, caps_s);
2771 gst_structure_remove_field (caps_s, "codec_data");
2774 gst_buffer_unmap (buf, &mapinfo);
2779 /* For a 3D video, set multiview information into the caps based on
2780 * what was detected during object parsing */
2781 if (demux->asf_3D_mode != GST_ASF_3D_NONE) {
2782 GstVideoMultiviewMode mv_mode = GST_VIDEO_MULTIVIEW_MODE_NONE;
2783 GstVideoMultiviewFlags mv_flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
2784 const gchar *mview_mode_str;
2786 switch (demux->asf_3D_mode) {
2787 case GST_ASF_3D_SIDE_BY_SIDE_HALF_LR:
2788 mv_mode = GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE;
2790 case GST_ASF_3D_SIDE_BY_SIDE_HALF_RL:
2791 mv_mode = GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE;
2792 mv_flags = GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST;
2794 case GST_ASF_3D_TOP_AND_BOTTOM_HALF_LR:
2795 mv_mode = GST_VIDEO_MULTIVIEW_MODE_TOP_BOTTOM;
2797 case GST_ASF_3D_TOP_AND_BOTTOM_HALF_RL:
2798 mv_mode = GST_VIDEO_MULTIVIEW_MODE_TOP_BOTTOM;
2799 mv_flags = GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST;
2801 case GST_ASF_3D_DUAL_STREAM:{
2802 gboolean is_right_view = FALSE;
2803 /* if Advanced_Mutual_Exclusion object exists, use it
2804 * to figure out which is the left view (lower ID) */
2805 if (demux->mut_ex_streams != NULL) {
2809 length = g_slist_length (demux->mut_ex_streams);
2811 for (i = 0; i < length; i++) {
2814 v_s_id = g_slist_nth_data (demux->mut_ex_streams, i);
2816 GST_DEBUG_OBJECT (demux,
2817 "has Mutual_Exclusion object. stream id in object is %d",
2818 GPOINTER_TO_INT (v_s_id));
2820 if (id > GPOINTER_TO_INT (v_s_id))
2821 is_right_view = TRUE;
2824 /* if the Advaced_Mutual_Exclusion object doesn't exist, assume the
2825 * first video stream encountered has the lower ID */
2826 if (demux->num_video_streams > 0) {
2827 /* This is not the first video stream, assuming right eye view */
2828 is_right_view = TRUE;
2832 mv_mode = GST_VIDEO_MULTIVIEW_MODE_RIGHT;
2834 mv_mode = GST_VIDEO_MULTIVIEW_MODE_LEFT;
2841 GST_INFO_OBJECT (demux,
2842 "stream_id %d, has multiview-mode %d flags 0x%x", id, mv_mode,
2845 mview_mode_str = gst_video_multiview_mode_to_caps_string (mv_mode);
2846 if (mview_mode_str != NULL) {
2847 if (gst_video_multiview_guess_half_aspect (mv_mode, video->width,
2848 video->height, par_w, par_h))
2849 mv_flags |= GST_VIDEO_MULTIVIEW_FLAGS_HALF_ASPECT;
2851 gst_caps_set_simple (caps,
2852 "multiview-mode", G_TYPE_STRING, mview_mode_str,
2853 "multiview-flags", GST_TYPE_VIDEO_MULTIVIEW_FLAGSET, mv_flags,
2854 GST_FLAG_SET_MASK_EXACT, NULL);
2859 tags = gst_tag_list_new (GST_TAG_VIDEO_CODEC, codec_name, NULL);
2860 g_free (codec_name);
2864 gst_buffer_unref (extradata);
2866 GST_INFO ("Adding video stream #%u, id %u, codec %"
2867 GST_FOURCC_FORMAT " (0x%08x)", demux->num_video_streams, id,
2868 GST_FOURCC_ARGS (video->tag), video->tag);
2870 ++demux->num_video_streams;
2872 return gst_asf_demux_setup_pad (demux, src_pad, caps, id, TRUE,
2873 streamheader, tags);
2877 gst_asf_demux_activate_stream (GstASFDemux * demux, AsfStream * stream)
2879 if (!stream->active) {
2883 GST_INFO_OBJECT (demux, "Activating stream %2u, pad %s, caps %"
2884 GST_PTR_FORMAT, stream->id, GST_PAD_NAME (stream->pad), stream->caps);
2885 gst_pad_set_active (stream->pad, TRUE);
2888 gst_pad_create_stream_id_printf (stream->pad, GST_ELEMENT_CAST (demux),
2889 "%03u", stream->id);
2892 gst_pad_get_sticky_event (demux->sinkpad, GST_EVENT_STREAM_START, 0);
2894 if (gst_event_parse_group_id (event, &demux->group_id))
2895 demux->have_group_id = TRUE;
2897 demux->have_group_id = FALSE;
2898 gst_event_unref (event);
2899 } else if (!demux->have_group_id) {
2900 demux->have_group_id = TRUE;
2901 demux->group_id = gst_util_group_id_next ();
2904 event = gst_event_new_stream_start (stream_id);
2905 if (demux->have_group_id)
2906 gst_event_set_group_id (event, demux->group_id);
2908 gst_pad_push_event (stream->pad, event);
2910 gst_pad_set_caps (stream->pad, stream->caps);
2912 gst_element_add_pad (GST_ELEMENT_CAST (demux), stream->pad);
2913 gst_flow_combiner_add_pad (demux->flowcombiner, stream->pad);
2914 stream->active = TRUE;
2919 gst_asf_demux_parse_stream_object (GstASFDemux * demux, guint8 * data,
2922 AsfCorrectionType correction_type;
2923 AsfStreamType stream_type;
2924 GstClockTime time_offset;
2925 gboolean is_encrypted G_GNUC_UNUSED;
2929 guint stream_specific_size;
2930 guint type_specific_size G_GNUC_UNUSED;
2931 guint unknown G_GNUC_UNUSED;
2932 gboolean inspect_payload = FALSE;
2933 AsfStream *stream = NULL;
2935 /* Get the rest of the header's header */
2936 if (size < (16 + 16 + 8 + 4 + 4 + 2 + 4))
2937 goto not_enough_data;
2939 gst_asf_demux_get_guid (&guid, &data, &size);
2940 stream_type = gst_asf_demux_identify_guid (asf_stream_guids, &guid);
2942 gst_asf_demux_get_guid (&guid, &data, &size);
2943 correction_type = gst_asf_demux_identify_guid (asf_correction_guids, &guid);
2945 time_offset = gst_asf_demux_get_uint64 (&data, &size) * 100;
2947 type_specific_size = gst_asf_demux_get_uint32 (&data, &size);
2948 stream_specific_size = gst_asf_demux_get_uint32 (&data, &size);
2950 flags = gst_asf_demux_get_uint16 (&data, &size);
2951 stream_id = flags & 0x7f;
2952 is_encrypted = ! !((flags & 0x8000) << 15);
2953 unknown = gst_asf_demux_get_uint32 (&data, &size);
2955 GST_DEBUG_OBJECT (demux, "Found stream %u, time_offset=%" GST_TIME_FORMAT,
2956 stream_id, GST_TIME_ARGS (time_offset));
2958 /* dvr-ms has audio stream declared in stream specific data */
2959 if (stream_type == ASF_STREAM_EXT_EMBED_HEADER) {
2960 AsfExtStreamType ext_stream_type;
2961 gst_asf_demux_get_guid (&guid, &data, &size);
2962 ext_stream_type = gst_asf_demux_identify_guid (asf_ext_stream_guids, &guid);
2964 if (ext_stream_type == ASF_EXT_STREAM_AUDIO) {
2965 inspect_payload = TRUE;
2967 gst_asf_demux_get_guid (&guid, &data, &size);
2968 gst_asf_demux_get_uint32 (&data, &size);
2969 gst_asf_demux_get_uint32 (&data, &size);
2970 gst_asf_demux_get_uint32 (&data, &size);
2971 gst_asf_demux_get_guid (&guid, &data, &size);
2972 gst_asf_demux_get_uint32 (&data, &size);
2973 stream_type = ASF_STREAM_AUDIO;
2977 switch (stream_type) {
2978 case ASF_STREAM_AUDIO:{
2979 asf_stream_audio audio_object;
2981 if (!gst_asf_demux_get_stream_audio (&audio_object, &data, &size))
2982 goto not_enough_data;
2984 GST_INFO ("Object is an audio stream with %u bytes of additional data",
2987 stream = gst_asf_demux_add_audio_stream (demux, &audio_object, stream_id,
2990 switch (correction_type) {
2991 case ASF_CORRECTION_ON:{
2992 guint span, packet_size, chunk_size, data_size, silence_data;
2994 GST_INFO ("Using error correction");
2996 if (size < (1 + 2 + 2 + 2 + 1))
2997 goto not_enough_data;
2999 span = gst_asf_demux_get_uint8 (&data, &size);
3000 packet_size = gst_asf_demux_get_uint16 (&data, &size);
3001 chunk_size = gst_asf_demux_get_uint16 (&data, &size);
3002 data_size = gst_asf_demux_get_uint16 (&data, &size);
3003 silence_data = gst_asf_demux_get_uint8 (&data, &size);
3005 stream->span = span;
3007 GST_DEBUG_OBJECT (demux, "Descrambling ps:%u cs:%u ds:%u s:%u sd:%u",
3008 packet_size, chunk_size, data_size, span, silence_data);
3010 if (stream->span > 1) {
3011 if (chunk_size == 0 || ((packet_size / chunk_size) <= 1)) {
3012 /* Disable descrambling */
3015 /* FIXME: this else branch was added for
3016 * weird_al_yankovic - the saga begins.asf */
3017 stream->ds_packet_size = packet_size;
3018 stream->ds_chunk_size = chunk_size;
3021 /* Descambling is enabled */
3022 stream->ds_packet_size = packet_size;
3023 stream->ds_chunk_size = chunk_size;
3026 /* Now skip the rest of the silence data */
3028 gst_bytestream_flush (demux->bs, data_size - 1);
3030 /* FIXME: CHECKME. And why -1? */
3031 if (data_size > 1) {
3032 if (!gst_asf_demux_skip_bytes (data_size - 1, &data, &size)) {
3033 goto not_enough_data;
3039 case ASF_CORRECTION_OFF:{
3040 GST_INFO ("Error correction off");
3041 if (!gst_asf_demux_skip_bytes (stream_specific_size, &data, &size))
3042 goto not_enough_data;
3046 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3047 ("Audio stream using unknown error correction"));
3054 case ASF_STREAM_VIDEO:{
3055 asf_stream_video_format video_format_object;
3056 asf_stream_video video_object;
3059 if (!gst_asf_demux_get_stream_video (&video_object, &data, &size))
3060 goto not_enough_data;
3062 vsize = video_object.size - 40; /* Byte order gets offset by single byte */
3064 GST_INFO ("object is a video stream with %u bytes of "
3065 "additional data", vsize);
3067 if (!gst_asf_demux_get_stream_video_format (&video_format_object,
3069 goto not_enough_data;
3072 stream = gst_asf_demux_add_video_stream (demux, &video_format_object,
3073 stream_id, &data, &size);
3079 GST_WARNING_OBJECT (demux, "Unknown stream type for stream %u",
3081 demux->other_streams =
3082 g_slist_append (demux->other_streams, GINT_TO_POINTER (stream_id));
3087 stream->inspect_payload = inspect_payload;
3092 GST_WARNING_OBJECT (demux, "Unexpected end of data parsing stream object");
3093 /* we'll error out later if we found no streams */
3098 static const gchar *
3099 gst_asf_demux_get_gst_tag_from_tag_name (const gchar * name_utf8)
3103 const gchar *asf_name;
3104 const gchar *gst_name;
3107 "WM/Genre", GST_TAG_GENRE}, {
3108 "WM/AlbumTitle", GST_TAG_ALBUM}, {
3109 "WM/AlbumArtist", GST_TAG_ARTIST}, {
3110 "WM/Picture", GST_TAG_IMAGE}, {
3111 "WM/Track", GST_TAG_TRACK_NUMBER}, {
3112 "WM/TrackNumber", GST_TAG_TRACK_NUMBER}, {
3113 "WM/Year", GST_TAG_DATE_TIME}
3114 /* { "WM/Composer", GST_TAG_COMPOSER } */
3119 if (name_utf8 == NULL) {
3120 GST_WARNING ("Failed to convert name to UTF8, skipping");
3124 out = strlen (name_utf8);
3126 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
3127 if (strncmp (tags[i].asf_name, name_utf8, out) == 0) {
3128 GST_LOG ("map tagname '%s' -> '%s'", name_utf8, tags[i].gst_name);
3129 return tags[i].gst_name;
3136 /* gst_asf_demux_add_global_tags() takes ownership of taglist! */
3138 gst_asf_demux_add_global_tags (GstASFDemux * demux, GstTagList * taglist)
3142 GST_DEBUG_OBJECT (demux, "adding global tags: %" GST_PTR_FORMAT, taglist);
3144 if (taglist == NULL)
3147 if (gst_tag_list_is_empty (taglist)) {
3148 gst_tag_list_unref (taglist);
3152 t = gst_tag_list_merge (demux->taglist, taglist, GST_TAG_MERGE_APPEND);
3153 gst_tag_list_set_scope (t, GST_TAG_SCOPE_GLOBAL);
3155 gst_tag_list_unref (demux->taglist);
3156 gst_tag_list_unref (taglist);
3158 GST_LOG_OBJECT (demux, "global tags now: %" GST_PTR_FORMAT, demux->taglist);
3161 #define ASF_DEMUX_DATA_TYPE_UTF16LE_STRING 0
3162 #define ASF_DEMUX_DATA_TYPE_BYTE_ARRAY 1
3163 #define ASF_DEMUX_DATA_TYPE_BOOL 2
3164 #define ASF_DEMUX_DATA_TYPE_DWORD 3
3167 asf_demux_parse_picture_tag (GstTagList * tags, const guint8 * tag_data,
3171 const guint8 *img_data = NULL;
3172 guint32 img_data_len = 0;
3173 guint8 pic_type = 0;
3175 gst_byte_reader_init (&r, tag_data, tag_data_len);
3177 /* skip mime type string (we don't trust it and do our own typefinding),
3178 * and also skip the description string, since we don't use it */
3179 if (!gst_byte_reader_get_uint8 (&r, &pic_type) ||
3180 !gst_byte_reader_get_uint32_le (&r, &img_data_len) ||
3181 !gst_byte_reader_skip_string_utf16 (&r) ||
3182 !gst_byte_reader_skip_string_utf16 (&r) ||
3183 !gst_byte_reader_get_data (&r, img_data_len, &img_data)) {
3184 goto not_enough_data;
3188 if (!gst_tag_list_add_id3_image (tags, img_data, img_data_len, pic_type))
3189 GST_DEBUG ("failed to add image extracted from WM/Picture tag to taglist");
3195 GST_DEBUG ("Failed to read WM/Picture tag: not enough data");
3196 GST_MEMDUMP ("WM/Picture data", tag_data, tag_data_len);
3201 /* Extended Content Description Object */
3202 static GstFlowReturn
3203 gst_asf_demux_process_ext_content_desc (GstASFDemux * demux, guint8 * data,
3206 /* Other known (and unused) 'text/unicode' metadata available :
3209 * WM/MediaPrimaryClassID = {D1607DBC-E323-4BE2-86A1-48A42A28441E}
3210 * WMFSDKVersion = 9.00.00.2980
3211 * WMFSDKNeeded = 0.0.0.0000
3212 * WM/UniqueFileIdentifier = AMGa_id=R 15334;AMGp_id=P 5149;AMGt_id=T 2324984
3213 * WM/Publisher = 4AD
3215 * WM/ProviderRating = 8
3216 * WM/ProviderStyle = Rock (similar to WM/Genre)
3217 * WM/GenreID (similar to WM/Genre)
3218 * WM/TrackNumber (same as WM/Track but as a string)
3220 * Other known (and unused) 'non-text' metadata available :
3226 * We might want to read WM/TrackNumber and use atoi() if we don't have
3230 GstTagList *taglist;
3231 guint16 blockcount, i;
3232 gboolean content3D = FALSE;
3236 const gchar *interleave_name;
3237 GstASF3DMode interleaving_type;
3238 } stereoscopic_layout_map[] = {
3240 "SideBySideRF", GST_ASF_3D_SIDE_BY_SIDE_HALF_RL}, {
3241 "SideBySideLF", GST_ASF_3D_SIDE_BY_SIDE_HALF_LR}, {
3242 "OverUnderRT", GST_ASF_3D_TOP_AND_BOTTOM_HALF_RL}, {
3243 "OverUnderLT", GST_ASF_3D_TOP_AND_BOTTOM_HALF_LR}, {
3244 "DualStream", GST_ASF_3D_DUAL_STREAM}
3246 GST_INFO_OBJECT (demux, "object is an extended content description");
3248 taglist = gst_tag_list_new_empty ();
3250 /* Content Descriptor Count */
3252 goto not_enough_data;
3254 blockcount = gst_asf_demux_get_uint16 (&data, &size);
3256 for (i = 1; i <= blockcount; ++i) {
3257 const gchar *gst_tag_name;
3261 GValue tag_value = { 0, };
3264 gchar *name_utf8 = NULL;
3268 if (!gst_asf_demux_get_string (&name, &name_len, &data, &size))
3269 goto not_enough_data;
3273 goto not_enough_data;
3275 /* Descriptor Value Data Type */
3276 datatype = gst_asf_demux_get_uint16 (&data, &size);
3278 /* Descriptor Value (not really a string, but same thing reading-wise) */
3279 if (!gst_asf_demux_get_string (&value, &value_len, &data, &size)) {
3281 goto not_enough_data;
3285 g_convert (name, name_len, "UTF-8", "UTF-16LE", &in, &out, NULL);
3287 if (name_utf8 != NULL) {
3288 GST_DEBUG ("Found tag/metadata %s", name_utf8);
3290 gst_tag_name = gst_asf_demux_get_gst_tag_from_tag_name (name_utf8);
3291 GST_DEBUG ("gst_tag_name %s", GST_STR_NULL (gst_tag_name));
3294 case ASF_DEMUX_DATA_TYPE_UTF16LE_STRING:{
3297 value_utf8 = g_convert (value, value_len, "UTF-8", "UTF-16LE",
3300 /* get rid of tags with empty value */
3301 if (value_utf8 != NULL && *value_utf8 != '\0') {
3302 GST_DEBUG ("string value %s", value_utf8);
3304 value_utf8[out] = '\0';
3306 if (gst_tag_name != NULL) {
3307 if (strcmp (gst_tag_name, GST_TAG_DATE_TIME) == 0) {
3308 guint year = atoi (value_utf8);
3311 g_value_init (&tag_value, GST_TYPE_DATE_TIME);
3312 g_value_take_boxed (&tag_value, gst_date_time_new_y (year));
3314 } else if (strcmp (gst_tag_name, GST_TAG_GENRE) == 0) {
3315 guint id3v1_genre_id;
3316 const gchar *genre_str;
3318 if (sscanf (value_utf8, "(%u)", &id3v1_genre_id) == 1 &&
3319 ((genre_str = gst_tag_id3_genre_get (id3v1_genre_id)))) {
3320 GST_DEBUG ("Genre: %s -> %s", value_utf8, genre_str);
3321 g_free (value_utf8);
3322 value_utf8 = g_strdup (genre_str);
3327 /* convert tag from string to other type if required */
3328 tag_type = gst_tag_get_type (gst_tag_name);
3329 g_value_init (&tag_value, tag_type);
3330 if (!gst_value_deserialize (&tag_value, value_utf8)) {
3331 GValue from_val = { 0, };
3333 g_value_init (&from_val, G_TYPE_STRING);
3334 g_value_set_string (&from_val, value_utf8);
3335 if (!g_value_transform (&from_val, &tag_value)) {
3336 GST_WARNING_OBJECT (demux,
3337 "Could not transform string tag to " "%s tag type %s",
3338 gst_tag_name, g_type_name (tag_type));
3339 g_value_unset (&tag_value);
3341 g_value_unset (&from_val);
3346 GST_DEBUG ("Setting metadata");
3347 g_value_init (&tag_value, G_TYPE_STRING);
3348 g_value_set_string (&tag_value, value_utf8);
3349 /* If we found a stereoscopic marker, look for StereoscopicLayout
3353 if (strncmp ("StereoscopicLayout", name_utf8,
3354 strlen (name_utf8)) == 0) {
3355 for (i = 0; i < G_N_ELEMENTS (stereoscopic_layout_map); i++) {
3356 if (g_str_equal (stereoscopic_layout_map[i].interleave_name,
3358 demux->asf_3D_mode =
3359 stereoscopic_layout_map[i].interleaving_type;
3360 GST_INFO ("find interleave type %u", demux->asf_3D_mode);
3364 GST_INFO_OBJECT (demux, "3d type is %u", demux->asf_3D_mode);
3366 demux->asf_3D_mode = GST_ASF_3D_NONE;
3367 GST_INFO_OBJECT (demux, "None 3d type");
3370 } else if (value_utf8 == NULL) {
3371 GST_WARNING ("Failed to convert string value to UTF8, skipping");
3373 GST_DEBUG ("Skipping empty string value for %s",
3374 GST_STR_NULL (gst_tag_name));
3376 g_free (value_utf8);
3379 case ASF_DEMUX_DATA_TYPE_BYTE_ARRAY:{
3381 if (!g_str_equal (gst_tag_name, GST_TAG_IMAGE)) {
3382 GST_FIXME ("Unhandled byte array tag %s",
3383 GST_STR_NULL (gst_tag_name));
3386 asf_demux_parse_picture_tag (taglist, (guint8 *) value,
3392 case ASF_DEMUX_DATA_TYPE_DWORD:{
3393 guint uint_val = GST_READ_UINT32_LE (value);
3395 /* this is the track number */
3396 g_value_init (&tag_value, G_TYPE_UINT);
3398 /* WM/Track counts from 0 */
3399 if (!strcmp (name_utf8, "WM/Track"))
3402 g_value_set_uint (&tag_value, uint_val);
3406 case ASF_DEMUX_DATA_TYPE_BOOL:{
3407 gboolean bool_val = GST_READ_UINT32_LE (value);
3409 if (strncmp ("Stereoscopic", name_utf8, strlen (name_utf8)) == 0) {
3411 GST_INFO_OBJECT (demux, "This is 3D contents");
3414 GST_INFO_OBJECT (demux, "This is not 3D contenst");
3422 GST_DEBUG ("Skipping tag %s of type %d", gst_tag_name, datatype);
3427 if (G_IS_VALUE (&tag_value)) {
3429 GstTagMergeMode merge_mode = GST_TAG_MERGE_APPEND;
3431 /* WM/TrackNumber is more reliable than WM/Track, since the latter
3432 * is supposed to have a 0 base but is often wrongly written to start
3433 * from 1 as well, so prefer WM/TrackNumber when we have it: either
3434 * replace the value added earlier from WM/Track or put it first in
3435 * the list, so that it will get picked up by _get_uint() */
3436 if (strcmp (name_utf8, "WM/TrackNumber") == 0)
3437 merge_mode = GST_TAG_MERGE_REPLACE;
3439 gst_tag_list_add_values (taglist, merge_mode, gst_tag_name,
3442 GST_DEBUG ("Setting global metadata %s", name_utf8);
3443 gst_structure_set_value (demux->global_metadata, name_utf8,
3447 g_value_unset (&tag_value);
3456 gst_asf_demux_add_global_tags (demux, taglist);
3463 GST_WARNING ("Unexpected end of data parsing ext content desc object");
3464 gst_tag_list_unref (taglist);
3465 return GST_FLOW_OK; /* not really fatal */
3469 static GstStructure *
3470 gst_asf_demux_get_metadata_for_stream (GstASFDemux * demux, guint stream_num)
3475 g_snprintf (sname, sizeof (sname), "stream-%u", stream_num);
3477 for (i = 0; i < gst_caps_get_size (demux->metadata); ++i) {
3480 s = gst_caps_get_structure (demux->metadata, i);
3481 if (gst_structure_has_name (s, sname))
3485 gst_caps_append_structure (demux->metadata, gst_structure_new_empty (sname));
3487 /* try lookup again; demux->metadata took ownership of the structure, so we
3488 * can't really make any assumptions about what happened to it, so we can't
3489 * just return it directly after appending it */
3490 return gst_asf_demux_get_metadata_for_stream (demux, stream_num);
3493 static GstFlowReturn
3494 gst_asf_demux_process_metadata (GstASFDemux * demux, guint8 * data,
3497 guint16 blockcount, i;
3499 GST_INFO_OBJECT (demux, "object is a metadata object");
3501 /* Content Descriptor Count */
3503 goto not_enough_data;
3505 blockcount = gst_asf_demux_get_uint16 (&data, &size);
3507 for (i = 0; i < blockcount; ++i) {
3509 guint16 stream_num, name_len, data_type, lang_idx G_GNUC_UNUSED;
3510 guint32 data_len, ival;
3513 if (size < (2 + 2 + 2 + 2 + 4))
3514 goto not_enough_data;
3516 lang_idx = gst_asf_demux_get_uint16 (&data, &size);
3517 stream_num = gst_asf_demux_get_uint16 (&data, &size);
3518 name_len = gst_asf_demux_get_uint16 (&data, &size);
3519 data_type = gst_asf_demux_get_uint16 (&data, &size);
3520 data_len = gst_asf_demux_get_uint32 (&data, &size);
3522 if (size < name_len + data_len)
3523 goto not_enough_data;
3525 /* convert name to UTF-8 */
3526 name_utf8 = g_convert ((gchar *) data, name_len, "UTF-8", "UTF-16LE",
3528 gst_asf_demux_skip_bytes (name_len, &data, &size);
3530 if (name_utf8 == NULL) {
3531 GST_WARNING ("Failed to convert value name to UTF8, skipping");
3532 gst_asf_demux_skip_bytes (data_len, &data, &size);
3536 if (data_type != ASF_DEMUX_DATA_TYPE_DWORD) {
3537 gst_asf_demux_skip_bytes (data_len, &data, &size);
3545 goto not_enough_data;
3548 ival = gst_asf_demux_get_uint32 (&data, &size);
3550 /* skip anything else there may be, just in case */
3551 gst_asf_demux_skip_bytes (data_len - 4, &data, &size);
3553 s = gst_asf_demux_get_metadata_for_stream (demux, stream_num);
3554 gst_structure_set (s, name_utf8, G_TYPE_INT, ival, NULL);
3558 GST_INFO_OBJECT (demux, "metadata = %" GST_PTR_FORMAT, demux->metadata);
3564 GST_WARNING ("Unexpected end of data parsing metadata object");
3565 return GST_FLOW_OK; /* not really fatal */
3569 static GstFlowReturn
3570 gst_asf_demux_process_header (GstASFDemux * demux, guint8 * data, guint64 size)
3572 GstFlowReturn ret = GST_FLOW_OK;
3573 guint32 i, num_objects;
3574 guint8 unknown G_GNUC_UNUSED;
3576 /* Get the rest of the header's header */
3577 if (size < (4 + 1 + 1))
3578 goto not_enough_data;
3580 num_objects = gst_asf_demux_get_uint32 (&data, &size);
3581 unknown = gst_asf_demux_get_uint8 (&data, &size);
3582 unknown = gst_asf_demux_get_uint8 (&data, &size);
3584 GST_INFO_OBJECT (demux, "object is a header with %u parts", num_objects);
3585 demux->saw_file_header = FALSE;
3586 /* Loop through the header's objects, processing those */
3587 for (i = 0; i < num_objects; ++i) {
3588 GST_INFO_OBJECT (demux, "reading header part %u", i);
3589 ret = gst_asf_demux_process_object (demux, &data, &size);
3590 if (ret != GST_FLOW_OK) {
3591 GST_WARNING ("process_object returned %s", gst_asf_get_flow_name (ret));
3595 if (!demux->saw_file_header) {
3596 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3597 ("Header does not have mandatory FILE section"));
3598 return GST_FLOW_ERROR;
3605 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3606 ("short read parsing HEADER object"));
3607 return GST_FLOW_ERROR;
3611 static GstFlowReturn
3612 gst_asf_demux_process_file (GstASFDemux * demux, guint8 * data, guint64 size)
3614 guint64 creation_time G_GNUC_UNUSED;
3615 guint64 file_size G_GNUC_UNUSED;
3616 guint64 send_time G_GNUC_UNUSED;
3617 guint64 packets_count, play_time, preroll;
3618 guint32 flags, min_pktsize, max_pktsize, min_bitrate G_GNUC_UNUSED;
3620 if (size < (16 + 8 + 8 + 8 + 8 + 8 + 8 + 4 + 4 + 4 + 4))
3621 goto not_enough_data;
3623 gst_asf_demux_skip_bytes (16, &data, &size); /* skip GUID */
3624 file_size = gst_asf_demux_get_uint64 (&data, &size);
3625 creation_time = gst_asf_demux_get_uint64 (&data, &size);
3626 packets_count = gst_asf_demux_get_uint64 (&data, &size);
3627 play_time = gst_asf_demux_get_uint64 (&data, &size);
3628 send_time = gst_asf_demux_get_uint64 (&data, &size);
3629 preroll = gst_asf_demux_get_uint64 (&data, &size);
3630 flags = gst_asf_demux_get_uint32 (&data, &size);
3631 min_pktsize = gst_asf_demux_get_uint32 (&data, &size);
3632 max_pktsize = gst_asf_demux_get_uint32 (&data, &size);
3633 min_bitrate = gst_asf_demux_get_uint32 (&data, &size);
3635 demux->broadcast = ! !(flags & 0x01);
3636 demux->seekable = ! !(flags & 0x02);
3638 GST_DEBUG_OBJECT (demux, "min_pktsize = %u", min_pktsize);
3639 GST_DEBUG_OBJECT (demux, "flags::broadcast = %d", demux->broadcast);
3640 GST_DEBUG_OBJECT (demux, "flags::seekable = %d", demux->seekable);
3642 if (demux->broadcast) {
3643 /* these fields are invalid if the broadcast flag is set */
3648 if (min_pktsize != max_pktsize)
3649 goto non_fixed_packet_size;
3651 demux->packet_size = max_pktsize;
3653 /* FIXME: do we need send_time as well? what is it? */
3654 if ((play_time * 100) >= (preroll * GST_MSECOND))
3655 demux->play_time = (play_time * 100) - (preroll * GST_MSECOND);
3657 demux->play_time = 0;
3659 demux->preroll = preroll * GST_MSECOND;
3661 /* initial latency */
3662 demux->latency = demux->preroll;
3664 if (demux->play_time == 0)
3665 demux->seekable = FALSE;
3667 GST_DEBUG_OBJECT (demux, "play_time %" GST_TIME_FORMAT,
3668 GST_TIME_ARGS (demux->play_time));
3669 GST_DEBUG_OBJECT (demux, "preroll %" GST_TIME_FORMAT,
3670 GST_TIME_ARGS (demux->preroll));
3672 if (demux->play_time > 0) {
3673 demux->segment.duration = demux->play_time;
3676 GST_INFO ("object is a file with %" G_GUINT64_FORMAT " data packets",
3678 GST_INFO ("preroll = %" G_GUINT64_FORMAT, demux->preroll);
3680 demux->saw_file_header = TRUE;
3685 non_fixed_packet_size:
3687 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3688 ("packet size must be fixed"));
3689 return GST_FLOW_ERROR;
3693 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3694 ("short read parsing FILE object"));
3695 return GST_FLOW_ERROR;
3699 /* Content Description Object */
3700 static GstFlowReturn
3701 gst_asf_demux_process_comment (GstASFDemux * demux, guint8 * data, guint64 size)
3705 const gchar *gst_tag;
3710 GST_TAG_TITLE, 0, NULL}, {
3711 GST_TAG_ARTIST, 0, NULL}, {
3712 GST_TAG_COPYRIGHT, 0, NULL}, {
3713 GST_TAG_DESCRIPTION, 0, NULL}, {
3714 GST_TAG_COMMENT, 0, NULL}
3716 GstTagList *taglist;
3717 GValue value = { 0 };
3721 GST_INFO_OBJECT (demux, "object is a comment");
3723 if (size < (2 + 2 + 2 + 2 + 2))
3724 goto not_enough_data;
3726 tags[0].val_length = gst_asf_demux_get_uint16 (&data, &size);
3727 tags[1].val_length = gst_asf_demux_get_uint16 (&data, &size);
3728 tags[2].val_length = gst_asf_demux_get_uint16 (&data, &size);
3729 tags[3].val_length = gst_asf_demux_get_uint16 (&data, &size);
3730 tags[4].val_length = gst_asf_demux_get_uint16 (&data, &size);
3732 GST_DEBUG_OBJECT (demux, "Comment lengths: title=%d author=%d copyright=%d "
3733 "description=%d rating=%d", tags[0].val_length, tags[1].val_length,
3734 tags[2].val_length, tags[3].val_length, tags[4].val_length);
3736 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
3737 if (size < tags[i].val_length)
3738 goto not_enough_data;
3740 /* might be just '/0', '/0'... */
3741 if (tags[i].val_length > 2 && tags[i].val_length % 2 == 0) {
3742 /* convert to UTF-8 */
3743 tags[i].val_utf8 = g_convert ((gchar *) data, tags[i].val_length,
3744 "UTF-8", "UTF-16LE", &in, &out, NULL);
3746 gst_asf_demux_skip_bytes (tags[i].val_length, &data, &size);
3749 /* parse metadata into taglist */
3750 taglist = gst_tag_list_new_empty ();
3751 g_value_init (&value, G_TYPE_STRING);
3752 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
3753 if (tags[i].val_utf8 && strlen (tags[i].val_utf8) > 0 && tags[i].gst_tag) {
3754 g_value_set_string (&value, tags[i].val_utf8);
3755 gst_tag_list_add_values (taglist, GST_TAG_MERGE_APPEND,
3756 tags[i].gst_tag, &value, NULL);
3759 g_value_unset (&value);
3761 gst_asf_demux_add_global_tags (demux, taglist);
3763 for (i = 0; i < G_N_ELEMENTS (tags); ++i)
3764 g_free (tags[i].val_utf8);
3770 GST_WARNING_OBJECT (demux, "unexpectedly short of data while processing "
3771 "comment tag section %d, skipping comment object", i);
3772 for (i = 0; i < G_N_ELEMENTS (tags); i++)
3773 g_free (tags[i].val_utf8);
3774 return GST_FLOW_OK; /* not really fatal */
3778 static GstFlowReturn
3779 gst_asf_demux_process_bitrate_props_object (GstASFDemux * demux, guint8 * data,
3782 guint16 num_streams, i;
3786 goto not_enough_data;
3788 num_streams = gst_asf_demux_get_uint16 (&data, &size);
3790 GST_INFO ("object is a bitrate properties object with %u streams",
3793 if (size < (num_streams * (2 + 4)))
3794 goto not_enough_data;
3796 for (i = 0; i < num_streams; ++i) {
3800 stream_id = gst_asf_demux_get_uint16 (&data, &size);
3801 bitrate = gst_asf_demux_get_uint32 (&data, &size);
3803 if (stream_id < GST_ASF_DEMUX_NUM_STREAM_IDS) {
3804 GST_DEBUG_OBJECT (demux, "bitrate of stream %u = %u", stream_id, bitrate);
3805 stream = gst_asf_demux_get_stream (demux, stream_id);
3807 if (stream->pending_tags == NULL)
3808 stream->pending_tags = gst_tag_list_new_empty ();
3809 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
3810 GST_TAG_BITRATE, bitrate, NULL);
3812 GST_WARNING_OBJECT (demux, "Stream id %u wasn't found", stream_id);
3815 GST_WARNING ("stream id %u is too large", stream_id);
3823 GST_WARNING_OBJECT (demux, "short read parsing bitrate props object!");
3824 return GST_FLOW_OK; /* not really fatal */
3828 static GstFlowReturn
3829 gst_asf_demux_process_header_ext (GstASFDemux * demux, guint8 * data,
3832 GstFlowReturn ret = GST_FLOW_OK;
3835 /* Get the rest of the header's header */
3836 if (size < (16 + 2 + 4))
3837 goto not_enough_data;
3839 /* skip GUID and two other bytes */
3840 gst_asf_demux_skip_bytes (16 + 2, &data, &size);
3841 hdr_size = gst_asf_demux_get_uint32 (&data, &size);
3843 GST_INFO ("extended header object with a size of %u bytes", (guint) size);
3845 /* FIXME: does data_size include the rest of the header that we have read? */
3846 if (hdr_size > size)
3847 goto not_enough_data;
3849 while (hdr_size > 0) {
3850 ret = gst_asf_demux_process_object (demux, &data, &hdr_size);
3851 if (ret != GST_FLOW_OK)
3859 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3860 ("short read parsing extended header object"));
3861 return GST_FLOW_ERROR;
3865 static GstFlowReturn
3866 gst_asf_demux_process_language_list (GstASFDemux * demux, guint8 * data,
3872 goto not_enough_data;
3874 if (demux->languages) {
3875 GST_WARNING ("More than one LANGUAGE_LIST object in stream");
3876 g_strfreev (demux->languages);
3877 demux->languages = NULL;
3878 demux->num_languages = 0;
3881 demux->num_languages = gst_asf_demux_get_uint16 (&data, &size);
3882 GST_LOG ("%u languages:", demux->num_languages);
3884 demux->languages = g_new0 (gchar *, demux->num_languages + 1);
3885 for (i = 0; i < demux->num_languages; ++i) {
3886 guint8 len, *lang_data = NULL;
3889 goto not_enough_data;
3890 len = gst_asf_demux_get_uint8 (&data, &size);
3891 if (gst_asf_demux_get_bytes (&lang_data, len, &data, &size)) {
3894 utf8 = g_convert ((gchar *) lang_data, len, "UTF-8", "UTF-16LE", NULL,
3897 /* truncate "en-us" etc. to just "en" */
3898 if (utf8 && strlen (utf8) >= 5 && (utf8[2] == '-' || utf8[2] == '_')) {
3901 GST_DEBUG ("[%u] %s", i, GST_STR_NULL (utf8));
3902 demux->languages[i] = utf8;
3905 goto not_enough_data;
3913 GST_WARNING_OBJECT (demux, "short read parsing language list object!");
3914 g_free (demux->languages);
3915 demux->languages = NULL;
3916 return GST_FLOW_OK; /* not fatal */
3920 static GstFlowReturn
3921 gst_asf_demux_process_simple_index (GstASFDemux * demux, guint8 * data,
3924 GstClockTime interval;
3927 if (size < (16 + 8 + 4 + 4))
3928 goto not_enough_data;
3931 gst_asf_demux_skip_bytes (16, &data, &size);
3932 interval = gst_asf_demux_get_uint64 (&data, &size) * (GstClockTime) 100;
3933 gst_asf_demux_skip_bytes (4, &data, &size);
3934 count = gst_asf_demux_get_uint32 (&data, &size);
3936 demux->sidx_interval = interval;
3937 demux->sidx_num_entries = count;
3938 g_free (demux->sidx_entries);
3939 demux->sidx_entries = g_new0 (AsfSimpleIndexEntry, count);
3941 for (i = 0; i < count; ++i) {
3942 if (G_UNLIKELY (size < 6)) {
3943 /* adjust for broken files, to avoid having entries at the end
3944 * of the parsed index that point to time=0. Resulting in seeking to
3945 * the end of the file leading back to the beginning */
3946 demux->sidx_num_entries -= (count - i);
3949 demux->sidx_entries[i].packet = gst_asf_demux_get_uint32 (&data, &size);
3950 demux->sidx_entries[i].count = gst_asf_demux_get_uint16 (&data, &size);
3951 GST_LOG_OBJECT (demux, "%" GST_TIME_FORMAT " = packet %4u count : %2d",
3952 GST_TIME_ARGS (i * interval), demux->sidx_entries[i].packet,
3953 demux->sidx_entries[i].count);
3956 GST_DEBUG_OBJECT (demux, "simple index object with 0 entries");
3963 GST_WARNING_OBJECT (demux, "short read parsing simple index object!");
3964 return GST_FLOW_OK; /* not fatal */
3968 static GstFlowReturn
3969 gst_asf_demux_process_advanced_mutual_exclusion (GstASFDemux * demux,
3970 guint8 * data, guint64 size)
3975 if (size < 16 + 2 + (2 * 2))
3976 goto not_enough_data;
3978 gst_asf_demux_get_guid (&guid, &data, &size);
3979 num = gst_asf_demux_get_uint16 (&data, &size);
3982 GST_WARNING_OBJECT (demux, "nonsensical mutually exclusive streams count");
3986 if (size < (num * sizeof (guint16)))
3987 goto not_enough_data;
3989 /* read mutually exclusive stream numbers */
3990 for (i = 0; i < num; ++i) {
3992 mes = gst_asf_demux_get_uint16 (&data, &size) & 0x7f;
3993 GST_LOG_OBJECT (demux, "mutually exclusive: stream %d", mes);
3995 demux->mut_ex_streams =
3996 g_slist_append (demux->mut_ex_streams, GINT_TO_POINTER (mes));
4005 GST_WARNING_OBJECT (demux, "short read parsing advanced mutual exclusion");
4006 return GST_FLOW_OK; /* not absolutely fatal */
4011 gst_asf_demux_is_unknown_stream (GstASFDemux * demux, guint stream_num)
4013 return g_slist_find (demux->other_streams,
4014 GINT_TO_POINTER (stream_num)) == NULL;
4017 static GstFlowReturn
4018 gst_asf_demux_process_ext_stream_props (GstASFDemux * demux, guint8 * data,
4021 AsfStreamExtProps esp;
4022 AsfStream *stream = NULL;
4023 AsfObject stream_obj;
4024 guint16 stream_name_count;
4025 guint16 num_payload_ext;
4027 guint8 *stream_obj_data = NULL;
4030 guint i, stream_num;
4033 obj_size = (guint) size;
4036 goto not_enough_data;
4039 esp.start_time = gst_asf_demux_get_uint64 (&data, &size) * GST_MSECOND;
4040 esp.end_time = gst_asf_demux_get_uint64 (&data, &size) * GST_MSECOND;
4041 esp.data_bitrate = gst_asf_demux_get_uint32 (&data, &size);
4042 esp.buffer_size = gst_asf_demux_get_uint32 (&data, &size);
4043 esp.intial_buf_fullness = gst_asf_demux_get_uint32 (&data, &size);
4044 esp.data_bitrate2 = gst_asf_demux_get_uint32 (&data, &size);
4045 esp.buffer_size2 = gst_asf_demux_get_uint32 (&data, &size);
4046 esp.intial_buf_fullness2 = gst_asf_demux_get_uint32 (&data, &size);
4047 esp.max_obj_size = gst_asf_demux_get_uint32 (&data, &size);
4048 esp.flags = gst_asf_demux_get_uint32 (&data, &size);
4049 stream_num = gst_asf_demux_get_uint16 (&data, &size);
4050 esp.lang_idx = gst_asf_demux_get_uint16 (&data, &size);
4051 esp.avg_time_per_frame = gst_asf_demux_get_uint64 (&data, &size);
4052 stream_name_count = gst_asf_demux_get_uint16 (&data, &size);
4053 num_payload_ext = gst_asf_demux_get_uint16 (&data, &size);
4055 GST_INFO ("start_time = %" GST_TIME_FORMAT,
4056 GST_TIME_ARGS (esp.start_time));
4057 GST_INFO ("end_time = %" GST_TIME_FORMAT,
4058 GST_TIME_ARGS (esp.end_time));
4059 GST_INFO ("flags = %08x", esp.flags);
4060 GST_INFO ("average time per frame = %" GST_TIME_FORMAT,
4061 GST_TIME_ARGS (esp.avg_time_per_frame * 100));
4062 GST_INFO ("stream number = %u", stream_num);
4063 GST_INFO ("stream language ID idx = %u (%s)", esp.lang_idx,
4064 (esp.lang_idx < demux->num_languages) ?
4065 GST_STR_NULL (demux->languages[esp.lang_idx]) : "??");
4066 GST_INFO ("stream name count = %u", stream_name_count);
4068 /* read stream names */
4069 for (i = 0; i < stream_name_count; ++i) {
4070 guint16 stream_lang_idx G_GNUC_UNUSED;
4071 gchar *stream_name = NULL;
4074 goto not_enough_data;
4075 stream_lang_idx = gst_asf_demux_get_uint16 (&data, &size);
4076 if (!gst_asf_demux_get_string (&stream_name, NULL, &data, &size))
4077 goto not_enough_data;
4078 GST_INFO ("stream name %d: %s", i, GST_STR_NULL (stream_name));
4079 g_free (stream_name); /* TODO: store names in struct */
4082 /* read payload extension systems stuff */
4083 GST_LOG ("payload extension systems count = %u", num_payload_ext);
4085 if (num_payload_ext > 0)
4086 esp.payload_extensions = g_new0 (AsfPayloadExtension, num_payload_ext + 1);
4088 esp.payload_extensions = NULL;
4090 for (i = 0; i < num_payload_ext; ++i) {
4091 AsfPayloadExtension ext;
4093 guint32 sys_info_len;
4095 if (size < 16 + 2 + 4)
4096 goto not_enough_data;
4098 gst_asf_demux_get_guid (&ext_guid, &data, &size);
4099 ext.id = gst_asf_demux_identify_guid (asf_payload_ext_guids, &ext_guid);
4100 ext.len = gst_asf_demux_get_uint16 (&data, &size);
4102 sys_info_len = gst_asf_demux_get_uint32 (&data, &size);
4103 GST_LOG ("payload systems info len = %u", sys_info_len);
4104 if (!gst_asf_demux_skip_bytes (sys_info_len, &data, &size))
4105 goto not_enough_data;
4107 esp.payload_extensions[i] = ext;
4110 GST_LOG ("bytes read: %u/%u", (guint) (data - data_start), obj_size);
4112 /* there might be an optional STREAM_INFO object here now; if not, we
4113 * should have parsed the corresponding stream info object already (since
4114 * we are parsing the extended stream properties objects delayed) */
4116 stream = gst_asf_demux_get_stream (demux, stream_num);
4120 /* get size of the stream object */
4121 if (!asf_demux_peek_object (demux, data, size, &stream_obj, TRUE))
4122 goto not_enough_data;
4124 if (stream_obj.id != ASF_OBJ_STREAM)
4125 goto expected_stream_object;
4127 if (stream_obj.size < ASF_OBJECT_HEADER_SIZE ||
4128 stream_obj.size > (10 * 1024 * 1024))
4129 goto not_enough_data;
4131 gst_asf_demux_skip_bytes (ASF_OBJECT_HEADER_SIZE, &data, &size);
4133 /* process this stream object later after all the other 'normal' ones
4134 * have been processed (since the others are more important/non-hidden) */
4135 len = stream_obj.size - ASF_OBJECT_HEADER_SIZE;
4136 if (!gst_asf_demux_get_bytes (&stream_obj_data, len, &data, &size))
4137 goto not_enough_data;
4139 /* parse stream object */
4140 stream = gst_asf_demux_parse_stream_object (demux, stream_obj_data, len);
4141 g_free (stream_obj_data);
4146 stream->ext_props = esp;
4148 /* try to set the framerate */
4149 if (stream->is_video && stream->caps) {
4150 GValue framerate = { 0 };
4154 g_value_init (&framerate, GST_TYPE_FRACTION);
4156 num = GST_SECOND / 100;
4157 denom = esp.avg_time_per_frame;
4159 /* avoid division by 0, assume 25/1 framerate */
4160 denom = GST_SECOND / 2500;
4163 gst_value_set_fraction (&framerate, num, denom);
4165 stream->caps = gst_caps_make_writable (stream->caps);
4166 s = gst_caps_get_structure (stream->caps, 0);
4167 gst_structure_set_value (s, "framerate", &framerate);
4168 g_value_unset (&framerate);
4169 GST_DEBUG_OBJECT (demux, "setting framerate of %d/%d = %f",
4170 num, denom, ((gdouble) num) / denom);
4173 /* add language info now if we have it */
4174 if (stream->ext_props.lang_idx < demux->num_languages) {
4175 if (stream->pending_tags == NULL)
4176 stream->pending_tags = gst_tag_list_new_empty ();
4177 GST_LOG_OBJECT (demux, "stream %u has language '%s'", stream->id,
4178 demux->languages[stream->ext_props.lang_idx]);
4179 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_APPEND,
4180 GST_TAG_LANGUAGE_CODE, demux->languages[stream->ext_props.lang_idx],
4183 } else if (gst_asf_demux_is_unknown_stream (demux, stream_num)) {
4184 GST_WARNING_OBJECT (demux, "Ext. stream properties for unknown stream");
4192 GST_WARNING_OBJECT (demux, "short read parsing ext stream props object!");
4193 return GST_FLOW_OK; /* not absolutely fatal */
4195 expected_stream_object:
4197 GST_WARNING_OBJECT (demux, "error parsing extended stream properties "
4198 "object: expected embedded stream object, but got %s object instead!",
4199 gst_asf_get_guid_nick (asf_object_guids, stream_obj.id));
4200 return GST_FLOW_OK; /* not absolutely fatal */
4204 static const gchar *
4205 gst_asf_demux_push_obj (GstASFDemux * demux, guint32 obj_id)
4209 nick = gst_asf_get_guid_nick (asf_object_guids, obj_id);
4210 if (g_str_has_prefix (nick, "ASF_OBJ_"))
4211 nick += strlen ("ASF_OBJ_");
4213 if (demux->objpath == NULL) {
4214 demux->objpath = g_strdup (nick);
4218 newpath = g_strdup_printf ("%s/%s", demux->objpath, nick);
4219 g_free (demux->objpath);
4220 demux->objpath = newpath;
4223 return (const gchar *) demux->objpath;
4227 gst_asf_demux_pop_obj (GstASFDemux * demux)
4231 if ((s = g_strrstr (demux->objpath, "/"))) {
4234 g_free (demux->objpath);
4235 demux->objpath = NULL;
4240 gst_asf_demux_process_queued_extended_stream_objects (GstASFDemux * demux)
4245 /* Parse the queued extended stream property objects and add the info
4246 * to the existing streams or add the new embedded streams, but without
4247 * activating them yet */
4248 GST_LOG_OBJECT (demux, "%u queued extended stream properties objects",
4249 g_slist_length (demux->ext_stream_props));
4251 for (l = demux->ext_stream_props, i = 0; l != NULL; l = l->next, ++i) {
4252 GstBuffer *buf = GST_BUFFER (l->data);
4255 gst_buffer_map (buf, &map, GST_MAP_READ);
4257 GST_LOG_OBJECT (demux, "parsing ext. stream properties object #%u", i);
4258 gst_asf_demux_process_ext_stream_props (demux, map.data, map.size);
4259 gst_buffer_unmap (buf, &map);
4260 gst_buffer_unref (buf);
4262 g_slist_free (demux->ext_stream_props);
4263 demux->ext_stream_props = NULL;
4268 gst_asf_demux_activate_ext_props_streams (GstASFDemux * demux)
4272 for (i = 0; i < demux->num_streams; ++i) {
4277 stream = &demux->stream[i];
4279 GST_LOG_OBJECT (demux, "checking stream %2u", stream->id);
4281 if (stream->active) {
4282 GST_LOG_OBJECT (demux, "stream %2u is already activated", stream->id);
4287 for (x = demux->mut_ex_streams; x != NULL; x = x->next) {
4290 /* check for each mutual exclusion whether it affects this stream */
4291 for (mes = (guint8 *) x->data; mes != NULL && *mes != 0xff; ++mes) {
4292 if (*mes == stream->id) {
4293 /* if yes, check if we've already added streams that are mutually
4294 * exclusive with the stream we're about to add */
4295 for (mes = (guint8 *) x->data; mes != NULL && *mes != 0xff; ++mes) {
4296 for (j = 0; j < demux->num_streams; ++j) {
4297 /* if the broadcast flag is set, assume the hidden streams aren't
4298 * actually streamed and hide them (or playbin won't work right),
4299 * otherwise assume their data is available */
4300 if (demux->stream[j].id == *mes && demux->broadcast) {
4302 GST_LOG_OBJECT (demux, "broadcast stream ID %d to be added is "
4303 "mutually exclusive with already existing stream ID %d, "
4304 "hiding stream", stream->id, demux->stream[j].id);
4316 /* FIXME: we should do stream activation based on preroll data in
4317 * streaming mode too */
4318 if (demux->streaming && !is_hidden)
4319 gst_asf_demux_activate_stream (demux, stream);
4324 static GstFlowReturn
4325 gst_asf_demux_process_object (GstASFDemux * demux, guint8 ** p_data,
4328 GstFlowReturn ret = GST_FLOW_OK;
4330 guint64 obj_data_size;
4332 if (*p_size < ASF_OBJECT_HEADER_SIZE)
4333 return ASF_FLOW_NEED_MORE_DATA;
4335 asf_demux_peek_object (demux, *p_data, ASF_OBJECT_HEADER_SIZE, &obj, TRUE);
4336 gst_asf_demux_skip_bytes (ASF_OBJECT_HEADER_SIZE, p_data, p_size);
4338 obj_data_size = obj.size - ASF_OBJECT_HEADER_SIZE;
4340 if (*p_size < obj_data_size)
4341 return ASF_FLOW_NEED_MORE_DATA;
4343 gst_asf_demux_push_obj (demux, obj.id);
4345 GST_INFO ("%s: size %" G_GUINT64_FORMAT, demux->objpath, obj.size);
4348 case ASF_OBJ_STREAM:
4349 gst_asf_demux_parse_stream_object (demux, *p_data, obj_data_size);
4353 ret = gst_asf_demux_process_file (demux, *p_data, obj_data_size);
4355 case ASF_OBJ_HEADER:
4356 ret = gst_asf_demux_process_header (demux, *p_data, obj_data_size);
4358 case ASF_OBJ_COMMENT:
4359 ret = gst_asf_demux_process_comment (demux, *p_data, obj_data_size);
4362 ret = gst_asf_demux_process_header_ext (demux, *p_data, obj_data_size);
4364 case ASF_OBJ_BITRATE_PROPS:
4366 gst_asf_demux_process_bitrate_props_object (demux, *p_data,
4369 case ASF_OBJ_EXT_CONTENT_DESC:
4371 gst_asf_demux_process_ext_content_desc (demux, *p_data,
4374 case ASF_OBJ_METADATA_OBJECT:
4375 ret = gst_asf_demux_process_metadata (demux, *p_data, obj_data_size);
4377 case ASF_OBJ_EXTENDED_STREAM_PROPS:{
4380 /* process these later, we might not have parsed the corresponding
4381 * stream object yet */
4382 GST_LOG ("%s: queued for later parsing", demux->objpath);
4383 buf = gst_buffer_new_and_alloc (obj_data_size);
4384 gst_buffer_fill (buf, 0, *p_data, obj_data_size);
4385 demux->ext_stream_props = g_slist_append (demux->ext_stream_props, buf);
4389 case ASF_OBJ_LANGUAGE_LIST:
4390 ret = gst_asf_demux_process_language_list (demux, *p_data, obj_data_size);
4392 case ASF_OBJ_ADVANCED_MUTUAL_EXCLUSION:
4393 ret = gst_asf_demux_process_advanced_mutual_exclusion (demux, *p_data,
4396 case ASF_OBJ_SIMPLE_INDEX:
4397 ret = gst_asf_demux_process_simple_index (demux, *p_data, obj_data_size);
4399 case ASF_OBJ_CONTENT_ENCRYPTION:
4400 case ASF_OBJ_EXT_CONTENT_ENCRYPTION:
4401 case ASF_OBJ_DIGITAL_SIGNATURE_OBJECT:
4402 case ASF_OBJ_UNKNOWN_ENCRYPTION_OBJECT:
4403 goto error_encrypted;
4404 case ASF_OBJ_CONCEAL_NONE:
4406 case ASF_OBJ_UNDEFINED:
4407 case ASF_OBJ_CODEC_COMMENT:
4409 case ASF_OBJ_PADDING:
4410 case ASF_OBJ_BITRATE_MUTEX:
4411 case ASF_OBJ_COMPATIBILITY:
4412 case ASF_OBJ_INDEX_PLACEHOLDER:
4413 case ASF_OBJ_INDEX_PARAMETERS:
4414 case ASF_OBJ_STREAM_PRIORITIZATION:
4415 case ASF_OBJ_SCRIPT_COMMAND:
4416 case ASF_OBJ_METADATA_LIBRARY_OBJECT:
4418 /* Unknown/unhandled object, skip it and hope for the best */
4419 GST_INFO ("%s: skipping object", demux->objpath);
4424 /* this can't fail, we checked the number of bytes available before */
4425 gst_asf_demux_skip_bytes (obj_data_size, p_data, p_size);
4427 GST_LOG ("%s: ret = %s", demux->objpath, gst_asf_get_flow_name (ret));
4429 gst_asf_demux_pop_obj (demux);
4436 GST_ELEMENT_ERROR (demux, STREAM, DECRYPT, (NULL), (NULL));
4437 return GST_FLOW_ERROR;
4442 gst_asf_demux_descramble_buffer (GstASFDemux * demux, AsfStream * stream,
4443 GstBuffer ** p_buffer)
4445 GstBuffer *descrambled_buffer;
4446 GstBuffer *scrambled_buffer;
4447 GstBuffer *sub_buffer;
4454 /* descrambled_buffer is initialised in the first iteration */
4455 descrambled_buffer = NULL;
4456 scrambled_buffer = *p_buffer;
4458 if (gst_buffer_get_size (scrambled_buffer) <
4459 stream->ds_packet_size * stream->span)
4462 for (offset = 0; offset < gst_buffer_get_size (scrambled_buffer);
4463 offset += stream->ds_chunk_size) {
4464 off = offset / stream->ds_chunk_size;
4465 row = off / stream->span;
4466 col = off % stream->span;
4467 idx = row + col * stream->ds_packet_size / stream->ds_chunk_size;
4468 GST_DEBUG ("idx=%u, row=%u, col=%u, off=%u, ds_chunk_size=%u", idx, row,
4469 col, off, stream->ds_chunk_size);
4470 GST_DEBUG ("scrambled buffer size=%" G_GSIZE_FORMAT
4471 ", span=%u, packet_size=%u", gst_buffer_get_size (scrambled_buffer),
4472 stream->span, stream->ds_packet_size);
4473 GST_DEBUG ("gst_buffer_get_size (scrambled_buffer) = %" G_GSIZE_FORMAT,
4474 gst_buffer_get_size (scrambled_buffer));
4476 gst_buffer_copy_region (scrambled_buffer, GST_BUFFER_COPY_MEMORY,
4477 idx * stream->ds_chunk_size, stream->ds_chunk_size);
4479 descrambled_buffer = sub_buffer;
4481 descrambled_buffer = gst_buffer_append (descrambled_buffer, sub_buffer);
4485 GST_BUFFER_TIMESTAMP (descrambled_buffer) =
4486 GST_BUFFER_TIMESTAMP (scrambled_buffer);
4487 GST_BUFFER_DURATION (descrambled_buffer) =
4488 GST_BUFFER_DURATION (scrambled_buffer);
4489 GST_BUFFER_OFFSET (descrambled_buffer) = GST_BUFFER_OFFSET (scrambled_buffer);
4490 GST_BUFFER_OFFSET_END (descrambled_buffer) =
4491 GST_BUFFER_OFFSET_END (scrambled_buffer);
4493 /* FIXME/CHECK: do we need to transfer buffer flags here too? */
4495 gst_buffer_unref (scrambled_buffer);
4496 *p_buffer = descrambled_buffer;
4500 gst_asf_demux_element_send_event (GstElement * element, GstEvent * event)
4502 GstASFDemux *demux = GST_ASF_DEMUX (element);
4505 GST_DEBUG ("handling element event of type %s", GST_EVENT_TYPE_NAME (event));
4507 for (i = 0; i < demux->num_streams; ++i) {
4508 gst_event_ref (event);
4509 if (gst_asf_demux_handle_src_event (demux->stream[i].pad,
4510 GST_OBJECT_CAST (element), event)) {
4511 gst_event_unref (event);
4516 gst_event_unref (event);
4520 /* takes ownership of the passed event */
4522 gst_asf_demux_send_event_unlocked (GstASFDemux * demux, GstEvent * event)
4524 gboolean ret = TRUE;
4527 GST_DEBUG_OBJECT (demux, "sending %s event to all source pads",
4528 GST_EVENT_TYPE_NAME (event));
4530 for (i = 0; i < demux->num_streams; ++i) {
4531 gst_event_ref (event);
4532 ret &= gst_pad_push_event (demux->stream[i].pad, event);
4534 gst_event_unref (event);
4539 gst_asf_demux_handle_src_query (GstPad * pad, GstObject * parent,
4543 gboolean res = FALSE;
4545 demux = GST_ASF_DEMUX (parent);
4547 GST_DEBUG ("handling %s query",
4548 gst_query_type_get_name (GST_QUERY_TYPE (query)));
4550 switch (GST_QUERY_TYPE (query)) {
4551 case GST_QUERY_DURATION:
4555 gst_query_parse_duration (query, &format, NULL);
4557 if (format != GST_FORMAT_TIME) {
4558 GST_LOG ("only support duration queries in TIME format");
4562 res = gst_pad_query_default (pad, parent, query);
4564 GST_OBJECT_LOCK (demux);
4566 if (demux->segment.duration != GST_CLOCK_TIME_NONE) {
4567 GST_LOG ("returning duration: %" GST_TIME_FORMAT,
4568 GST_TIME_ARGS (demux->segment.duration));
4570 gst_query_set_duration (query, GST_FORMAT_TIME,
4571 demux->segment.duration);
4575 GST_LOG ("duration not known yet");
4578 GST_OBJECT_UNLOCK (demux);
4583 case GST_QUERY_POSITION:{
4586 gst_query_parse_position (query, &format, NULL);
4588 if (format != GST_FORMAT_TIME) {
4589 GST_LOG ("only support position queries in TIME format");
4593 GST_OBJECT_LOCK (demux);
4595 if (demux->segment.position != GST_CLOCK_TIME_NONE) {
4596 GST_LOG ("returning position: %" GST_TIME_FORMAT,
4597 GST_TIME_ARGS (demux->segment.position));
4599 gst_query_set_position (query, GST_FORMAT_TIME,
4600 demux->segment.position);
4604 GST_LOG ("position not known yet");
4607 GST_OBJECT_UNLOCK (demux);
4611 case GST_QUERY_SEEKING:{
4614 gst_query_parse_seeking (query, &format, NULL, NULL, NULL);
4615 if (format == GST_FORMAT_TIME) {
4618 GST_OBJECT_LOCK (demux);
4619 duration = demux->segment.duration;
4620 GST_OBJECT_UNLOCK (demux);
4622 if (!demux->streaming || !demux->seekable) {
4623 gst_query_set_seeking (query, GST_FORMAT_TIME, demux->seekable, 0,
4630 /* try upstream first in TIME */
4631 res = gst_pad_query_default (pad, parent, query);
4633 gst_query_parse_seeking (query, &fmt, &seekable, NULL, NULL);
4634 GST_LOG_OBJECT (demux, "upstream %s seekable %d",
4635 GST_STR_NULL (gst_format_get_name (fmt)), seekable);
4636 /* if no luck, maybe in BYTES */
4637 if (!seekable || fmt != GST_FORMAT_TIME) {
4640 q = gst_query_new_seeking (GST_FORMAT_BYTES);
4641 if ((res = gst_pad_peer_query (demux->sinkpad, q))) {
4642 gst_query_parse_seeking (q, &fmt, &seekable, NULL, NULL);
4643 GST_LOG_OBJECT (demux, "upstream %s seekable %d",
4644 GST_STR_NULL (gst_format_get_name (fmt)), seekable);
4645 if (fmt != GST_FORMAT_BYTES)
4648 gst_query_unref (q);
4649 gst_query_set_seeking (query, GST_FORMAT_TIME, seekable, 0,
4655 GST_LOG_OBJECT (demux, "only support seeking in TIME format");
4659 case GST_QUERY_LATENCY:
4662 GstClockTime min, max;
4664 /* preroll delay does not matter in non-live pipeline,
4665 * but we might end up in a live (rtsp) one ... */
4668 res = gst_pad_query_default (pad, parent, query);
4672 gst_query_parse_latency (query, &live, &min, &max);
4674 GST_DEBUG_OBJECT (demux, "Peer latency: live %d, min %"
4675 GST_TIME_FORMAT " max %" GST_TIME_FORMAT, live,
4676 GST_TIME_ARGS (min), GST_TIME_ARGS (max));
4678 GST_OBJECT_LOCK (demux);
4679 min += demux->latency;
4681 max += demux->latency;
4682 GST_OBJECT_UNLOCK (demux);
4684 gst_query_set_latency (query, live, min, max);
4687 case GST_QUERY_SEGMENT:
4692 format = demux->segment.format;
4695 gst_segment_to_stream_time (&demux->segment, format,
4696 demux->segment.start);
4697 if ((stop = demux->segment.stop) == -1)
4698 stop = demux->segment.duration;
4700 stop = gst_segment_to_stream_time (&demux->segment, format, stop);
4702 gst_query_set_segment (query, demux->segment.rate, format, start, stop);
4707 res = gst_pad_query_default (pad, parent, query);
4714 static GstStateChangeReturn
4715 gst_asf_demux_change_state (GstElement * element, GstStateChange transition)
4717 GstASFDemux *demux = GST_ASF_DEMUX (element);
4718 GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
4720 switch (transition) {
4721 case GST_STATE_CHANGE_NULL_TO_READY:{
4722 gst_segment_init (&demux->segment, GST_FORMAT_TIME);
4723 demux->need_newsegment = TRUE;
4724 demux->segment_running = FALSE;
4725 demux->keyunit_sync = FALSE;
4726 demux->accurate = FALSE;
4727 demux->adapter = gst_adapter_new ();
4728 demux->metadata = gst_caps_new_empty ();
4729 demux->global_metadata = gst_structure_new_empty ("metadata");
4730 demux->data_size = 0;
4731 demux->data_offset = 0;
4732 demux->index_offset = 0;
4733 demux->base_offset = 0;
4734 demux->flowcombiner = gst_flow_combiner_new ();
4742 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
4743 if (ret == GST_STATE_CHANGE_FAILURE)
4746 switch (transition) {
4747 case GST_STATE_CHANGE_PAUSED_TO_READY:
4748 gst_asf_demux_reset (demux, FALSE);
4751 case GST_STATE_CHANGE_READY_TO_NULL:
4752 gst_asf_demux_reset (demux, FALSE);
4753 gst_flow_combiner_free (demux->flowcombiner);
4754 demux->flowcombiner = NULL;