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>
4 *
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.
9 *
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.
14 *
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., 59 Temple Place - Suite 330,
18 * Boston, MA 02111-1307, USA.
19 */
21 /* TODO:
22 *
23 * - _loop():
24 * stop if at end of segment if != end of file, ie. demux->segment.stop
25 *
26 * - fix packet parsing:
27 * there's something wrong with timestamps for packets with keyframes,
28 * and durations too.
29 */
31 #ifdef HAVE_CONFIG_H
32 #include "config.h"
33 #endif
35 #include <gst/gstutils.h>
36 #include <gst/base/gstbytereader.h>
37 #include <gst/riff/riff-media.h>
38 #include <gst/tag/tag.h>
39 #include <gst/gst-i18n-plugin.h>
40 #include <stdlib.h>
41 #include <string.h>
43 #include "gstasfdemux.h"
44 #include "asfheaders.h"
45 #include "asfpacket.h"
47 static GstStaticPadTemplate gst_asf_demux_sink_template =
48 GST_STATIC_PAD_TEMPLATE ("sink",
49 GST_PAD_SINK,
50 GST_PAD_ALWAYS,
51 GST_STATIC_CAPS ("video/x-ms-asf")
52 );
54 static GstStaticPadTemplate audio_src_template =
55 GST_STATIC_PAD_TEMPLATE ("audio_%02d",
56 GST_PAD_SRC,
57 GST_PAD_SOMETIMES,
58 GST_STATIC_CAPS_ANY);
60 static GstStaticPadTemplate video_src_template =
61 GST_STATIC_PAD_TEMPLATE ("video_%02d",
62 GST_PAD_SRC,
63 GST_PAD_SOMETIMES,
64 GST_STATIC_CAPS_ANY);
66 /* size of an ASF object header, ie. GUID (16 bytes) + object size (8 bytes) */
67 #define ASF_OBJECT_HEADER_SIZE (16+8)
69 /* FIXME: get rid of this */
70 /* abuse this GstFlowReturn enum for internal usage */
71 #define ASF_FLOW_NEED_MORE_DATA 99
73 #define gst_asf_get_flow_name(flow) \
74 (flow == ASF_FLOW_NEED_MORE_DATA) ? \
75 "need-more-data" : gst_flow_get_name (flow)
77 GST_DEBUG_CATEGORY (asfdemux_dbg);
79 static GstStateChangeReturn gst_asf_demux_change_state (GstElement * element,
80 GstStateChange transition);
81 static gboolean gst_asf_demux_element_send_event (GstElement * element,
82 GstEvent * event);
83 static gboolean gst_asf_demux_send_event_unlocked (GstASFDemux * demux,
84 GstEvent * event);
85 static gboolean gst_asf_demux_handle_src_query (GstPad * pad, GstQuery * query);
86 static const GstQueryType *gst_asf_demux_get_src_query_types (GstPad * pad);
87 static GstFlowReturn gst_asf_demux_chain (GstPad * pad, GstBuffer * buf);
88 static gboolean gst_asf_demux_sink_event (GstPad * pad, GstEvent * event);
89 static GstFlowReturn gst_asf_demux_process_object (GstASFDemux * demux,
90 guint8 ** p_data, guint64 * p_size);
91 static gboolean gst_asf_demux_activate (GstPad * sinkpad);
92 static gboolean gst_asf_demux_activate_push (GstPad * sinkpad, gboolean active);
93 static gboolean gst_asf_demux_activate_pull (GstPad * sinkpad, gboolean active);
94 static void gst_asf_demux_loop (GstASFDemux * demux);
95 static void
96 gst_asf_demux_process_queued_extended_stream_objects (GstASFDemux * demux);
97 static gboolean gst_asf_demux_pull_headers (GstASFDemux * demux);
98 static void gst_asf_demux_pull_indices (GstASFDemux * demux);
99 static void gst_asf_demux_reset_stream_state_after_discont (GstASFDemux * asf);
100 static gboolean
101 gst_asf_demux_parse_data_object_start (GstASFDemux * demux, guint8 * data);
102 static void gst_asf_demux_descramble_buffer (GstASFDemux * demux,
103 AsfStream * stream, GstBuffer ** p_buffer);
104 static void gst_asf_demux_activate_stream (GstASFDemux * demux,
105 AsfStream * stream);
106 static GstStructure *gst_asf_demux_get_metadata_for_stream (GstASFDemux * d,
107 guint stream_num);
109 GST_BOILERPLATE (GstASFDemux, gst_asf_demux, GstElement, GST_TYPE_ELEMENT);
111 static void
112 gst_asf_demux_base_init (gpointer g_class)
113 {
114 GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
115 static GstElementDetails gst_asf_demux_details = {
116 "ASF Demuxer",
117 "Codec/Demuxer",
118 "Demultiplexes ASF Streams",
119 "Owen Fraser-Green <owen@discobabe.net>"
120 };
122 gst_element_class_add_pad_template (element_class,
123 gst_static_pad_template_get (&audio_src_template));
124 gst_element_class_add_pad_template (element_class,
125 gst_static_pad_template_get (&video_src_template));
126 gst_element_class_add_pad_template (element_class,
127 gst_static_pad_template_get (&gst_asf_demux_sink_template));
129 gst_element_class_set_details (element_class, &gst_asf_demux_details);
130 }
132 static void
133 gst_asf_demux_class_init (GstASFDemuxClass * klass)
134 {
135 GstElementClass *gstelement_class;
137 gstelement_class = (GstElementClass *) klass;
139 gstelement_class->change_state =
140 GST_DEBUG_FUNCPTR (gst_asf_demux_change_state);
141 gstelement_class->send_event =
142 GST_DEBUG_FUNCPTR (gst_asf_demux_element_send_event);
143 }
145 static void
146 gst_asf_demux_free_stream (GstASFDemux * demux, AsfStream * stream)
147 {
148 gst_caps_replace (&stream->caps, NULL);
149 if (stream->pending_tags) {
150 gst_tag_list_free (stream->pending_tags);
151 stream->pending_tags = NULL;
152 }
153 if (stream->pad) {
154 if (stream->active)
155 gst_element_remove_pad (GST_ELEMENT_CAST (demux), stream->pad);
156 else
157 gst_object_unref (stream->pad);
158 stream->pad = NULL;
159 }
160 if (stream->payloads) {
161 g_array_free (stream->payloads, TRUE);
162 stream->payloads = NULL;
163 }
164 if (stream->ext_props.valid) {
165 g_free (stream->ext_props.payload_extensions);
166 stream->ext_props.payload_extensions = NULL;
167 }
168 }
170 static void
171 gst_asf_demux_reset (GstASFDemux * demux)
172 {
173 GST_LOG_OBJECT (demux, "resetting");
175 gst_segment_init (&demux->segment, GST_FORMAT_UNDEFINED);
176 demux->segment_running = FALSE;
177 if (demux->adapter) {
178 gst_adapter_clear (demux->adapter);
179 g_object_unref (demux->adapter);
180 demux->adapter = NULL;
181 }
182 if (demux->taglist) {
183 gst_tag_list_free (demux->taglist);
184 demux->taglist = NULL;
185 }
186 if (demux->metadata) {
187 gst_caps_unref (demux->metadata);
188 demux->metadata = NULL;
189 }
190 if (demux->global_metadata) {
191 gst_structure_free (demux->global_metadata);
192 demux->global_metadata = NULL;
193 }
195 demux->state = GST_ASF_DEMUX_STATE_HEADER;
196 g_free (demux->objpath);
197 demux->objpath = NULL;
198 g_strfreev (demux->languages);
199 demux->languages = NULL;
200 demux->num_languages = 0;
201 g_slist_foreach (demux->ext_stream_props, (GFunc) gst_mini_object_unref,
202 NULL);
203 g_slist_free (demux->ext_stream_props);
204 demux->ext_stream_props = NULL;
205 while (demux->num_streams > 0) {
206 gst_asf_demux_free_stream (demux, &demux->stream[demux->num_streams - 1]);
207 --demux->num_streams;
208 }
209 memset (demux->stream, 0, sizeof (demux->stream));
210 demux->num_audio_streams = 0;
211 demux->num_video_streams = 0;
212 demux->num_streams = 0;
213 demux->activated_streams = FALSE;
214 demux->first_ts = GST_CLOCK_TIME_NONE;
215 demux->segment_ts = GST_CLOCK_TIME_NONE;
216 demux->in_gap = 0;
217 gst_segment_init (&demux->in_segment, GST_FORMAT_UNDEFINED);
218 demux->state = GST_ASF_DEMUX_STATE_HEADER;
219 demux->seekable = FALSE;
220 demux->broadcast = FALSE;
221 demux->sidx_interval = 0;
222 demux->sidx_num_entries = 0;
223 g_free (demux->sidx_entries);
224 demux->sidx_entries = NULL;
225 }
227 static void
228 gst_asf_demux_init (GstASFDemux * demux, GstASFDemuxClass * klass)
229 {
230 demux->sinkpad =
231 gst_pad_new_from_static_template (&gst_asf_demux_sink_template, "sink");
232 gst_pad_set_chain_function (demux->sinkpad,
233 GST_DEBUG_FUNCPTR (gst_asf_demux_chain));
234 gst_pad_set_event_function (demux->sinkpad,
235 GST_DEBUG_FUNCPTR (gst_asf_demux_sink_event));
236 gst_pad_set_activate_function (demux->sinkpad,
237 GST_DEBUG_FUNCPTR (gst_asf_demux_activate));
238 gst_pad_set_activatepull_function (demux->sinkpad,
239 GST_DEBUG_FUNCPTR (gst_asf_demux_activate_pull));
240 gst_pad_set_activatepush_function (demux->sinkpad,
241 GST_DEBUG_FUNCPTR (gst_asf_demux_activate_push));
242 gst_element_add_pad (GST_ELEMENT (demux), demux->sinkpad);
244 /* set initial state */
245 gst_asf_demux_reset (demux);
246 }
248 static gboolean
249 gst_asf_demux_activate (GstPad * sinkpad)
250 {
251 if (gst_pad_check_pull_range (sinkpad)) {
252 return gst_pad_activate_pull (sinkpad, TRUE);
253 } else {
254 return gst_pad_activate_push (sinkpad, TRUE);
255 }
256 }
258 static gboolean
259 gst_asf_demux_activate_push (GstPad * sinkpad, gboolean active)
260 {
261 GstASFDemux *demux;
263 demux = GST_ASF_DEMUX (GST_OBJECT_PARENT (sinkpad));
265 demux->state = GST_ASF_DEMUX_STATE_HEADER;
266 demux->streaming = TRUE;
268 return TRUE;
269 }
271 static gboolean
272 gst_asf_demux_activate_pull (GstPad * pad, gboolean active)
273 {
274 GstASFDemux *demux;
276 demux = GST_ASF_DEMUX (GST_OBJECT_PARENT (pad));
278 if (active) {
279 demux->state = GST_ASF_DEMUX_STATE_HEADER;
280 demux->streaming = FALSE;
282 return gst_pad_start_task (pad, (GstTaskFunction) gst_asf_demux_loop,
283 demux);
284 } else {
285 return gst_pad_stop_task (pad);
286 }
287 }
290 static gboolean
291 gst_asf_demux_sink_event (GstPad * pad, GstEvent * event)
292 {
293 GstASFDemux *demux;
294 gboolean ret = TRUE;
296 demux = GST_ASF_DEMUX (gst_pad_get_parent (pad));
298 GST_LOG_OBJECT (demux, "handling %s event", GST_EVENT_TYPE_NAME (event));
299 switch (GST_EVENT_TYPE (event)) {
300 case GST_EVENT_NEWSEGMENT:{
301 GstFormat newsegment_format;
302 gint64 newsegment_start, stop, time;
303 gdouble rate, arate;
304 gboolean update;
306 gst_event_parse_new_segment_full (event, &update, &rate, &arate,
307 &newsegment_format, &newsegment_start, &stop, &time);
309 if (newsegment_format == GST_FORMAT_BYTES) {
310 if (demux->packet_size && newsegment_start > demux->data_offset)
311 demux->packet = (newsegment_start - demux->data_offset) /
312 demux->packet_size;
313 else
314 demux->packet = 0;
315 } else if (newsegment_format == GST_FORMAT_TIME) {
316 /* do not know packet position, not really a problem */
317 demux->packet = -1;
318 } else {
319 GST_WARNING_OBJECT (demux, "unsupported newsegment format, ignoring");
320 gst_event_unref (event);
321 break;
322 }
324 /* record upstream segment for interpolation */
325 if (newsegment_format != demux->in_segment.format)
326 gst_segment_init (&demux->in_segment, GST_FORMAT_UNDEFINED);
327 gst_segment_set_newsegment_full (&demux->in_segment, update, rate, arate,
328 newsegment_format, newsegment_start, stop, time);
330 /* in either case, clear some state and generate newsegment later on */
331 GST_OBJECT_LOCK (demux);
332 demux->segment_ts = GST_CLOCK_TIME_NONE;
333 demux->in_gap = GST_CLOCK_TIME_NONE;
334 demux->need_newsegment = TRUE;
335 gst_asf_demux_reset_stream_state_after_discont (demux);
336 GST_OBJECT_UNLOCK (demux);
338 gst_event_unref (event);
339 break;
340 }
341 case GST_EVENT_EOS:{
342 if (demux->state == GST_ASF_DEMUX_STATE_HEADER) {
343 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
344 (_("This stream contains no data.")),
345 ("got eos and didn't receive a complete header object"));
346 break;
347 }
348 GST_OBJECT_LOCK (demux);
349 gst_adapter_clear (demux->adapter);
350 GST_OBJECT_UNLOCK (demux);
351 gst_asf_demux_send_event_unlocked (demux, event);
352 break;
353 }
355 case GST_EVENT_FLUSH_STOP:
356 GST_OBJECT_LOCK (demux);
357 gst_asf_demux_reset_stream_state_after_discont (demux);
358 GST_OBJECT_UNLOCK (demux);
359 gst_asf_demux_send_event_unlocked (demux, event);
360 /* upon activation, latency is no longer introduced, e.g. after seek */
361 if (demux->activated_streams)
362 demux->latency = 0;
363 break;
365 default:
366 ret = gst_pad_event_default (pad, event);
367 break;
368 }
370 gst_object_unref (demux);
371 return ret;
372 }
374 static gboolean
375 gst_asf_demux_seek_index_lookup (GstASFDemux * demux, guint * packet,
376 GstClockTime seek_time, GstClockTime * p_idx_time)
377 {
378 GstClockTime idx_time;
379 guint idx;
381 if (demux->sidx_num_entries == 0 || demux->sidx_interval == 0)
382 return FALSE;
384 idx = (guint) ((seek_time + demux->preroll) / demux->sidx_interval);
386 /* FIXME: seek beyond end of file should result in immediate EOS from
387 * streaming thread instead of a failed seek */
388 if (idx >= demux->sidx_num_entries)
389 return FALSE;
391 *packet = demux->sidx_entries[idx];
393 /* so we get closer to the actual time of the packet ... actually, let's not
394 * do this, since we throw away superfluous payloads before the seek position
395 * anyway; this way, our key unit seek 'snap resolution' is a bit better
396 * (ie. same as index resolution) */
397 /*
398 while (idx > 0 && demux->sidx_entries[idx-1] == demux->sidx_entries[idx])
399 --idx;
400 */
402 idx_time = demux->sidx_interval * idx;
403 if (G_LIKELY (idx_time >= demux->preroll))
404 idx_time -= demux->preroll;
406 GST_DEBUG_OBJECT (demux, "%" GST_TIME_FORMAT " => packet %u at %"
407 GST_TIME_FORMAT, GST_TIME_ARGS (seek_time), *packet,
408 GST_TIME_ARGS (idx_time));
410 if (p_idx_time)
411 *p_idx_time = idx_time;
413 return TRUE;
414 }
416 static void
417 gst_asf_demux_reset_stream_state_after_discont (GstASFDemux * demux)
418 {
419 guint n;
421 gst_adapter_clear (demux->adapter);
423 GST_DEBUG_OBJECT (demux, "reset stream state");
425 for (n = 0; n < demux->num_streams; n++) {
426 demux->stream[n].discont = TRUE;
427 demux->stream[n].last_flow = GST_FLOW_OK;
429 while (demux->stream[n].payloads->len > 0) {
430 AsfPayload *payload;
431 guint last;
433 last = demux->stream[n].payloads->len - 1;
434 payload = &g_array_index (demux->stream[n].payloads, AsfPayload, last);
435 gst_buffer_replace (&payload->buf, NULL);
436 g_array_remove_index (demux->stream[n].payloads, last);
437 }
438 }
439 }
441 static void
442 gst_asf_demux_mark_discont (GstASFDemux * demux)
443 {
444 guint n;
446 GST_DEBUG_OBJECT (demux, "Mark stream discont");
448 for (n = 0; n < demux->num_streams; n++)
449 demux->stream[n].discont = TRUE;
450 }
452 /* do a seek in push based mode */
453 static gboolean
454 gst_asf_demux_handle_seek_push (GstASFDemux * demux, GstEvent * event)
455 {
456 gdouble rate;
457 GstFormat format;
458 GstSeekFlags flags;
459 GstSeekType cur_type, stop_type;
460 gint64 cur, stop;
461 guint packet;
462 gboolean res;
464 gst_event_parse_seek (event, &rate, &format, &flags, &cur_type, &cur,
465 &stop_type, &stop);
467 stop_type = GST_SEEK_TYPE_NONE;
468 stop = -1;
470 GST_DEBUG_OBJECT (demux, "seeking to %" GST_TIME_FORMAT, GST_TIME_ARGS (cur));
472 /* determine packet, by index or by estimation */
473 if (!gst_asf_demux_seek_index_lookup (demux, &packet, cur, NULL)) {
474 packet = (guint) gst_util_uint64_scale (demux->num_packets,
475 cur, demux->play_time);
476 }
478 if (packet > demux->num_packets) {
479 GST_DEBUG_OBJECT (demux, "could not determine packet to seek to, "
480 "seek aborted.");
481 return FALSE;
482 }
484 GST_DEBUG_OBJECT (demux, "seeking to packet %d", packet);
486 cur = demux->data_offset + (packet * demux->packet_size);
488 GST_DEBUG_OBJECT (demux, "Pushing BYTE seek rate %g, "
489 "start %" G_GINT64_FORMAT ", stop %" G_GINT64_FORMAT, rate, cur, stop);
490 /* BYTE seek event */
491 event = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags, cur_type, cur,
492 stop_type, stop);
493 res = gst_pad_push_event (demux->sinkpad, event);
495 return res;
496 }
498 static gboolean
499 gst_asf_demux_handle_seek_event (GstASFDemux * demux, GstEvent * event)
500 {
501 GstClockTime idx_time;
502 GstSegment segment;
503 GstSeekFlags flags;
504 GstSeekType cur_type, stop_type;
505 GstFormat format;
506 gboolean only_need_update;
507 gboolean keyunit_sync;
508 gboolean accurate;
509 gboolean flush;
510 gdouble rate;
511 gint64 cur, stop;
512 gint64 seek_time;
513 guint packet;
515 if (demux->seekable == FALSE || demux->packet_size == 0 ||
516 demux->num_packets == 0 || demux->play_time == 0) {
517 GST_LOG_OBJECT (demux, "stream is not seekable");
518 return FALSE;
519 }
521 if (!demux->activated_streams) {
522 GST_LOG_OBJECT (demux, "streams not yet activated, ignoring seek");
523 return FALSE;
524 }
526 gst_event_parse_seek (event, &rate, &format, &flags, &cur_type, &cur,
527 &stop_type, &stop);
529 if (format != GST_FORMAT_TIME) {
530 GST_LOG_OBJECT (demux, "seeking is only supported in TIME format");
531 return FALSE;
532 }
534 if (rate <= 0.0) {
535 GST_LOG_OBJECT (demux, "backward playback is not supported yet");
536 return FALSE;
537 }
539 flush = ((flags & GST_SEEK_FLAG_FLUSH) == GST_SEEK_FLAG_FLUSH);
540 accurate = ((flags & GST_SEEK_FLAG_ACCURATE) == GST_SEEK_FLAG_ACCURATE);
541 keyunit_sync = ((flags & GST_SEEK_FLAG_KEY_UNIT) == GST_SEEK_FLAG_KEY_UNIT);
543 if (demux->streaming) {
544 /* support it safely needs more segment handling, e.g. closing etc */
545 if (!flush) {
546 GST_LOG_OBJECT (demux, "streaming; non-flushing seek not supported");
547 return FALSE;
548 }
549 /* we can (re)construct the start later on, but not the end */
550 if (stop_type != GST_SEEK_TYPE_NONE) {
551 GST_LOG_OBJECT (demux, "streaming; end type must be NONE");
552 return FALSE;
553 }
554 gst_event_ref (event);
555 /* upstream might handle TIME seek, e.g. mms or rtsp,
556 * or not, e.g. http, then we give it a hand */
557 if (!gst_pad_push_event (demux->sinkpad, event))
558 return gst_asf_demux_handle_seek_push (demux, event);
559 else
560 return TRUE;
561 }
563 /* unlock the streaming thread */
564 if (flush) {
565 gst_pad_push_event (demux->sinkpad, gst_event_new_flush_start ());
566 gst_asf_demux_send_event_unlocked (demux, gst_event_new_flush_start ());
567 } else {
568 gst_pad_pause_task (demux->sinkpad);
569 }
571 /* grab the stream lock so that streaming cannot continue, for
572 * non flushing seeks when the element is in PAUSED this could block
573 * forever */
574 GST_PAD_STREAM_LOCK (demux->sinkpad);
576 /* we now can stop flushing, since we have the stream lock now */
577 gst_pad_push_event (demux->sinkpad, gst_event_new_flush_stop ());
579 if (flush)
580 gst_asf_demux_send_event_unlocked (demux, gst_event_new_flush_stop ());
582 /* operating on copy of segment until we know the seek worked */
583 segment = demux->segment;
585 if (demux->segment_running && !flush) {
586 GstEvent *newseg;
588 /* create the segment event to close the current segment */
589 newseg = gst_event_new_new_segment (TRUE, segment.rate,
590 GST_FORMAT_TIME, segment.start, segment.last_stop, segment.time);
592 gst_asf_demux_send_event_unlocked (demux, newseg);
593 }
595 gst_segment_set_seek (&segment, rate, format, flags, cur_type,
596 cur, stop_type, stop, &only_need_update);
598 GST_DEBUG_OBJECT (demux, "seeking to time %" GST_TIME_FORMAT ", segment: "
599 "%" GST_SEGMENT_FORMAT, GST_TIME_ARGS (segment.start), &segment);
601 seek_time = segment.start;
603 /* FIXME: should check the KEY_UNIT flag; need to adjust last_stop to
604 * real start of data and segment_start to indexed time for key unit seek*/
605 if (!gst_asf_demux_seek_index_lookup (demux, &packet, seek_time, &idx_time)) {
606 /* First try to query our source to see if it can convert for us. This is
607 the case when our source is an mms stream, notice that in this case
608 gstmms will do a time based seek to get the byte offset, this is not a
609 problem as the seek to this offset needs to happen anway. */
610 gint64 offset;
611 GstFormat dest_format = GST_FORMAT_BYTES;
613 if (gst_pad_query_peer_convert (demux->sinkpad, GST_FORMAT_TIME, seek_time,
614 &dest_format, &offset) && dest_format == GST_FORMAT_BYTES) {
615 packet = (offset - demux->data_offset) / demux->packet_size;
616 GST_LOG_OBJECT (demux, "convert %" GST_TIME_FORMAT
617 " to bytes query result: %lld, data_ofset: %llu, packet_size: %u,"
618 " resulting packet: %u\n", GST_TIME_ARGS (seek_time), offset,
619 demux->data_offset, demux->packet_size, packet);
620 } else {
621 /* Hackety hack, this sucks. We just seek to an earlier position
622 * and let the sinks throw away the stuff before the segment start */
623 if (flush && (accurate || keyunit_sync)) {
624 seek_time -= 5 * GST_SECOND;
625 if (seek_time < 0)
626 seek_time = 0;
627 }
629 packet = (guint) gst_util_uint64_scale (demux->num_packets,
630 seek_time, demux->play_time);
632 if (packet > demux->num_packets)
633 packet = demux->num_packets;
634 }
635 } else {
636 if (keyunit_sync) {
637 GST_DEBUG_OBJECT (demux, "key unit seek, adjust seek_time = %"
638 GST_TIME_FORMAT " to index_time = %" GST_TIME_FORMAT,
639 GST_TIME_ARGS (seek_time), GST_TIME_ARGS (idx_time));
640 segment.start = idx_time;
641 segment.last_stop = idx_time;
642 segment.time = idx_time;
643 }
644 }
646 GST_DEBUG_OBJECT (demux, "seeking to packet %u", packet);
648 GST_OBJECT_LOCK (demux);
649 demux->segment = segment;
650 demux->packet = packet;
651 demux->need_newsegment = TRUE;
652 gst_asf_demux_reset_stream_state_after_discont (demux);
653 GST_OBJECT_UNLOCK (demux);
655 /* restart our task since it might have been stopped when we did the flush */
656 gst_pad_start_task (demux->sinkpad, (GstTaskFunction) gst_asf_demux_loop,
657 demux);
659 /* streaming can continue now */
660 GST_PAD_STREAM_UNLOCK (demux->sinkpad);
662 return TRUE;
663 }
665 static gboolean
666 gst_asf_demux_handle_src_event (GstPad * pad, GstEvent * event)
667 {
668 GstASFDemux *demux;
669 gboolean ret;
671 demux = GST_ASF_DEMUX (gst_pad_get_parent (pad));
673 switch (GST_EVENT_TYPE (event)) {
674 case GST_EVENT_SEEK:
675 GST_LOG_OBJECT (pad, "seek event");
676 ret = gst_asf_demux_handle_seek_event (demux, event);
677 gst_event_unref (event);
678 break;
679 case GST_EVENT_QOS:
680 case GST_EVENT_NAVIGATION:
681 /* just drop these two silently */
682 gst_event_unref (event);
683 ret = FALSE;
684 break;
685 default:
686 GST_LOG_OBJECT (pad, "%s event", GST_EVENT_TYPE_NAME (event));
687 ret = gst_pad_event_default (pad, event);
688 break;
689 }
691 gst_object_unref (demux);
692 return ret;
693 }
695 static inline guint32
696 gst_asf_demux_identify_guid (const ASFGuidHash * guids, ASFGuid * guid)
697 {
698 guint32 ret;
700 ret = gst_asf_identify_guid (guids, guid);
702 GST_LOG ("%s 0x%08x-0x%08x-0x%08x-0x%08x",
703 gst_asf_get_guid_nick (guids, ret),
704 guid->v1, guid->v2, guid->v3, guid->v4);
706 return ret;
707 }
709 typedef struct
710 {
711 AsfObjectID id;
712 guint64 size;
713 } AsfObject;
715 static gboolean
716 asf_demux_peek_object (GstASFDemux * demux, const guint8 * data,
717 guint data_len, AsfObject * object)
718 {
719 ASFGuid guid;
721 if (data_len < ASF_OBJECT_HEADER_SIZE)
722 return FALSE;
724 guid.v1 = GST_READ_UINT32_LE (data + 0);
725 guid.v2 = GST_READ_UINT32_LE (data + 4);
726 guid.v3 = GST_READ_UINT32_LE (data + 8);
727 guid.v4 = GST_READ_UINT32_LE (data + 12);
729 object->size = GST_READ_UINT64_LE (data + 16);
731 /* FIXME: make asf_demux_identify_object_guid() */
732 object->id = gst_asf_demux_identify_guid (asf_object_guids, &guid);
733 if (object->id == ASF_OBJ_UNDEFINED) {
734 GST_WARNING_OBJECT (demux, "Unknown object %08x-%08x-%08x-%08x",
735 guid.v1, guid.v2, guid.v3, guid.v4);
736 }
738 return TRUE;
739 }
741 static GstFlowReturn
742 gst_asf_demux_chain_headers (GstASFDemux * demux)
743 {
744 GstFlowReturn flow;
745 AsfObject obj;
746 guint8 *header_data, *data = NULL;
747 const guint8 *cdata = NULL;
748 guint64 header_size;
750 cdata = (guint8 *) gst_adapter_peek (demux->adapter, ASF_OBJECT_HEADER_SIZE);
751 if (cdata == NULL)
752 goto need_more_data;
754 asf_demux_peek_object (demux, cdata, ASF_OBJECT_HEADER_SIZE, &obj);
755 if (obj.id != ASF_OBJ_HEADER)
756 goto wrong_type;
758 GST_LOG_OBJECT (demux, "header size = %u", (guint) obj.size);
760 /* + 50 for non-packet data at beginning of ASF_OBJ_DATA */
761 if (gst_adapter_available (demux->adapter) < obj.size + 50)
762 goto need_more_data;
764 data = gst_adapter_take (demux->adapter, obj.size + 50);
766 header_data = data;
767 header_size = obj.size;
768 flow = gst_asf_demux_process_object (demux, &header_data, &header_size);
769 if (flow != GST_FLOW_OK)
770 goto parse_failed;
772 /* calculate where the packet data starts */
773 demux->data_offset = obj.size + 50;
775 /* now parse the beginning of the ASF_OBJ_DATA object */
776 if (!gst_asf_demux_parse_data_object_start (demux, data + obj.size))
777 goto wrong_type;
779 if (demux->num_streams == 0)
780 goto no_streams;
782 g_free (data);
783 return GST_FLOW_OK;
785 /* NON-FATAL */
786 need_more_data:
787 {
788 GST_LOG_OBJECT (demux, "not enough data in adapter yet");
789 return GST_FLOW_OK;
790 }
792 /* ERRORS */
793 wrong_type:
794 {
795 GST_ELEMENT_ERROR (demux, STREAM, WRONG_TYPE, (NULL),
796 ("This doesn't seem to be an ASF file"));
797 g_free (data);
798 return GST_FLOW_ERROR;
799 }
800 no_streams:
801 parse_failed:
802 {
803 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
804 ("header parsing failed, or no streams found, flow = %s",
805 gst_flow_get_name (flow)));
806 g_free (data);
807 return GST_FLOW_ERROR;
808 }
809 }
811 static GstFlowReturn
812 gst_asf_demux_aggregate_flow_return (GstASFDemux * demux)
813 {
814 int i;
815 GST_DEBUG_OBJECT (demux, "Aggregating");
817 for (i = 0; i < demux->num_streams; i++) {
818 if (demux->stream[i].active) {
819 GstFlowReturn flowret = demux->stream[i].last_flow;
820 GST_DEBUG_OBJECT (demux, "Aggregating: flow %i return %s", i,
821 gst_flow_get_name (flowret));
822 if (flowret != GST_FLOW_NOT_LINKED)
823 return flowret;
824 }
825 }
827 /* If we got here, then all our active streams are not linked */
828 return GST_FLOW_NOT_LINKED;
829 }
831 static gboolean
832 gst_asf_demux_pull_data (GstASFDemux * demux, guint64 offset, guint size,
833 GstBuffer ** p_buf, GstFlowReturn * p_flow)
834 {
835 GstFlowReturn flow;
837 GST_LOG_OBJECT (demux, "pulling buffer at %" G_GUINT64_FORMAT "+%u",
838 offset, size);
840 flow = gst_pad_pull_range (demux->sinkpad, offset, size, p_buf);
842 if (p_flow)
843 *p_flow = flow;
845 if (flow != GST_FLOW_OK) {
846 GST_DEBUG_OBJECT (demux, "flow %s pulling buffer at %" G_GUINT64_FORMAT
847 "+%u", gst_flow_get_name (flow), offset, size);
848 *p_buf = NULL;
849 return FALSE;
850 }
852 g_assert (*p_buf != NULL);
854 if (GST_BUFFER_SIZE (*p_buf) < size) {
855 GST_DEBUG_OBJECT (demux, "short read pulling buffer at %" G_GUINT64_FORMAT
856 "+%u (got only %u bytes)", offset, size, GST_BUFFER_SIZE (*p_buf));
857 gst_buffer_unref (*p_buf);
858 if (p_flow)
859 *p_flow = GST_FLOW_UNEXPECTED;
860 *p_buf = NULL;
861 return FALSE;
862 }
864 return TRUE;
865 }
867 static void
868 gst_asf_demux_pull_indices (GstASFDemux * demux)
869 {
870 GstBuffer *buf = NULL;
871 guint64 offset;
872 guint num_read = 0;
874 offset = demux->index_offset;
876 if (offset == 0) {
877 GST_DEBUG_OBJECT (demux, "can't read indices, don't know index offset");
878 return;
879 }
881 while (gst_asf_demux_pull_data (demux, offset, 16 + 8, &buf, NULL)) {
882 GstFlowReturn flow;
883 AsfObject obj;
885 asf_demux_peek_object (demux, GST_BUFFER_DATA (buf), 16 + 8, &obj);
886 gst_buffer_replace (&buf, NULL);
888 /* check for sanity */
889 if (obj.size > (5 * 1024 * 1024)) {
890 GST_DEBUG_OBJECT (demux, "implausible index object size, bailing out");
891 break;
892 }
894 if (!gst_asf_demux_pull_data (demux, offset, obj.size, &buf, NULL))
895 break;
897 GST_LOG_OBJECT (demux, "index object at offset 0x%" G_GINT64_MODIFIER "X"
898 ", size %u", offset, (guint) obj.size);
900 offset += obj.size; /* increase before _process_object changes it */
902 flow = gst_asf_demux_process_object (demux, &buf->data, &obj.size);
903 gst_buffer_replace (&buf, NULL);
905 if (flow != GST_FLOW_OK)
906 break;
908 ++num_read;
909 }
910 GST_DEBUG_OBJECT (demux, "read %u index objects", num_read);
911 }
913 static gboolean
914 gst_asf_demux_parse_data_object_start (GstASFDemux * demux, guint8 * data)
915 {
916 AsfObject obj;
918 asf_demux_peek_object (demux, data, 50, &obj);
919 if (obj.id != ASF_OBJ_DATA) {
920 GST_WARNING_OBJECT (demux, "headers not followed by a DATA object");
921 return FALSE;
922 }
924 demux->state = GST_ASF_DEMUX_STATE_DATA;
926 if (!demux->broadcast && obj.size > 50) {
927 demux->data_size = obj.size - 50;
928 /* CHECKME: for at least one file this is off by +158 bytes?! */
929 demux->index_offset = demux->data_offset + demux->data_size;
930 } else {
931 demux->data_size = 0;
932 demux->index_offset = 0;
933 }
935 demux->packet = 0;
937 if (!demux->broadcast) {
938 /* skip object header (24 bytes) and file GUID (16 bytes) */
939 demux->num_packets = GST_READ_UINT64_LE (data + (16 + 8) + 16);
940 } else {
941 demux->num_packets = 0;
942 }
944 if (demux->num_packets == 0)
945 demux->seekable = FALSE;
947 /* fallback in the unlikely case that headers are inconsistent, can't hurt */
948 if (demux->data_size == 0 && demux->num_packets > 0) {
949 demux->data_size = demux->num_packets * demux->packet_size;
950 demux->index_offset = demux->data_offset + demux->data_size;
951 }
953 /* process pending stream objects and create pads for those */
954 gst_asf_demux_process_queued_extended_stream_objects (demux);
956 GST_INFO_OBJECT (demux, "Stream has %" G_GUINT64_FORMAT " packets, "
957 "data_offset=%" G_GINT64_FORMAT ", data_size=%" G_GINT64_FORMAT
958 ", index_offset=%" G_GUINT64_FORMAT, demux->num_packets,
959 demux->data_offset, demux->data_size, demux->index_offset);
961 return TRUE;
962 }
964 static gboolean
965 gst_asf_demux_pull_headers (GstASFDemux * demux)
966 {
967 GstFlowReturn flow;
968 AsfObject obj;
969 GstBuffer *buf = NULL;
970 guint64 size;
972 GST_LOG_OBJECT (demux, "reading headers");
974 /* pull HEADER object header, so we know its size */
975 if (!gst_asf_demux_pull_data (demux, 0, 16 + 8, &buf, NULL))
976 goto read_failed;
978 asf_demux_peek_object (demux, GST_BUFFER_DATA (buf), 16 + 8, &obj);
979 gst_buffer_replace (&buf, NULL);
981 if (obj.id != ASF_OBJ_HEADER)
982 goto wrong_type;
984 GST_LOG_OBJECT (demux, "header size = %u", (guint) obj.size);
986 /* pull HEADER object */
987 if (!gst_asf_demux_pull_data (demux, 0, obj.size, &buf, NULL))
988 goto read_failed;
990 size = obj.size; /* don't want obj.size changed */
991 flow = gst_asf_demux_process_object (demux, &buf->data, &size);
992 gst_buffer_replace (&buf, NULL);
994 if (flow != GST_FLOW_OK) {
995 GST_WARNING_OBJECT (demux, "process_object: %s", gst_flow_get_name (flow));
996 goto parse_failed;
997 }
999 /* calculate where the packet data starts */
1000 demux->data_offset = obj.size + 50;
1002 /* now pull beginning of DATA object before packet data */
1003 if (!gst_asf_demux_pull_data (demux, obj.size, 50, &buf, NULL))
1004 goto read_failed;
1006 if (!gst_asf_demux_parse_data_object_start (demux, GST_BUFFER_DATA (buf)))
1007 goto wrong_type;
1009 if (demux->num_streams == 0)
1010 goto no_streams;
1012 gst_buffer_replace (&buf, NULL);
1013 return TRUE;
1015 /* ERRORS */
1016 wrong_type:
1017 {
1018 gst_buffer_replace (&buf, NULL);
1019 GST_ELEMENT_ERROR (demux, STREAM, WRONG_TYPE, (NULL),
1020 ("This doesn't seem to be an ASF file"));
1021 return FALSE;
1022 }
1023 no_streams:
1024 read_failed:
1025 parse_failed:
1026 {
1027 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL), (NULL));
1028 return FALSE;
1029 }
1030 }
1032 static gboolean
1033 all_streams_prerolled (GstASFDemux * demux)
1034 {
1035 GstClockTime preroll_time;
1036 guint i, num_no_data = 0;
1038 preroll_time = demux->preroll;
1040 /* returns TRUE as long as there isn't a stream which (a) has data queued
1041 * and (b) the timestamp of last piece of data queued is < demux->preroll
1042 * AND there is at least one other stream with data queued */
1043 for (i = 0; i < demux->num_streams; ++i) {
1044 AsfPayload *last_payload;
1045 AsfStream *stream;
1046 guint last_idx;
1048 stream = &demux->stream[i];
1049 if (stream->payloads->len == 0) {
1050 ++num_no_data;
1051 GST_LOG_OBJECT (stream->pad, "no data queued");
1052 continue;
1053 }
1055 last_idx = stream->payloads->len - 1;
1056 last_payload = &g_array_index (stream->payloads, AsfPayload, last_idx);
1058 GST_LOG_OBJECT (stream->pad, "checking if %" GST_TIME_FORMAT " > %"
1059 GST_TIME_FORMAT, GST_TIME_ARGS (last_payload->ts),
1060 GST_TIME_ARGS (preroll_time));
1061 if (last_payload->ts <= preroll_time) {
1062 GST_LOG_OBJECT (stream->pad, "not beyond preroll point yet");
1063 return FALSE;
1064 }
1065 }
1067 if (num_no_data == demux->num_streams)
1068 return FALSE;
1070 return TRUE;
1071 }
1073 #if 0
1074 static gboolean
1075 gst_asf_demux_have_mutually_exclusive_active_stream (GstASFDemux * demux,
1076 AsfStream * stream)
1077 {
1078 GSList *l;
1080 for (l = demux->mut_ex_streams; l != NULL; l = l->next) {
1081 guint8 *mes;
1083 /* check for each mutual exclusion group whether it affects this stream */
1084 for (mes = (guint8 *) l->data; mes != NULL && *mes != 0xff; ++mes) {
1085 if (*mes == stream->id) {
1086 /* we are in this group; let's check if we've already activated streams
1087 * that are in the same group (and hence mutually exclusive to this
1088 * one) */
1089 for (mes = (guint8 *) l->data; mes != NULL && *mes != 0xff; ++mes) {
1090 guint i;
1092 for (i = 0; i < demux->num_streams; ++i) {
1093 if (demux->stream[i].id == *mes && demux->stream[i].active) {
1094 GST_LOG_OBJECT (demux, "stream with ID %d is mutually exclusive "
1095 "to already active stream with ID %d", stream->id,
1096 demux->stream[i].id);
1097 return TRUE;
1098 }
1099 }
1100 }
1101 /* we can only be in this group once, let's break out and move on to
1102 * the next mutual exclusion group */
1103 break;
1104 }
1105 }
1106 }
1108 return FALSE;
1109 }
1110 #endif
1112 static gboolean
1113 gst_asf_demux_check_activate_streams (GstASFDemux * demux, gboolean force)
1114 {
1115 guint i;
1117 if (demux->activated_streams)
1118 return TRUE;
1120 if (!all_streams_prerolled (demux) && !force) {
1121 GST_DEBUG_OBJECT (demux, "not all streams with data beyond preroll yet");
1122 return FALSE;
1123 }
1125 for (i = 0; i < demux->num_streams; ++i) {
1126 AsfStream *stream = &demux->stream[i];
1128 if (stream->payloads->len > 0) {
1129 /* we don't check mutual exclusion stuff here; either we have data for
1130 * a stream, then we active it, or we don't, then we'll ignore it */
1131 GST_LOG_OBJECT (stream->pad, "is prerolled - activate!");
1132 gst_asf_demux_activate_stream (demux, stream);
1133 } else {
1134 GST_LOG_OBJECT (stream->pad, "no data, ignoring stream");
1135 }
1136 }
1138 demux->activated_streams = TRUE;
1139 GST_LOG_OBJECT (demux, "signalling no more pads");
1140 gst_element_no_more_pads (GST_ELEMENT (demux));
1141 return TRUE;
1142 }
1144 /* returns the stream that has a complete payload with the lowest timestamp
1145 * queued, or NULL (we push things by timestamp because during the internal
1146 * prerolling we might accumulate more data then the external queues can take,
1147 * so we'd lock up if we pushed all accumulated data for stream N in one go) */
1148 static AsfStream *
1149 gst_asf_demux_find_stream_with_complete_payload (GstASFDemux * demux)
1150 {
1151 AsfPayload *best_payload = NULL;
1152 AsfStream *best_stream = NULL;
1153 guint i;
1155 for (i = 0; i < demux->num_streams; ++i) {
1156 AsfStream *stream;
1158 stream = &demux->stream[i];
1160 /* Don't push any data until we have at least one payload that falls within
1161 * the current segment. This way we can remove out-of-segment payloads that
1162 * don't need to be decoded after a seek, sending only data from the
1163 * keyframe directly before our segment start */
1164 if (stream->payloads->len > 0) {
1165 AsfPayload *payload;
1166 guint last_idx;
1168 last_idx = stream->payloads->len - 1;
1169 payload = &g_array_index (stream->payloads, AsfPayload, last_idx);
1170 if (GST_CLOCK_TIME_IS_VALID (payload->ts) &&
1171 payload->ts < demux->segment.start) {
1172 GST_DEBUG_OBJECT (stream->pad, "Last queued payload has timestamp %"
1173 GST_TIME_FORMAT " which is before our segment start %"
1174 GST_TIME_FORMAT ", not pushing yet", GST_TIME_ARGS (payload->ts),
1175 GST_TIME_ARGS (demux->segment.start));
1176 continue;
1177 }
1178 }
1180 /* Now see if there's a complete payload queued for this stream */
1181 if (stream->payloads->len > 0) {
1182 AsfPayload *payload;
1184 payload = &g_array_index (stream->payloads, AsfPayload, 0);
1185 if (!gst_asf_payload_is_complete (payload))
1186 continue;
1188 /* ... and whether its timestamp is lower than the current best */
1189 if (best_stream == NULL || best_payload->ts > payload->ts) {
1190 best_stream = stream;
1191 best_payload = payload;
1192 }
1193 }
1194 }
1196 return best_stream;
1197 }
1199 static GstFlowReturn
1200 gst_asf_demux_push_complete_payloads (GstASFDemux * demux, gboolean force)
1201 {
1202 AsfStream *stream;
1204 if (G_UNLIKELY (!demux->activated_streams)) {
1205 if (!gst_asf_demux_check_activate_streams (demux, force))
1206 return GST_FLOW_OK;
1207 /* streams are now activated */
1208 }
1210 /* do we need to send a newsegment event */
1211 if (demux->need_newsegment) {
1213 /* wait until we had a chance to "lock on" some payload's timestamp */
1214 if (!GST_CLOCK_TIME_IS_VALID (demux->segment_ts))
1215 return GST_FLOW_OK;
1216 else {
1217 /* safe default if insufficient upstream info */
1218 if (!GST_CLOCK_TIME_IS_VALID (demux->in_gap))
1219 demux->in_gap = 0;
1220 }
1222 if (demux->segment.stop == GST_CLOCK_TIME_NONE &&
1223 demux->segment.duration > 0) {
1224 /* slight HACK; prevent clipping of last bit */
1225 demux->segment.stop = demux->segment.duration + demux->in_gap;
1226 }
1228 GST_DEBUG_OBJECT (demux, "sending new-segment event %" GST_SEGMENT_FORMAT,
1229 &demux->segment);
1231 /* note: we fix up all timestamps to start from 0, so this should be ok */
1232 gst_asf_demux_send_event_unlocked (demux,
1233 gst_event_new_new_segment (FALSE, demux->segment.rate,
1234 GST_FORMAT_TIME, demux->segment.start, demux->segment.stop,
1235 demux->segment.start));
1237 /* now post any global tags we may have found */
1238 if (demux->taglist == NULL)
1239 demux->taglist = gst_tag_list_new ();
1241 gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
1242 GST_TAG_CONTAINER_FORMAT, "ASF", NULL);
1244 GST_DEBUG_OBJECT (demux, "global tags: %" GST_PTR_FORMAT, demux->taglist);
1245 gst_element_found_tags (GST_ELEMENT (demux), demux->taglist);
1246 demux->taglist = NULL;
1248 demux->need_newsegment = FALSE;
1249 demux->segment_running = TRUE;
1250 }
1252 while ((stream = gst_asf_demux_find_stream_with_complete_payload (demux))) {
1253 AsfPayload *payload;
1255 payload = &g_array_index (stream->payloads, AsfPayload, 0);
1257 /* Do we have tags pending for this stream? */
1258 if (stream->pending_tags) {
1259 GST_LOG_OBJECT (stream->pad, "%" GST_PTR_FORMAT, stream->pending_tags);
1260 gst_element_found_tags_for_pad (GST_ELEMENT (demux), stream->pad,
1261 stream->pending_tags);
1262 stream->pending_tags = NULL;
1263 }
1265 /* We have the whole packet now so we should push the packet to
1266 * the src pad now. First though we should check if we need to do
1267 * descrambling */
1268 if (demux->span > 1) {
1269 gst_asf_demux_descramble_buffer (demux, stream, &payload->buf);
1270 }
1272 payload->buf = gst_buffer_make_metadata_writable (payload->buf);
1274 if (!payload->keyframe) {
1275 GST_BUFFER_FLAG_SET (payload->buf, GST_BUFFER_FLAG_DELTA_UNIT);
1276 }
1278 if (stream->discont) {
1279 GST_DEBUG_OBJECT (stream->pad, "marking DISCONT on stream");
1280 GST_BUFFER_FLAG_SET (payload->buf, GST_BUFFER_FLAG_DISCONT);
1281 stream->discont = FALSE;
1282 }
1284 if (G_UNLIKELY (stream->is_video && payload->par_x && payload->par_y &&
1285 (payload->par_x != stream->par_x) &&
1286 (payload->par_y != stream->par_y))) {
1287 GST_DEBUG ("Updating PAR (%d/%d => %d/%d)",
1288 stream->par_x, stream->par_y, payload->par_x, payload->par_y);
1289 stream->par_x = payload->par_x;
1290 stream->par_y = payload->par_y;
1291 gst_caps_set_simple (stream->caps, "pixel-aspect-ratio",
1292 GST_TYPE_FRACTION, stream->par_x, stream->par_y, NULL);
1293 gst_pad_set_caps (stream->pad, stream->caps);
1294 }
1296 if (G_UNLIKELY (stream->interlaced != payload->interlaced)) {
1297 GST_DEBUG ("Updating interlaced status (%d => %d)", stream->interlaced,
1298 payload->interlaced);
1299 stream->interlaced = payload->interlaced;
1300 gst_caps_set_simple (stream->caps, "interlaced", G_TYPE_BOOLEAN,
1301 stream->interlaced, NULL);
1302 }
1304 gst_buffer_set_caps (payload->buf, stream->caps);
1306 /* (sort of) interpolate timestamps using upstream "frame of reference",
1307 * typically useful for live src, but might (unavoidably) mess with
1308 * position reporting if a live src is playing not so live content
1309 * (e.g. rtspsrc taking some time to fall back to tcp) */
1310 GST_BUFFER_TIMESTAMP (payload->buf) = payload->ts + demux->in_gap;
1311 GST_BUFFER_DURATION (payload->buf) = payload->duration;
1313 /* FIXME: we should really set durations on buffers if we can */
1315 GST_LOG_OBJECT (stream->pad, "pushing buffer, ts=%" GST_TIME_FORMAT
1316 ", dur=%" GST_TIME_FORMAT " size=%u",
1317 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (payload->buf)),
1318 GST_TIME_ARGS (GST_BUFFER_DURATION (payload->buf)),
1319 GST_BUFFER_SIZE (payload->buf));
1321 stream->last_flow = gst_pad_push (stream->pad, payload->buf);
1322 payload->buf = NULL;
1323 g_array_remove_index (stream->payloads, 0);
1324 }
1326 return gst_asf_demux_aggregate_flow_return (demux);
1327 }
1329 static void
1330 gst_asf_demux_loop (GstASFDemux * demux)
1331 {
1332 GstFlowReturn flow = GST_FLOW_OK;
1333 GstBuffer *buf = NULL;
1334 guint64 off;
1336 if (demux->state == GST_ASF_DEMUX_STATE_HEADER) {
1337 if (!gst_asf_demux_pull_headers (demux)) {
1338 flow = GST_FLOW_ERROR;
1339 goto pause;
1340 }
1342 gst_asf_demux_pull_indices (demux);
1343 }
1345 g_assert (demux->state == GST_ASF_DEMUX_STATE_DATA);
1347 if (demux->num_packets != 0 && demux->packet >= demux->num_packets)
1348 goto eos;
1350 GST_LOG_OBJECT (demux, "packet %u/%u", (guint) demux->packet + 1,
1351 (guint) demux->num_packets);
1353 off = demux->data_offset + (demux->packet * demux->packet_size);
1355 if (!gst_asf_demux_pull_data (demux, off, demux->packet_size, &buf, &flow)) {
1356 GST_DEBUG_OBJECT (demux, "got flow %s", gst_flow_get_name (flow));
1357 if (flow == GST_FLOW_UNEXPECTED)
1358 goto eos;
1359 else if (!GST_FLOW_IS_FATAL (flow)) {
1360 GST_DEBUG_OBJECT (demux, "Not fatal");
1361 goto pause;
1362 } else
1363 goto read_failed;
1364 }
1366 /* FIXME: maybe we should just skip broken packets and error out only
1367 * after a few broken packets in a row? */
1368 if (!gst_asf_demux_parse_packet (demux, buf))
1369 goto parse_error;
1371 gst_buffer_unref (buf);
1373 flow = gst_asf_demux_push_complete_payloads (demux, FALSE);
1375 ++demux->packet;
1377 if (demux->num_packets > 0 && demux->packet >= demux->num_packets) {
1378 GST_LOG_OBJECT (demux, "reached EOS");
1379 goto eos;
1380 }
1382 if (flow != GST_FLOW_OK) {
1383 GST_DEBUG_OBJECT (demux, "pushing complete payloads failed");
1384 goto pause;
1385 }
1387 /* check if we're at the end of the configured segment */
1388 /* FIXME: check if segment end reached etc. */
1390 return;
1392 eos:
1393 {
1394 /* if we haven't activated our streams yet, this might be because we have
1395 * less data queued than required for preroll; force stream activation and
1396 * send any pending payloads before sending EOS */
1397 if (!demux->activated_streams)
1398 gst_asf_demux_push_complete_payloads (demux, TRUE);
1400 /* we want to push an eos or post a segment-done in any case */
1401 if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
1402 gint64 stop;
1404 /* for segment playback we need to post when (in stream time)
1405 * we stopped, this is either stop (when set) or the duration. */
1406 if ((stop = demux->segment.stop) == -1)
1407 stop = demux->segment.duration;
1409 GST_INFO_OBJECT (demux, "Posting segment-done, at end of segment");
1410 gst_element_post_message (GST_ELEMENT_CAST (demux),
1411 gst_message_new_segment_done (GST_OBJECT (demux), GST_FORMAT_TIME,
1412 stop));
1413 } else {
1414 /* normal playback, send EOS to all linked pads */
1415 GST_INFO_OBJECT (demux, "Sending EOS, at end of stream");
1416 gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
1417 }
1418 /* ... and fall through to pause */
1419 GST_DEBUG_OBJECT (demux, "EOSing");
1420 }
1421 pause:
1422 {
1423 GST_DEBUG_OBJECT (demux, "pausing task");
1424 demux->segment_running = FALSE;
1425 gst_pad_pause_task (demux->sinkpad);
1427 /* For the error cases (not EOS) */
1428 if (GST_FLOW_IS_FATAL (flow) || flow == GST_FLOW_NOT_LINKED) {
1429 /* Post an error. Hopefully something else already has, but if not... */
1430 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
1431 (_("Internal data stream error.")),
1432 ("streaming stopped, reason %s", gst_flow_get_name (flow)));
1433 }
1434 return;
1435 }
1437 /* ERRORS */
1438 read_failed:
1439 {
1440 GST_DEBUG_OBJECT (demux, "Read failed, doh");
1441 gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
1442 flow = GST_FLOW_UNEXPECTED;
1443 goto pause;
1444 }
1445 parse_error:
1446 {
1447 gst_buffer_unref (buf);
1448 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
1449 ("Error parsing ASF packet %u", (guint) demux->packet));
1450 gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
1451 flow = GST_FLOW_ERROR;
1452 goto pause;
1453 }
1454 }
1456 static GstFlowReturn
1457 gst_asf_demux_chain (GstPad * pad, GstBuffer * buf)
1458 {
1459 GstFlowReturn ret = GST_FLOW_OK;
1460 GstASFDemux *demux;
1462 demux = GST_ASF_DEMUX (GST_PAD_PARENT (pad));
1464 GST_LOG_OBJECT (demux, "buffer: size=%u, offset=%" G_GINT64_FORMAT ", time=%"
1465 GST_TIME_FORMAT, GST_BUFFER_SIZE (buf), GST_BUFFER_OFFSET (buf),
1466 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)));
1468 if (GST_BUFFER_IS_DISCONT (buf)) {
1469 GST_DEBUG_OBJECT (demux, "received DISCONT");
1470 gst_asf_demux_mark_discont (demux);
1471 }
1473 if (!GST_CLOCK_TIME_IS_VALID (demux->in_gap) &&
1474 GST_BUFFER_TIMESTAMP_IS_VALID (buf)) {
1475 demux->in_gap = GST_BUFFER_TIMESTAMP (buf) - demux->in_segment.start;
1476 GST_DEBUG_OBJECT (demux, "upstream segment start %" GST_TIME_FORMAT
1477 ", interpolation gap: %" GST_TIME_FORMAT,
1478 GST_TIME_ARGS (demux->in_segment.start), GST_TIME_ARGS (demux->in_gap));
1479 }
1481 gst_adapter_push (demux->adapter, buf);
1483 switch (demux->state) {
1484 case GST_ASF_DEMUX_STATE_HEADER:{
1485 ret = gst_asf_demux_chain_headers (demux);
1486 if (demux->state != GST_ASF_DEMUX_STATE_DATA)
1487 break;
1488 /* otherwise fall through */
1489 }
1490 case GST_ASF_DEMUX_STATE_DATA:
1491 {
1492 guint64 data_size;
1494 data_size = demux->packet_size;
1496 while (gst_adapter_available (demux->adapter) >= data_size) {
1497 GstBuffer *buf;
1499 /* do not overshoot data section when streaming */
1500 if (demux->num_packets != 0 && demux->packet >= 0
1501 && demux->packet >= demux->num_packets)
1502 goto eos;
1504 buf = gst_adapter_take_buffer (demux->adapter, data_size);
1506 /* FIXME: maybe we should just skip broken packets and error out only
1507 * after a few broken packets in a row? */
1508 if (!gst_asf_demux_parse_packet (demux, buf)) {
1509 GST_WARNING_OBJECT (demux, "Parse error");
1510 }
1512 gst_buffer_unref (buf);
1514 ret = gst_asf_demux_push_complete_payloads (demux, FALSE);
1516 if (demux->packet >= 0)
1517 ++demux->packet;
1518 }
1519 break;
1520 }
1521 default:
1522 g_assert_not_reached ();
1523 }
1525 done:
1526 if (ret != GST_FLOW_OK)
1527 GST_DEBUG_OBJECT (demux, "flow: %s", gst_flow_get_name (ret));
1529 return ret;
1531 eos:
1532 {
1533 GST_DEBUG_OBJECT (demux, "Handled last packet, setting EOS");
1534 ret = GST_FLOW_UNEXPECTED;
1535 goto done;
1536 }
1537 }
1539 static inline gboolean
1540 gst_asf_demux_skip_bytes (guint num_bytes, guint8 ** p_data, guint64 * p_size)
1541 {
1542 if (*p_size < num_bytes)
1543 return FALSE;
1545 *p_data += num_bytes;
1546 *p_size -= num_bytes;
1547 return TRUE;
1548 }
1550 static inline guint8
1551 gst_asf_demux_get_uint8 (guint8 ** p_data, guint64 * p_size)
1552 {
1553 guint8 ret;
1555 g_assert (*p_size >= 1);
1556 ret = GST_READ_UINT8 (*p_data);
1557 *p_data += sizeof (guint8);
1558 *p_size -= sizeof (guint8);
1559 return ret;
1560 }
1562 static inline guint16
1563 gst_asf_demux_get_uint16 (guint8 ** p_data, guint64 * p_size)
1564 {
1565 guint16 ret;
1567 g_assert (*p_size >= 2);
1568 ret = GST_READ_UINT16_LE (*p_data);
1569 *p_data += sizeof (guint16);
1570 *p_size -= sizeof (guint16);
1571 return ret;
1572 }
1574 static inline guint32
1575 gst_asf_demux_get_uint32 (guint8 ** p_data, guint64 * p_size)
1576 {
1577 guint32 ret;
1579 g_assert (*p_size >= 4);
1580 ret = GST_READ_UINT32_LE (*p_data);
1581 *p_data += sizeof (guint32);
1582 *p_size -= sizeof (guint32);
1583 return ret;
1584 }
1586 static inline guint64
1587 gst_asf_demux_get_uint64 (guint8 ** p_data, guint64 * p_size)
1588 {
1589 guint64 ret;
1591 g_assert (*p_size >= 8);
1592 ret = GST_READ_UINT64_LE (*p_data);
1593 *p_data += sizeof (guint64);
1594 *p_size -= sizeof (guint64);
1595 return ret;
1596 }
1598 static inline guint32
1599 gst_asf_demux_get_var_length (guint8 type, guint8 ** p_data, guint64 * p_size)
1600 {
1601 switch (type) {
1602 case 0:
1603 return 0;
1605 case 1:
1606 g_assert (*p_size >= 1);
1607 return gst_asf_demux_get_uint8 (p_data, p_size);
1609 case 2:
1610 g_assert (*p_size >= 2);
1611 return gst_asf_demux_get_uint16 (p_data, p_size);
1613 case 3:
1614 g_assert (*p_size >= 4);
1615 return gst_asf_demux_get_uint32 (p_data, p_size);
1617 default:
1618 break;
1619 }
1621 g_assert_not_reached ();
1622 }
1624 static gboolean
1625 gst_asf_demux_get_buffer (GstBuffer ** p_buf, guint num_bytes_to_read,
1626 guint8 ** p_data, guint64 * p_size)
1627 {
1628 *p_buf = NULL;
1630 if (*p_size < num_bytes_to_read)
1631 return FALSE;
1633 *p_buf = gst_buffer_new_and_alloc (num_bytes_to_read);
1634 memcpy (GST_BUFFER_DATA (*p_buf), *p_data, num_bytes_to_read);
1635 *p_data += num_bytes_to_read;
1636 *p_size -= num_bytes_to_read;
1637 return TRUE;
1638 }
1640 static gboolean
1641 gst_asf_demux_get_bytes (guint8 ** p_buf, guint num_bytes_to_read,
1642 guint8 ** p_data, guint64 * p_size)
1643 {
1644 *p_buf = NULL;
1646 if (*p_size < num_bytes_to_read)
1647 return FALSE;
1649 *p_buf = g_memdup (*p_data, num_bytes_to_read);
1650 *p_data += num_bytes_to_read;
1651 *p_size -= num_bytes_to_read;
1652 return TRUE;
1653 }
1655 static gboolean
1656 gst_asf_demux_get_string (gchar ** p_str, guint16 * p_strlen,
1657 guint8 ** p_data, guint64 * p_size)
1658 {
1659 guint16 s_length;
1660 guint8 *s;
1662 *p_str = NULL;
1664 if (*p_size < 2)
1665 return FALSE;
1667 s_length = gst_asf_demux_get_uint16 (p_data, p_size);
1669 if (p_strlen)
1670 *p_strlen = s_length;
1672 if (s_length == 0) {
1673 GST_WARNING ("zero-length string");
1674 *p_str = g_strdup ("");
1675 return TRUE;
1676 }
1678 if (!gst_asf_demux_get_bytes (&s, s_length, p_data, p_size))
1679 return FALSE;
1681 g_assert (s != NULL);
1683 /* just because They don't exist doesn't
1684 * mean They are not out to get you ... */
1685 if (s[s_length - 1] != '\0') {
1686 s = g_realloc (s, s_length + 1);
1687 s[s_length] = '\0';
1688 }
1690 *p_str = (gchar *) s;
1691 return TRUE;
1692 }
1695 static void
1696 gst_asf_demux_get_guid (ASFGuid * guid, guint8 ** p_data, guint64 * p_size)
1697 {
1698 g_assert (*p_size >= 4 * sizeof (guint32));
1700 guid->v1 = gst_asf_demux_get_uint32 (p_data, p_size);
1701 guid->v2 = gst_asf_demux_get_uint32 (p_data, p_size);
1702 guid->v3 = gst_asf_demux_get_uint32 (p_data, p_size);
1703 guid->v4 = gst_asf_demux_get_uint32 (p_data, p_size);
1704 }
1706 static gboolean
1707 gst_asf_demux_get_stream_audio (asf_stream_audio * audio, guint8 ** p_data,
1708 guint64 * p_size)
1709 {
1710 if (*p_size < (2 + 2 + 4 + 4 + 2 + 2 + 2))
1711 return FALSE;
1713 /* WAVEFORMATEX Structure */
1714 audio->codec_tag = gst_asf_demux_get_uint16 (p_data, p_size);
1715 audio->channels = gst_asf_demux_get_uint16 (p_data, p_size);
1716 audio->sample_rate = gst_asf_demux_get_uint32 (p_data, p_size);
1717 audio->byte_rate = gst_asf_demux_get_uint32 (p_data, p_size);
1718 audio->block_align = gst_asf_demux_get_uint16 (p_data, p_size);
1719 audio->word_size = gst_asf_demux_get_uint16 (p_data, p_size);
1720 /* Codec specific data size */
1721 audio->size = gst_asf_demux_get_uint16 (p_data, p_size);
1722 return TRUE;
1723 }
1725 static gboolean
1726 gst_asf_demux_get_stream_video (asf_stream_video * video, guint8 ** p_data,
1727 guint64 * p_size)
1728 {
1729 if (*p_size < (4 + 4 + 1 + 2))
1730 return FALSE;
1732 video->width = gst_asf_demux_get_uint32 (p_data, p_size);
1733 video->height = gst_asf_demux_get_uint32 (p_data, p_size);
1734 video->unknown = gst_asf_demux_get_uint8 (p_data, p_size);
1735 video->size = gst_asf_demux_get_uint16 (p_data, p_size);
1736 return TRUE;
1737 }
1739 static gboolean
1740 gst_asf_demux_get_stream_video_format (asf_stream_video_format * fmt,
1741 guint8 ** p_data, guint64 * p_size)
1742 {
1743 if (*p_size < (4 + 4 + 4 + 2 + 2 + 4 + 4 + 4 + 4 + 4 + 4))
1744 return FALSE;
1746 fmt->size = gst_asf_demux_get_uint32 (p_data, p_size);
1747 fmt->width = gst_asf_demux_get_uint32 (p_data, p_size);
1748 fmt->height = gst_asf_demux_get_uint32 (p_data, p_size);
1749 fmt->planes = gst_asf_demux_get_uint16 (p_data, p_size);
1750 fmt->depth = gst_asf_demux_get_uint16 (p_data, p_size);
1751 fmt->tag = gst_asf_demux_get_uint32 (p_data, p_size);
1752 fmt->image_size = gst_asf_demux_get_uint32 (p_data, p_size);
1753 fmt->xpels_meter = gst_asf_demux_get_uint32 (p_data, p_size);
1754 fmt->ypels_meter = gst_asf_demux_get_uint32 (p_data, p_size);
1755 fmt->num_colors = gst_asf_demux_get_uint32 (p_data, p_size);
1756 fmt->imp_colors = gst_asf_demux_get_uint32 (p_data, p_size);
1757 return TRUE;
1758 }
1760 AsfStream *
1761 gst_asf_demux_get_stream (GstASFDemux * demux, guint16 id)
1762 {
1763 guint i;
1765 for (i = 0; i < demux->num_streams; i++) {
1766 if (demux->stream[i].id == id)
1767 return &demux->stream[i];
1768 }
1770 GST_WARNING ("Segment found for undefined stream: (%d)", id);
1771 return NULL;
1772 }
1774 static void
1775 gst_asf_demux_setup_pad (GstASFDemux * demux, GstPad * src_pad,
1776 GstCaps * caps, guint16 id, gboolean is_video, GstTagList * tags)
1777 {
1778 AsfStream *stream;
1780 gst_pad_use_fixed_caps (src_pad);
1781 gst_pad_set_caps (src_pad, caps);
1783 gst_pad_set_event_function (src_pad,
1784 GST_DEBUG_FUNCPTR (gst_asf_demux_handle_src_event));
1785 gst_pad_set_query_type_function (src_pad,
1786 GST_DEBUG_FUNCPTR (gst_asf_demux_get_src_query_types));
1787 gst_pad_set_query_function (src_pad,
1788 GST_DEBUG_FUNCPTR (gst_asf_demux_handle_src_query));
1790 stream = &demux->stream[demux->num_streams];
1791 stream->caps = caps;
1792 stream->pad = src_pad;
1793 stream->id = id;
1794 stream->fps_known = !is_video; /* bit hacky for audio */
1795 stream->is_video = is_video;
1796 stream->pending_tags = tags;
1797 stream->discont = TRUE;
1798 if (is_video) {
1799 GstStructure *st;
1800 gint par_x, par_y;
1801 st = gst_caps_get_structure (caps, 0);
1802 if (gst_structure_get_fraction (st, "pixel-aspect-ratio", &par_x, &par_y) &&
1803 par_x > 0 && par_y > 0) {
1804 GST_DEBUG ("PAR %d/%d", par_x, par_y);
1805 stream->par_x = par_x;
1806 stream->par_y = par_y;
1807 }
1808 }
1810 stream->payloads = g_array_new (FALSE, FALSE, sizeof (AsfPayload));
1812 GST_INFO ("Created pad %s for stream %u with caps %" GST_PTR_FORMAT,
1813 GST_PAD_NAME (src_pad), demux->num_streams, caps);
1815 ++demux->num_streams;
1817 stream->active = FALSE;
1818 }
1820 static void
1821 gst_asf_demux_add_audio_stream (GstASFDemux * demux,
1822 asf_stream_audio * audio, guint16 id, guint8 ** p_data, guint64 * p_size)
1823 {
1824 GstTagList *tags = NULL;
1825 GstBuffer *extradata = NULL;
1826 GstPad *src_pad;
1827 GstCaps *caps;
1828 guint16 size_left = 0;
1829 gchar *codec_name = NULL;
1830 gchar *name = NULL;
1832 size_left = audio->size;
1834 /* Create the audio pad */
1835 name = g_strdup_printf ("audio_%02d", demux->num_audio_streams);
1837 src_pad = gst_pad_new_from_static_template (&audio_src_template, name);
1838 g_free (name);
1840 /* Swallow up any left over data and set up the
1841 * standard properties from the header info */
1842 if (size_left) {
1843 GST_INFO_OBJECT (demux, "Audio header contains %d bytes of "
1844 "codec specific data", size_left);
1846 g_assert (size_left <= *p_size);
1847 gst_asf_demux_get_buffer (&extradata, size_left, p_data, p_size);
1848 }
1850 /* asf_stream_audio is the same as gst_riff_strf_auds, but with an
1851 * additional two bytes indicating extradata. */
1852 caps = gst_riff_create_audio_caps (audio->codec_tag, NULL,
1853 (gst_riff_strf_auds *) audio, extradata, NULL, &codec_name);
1855 if (caps == NULL) {
1856 caps = gst_caps_new_simple ("audio/x-asf-unknown", "codec_id",
1857 G_TYPE_INT, (gint) audio->codec_tag, NULL);
1858 }
1860 /* Informing about that audio format we just added */
1861 if (codec_name) {
1862 tags = gst_tag_list_new ();
1863 gst_tag_list_add (tags, GST_TAG_MERGE_APPEND, GST_TAG_AUDIO_CODEC,
1864 codec_name, NULL);
1865 g_free (codec_name);
1866 }
1868 if (extradata)
1869 gst_buffer_unref (extradata);
1871 GST_INFO ("Adding audio stream #%u, id %u codec %u (0x%04x), tags=%"
1872 GST_PTR_FORMAT, demux->num_audio_streams, id, audio->codec_tag,
1873 audio->codec_tag, tags);
1875 ++demux->num_audio_streams;
1877 gst_asf_demux_setup_pad (demux, src_pad, caps, id, FALSE, tags);
1878 }
1880 static void
1881 gst_asf_demux_add_video_stream (GstASFDemux * demux,
1882 asf_stream_video_format * video, guint16 id,
1883 guint8 ** p_data, guint64 * p_size)
1884 {
1885 GstTagList *tags = NULL;
1886 GstBuffer *extradata = NULL;
1887 GstPad *src_pad;
1888 GstCaps *caps;
1889 gchar *name = NULL;
1890 gchar *codec_name = NULL;
1891 gint size_left = video->size - 40;
1893 /* Create the video pad */
1894 name = g_strdup_printf ("video_%02d", demux->num_video_streams);
1895 src_pad = gst_pad_new_from_static_template (&video_src_template, name);
1896 g_free (name);
1898 /* Now try some gstreamer formatted MIME types (from gst_avi_demux_strf_vids) */
1899 if (size_left) {
1900 GST_LOG ("Video header has %d bytes of codec specific data", size_left);
1901 g_assert (size_left <= *p_size);
1902 gst_asf_demux_get_buffer (&extradata, size_left, p_data, p_size);
1903 }
1905 GST_DEBUG ("video codec %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (video->tag));
1907 /* yes, asf_stream_video_format and gst_riff_strf_vids are the same */
1908 caps = gst_riff_create_video_caps (video->tag, NULL,
1909 (gst_riff_strf_vids *) video, extradata, NULL, &codec_name);
1911 if (caps == NULL) {
1912 caps = gst_caps_new_simple ("video/x-asf-unknown", "fourcc",
1913 GST_TYPE_FOURCC, video->tag, NULL);
1914 } else {
1915 GstStructure *s;
1916 gint ax, ay;
1918 s = gst_asf_demux_get_metadata_for_stream (demux, id);
1919 if (gst_structure_get_int (s, "AspectRatioX", &ax) &&
1920 gst_structure_get_int (s, "AspectRatioY", &ay) && (ax > 0 && ay > 0)) {
1921 gst_caps_set_simple (caps, "pixel-aspect-ratio", GST_TYPE_FRACTION,
1922 ax, ay, NULL);
1924 } else {
1925 guint ax, ay;
1926 /* retry with the global metadata */
1927 GST_DEBUG ("Retrying with global metadata %" GST_PTR_FORMAT,
1928 demux->global_metadata);
1929 s = demux->global_metadata;
1930 if (gst_structure_get_uint (s, "AspectRatioX", &ax) &&
1931 gst_structure_get_uint (s, "AspectRatioY", &ay)) {
1932 GST_DEBUG ("ax:%d, ay:%d", ax, ay);
1933 if (ax > 0 && ay > 0)
1934 gst_caps_set_simple (caps, "pixel-aspect-ratio", GST_TYPE_FRACTION,
1935 ax, ay, NULL);
1936 }
1937 }
1938 s = gst_caps_get_structure (caps, 0);
1939 gst_structure_remove_field (s, "framerate");
1940 }
1942 /* add fourcc format to caps, some proprietary decoders seem to need it */
1943 gst_caps_set_simple (caps, "format", GST_TYPE_FOURCC, video->tag, NULL);
1945 if (codec_name) {
1946 tags = gst_tag_list_new ();
1947 gst_tag_list_add (tags, GST_TAG_MERGE_APPEND, GST_TAG_VIDEO_CODEC,
1948 codec_name, NULL);
1949 g_free (codec_name);
1950 }
1952 if (extradata)
1953 gst_buffer_unref (extradata);
1955 GST_INFO ("Adding video stream #%u, id %u, codec %"
1956 GST_FOURCC_FORMAT " (0x%08x)", demux->num_video_streams, id,
1957 GST_FOURCC_ARGS (video->tag), video->tag);
1959 ++demux->num_video_streams;
1961 gst_asf_demux_setup_pad (demux, src_pad, caps, id, TRUE, tags);
1962 }
1964 static void
1965 gst_asf_demux_activate_stream (GstASFDemux * demux, AsfStream * stream)
1966 {
1967 if (!stream->active) {
1968 GST_INFO_OBJECT (demux, "Activating stream %2u, pad %s, caps %"
1969 GST_PTR_FORMAT, stream->id, GST_PAD_NAME (stream->pad), stream->caps);
1970 gst_pad_set_active (stream->pad, TRUE);
1971 gst_element_add_pad (GST_ELEMENT_CAST (demux), stream->pad);
1972 stream->active = TRUE;
1973 }
1974 }
1976 static AsfStream *
1977 gst_asf_demux_parse_stream_object (GstASFDemux * demux, guint8 * data,
1978 guint64 size)
1979 {
1980 AsfCorrectionType correction_type;
1981 AsfStreamType stream_type;
1982 GstClockTime time_offset;
1983 gboolean is_encrypted;
1984 guint16 stream_id;
1985 guint16 flags;
1986 ASFGuid guid;
1987 guint stream_specific_size;
1988 guint type_specific_size;
1989 guint unknown;
1991 /* Get the rest of the header's header */
1992 if (size < (16 + 16 + 8 + 4 + 4 + 2 + 4))
1993 goto not_enough_data;
1995 gst_asf_demux_get_guid (&guid, &data, &size);
1996 stream_type = gst_asf_demux_identify_guid (asf_stream_guids, &guid);
1998 gst_asf_demux_get_guid (&guid, &data, &size);
1999 correction_type = gst_asf_demux_identify_guid (asf_correction_guids, &guid);
2001 time_offset = gst_asf_demux_get_uint64 (&data, &size) * 100;
2003 type_specific_size = gst_asf_demux_get_uint32 (&data, &size);
2004 stream_specific_size = gst_asf_demux_get_uint32 (&data, &size);
2006 flags = gst_asf_demux_get_uint16 (&data, &size);
2007 stream_id = flags & 0x7f;
2008 is_encrypted = !!((flags & 0x8000) << 15);
2009 unknown = gst_asf_demux_get_uint32 (&data, &size);
2011 GST_DEBUG_OBJECT (demux, "Found stream %u, time_offset=%" GST_TIME_FORMAT,
2012 stream_id, GST_TIME_ARGS (time_offset));
2014 switch (stream_type) {
2015 case ASF_STREAM_AUDIO:{
2016 asf_stream_audio audio_object;
2018 if (!gst_asf_demux_get_stream_audio (&audio_object, &data, &size))
2019 goto not_enough_data;
2021 GST_INFO ("Object is an audio stream with %u bytes of additional data",
2022 audio_object.size);
2024 gst_asf_demux_add_audio_stream (demux, &audio_object, stream_id,
2025 &data, &size);
2027 switch (correction_type) {
2028 case ASF_CORRECTION_ON:{
2029 guint span, packet_size, chunk_size, data_size, silence_data;
2031 GST_INFO ("Using error correction");
2033 if (size < (1 + 2 + 2 + 2 + 1))
2034 goto not_enough_data;
2036 span = gst_asf_demux_get_uint8 (&data, &size);
2037 packet_size = gst_asf_demux_get_uint16 (&data, &size);
2038 chunk_size = gst_asf_demux_get_uint16 (&data, &size);
2039 data_size = gst_asf_demux_get_uint16 (&data, &size);
2040 silence_data = gst_asf_demux_get_uint8 (&data, &size);
2042 /* FIXME: shouldn't this be per-stream? */
2043 demux->span = span;
2045 GST_DEBUG_OBJECT (demux, "Descrambling ps:%u cs:%u ds:%u s:%u sd:%u",
2046 packet_size, chunk_size, data_size, span, silence_data);
2048 if (demux->span > 1) {
2049 if (chunk_size == 0 || ((packet_size / chunk_size) <= 1)) {
2050 /* Disable descrambling */
2051 demux->span = 0;
2052 } else {
2053 /* FIXME: this else branch was added for
2054 * weird_al_yankovic - the saga begins.asf */
2055 demux->ds_packet_size = packet_size;
2056 demux->ds_chunk_size = chunk_size;
2057 }
2058 } else {
2059 /* Descambling is enabled */
2060 demux->ds_packet_size = packet_size;
2061 demux->ds_chunk_size = chunk_size;
2062 }
2063 #if 0
2064 /* Now skip the rest of the silence data */
2065 if (data_size > 1)
2066 gst_bytestream_flush (demux->bs, data_size - 1);
2067 #else
2068 /* FIXME: CHECKME. And why -1? */
2069 if (data_size > 1) {
2070 if (!gst_asf_demux_skip_bytes (data_size - 1, &data, &size)) {
2071 goto not_enough_data;
2072 }
2073 }
2074 #endif
2075 break;
2076 }
2077 case ASF_CORRECTION_OFF:{
2078 GST_INFO ("Error correction off");
2079 if (!gst_asf_demux_skip_bytes (stream_specific_size, &data, &size))
2080 goto not_enough_data;
2081 break;
2082 }
2083 default:
2084 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
2085 ("Audio stream using unknown error correction"));
2086 return NULL;
2087 }
2089 break;
2090 }
2092 case ASF_STREAM_VIDEO:{
2093 asf_stream_video_format video_format_object;
2094 asf_stream_video video_object;
2095 guint16 vsize;
2097 if (!gst_asf_demux_get_stream_video (&video_object, &data, &size))
2098 goto not_enough_data;
2100 vsize = video_object.size - 40; /* Byte order gets offset by single byte */
2102 GST_INFO ("object is a video stream with %u bytes of "
2103 "additional data", vsize);
2105 if (!gst_asf_demux_get_stream_video_format (&video_format_object,
2106 &data, &size)) {
2107 goto not_enough_data;
2108 }
2110 gst_asf_demux_add_video_stream (demux, &video_format_object, stream_id,
2111 &data, &size);
2113 break;
2114 }
2116 default:
2117 GST_WARNING_OBJECT (demux, "Unknown stream type for stream %u",
2118 stream_id);
2119 break;
2120 }
2122 return gst_asf_demux_get_stream (demux, stream_id);
2124 not_enough_data:
2125 {
2126 GST_WARNING_OBJECT (demux, "Unexpected end of data parsing stream object");
2127 /* we'll error out later if we found no streams */
2128 return NULL;
2129 }
2130 }
2132 static const gchar *
2133 gst_asf_demux_get_gst_tag_from_tag_name (const gchar * name_utf8)
2134 {
2135 const struct
2136 {
2137 const gchar *asf_name;
2138 const gchar *gst_name;
2139 } tags[] = {
2140 {
2141 "WM/Genre", GST_TAG_GENRE}, {
2142 "WM/AlbumTitle", GST_TAG_ALBUM}, {
2143 "WM/AlbumArtist", GST_TAG_ARTIST}, {
2144 "WM/Picture", GST_TAG_IMAGE}, {
2145 "WM/Track", GST_TAG_TRACK_NUMBER}, {
2146 "WM/Year", GST_TAG_DATE}
2147 /* { "WM/Composer", GST_TAG_COMPOSER } */
2148 };
2149 gsize out = strlen (name_utf8);
2150 guint i;
2152 if (name_utf8 == NULL) {
2153 GST_WARNING ("Failed to convert name to UTF8, skipping");
2154 return NULL;
2155 }
2157 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
2158 if (strncmp (tags[i].asf_name, name_utf8, out) == 0) {
2159 GST_LOG ("map tagname '%s' -> '%s'", name_utf8, tags[i].gst_name);
2160 return tags[i].gst_name;
2161 }
2162 }
2164 return NULL;
2165 }
2167 /* gst_asf_demux_add_global_tags() takes ownership of taglist! */
2168 static void
2169 gst_asf_demux_add_global_tags (GstASFDemux * demux, GstTagList * taglist)
2170 {
2171 GstTagList *t;
2173 GST_DEBUG_OBJECT (demux, "adding global tags: %" GST_PTR_FORMAT, taglist);
2175 if (taglist == NULL)
2176 return;
2178 if (gst_tag_list_is_empty (taglist)) {
2179 gst_tag_list_free (taglist);
2180 return;
2181 }
2183 t = gst_tag_list_merge (demux->taglist, taglist, GST_TAG_MERGE_APPEND);
2184 if (demux->taglist)
2185 gst_tag_list_free (demux->taglist);
2186 gst_tag_list_free (taglist);
2187 demux->taglist = t;
2188 GST_LOG_OBJECT (demux, "global tags now: %" GST_PTR_FORMAT, demux->taglist);
2189 }
2191 #define ASF_DEMUX_DATA_TYPE_UTF16LE_STRING 0
2192 #define ASF_DEMUX_DATA_TYPE_BYTE_ARRAY 1
2193 #define ASF_DEMUX_DATA_TYPE_DWORD 3
2195 static void
2196 asf_demux_parse_picture_tag (GstTagList * tags, const guint8 * tag_data,
2197 guint tag_data_len)
2198 {
2199 GstByteReader r;
2200 const guint8 *img_data;
2201 guint32 img_data_len;
2202 guint8 pic_type;
2204 gst_byte_reader_init (&r, tag_data, tag_data_len);
2206 /* skip mime type string (we don't trust it and do our own typefinding),
2207 * and also skip the description string, since we don't use it */
2208 if (!gst_byte_reader_get_uint8 (&r, &pic_type) ||
2209 !gst_byte_reader_get_uint32_le (&r, &img_data_len) ||
2210 !gst_byte_reader_skip_string_utf16 (&r) ||
2211 !gst_byte_reader_skip_string_utf16 (&r) ||
2212 !gst_byte_reader_get_data (&r, img_data_len, &img_data)) {
2213 goto not_enough_data;
2214 }
2217 if (!gst_tag_list_add_id3_image (tags, img_data, img_data_len, pic_type))
2218 GST_DEBUG ("failed to add image extracted from WM/Picture tag to taglist");
2220 return;
2222 not_enough_data:
2223 {
2224 GST_DEBUG ("Failed to read WM/Picture tag: not enough data");
2225 GST_MEMDUMP ("WM/Picture data", tag_data, tag_data_len);
2226 return;
2227 }
2228 }
2230 /* Extended Content Description Object */
2231 static GstFlowReturn
2232 gst_asf_demux_process_ext_content_desc (GstASFDemux * demux, guint8 * data,
2233 guint64 size)
2234 {
2235 /* Other known (and unused) 'text/unicode' metadata available :
2236 *
2237 * WM/Lyrics =
2238 * WM/MediaPrimaryClassID = {D1607DBC-E323-4BE2-86A1-48A42A28441E}
2239 * WMFSDKVersion = 9.00.00.2980
2240 * WMFSDKNeeded = 0.0.0.0000
2241 * WM/UniqueFileIdentifier = AMGa_id=R 15334;AMGp_id=P 5149;AMGt_id=T 2324984
2242 * WM/Publisher = 4AD
2243 * WM/Provider = AMG
2244 * WM/ProviderRating = 8
2245 * WM/ProviderStyle = Rock (similar to WM/Genre)
2246 * WM/GenreID (similar to WM/Genre)
2247 * WM/TrackNumber (same as WM/Track but as a string)
2248 *
2249 * Other known (and unused) 'non-text' metadata available :
2250 *
2251 * WM/EncodingTime
2252 * WM/MCDI
2253 * IsVBR
2254 *
2255 * We might want to read WM/TrackNumber and use atoi() if we don't have
2256 * WM/Track
2257 */
2259 GstTagList *taglist;
2260 guint16 blockcount, i;
2262 GST_INFO_OBJECT (demux, "object is an extended content description");
2264 taglist = gst_tag_list_new ();
2266 /* Content Descriptor Count */
2267 if (size < 2)
2268 goto not_enough_data;
2270 blockcount = gst_asf_demux_get_uint16 (&data, &size);
2272 for (i = 1; i <= blockcount; ++i) {
2273 const gchar *gst_tag_name;
2274 guint16 datatype;
2275 guint16 value_len;
2276 guint16 name_len;
2277 GValue tag_value = { 0, };
2278 gsize in, out;
2279 gchar *name;
2280 gchar *name_utf8 = NULL;
2281 gchar *value;
2283 /* Descriptor */
2284 if (!gst_asf_demux_get_string (&name, &name_len, &data, &size))
2285 goto not_enough_data;
2287 if (size < 2) {
2288 g_free (name);
2289 goto not_enough_data;
2290 }
2291 /* Descriptor Value Data Type */
2292 datatype = gst_asf_demux_get_uint16 (&data, &size);
2294 /* Descriptor Value (not really a string, but same thing reading-wise) */
2295 if (!gst_asf_demux_get_string (&value, &value_len, &data, &size)) {
2296 g_free (name);
2297 goto not_enough_data;
2298 }
2300 name_utf8 =
2301 g_convert (name, name_len, "UTF-8", "UTF-16LE", &in, &out, NULL);
2303 GST_DEBUG ("Found tag/metadata %s", name_utf8);
2305 gst_tag_name = gst_asf_demux_get_gst_tag_from_tag_name (name_utf8);
2307 GST_DEBUG ("gst_tag_name %s", gst_tag_name);
2309 if (name_utf8 != NULL) {
2310 switch (datatype) {
2311 case ASF_DEMUX_DATA_TYPE_UTF16LE_STRING:{
2312 gchar *value_utf8;
2314 value_utf8 = g_convert (value, value_len, "UTF-8", "UTF-16LE",
2315 &in, &out, NULL);
2317 GST_DEBUG ("string value %s", value_utf8);
2319 /* get rid of tags with empty value */
2320 if (value_utf8 != NULL && *value_utf8 != '\0') {
2321 value_utf8[out] = '\0';
2323 if (gst_tag_name != NULL) {
2324 if (strcmp (gst_tag_name, GST_TAG_DATE) == 0) {
2325 guint year = atoi (value_utf8);
2327 if (year > 0) {
2328 GDate *date = g_date_new_dmy (1, 1, year);
2330 g_value_init (&tag_value, GST_TYPE_DATE);
2331 gst_value_set_date (&tag_value, date);
2332 g_date_free (date);
2333 }
2334 } else if (strcmp (gst_tag_name, GST_TAG_GENRE) == 0) {
2335 guint id3v1_genre_id;
2336 const gchar *genre_str;
2338 if (sscanf (value_utf8, "(%u)", &id3v1_genre_id) == 1 &&
2339 ((genre_str = gst_tag_id3_genre_get (id3v1_genre_id)))) {
2340 GST_DEBUG ("Genre: %s -> %s", value_utf8, genre_str);
2341 g_free (value_utf8);
2342 value_utf8 = g_strdup (genre_str);
2343 }
2344 } else {
2345 GType tag_type;
2347 /* convert tag from string to other type if required */
2348 tag_type = gst_tag_get_type (gst_tag_name);
2349 g_value_init (&tag_value, tag_type);
2350 if (!gst_value_deserialize (&tag_value, value_utf8)) {
2351 GValue from_val = { 0, };
2353 g_value_init (&from_val, G_TYPE_STRING);
2354 g_value_set_string (&from_val, value_utf8);
2355 if (!g_value_transform (&from_val, &tag_value)) {
2356 GST_WARNING_OBJECT (demux,
2357 "Could not transform string tag to " "%s tag type %s",
2358 gst_tag_name, g_type_name (tag_type));
2359 g_value_unset (&tag_value);
2360 }
2361 g_value_unset (&from_val);
2362 }
2363 }
2364 } else {
2365 /* metadata ! */
2366 GST_DEBUG ("Setting metadata");
2367 g_value_init (&tag_value, G_TYPE_STRING);
2368 g_value_set_string (&tag_value, value_utf8);
2369 }
2370 } else if (value_utf8 == NULL) {
2371 GST_WARNING ("Failed to convert string value to UTF8, skipping");
2372 } else {
2373 GST_DEBUG ("Skipping empty string value for %s", gst_tag_name);
2374 }
2375 g_free (value_utf8);
2376 break;
2377 }
2378 case ASF_DEMUX_DATA_TYPE_BYTE_ARRAY:{
2379 if (gst_tag_name) {
2380 if (!g_str_equal (gst_tag_name, GST_TAG_IMAGE)) {
2381 GST_FIXME ("Unhandled byte array tag %s", gst_tag_name);
2382 break;
2383 } else {
2384 asf_demux_parse_picture_tag (taglist, (guint8 *) value,
2385 value_len);
2386 }
2387 }
2388 break;
2389 }
2390 case ASF_DEMUX_DATA_TYPE_DWORD:{
2391 /* this is the track number */
2392 g_value_init (&tag_value, G_TYPE_UINT);
2393 g_value_set_uint (&tag_value, (guint) GST_READ_UINT32_LE (value));
2394 break;
2395 }
2396 default:{
2397 GST_DEBUG ("Skipping tag %s of type %d", gst_tag_name, datatype);
2398 break;
2399 }
2400 }
2402 if (G_IS_VALUE (&tag_value)) {
2403 if (gst_tag_name) {
2404 gst_tag_list_add_values (taglist, GST_TAG_MERGE_APPEND,
2405 gst_tag_name, &tag_value, NULL);
2407 g_value_unset (&tag_value);
2408 } else {
2409 GST_DEBUG ("Setting global metadata %s", name_utf8);
2410 gst_structure_set_value (demux->global_metadata, name_utf8,
2411 &tag_value);
2412 }
2413 }
2414 }
2416 g_free (name);
2417 g_free (value);
2418 }
2420 gst_asf_demux_add_global_tags (demux, taglist);
2422 return GST_FLOW_OK;
2424 /* Errors */
2425 not_enough_data:
2426 {
2427 GST_WARNING ("Unexpected end of data parsing ext content desc object");
2428 gst_tag_list_free (taglist);
2429 return GST_FLOW_OK; /* not really fatal */
2430 }
2431 }
2433 static GstStructure *
2434 gst_asf_demux_get_metadata_for_stream (GstASFDemux * demux, guint stream_num)
2435 {
2436 gchar sname[32];
2437 guint i;
2439 g_snprintf (sname, sizeof (sname), "stream-%u", stream_num);
2441 for (i = 0; i < gst_caps_get_size (demux->metadata); ++i) {
2442 GstStructure *s;
2444 s = gst_caps_get_structure (demux->metadata, i);
2445 if (gst_structure_has_name (s, sname))
2446 return s;
2447 }
2449 gst_caps_append_structure (demux->metadata, gst_structure_empty_new (sname));
2451 /* try lookup again; demux->metadata took ownership of the structure, so we
2452 * can't really make any assumptions about what happened to it, so we can't
2453 * just return it directly after appending it */
2454 return gst_asf_demux_get_metadata_for_stream (demux, stream_num);
2455 }
2457 static GstFlowReturn
2458 gst_asf_demux_process_metadata (GstASFDemux * demux, guint8 * data,
2459 guint64 size)
2460 {
2461 guint16 blockcount, i;
2463 GST_INFO_OBJECT (demux, "object is a metadata object");
2465 /* Content Descriptor Count */
2466 if (size < 2)
2467 goto not_enough_data;
2469 blockcount = gst_asf_demux_get_uint16 (&data, &size);
2471 for (i = 0; i < blockcount; ++i) {
2472 GstStructure *s;
2473 guint16 lang_idx, stream_num, name_len, data_type;
2474 guint32 data_len, ival;
2475 gchar *name_utf8;
2477 if (size < (2 + 2 + 2 + 2 + 4))
2478 goto not_enough_data;
2480 lang_idx = gst_asf_demux_get_uint16 (&data, &size);
2481 stream_num = gst_asf_demux_get_uint16 (&data, &size);
2482 name_len = gst_asf_demux_get_uint16 (&data, &size);
2483 data_type = gst_asf_demux_get_uint16 (&data, &size);
2484 data_len = gst_asf_demux_get_uint32 (&data, &size);
2486 if (size < name_len + data_len)
2487 goto not_enough_data;
2489 /* convert name to UTF-8 */
2490 name_utf8 = g_convert ((gchar *) data, name_len, "UTF-8", "UTF-16LE",
2491 NULL, NULL, NULL);
2492 gst_asf_demux_skip_bytes (name_len, &data, &size);
2494 if (name_utf8 == NULL) {
2495 GST_WARNING ("Failed to convert value name to UTF8, skipping");
2496 gst_asf_demux_skip_bytes (data_len, &data, &size);
2497 continue;
2498 }
2500 if (data_type != ASF_DEMUX_DATA_TYPE_DWORD) {
2501 gst_asf_demux_skip_bytes (data_len, &data, &size);
2502 g_free (name_utf8);
2503 continue;
2504 }
2506 /* read DWORD */
2507 if (size < 4) {
2508 g_free (name_utf8);
2509 goto not_enough_data;
2510 }
2512 ival = gst_asf_demux_get_uint32 (&data, &size);
2514 /* skip anything else there may be, just in case */
2515 gst_asf_demux_skip_bytes (data_len - 4, &data, &size);
2517 s = gst_asf_demux_get_metadata_for_stream (demux, stream_num);
2518 gst_structure_set (s, name_utf8, G_TYPE_INT, ival, NULL);
2519 g_free (name_utf8);
2520 }
2522 GST_INFO_OBJECT (demux, "metadata = %" GST_PTR_FORMAT, demux->metadata);
2523 return GST_FLOW_OK;
2525 /* Errors */
2526 not_enough_data:
2527 {
2528 GST_WARNING ("Unexpected end of data parsing metadata object");
2529 return GST_FLOW_OK; /* not really fatal */
2530 }
2531 }
2533 static GstFlowReturn
2534 gst_asf_demux_process_header (GstASFDemux * demux, guint8 * data, guint64 size)
2535 {
2536 GstFlowReturn ret = GST_FLOW_OK;
2537 guint32 i, num_objects;
2538 guint8 unknown;
2540 /* Get the rest of the header's header */
2541 if (size < (4 + 1 + 1))
2542 goto not_enough_data;
2544 num_objects = gst_asf_demux_get_uint32 (&data, &size);
2545 unknown = gst_asf_demux_get_uint8 (&data, &size);
2546 unknown = gst_asf_demux_get_uint8 (&data, &size);
2548 GST_INFO_OBJECT (demux, "object is a header with %u parts", num_objects);
2550 /* Loop through the header's objects, processing those */
2551 for (i = 0; i < num_objects; ++i) {
2552 GST_INFO_OBJECT (demux, "reading header part %u", i);
2553 ret = gst_asf_demux_process_object (demux, &data, &size);
2554 if (ret != GST_FLOW_OK) {
2555 GST_WARNING ("process_object returned %s", gst_asf_get_flow_name (ret));
2556 break;
2557 }
2558 }
2560 return ret;
2562 not_enough_data:
2563 {
2564 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
2565 ("short read parsing HEADER object"));
2566 return GST_FLOW_ERROR;
2567 }
2568 }
2570 static GstFlowReturn
2571 gst_asf_demux_process_file (GstASFDemux * demux, guint8 * data, guint64 size)
2572 {
2573 guint64 file_size, creation_time, packets_count;
2574 guint64 play_time, send_time, preroll;
2575 guint32 flags, min_pktsize, max_pktsize, min_bitrate;
2577 if (size < (16 + 8 + 8 + 8 + 8 + 8 + 8 + 4 + 4 + 4 + 4))
2578 goto not_enough_data;
2580 gst_asf_demux_skip_bytes (16, &data, &size); /* skip GUID */
2581 file_size = gst_asf_demux_get_uint64 (&data, &size);
2582 creation_time = gst_asf_demux_get_uint64 (&data, &size);
2583 packets_count = gst_asf_demux_get_uint64 (&data, &size);
2584 play_time = gst_asf_demux_get_uint64 (&data, &size);
2585 send_time = gst_asf_demux_get_uint64 (&data, &size);
2586 preroll = gst_asf_demux_get_uint64 (&data, &size);
2587 flags = gst_asf_demux_get_uint32 (&data, &size);
2588 min_pktsize = gst_asf_demux_get_uint32 (&data, &size);
2589 max_pktsize = gst_asf_demux_get_uint32 (&data, &size);
2590 min_bitrate = gst_asf_demux_get_uint32 (&data, &size);
2592 demux->broadcast = !!(flags & 0x01);
2593 demux->seekable = !!(flags & 0x02);
2595 GST_DEBUG_OBJECT (demux, "min_pktsize = %u", min_pktsize);
2596 GST_DEBUG_OBJECT (demux, "flags::broadcast = %d", demux->broadcast);
2597 GST_DEBUG_OBJECT (demux, "flags::seekable = %d", demux->seekable);
2599 if (demux->broadcast) {
2600 /* these fields are invalid if the broadcast flag is set */
2601 play_time = 0;
2602 file_size = 0;
2603 }
2605 if (min_pktsize != max_pktsize)
2606 goto non_fixed_packet_size;
2608 demux->packet_size = max_pktsize;
2610 /* FIXME: do we need send_time as well? what is it? */
2611 if ((play_time * 100) >= (preroll * GST_MSECOND))
2612 demux->play_time = (play_time * 100) - (preroll * GST_MSECOND);
2613 else
2614 demux->play_time = 0;
2616 demux->preroll = preroll * GST_MSECOND;
2618 /* initial latency */
2619 demux->latency = demux->preroll;
2621 if (demux->play_time == 0)
2622 demux->seekable = FALSE;
2624 GST_DEBUG_OBJECT (demux, "play_time %" GST_TIME_FORMAT,
2625 GST_TIME_ARGS (demux->play_time));
2626 GST_DEBUG_OBJECT (demux, "preroll %" GST_TIME_FORMAT,
2627 GST_TIME_ARGS (demux->preroll));
2629 if (demux->play_time > 0) {
2630 gst_segment_set_duration (&demux->segment, GST_FORMAT_TIME,
2631 demux->play_time);
2632 }
2634 GST_INFO ("object is a file with %" G_GUINT64_FORMAT " data packets",
2635 packets_count);
2636 GST_INFO ("preroll = %" G_GUINT64_FORMAT, demux->preroll);
2638 return GST_FLOW_OK;
2640 /* ERRORS */
2641 non_fixed_packet_size:
2642 {
2643 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
2644 ("packet size must be fixed"));
2645 return GST_FLOW_ERROR;
2646 }
2647 not_enough_data:
2648 {
2649 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
2650 ("short read parsing FILE object"));
2651 return GST_FLOW_ERROR;
2652 }
2653 }
2655 /* Content Description Object */
2656 static GstFlowReturn
2657 gst_asf_demux_process_comment (GstASFDemux * demux, guint8 * data, guint64 size)
2658 {
2659 struct
2660 {
2661 const gchar *gst_tag;
2662 guint16 val_length;
2663 gchar *val_utf8;
2664 } tags[5] = {
2665 {
2666 GST_TAG_TITLE, 0, NULL}, {
2667 GST_TAG_ARTIST, 0, NULL}, {
2668 GST_TAG_COPYRIGHT, 0, NULL}, {
2669 GST_TAG_DESCRIPTION, 0, NULL}, {
2670 GST_TAG_COMMENT, 0, NULL}
2671 };
2672 GstTagList *taglist;
2673 GValue value = { 0 };
2674 gsize in, out;
2675 gint i = -1;
2677 GST_INFO_OBJECT (demux, "object is a comment");
2679 if (size < (2 + 2 + 2 + 2 + 2))
2680 goto not_enough_data;
2682 tags[0].val_length = gst_asf_demux_get_uint16 (&data, &size);
2683 tags[1].val_length = gst_asf_demux_get_uint16 (&data, &size);
2684 tags[2].val_length = gst_asf_demux_get_uint16 (&data, &size);
2685 tags[3].val_length = gst_asf_demux_get_uint16 (&data, &size);
2686 tags[4].val_length = gst_asf_demux_get_uint16 (&data, &size);
2688 GST_DEBUG_OBJECT (demux, "Comment lengths: title=%d author=%d copyright=%d "
2689 "description=%d rating=%d", tags[0].val_length, tags[1].val_length,
2690 tags[2].val_length, tags[3].val_length, tags[4].val_length);
2692 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
2693 if (size < tags[i].val_length)
2694 goto not_enough_data;
2696 /* might be just '/0', '/0'... */
2697 if (tags[i].val_length > 2 && tags[i].val_length % 2 == 0) {
2698 /* convert to UTF-8 */
2699 tags[i].val_utf8 = g_convert ((gchar *) data, tags[i].val_length,
2700 "UTF-8", "UTF-16LE", &in, &out, NULL);
2701 }
2702 gst_asf_demux_skip_bytes (tags[i].val_length, &data, &size);
2703 }
2705 /* parse metadata into taglist */
2706 taglist = gst_tag_list_new ();
2707 g_value_init (&value, G_TYPE_STRING);
2708 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
2709 if (tags[i].val_utf8 && strlen (tags[i].val_utf8) > 0 && tags[i].gst_tag) {
2710 g_value_set_string (&value, tags[i].val_utf8);
2711 gst_tag_list_add_values (taglist, GST_TAG_MERGE_APPEND,
2712 tags[i].gst_tag, &value, NULL);
2713 }
2714 }
2715 g_value_unset (&value);
2717 gst_asf_demux_add_global_tags (demux, taglist);
2719 for (i = 0; i < G_N_ELEMENTS (tags); ++i)
2720 g_free (tags[i].val_utf8);
2722 return GST_FLOW_OK;
2724 not_enough_data:
2725 {
2726 GST_WARNING_OBJECT (demux, "unexpectedly short of data while processing "
2727 "comment tag section %d, skipping comment object", i);
2728 for (i = 0; i < G_N_ELEMENTS (tags); i++)
2729 g_free (tags[i].val_utf8);
2730 return GST_FLOW_OK; /* not really fatal */
2731 }
2732 }
2734 static GstFlowReturn
2735 gst_asf_demux_process_bitrate_props_object (GstASFDemux * demux, guint8 * data,
2736 guint64 size)
2737 {
2738 guint16 num_streams, i;
2740 if (size < 2)
2741 goto not_enough_data;
2743 num_streams = gst_asf_demux_get_uint16 (&data, &size);
2745 GST_INFO ("object is a bitrate properties object with %u streams",
2746 num_streams);
2748 if (size < (num_streams * (2 + 4)))
2749 goto not_enough_data;
2751 for (i = 0; i < num_streams; ++i) {
2752 guint32 bitrate;
2753 guint16 stream_id;
2755 stream_id = gst_asf_demux_get_uint16 (&data, &size);
2756 bitrate = gst_asf_demux_get_uint32 (&data, &size);
2758 if (stream_id < GST_ASF_DEMUX_NUM_STREAM_IDS) {
2759 demux->bitrate[stream_id] = bitrate;
2760 GST_DEBUG ("bitrate[%u] = %u", stream_id, bitrate);
2761 } else {
2762 GST_WARNING ("stream id %u is too large", stream_id);
2763 }
2764 }
2766 return GST_FLOW_OK;
2768 not_enough_data:
2769 {
2770 GST_WARNING_OBJECT (demux, "short read parsing bitrate props object!");
2771 return GST_FLOW_OK; /* not really fatal */
2772 }
2773 }
2775 static GstFlowReturn
2776 gst_asf_demux_process_header_ext (GstASFDemux * demux, guint8 * data,
2777 guint64 size)
2778 {
2779 GstFlowReturn ret = GST_FLOW_OK;
2780 guint64 hdr_size;
2782 /* Get the rest of the header's header */
2783 if (size < (16 + 2 + 4))
2784 goto not_enough_data;
2786 /* skip GUID and two other bytes */
2787 gst_asf_demux_skip_bytes (16 + 2, &data, &size);
2788 hdr_size = gst_asf_demux_get_uint32 (&data, &size);
2790 GST_INFO ("extended header object with a size of %u bytes", (guint) size);
2792 /* FIXME: does data_size include the rest of the header that we have read? */
2793 if (hdr_size > size)
2794 goto not_enough_data;
2796 while (hdr_size > 0) {
2797 ret = gst_asf_demux_process_object (demux, &data, &hdr_size);
2798 if (ret != GST_FLOW_OK)
2799 break;
2800 }
2802 return ret;
2804 not_enough_data:
2805 {
2806 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
2807 ("short read parsing extended header object"));
2808 return GST_FLOW_ERROR;
2809 }
2810 }
2812 static GstFlowReturn
2813 gst_asf_demux_process_language_list (GstASFDemux * demux, guint8 * data,
2814 guint64 size)
2815 {
2816 guint i;
2818 if (size < 2)
2819 goto not_enough_data;
2821 if (demux->languages) {
2822 GST_WARNING ("More than one LANGUAGE_LIST object in stream");
2823 g_strfreev (demux->languages);
2824 demux->languages = NULL;
2825 demux->num_languages = 0;
2826 }
2828 demux->num_languages = gst_asf_demux_get_uint16 (&data, &size);
2829 GST_LOG ("%u languages:", demux->num_languages);
2831 demux->languages = g_new0 (gchar *, demux->num_languages + 1);
2832 for (i = 0; i < demux->num_languages; ++i) {
2833 guint8 len, *lang_data = NULL;
2835 if (size < 1)
2836 goto not_enough_data;
2837 len = gst_asf_demux_get_uint8 (&data, &size);
2838 if (gst_asf_demux_get_bytes (&lang_data, len, &data, &size)) {
2839 gchar *utf8;
2841 utf8 = g_convert ((gchar *) lang_data, len, "UTF-8", "UTF-16LE", NULL,
2842 NULL, NULL);
2844 /* truncate "en-us" etc. to just "en" */
2845 if (utf8 && strlen (utf8) >= 5 && (utf8[2] == '-' || utf8[2] == '_')) {
2846 utf8[2] = '\0';
2847 }
2848 GST_DEBUG ("[%u] %s", i, GST_STR_NULL (utf8));
2849 demux->languages[i] = utf8;
2850 g_free (lang_data);
2851 } else {
2852 goto not_enough_data;
2853 }
2854 }
2856 return GST_FLOW_OK;
2858 not_enough_data:
2859 {
2860 GST_WARNING_OBJECT (demux, "short read parsing language list object!");
2861 g_free (demux->languages);
2862 demux->languages = NULL;
2863 return GST_FLOW_OK; /* not fatal */
2864 }
2865 }
2867 static GstFlowReturn
2868 gst_asf_demux_process_simple_index (GstASFDemux * demux, guint8 * data,
2869 guint64 size)
2870 {
2871 GstClockTime interval;
2872 guint32 x, count, i;
2874 if (size < (16 + 8 + 4 + 4))
2875 goto not_enough_data;
2877 /* skip file id */
2878 gst_asf_demux_skip_bytes (16, &data, &size);
2879 interval = gst_asf_demux_get_uint64 (&data, &size) * (GstClockTime) 100;
2880 x = gst_asf_demux_get_uint32 (&data, &size);
2881 count = gst_asf_demux_get_uint32 (&data, &size);
2882 if (count > 0) {
2883 demux->sidx_interval = interval;
2884 demux->sidx_num_entries = count;
2885 g_free (demux->sidx_entries);
2886 demux->sidx_entries = g_new0 (guint32, count);
2888 for (i = 0; i < count && size > (4 + 2); ++i) {
2889 demux->sidx_entries[i] = gst_asf_demux_get_uint32 (&data, &size);
2890 x = (guint32) gst_asf_demux_get_uint16 (&data, &size);
2891 GST_LOG_OBJECT (demux, "%" GST_TIME_FORMAT " = packet %4u",
2892 GST_TIME_ARGS (i * interval), demux->sidx_entries[i]);
2893 }
2894 } else {
2895 GST_DEBUG_OBJECT (demux, "simple index object with 0 entries");
2896 }
2898 return GST_FLOW_OK;
2900 not_enough_data:
2901 {
2902 GST_WARNING_OBJECT (demux, "short read parsing simple index object!");
2903 return GST_FLOW_OK; /* not fatal */
2904 }
2905 }
2907 static GstFlowReturn
2908 gst_asf_demux_process_advanced_mutual_exclusion (GstASFDemux * demux,
2909 guint8 * data, guint64 size)
2910 {
2911 ASFGuid guid;
2912 guint16 num, i;
2913 guint8 *mes;
2915 if (size < 16 + 2 + (2 * 2))
2916 goto not_enough_data;
2918 gst_asf_demux_get_guid (&guid, &data, &size);
2919 num = gst_asf_demux_get_uint16 (&data, &size);
2921 if (num < 2) {
2922 GST_WARNING_OBJECT (demux, "nonsensical mutually exclusive streams count");
2923 return GST_FLOW_OK;
2924 }
2926 if (size < (num * sizeof (guint16)))
2927 goto not_enough_data;
2929 /* read mutually exclusive stream numbers */
2930 mes = g_new (guint8, num + 1);
2931 for (i = 0; i < num; ++i) {
2932 mes[i] = gst_asf_demux_get_uint16 (&data, &size) & 0x7f;
2933 GST_LOG_OBJECT (demux, "mutually exclusive: stream #%d", mes[i]);
2934 }
2936 /* add terminator so we can easily get the count or know when to stop */
2937 mes[i] = (guint8) - 1;
2939 demux->mut_ex_streams = g_slist_append (demux->mut_ex_streams, mes);
2941 return GST_FLOW_OK;
2943 /* Errors */
2944 not_enough_data:
2945 {
2946 GST_WARNING_OBJECT (demux, "short read parsing advanced mutual exclusion");
2947 return GST_FLOW_OK; /* not absolutely fatal */
2948 }
2949 }
2951 static GstFlowReturn
2952 gst_asf_demux_process_ext_stream_props (GstASFDemux * demux, guint8 * data,
2953 guint64 size)
2954 {
2955 AsfStreamExtProps esp;
2956 AsfStream *stream = NULL;
2957 AsfObject stream_obj;
2958 guint16 stream_name_count;
2959 guint16 num_payload_ext;
2960 guint64 len;
2961 guint8 *stream_obj_data = NULL;
2962 guint8 *data_start;
2963 guint obj_size;
2964 guint i, stream_num;
2966 data_start = data;
2967 obj_size = (guint) size;
2969 if (size < 64)
2970 goto not_enough_data;
2972 esp.valid = TRUE;
2973 esp.start_time = gst_asf_demux_get_uint64 (&data, &size) * GST_MSECOND;
2974 esp.end_time = gst_asf_demux_get_uint64 (&data, &size) * GST_MSECOND;
2975 esp.data_bitrate = gst_asf_demux_get_uint32 (&data, &size);
2976 esp.buffer_size = gst_asf_demux_get_uint32 (&data, &size);
2977 esp.intial_buf_fullness = gst_asf_demux_get_uint32 (&data, &size);
2978 esp.data_bitrate2 = gst_asf_demux_get_uint32 (&data, &size);
2979 esp.buffer_size2 = gst_asf_demux_get_uint32 (&data, &size);
2980 esp.intial_buf_fullness2 = gst_asf_demux_get_uint32 (&data, &size);
2981 esp.max_obj_size = gst_asf_demux_get_uint32 (&data, &size);
2982 esp.flags = gst_asf_demux_get_uint32 (&data, &size);
2983 stream_num = gst_asf_demux_get_uint16 (&data, &size);
2984 esp.lang_idx = gst_asf_demux_get_uint16 (&data, &size);
2985 esp.avg_time_per_frame = gst_asf_demux_get_uint64 (&data, &size);
2986 stream_name_count = gst_asf_demux_get_uint16 (&data, &size);
2987 num_payload_ext = gst_asf_demux_get_uint16 (&data, &size);
2989 GST_INFO ("start_time = %" GST_TIME_FORMAT,
2990 GST_TIME_ARGS (esp.start_time));
2991 GST_INFO ("end_time = %" GST_TIME_FORMAT,
2992 GST_TIME_ARGS (esp.end_time));
2993 GST_INFO ("flags = %08x", esp.flags);
2994 GST_INFO ("average time per frame = %" GST_TIME_FORMAT,
2995 GST_TIME_ARGS (esp.avg_time_per_frame * 100));
2996 GST_INFO ("stream number = %u", stream_num);
2997 GST_INFO ("stream language ID idx = %u (%s)", esp.lang_idx,
2998 (esp.lang_idx < demux->num_languages) ?
2999 GST_STR_NULL (demux->languages[esp.lang_idx]) : "??");
3000 GST_INFO ("stream name count = %u", stream_name_count);
3002 /* read stream names */
3003 for (i = 0; i < stream_name_count; ++i) {
3004 guint16 stream_lang_idx;
3005 gchar *stream_name = NULL;
3007 if (size < 2)
3008 goto not_enough_data;
3009 stream_lang_idx = gst_asf_demux_get_uint16 (&data, &size);
3010 if (!gst_asf_demux_get_string (&stream_name, NULL, &data, &size))
3011 goto not_enough_data;
3012 GST_INFO ("stream name %d: %s", i, GST_STR_NULL (stream_name));
3013 g_free (stream_name); /* TODO: store names in struct */
3014 }
3016 /* read payload extension systems stuff */
3017 GST_LOG ("payload extension systems count = %u", num_payload_ext);
3019 if (num_payload_ext > 0)
3020 esp.payload_extensions = g_new0 (AsfPayloadExtension, num_payload_ext + 1);
3021 else
3022 esp.payload_extensions = NULL;
3024 for (i = 0; i < num_payload_ext; ++i) {
3025 AsfPayloadExtension ext;
3026 ASFGuid ext_guid;
3027 guint32 sys_info_len;
3029 if (size < 16 + 2 + 4)
3030 goto not_enough_data;
3032 gst_asf_demux_get_guid (&ext_guid, &data, &size);
3033 ext.id = gst_asf_demux_identify_guid (asf_payload_ext_guids, &ext_guid);
3034 ext.len = gst_asf_demux_get_uint16 (&data, &size);
3036 sys_info_len = gst_asf_demux_get_uint32 (&data, &size);
3037 GST_LOG ("payload systems info len = %u", sys_info_len);
3038 if (!gst_asf_demux_skip_bytes (sys_info_len, &data, &size))
3039 goto not_enough_data;
3041 esp.payload_extensions[i] = ext;
3042 }
3044 GST_LOG ("bytes read: %u/%u", (guint) (data - data_start), obj_size);
3046 /* there might be an optional STREAM_INFO object here now; if not, we
3047 * should have parsed the corresponding stream info object already (since
3048 * we are parsing the extended stream properties objects delayed) */
3049 if (size == 0) {
3050 stream = gst_asf_demux_get_stream (demux, stream_num);
3051 goto done;
3052 }
3054 /* get size of the stream object */
3055 if (!asf_demux_peek_object (demux, data, size, &stream_obj))
3056 goto not_enough_data;
3058 if (stream_obj.id != ASF_OBJ_STREAM)
3059 goto expected_stream_object;
3061 if (stream_obj.size < ASF_OBJECT_HEADER_SIZE ||
3062 stream_obj.size > (10 * 1024 * 1024))
3063 goto not_enough_data;
3065 gst_asf_demux_skip_bytes (ASF_OBJECT_HEADER_SIZE, &data, &size);
3067 /* process this stream object later after all the other 'normal' ones
3068 * have been processed (since the others are more important/non-hidden) */
3069 len = stream_obj.size - ASF_OBJECT_HEADER_SIZE;
3070 if (!gst_asf_demux_get_bytes (&stream_obj_data, len, &data, &size))
3071 goto not_enough_data;
3073 /* parse stream object */
3074 stream = gst_asf_demux_parse_stream_object (demux, stream_obj_data, len);
3075 g_free (stream_obj_data);
3077 done:
3079 if (stream) {
3080 stream->ext_props = esp;
3082 /* try to set the framerate */
3083 if (stream->is_video && stream->caps) {
3084 GValue framerate = { 0 };
3085 GstStructure *s;
3086 gint num, denom;
3088 g_value_init (&framerate, GST_TYPE_FRACTION);
3090 num = GST_SECOND / 100;
3091 denom = esp.avg_time_per_frame;
3092 if (denom == 0) {
3093 /* avoid division by 0, assume 25/1 framerate */
3094 denom = GST_SECOND / 2500;
3095 }
3097 gst_value_set_fraction (&framerate, num, denom);
3099 stream->caps = gst_caps_make_writable (stream->caps);
3100 s = gst_caps_get_structure (stream->caps, 0);
3101 gst_structure_set_value (s, "framerate", &framerate);
3102 g_value_unset (&framerate);
3103 GST_DEBUG_OBJECT (demux, "setting framerate of %d/%d = %f",
3104 num, denom, ((gdouble) num) / denom);
3105 }
3107 /* add language info now if we have it */
3108 if (stream->ext_props.lang_idx < demux->num_languages) {
3109 if (stream->pending_tags == NULL)
3110 stream->pending_tags = gst_tag_list_new ();
3111 GST_LOG_OBJECT (demux, "stream %u has language '%s'", stream->id,
3112 demux->languages[stream->ext_props.lang_idx]);
3113 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_APPEND,
3114 GST_TAG_LANGUAGE_CODE, demux->languages[stream->ext_props.lang_idx],
3115 NULL);
3116 }
3117 } else {
3118 GST_WARNING_OBJECT (demux, "Ext. stream properties for unknown stream");
3119 }
3121 return GST_FLOW_OK;
3123 /* Errors */
3124 not_enough_data:
3125 {
3126 GST_WARNING_OBJECT (demux, "short read parsing ext stream props object!");
3127 return GST_FLOW_OK; /* not absolutely fatal */
3128 }
3129 expected_stream_object:
3130 {
3131 GST_WARNING_OBJECT (demux, "error parsing extended stream properties "
3132 "object: expected embedded stream object, but got %s object instead!",
3133 gst_asf_get_guid_nick (asf_object_guids, stream_obj.id));
3134 return GST_FLOW_OK; /* not absolutely fatal */
3135 }
3136 }
3138 static const gchar *
3139 gst_asf_demux_push_obj (GstASFDemux * demux, guint32 obj_id)
3140 {
3141 const gchar *nick;
3143 nick = gst_asf_get_guid_nick (asf_object_guids, obj_id);
3144 if (g_str_has_prefix (nick, "ASF_OBJ_"))
3145 nick += strlen ("ASF_OBJ_");
3147 if (demux->objpath == NULL) {
3148 demux->objpath = g_strdup (nick);
3149 } else {
3150 gchar *newpath;
3152 newpath = g_strdup_printf ("%s/%s", demux->objpath, nick);
3153 g_free (demux->objpath);
3154 demux->objpath = newpath;
3155 }
3157 return (const gchar *) demux->objpath;
3158 }
3160 static void
3161 gst_asf_demux_pop_obj (GstASFDemux * demux)
3162 {
3163 gchar *s;
3165 if ((s = g_strrstr (demux->objpath, "/"))) {
3166 *s = '\0';
3167 } else {
3168 g_free (demux->objpath);
3169 demux->objpath = NULL;
3170 }
3171 }
3173 static void
3174 gst_asf_demux_process_queued_extended_stream_objects (GstASFDemux * demux)
3175 {
3176 GSList *l;
3177 guint i;
3179 /* Parse the queued extended stream property objects and add the info
3180 * to the existing streams or add the new embedded streams, but without
3181 * activating them yet */
3182 GST_LOG_OBJECT (demux, "%u queued extended stream properties objects",
3183 g_slist_length (demux->ext_stream_props));
3185 for (l = demux->ext_stream_props, i = 0; l != NULL; l = l->next, ++i) {
3186 GstBuffer *buf = GST_BUFFER (l->data);
3188 GST_LOG_OBJECT (demux, "parsing ext. stream properties object #%u", i);
3189 gst_asf_demux_process_ext_stream_props (demux, GST_BUFFER_DATA (buf),
3190 GST_BUFFER_SIZE (buf));
3191 gst_buffer_unref (buf);
3192 }
3193 g_slist_free (demux->ext_stream_props);
3194 demux->ext_stream_props = NULL;
3195 }
3197 #if 0
3198 static void
3199 gst_asf_demux_activate_ext_props_streams (GstASFDemux * demux)
3200 {
3201 guint i, j;
3203 for (i = 0; i < demux->num_streams; ++i) {
3204 AsfStream *stream;
3205 gboolean is_hidden;
3206 GSList *x;
3208 stream = &demux->stream[i];
3210 GST_LOG_OBJECT (demux, "checking stream %2u", stream->id);
3212 if (stream->active) {
3213 GST_LOG_OBJECT (demux, "stream %2u is already activated", stream->id);
3214 continue;
3215 }
3217 is_hidden = FALSE;
3218 for (x = demux->mut_ex_streams; x != NULL; x = x->next) {
3219 guint8 *mes;
3221 /* check for each mutual exclusion whether it affects this stream */
3222 for (mes = (guint8 *) x->data; mes != NULL && *mes != 0xff; ++mes) {
3223 if (*mes == stream->id) {
3224 /* if yes, check if we've already added streams that are mutually
3225 * exclusive with the stream we're about to add */
3226 for (mes = (guint8 *) x->data; mes != NULL && *mes != 0xff; ++mes) {
3227 for (j = 0; j < demux->num_streams; ++j) {
3228 /* if the broadcast flag is set, assume the hidden streams aren't
3229 * actually streamed and hide them (or playbin won't work right),
3230 * otherwise assume their data is available */
3231 if (demux->stream[j].id == *mes && demux->broadcast) {
3232 is_hidden = TRUE;
3233 GST_LOG_OBJECT (demux, "broadcast stream ID %d to be added is "
3234 "mutually exclusive with already existing stream ID %d, "
3235 "hiding stream", stream->id, demux->stream[j].id);
3236 goto next;
3237 }
3238 }
3239 }
3240 break;
3241 }
3242 }
3243 }
3245 next:
3247 /* FIXME: we should do stream activation based on preroll data in
3248 * streaming mode too */
3249 if (demux->streaming && !is_hidden)
3250 gst_asf_demux_activate_stream (demux, stream);
3251 }
3252 }
3253 #endif
3255 static GstFlowReturn
3256 gst_asf_demux_process_object (GstASFDemux * demux, guint8 ** p_data,
3257 guint64 * p_size)
3258 {
3259 GstFlowReturn ret = GST_FLOW_OK;
3260 AsfObject obj;
3261 guint64 obj_data_size;
3263 if (*p_size < ASF_OBJECT_HEADER_SIZE)
3264 return ASF_FLOW_NEED_MORE_DATA;
3266 asf_demux_peek_object (demux, *p_data, ASF_OBJECT_HEADER_SIZE, &obj);
3267 gst_asf_demux_skip_bytes (ASF_OBJECT_HEADER_SIZE, p_data, p_size);
3269 obj_data_size = obj.size - ASF_OBJECT_HEADER_SIZE;
3271 if (*p_size < obj_data_size)
3272 return ASF_FLOW_NEED_MORE_DATA;
3274 gst_asf_demux_push_obj (demux, obj.id);
3276 GST_INFO ("%s: size %" G_GUINT64_FORMAT, demux->objpath, obj.size);
3278 switch (obj.id) {
3279 case ASF_OBJ_STREAM:{
3280 AsfStream *stream;
3282 stream =
3283 gst_asf_demux_parse_stream_object (demux, *p_data, obj_data_size);
3285 ret = GST_FLOW_OK;
3286 break;
3287 }
3288 case ASF_OBJ_FILE:
3289 ret = gst_asf_demux_process_file (demux, *p_data, obj_data_size);
3290 break;
3291 case ASF_OBJ_HEADER:
3292 ret = gst_asf_demux_process_header (demux, *p_data, obj_data_size);
3293 break;
3294 case ASF_OBJ_COMMENT:
3295 ret = gst_asf_demux_process_comment (demux, *p_data, obj_data_size);
3296 break;
3297 case ASF_OBJ_HEAD1:
3298 ret = gst_asf_demux_process_header_ext (demux, *p_data, obj_data_size);
3299 break;
3300 case ASF_OBJ_BITRATE_PROPS:
3301 ret =
3302 gst_asf_demux_process_bitrate_props_object (demux, *p_data,
3303 obj_data_size);
3304 break;
3305 case ASF_OBJ_EXT_CONTENT_DESC:
3306 ret =
3307 gst_asf_demux_process_ext_content_desc (demux, *p_data,
3308 obj_data_size);
3309 break;
3310 case ASF_OBJ_METADATA_OBJECT:
3311 ret = gst_asf_demux_process_metadata (demux, *p_data, obj_data_size);
3312 break;
3313 case ASF_OBJ_EXTENDED_STREAM_PROPS:{
3314 GstBuffer *buf;
3316 /* process these later, we might not have parsed the corresponding
3317 * stream object yet */
3318 GST_LOG ("%s: queued for later parsing", demux->objpath);
3319 buf = gst_buffer_new_and_alloc (obj_data_size);
3320 memcpy (GST_BUFFER_DATA (buf), *p_data, obj_data_size);
3321 demux->ext_stream_props = g_slist_append (demux->ext_stream_props, buf);
3322 ret = GST_FLOW_OK;
3323 break;
3324 }
3325 case ASF_OBJ_LANGUAGE_LIST:
3326 ret = gst_asf_demux_process_language_list (demux, *p_data, obj_data_size);
3327 break;
3328 case ASF_OBJ_ADVANCED_MUTUAL_EXCLUSION:
3329 ret = gst_asf_demux_process_advanced_mutual_exclusion (demux, *p_data,
3330 obj_data_size);
3331 break;
3332 case ASF_OBJ_SIMPLE_INDEX:
3333 ret = gst_asf_demux_process_simple_index (demux, *p_data, obj_data_size);
3334 break;
3335 case ASF_OBJ_CONTENT_ENCRYPTION:
3336 case ASF_OBJ_EXT_CONTENT_ENCRYPTION:
3337 case ASF_OBJ_DIGITAL_SIGNATURE_OBJECT:
3338 goto error_encrypted;
3339 case ASF_OBJ_CONCEAL_NONE:
3340 case ASF_OBJ_HEAD2:
3341 case ASF_OBJ_UNDEFINED:
3342 case ASF_OBJ_CODEC_COMMENT:
3343 case ASF_OBJ_INDEX:
3344 case ASF_OBJ_PADDING:
3345 case ASF_OBJ_BITRATE_MUTEX:
3346 case ASF_OBJ_COMPATIBILITY:
3347 case ASF_OBJ_INDEX_PLACEHOLDER:
3348 case ASF_OBJ_INDEX_PARAMETERS:
3349 case ASF_OBJ_STREAM_PRIORITIZATION:
3350 case ASF_OBJ_SCRIPT_COMMAND:
3351 default:
3352 /* Unknown/unhandled object, skip it and hope for the best */
3353 GST_INFO ("%s: skipping object", demux->objpath);
3354 ret = GST_FLOW_OK;
3355 break;
3356 }
3358 /* this can't fail, we checked the number of bytes available before */
3359 gst_asf_demux_skip_bytes (obj_data_size, p_data, p_size);
3361 GST_LOG ("%s: ret = %s", demux->objpath, gst_asf_get_flow_name (ret));
3363 gst_asf_demux_pop_obj (demux);
3365 return ret;
3367 /* ERRORS */
3368 error_encrypted:
3369 {
3370 GST_ELEMENT_ERROR (demux, STREAM, DECRYPT, (NULL), (NULL));
3371 return GST_FLOW_ERROR;
3372 }
3373 }
3375 static void
3376 gst_asf_demux_descramble_buffer (GstASFDemux * demux, AsfStream * stream,
3377 GstBuffer ** p_buffer)
3378 {
3379 GstBuffer *descrambled_buffer;
3380 GstBuffer *scrambled_buffer;
3381 GstBuffer *sub_buffer;
3382 guint offset;
3383 guint off;
3384 guint row;
3385 guint col;
3386 guint idx;
3388 /* descrambled_buffer is initialised in the first iteration */
3389 descrambled_buffer = NULL;
3390 scrambled_buffer = *p_buffer;
3392 if (GST_BUFFER_SIZE (scrambled_buffer) < demux->ds_packet_size * demux->span)
3393 return;
3395 for (offset = 0; offset < GST_BUFFER_SIZE (scrambled_buffer);
3396 offset += demux->ds_chunk_size) {
3397 off = offset / demux->ds_chunk_size;
3398 row = off / demux->span;
3399 col = off % demux->span;
3400 idx = row + col * demux->ds_packet_size / demux->ds_chunk_size;
3401 GST_DEBUG ("idx=%u, row=%u, col=%u, off=%u, ds_chunk_size=%u", idx, row,
3402 col, off, demux->ds_chunk_size);
3403 GST_DEBUG ("scrambled buffer size=%u, span=%u, packet_size=%u",
3404 GST_BUFFER_SIZE (scrambled_buffer), demux->span, demux->ds_packet_size);
3405 GST_DEBUG ("GST_BUFFER_SIZE (scrambled_buffer) = %u",
3406 GST_BUFFER_SIZE (scrambled_buffer));
3407 sub_buffer =
3408 gst_buffer_create_sub (scrambled_buffer, idx * demux->ds_chunk_size,
3409 demux->ds_chunk_size);
3410 if (!offset) {
3411 descrambled_buffer = sub_buffer;
3412 } else {
3413 descrambled_buffer = gst_buffer_join (descrambled_buffer, sub_buffer);
3414 }
3415 }
3417 gst_buffer_copy_metadata (descrambled_buffer, scrambled_buffer,
3418 GST_BUFFER_COPY_TIMESTAMPS);
3420 /* FIXME/CHECK: do we need to transfer buffer flags here too? */
3422 gst_buffer_unref (scrambled_buffer);
3423 *p_buffer = descrambled_buffer;
3424 }
3426 static gboolean
3427 gst_asf_demux_element_send_event (GstElement * element, GstEvent * event)
3428 {
3429 GstASFDemux *demux = GST_ASF_DEMUX (element);
3430 gint i;
3432 GST_DEBUG ("handling element event of type %s", GST_EVENT_TYPE_NAME (event));
3434 for (i = 0; i < demux->num_streams; ++i) {
3435 gst_event_ref (event);
3436 if (gst_asf_demux_handle_src_event (demux->stream[i].pad, event)) {
3437 gst_event_unref (event);
3438 return TRUE;
3439 }
3440 }
3442 gst_event_unref (event);
3443 return FALSE;
3444 }
3446 /* takes ownership of the passed event */
3447 static gboolean
3448 gst_asf_demux_send_event_unlocked (GstASFDemux * demux, GstEvent * event)
3449 {
3450 gboolean ret = TRUE;
3451 gint i;
3453 GST_DEBUG_OBJECT (demux, "sending %s event to all source pads",
3454 GST_EVENT_TYPE_NAME (event));
3456 for (i = 0; i < demux->num_streams; ++i) {
3457 gst_event_ref (event);
3458 ret &= gst_pad_push_event (demux->stream[i].pad, event);
3459 }
3460 gst_event_unref (event);
3461 return ret;
3462 }
3464 static const GstQueryType *
3465 gst_asf_demux_get_src_query_types (GstPad * pad)
3466 {
3467 static const GstQueryType types[] = {
3468 GST_QUERY_POSITION,
3469 GST_QUERY_DURATION,
3470 GST_QUERY_SEEKING,
3471 0
3472 };
3474 return types;
3475 }
3477 static gboolean
3478 gst_asf_demux_handle_src_query (GstPad * pad, GstQuery * query)
3479 {
3480 GstASFDemux *demux;
3481 gboolean res = FALSE;
3483 demux = GST_ASF_DEMUX (gst_pad_get_parent (pad));
3485 GST_DEBUG ("handling %s query",
3486 gst_query_type_get_name (GST_QUERY_TYPE (query)));
3488 switch (GST_QUERY_TYPE (query)) {
3489 case GST_QUERY_DURATION:
3490 {
3491 GstFormat format;
3493 gst_query_parse_duration (query, &format, NULL);
3495 if (format != GST_FORMAT_TIME) {
3496 GST_LOG ("only support duration queries in TIME format");
3497 break;
3498 }
3500 GST_OBJECT_LOCK (demux);
3502 if (demux->segment.duration != GST_CLOCK_TIME_NONE) {
3503 GST_LOG ("returning duration: %" GST_TIME_FORMAT,
3504 GST_TIME_ARGS (demux->segment.duration));
3506 gst_query_set_duration (query, GST_FORMAT_TIME,
3507 demux->segment.duration);
3509 res = TRUE;
3510 } else {
3511 GST_LOG ("duration not known yet");
3512 }
3514 GST_OBJECT_UNLOCK (demux);
3515 break;
3516 }
3518 case GST_QUERY_POSITION:{
3519 GstFormat format;
3521 gst_query_parse_position (query, &format, NULL);
3523 if (format != GST_FORMAT_TIME) {
3524 GST_LOG ("only support position queries in TIME format");
3525 break;
3526 }
3528 GST_OBJECT_LOCK (demux);
3530 if (demux->segment.last_stop != GST_CLOCK_TIME_NONE) {
3531 GST_LOG ("returning position: %" GST_TIME_FORMAT,
3532 GST_TIME_ARGS (demux->segment.last_stop));
3534 gst_query_set_position (query, GST_FORMAT_TIME,
3535 demux->segment.last_stop);
3537 res = TRUE;
3538 } else {
3539 GST_LOG ("position not known yet");
3540 }
3542 GST_OBJECT_UNLOCK (demux);
3543 break;
3544 }
3546 case GST_QUERY_SEEKING:{
3547 GstFormat format;
3549 gst_query_parse_seeking (query, &format, NULL, NULL, NULL);
3550 if (format == GST_FORMAT_TIME) {
3551 gint64 duration;
3553 GST_OBJECT_LOCK (demux);
3554 duration = demux->segment.duration;
3555 GST_OBJECT_UNLOCK (demux);
3557 if (!demux->streaming || !demux->seekable) {
3558 gst_query_set_seeking (query, GST_FORMAT_TIME, demux->seekable, 0,
3559 duration);
3560 res = TRUE;
3561 } else {
3562 GstFormat fmt;
3563 gboolean seekable;
3565 /* try downstream first in TIME */
3566 res = gst_pad_query_default (pad, query);
3568 gst_query_parse_seeking (query, &fmt, &seekable, NULL, NULL);
3569 GST_LOG_OBJECT (demux, "upstream %s seekable %d",
3570 GST_STR_NULL (gst_format_get_name (fmt)), seekable);
3571 /* if no luck, maybe in BYTES */
3572 if (!seekable || fmt != GST_FORMAT_TIME) {
3573 GstQuery *q;
3575 q = gst_query_new_seeking (GST_FORMAT_BYTES);
3576 if ((res = gst_pad_peer_query (demux->sinkpad, q))) {
3577 gst_query_parse_seeking (q, &fmt, &seekable, NULL, NULL);
3578 GST_LOG_OBJECT (demux, "upstream %s seekable %d",
3579 GST_STR_NULL (gst_format_get_name (fmt)), seekable);
3580 if (fmt != GST_FORMAT_BYTES)
3581 seekable = FALSE;
3582 }
3583 gst_query_unref (q);
3584 gst_query_set_seeking (query, GST_FORMAT_TIME, seekable, 0,
3585 duration);
3586 res = TRUE;
3587 }
3588 }
3589 } else
3590 GST_LOG_OBJECT (demux, "only support seeking in TIME format");
3591 break;
3592 }
3594 case GST_QUERY_LATENCY:
3595 {
3596 gboolean live;
3597 GstClockTime min, max;
3599 /* preroll delay does not matter in non-live pipeline,
3600 * but we might end up in a live (rtsp) one ... */
3602 /* first forward */
3603 res = gst_pad_query_default (pad, query);
3604 if (!res)
3605 break;
3607 gst_query_parse_latency (query, &live, &min, &max);
3609 GST_DEBUG_OBJECT (demux, "Peer latency: live %d, min %"
3610 GST_TIME_FORMAT " max %" GST_TIME_FORMAT, live,
3611 GST_TIME_ARGS (min), GST_TIME_ARGS (max));
3613 GST_OBJECT_LOCK (demux);
3614 if (min != -1)
3615 min += demux->latency;
3616 if (max != -1)
3617 max += demux->latency;
3618 GST_OBJECT_UNLOCK (demux);
3620 gst_query_set_latency (query, live, min, max);
3621 break;
3622 }
3623 default:
3624 res = gst_pad_query_default (pad, query);
3625 break;
3626 }
3628 gst_object_unref (demux);
3629 return res;
3630 }
3632 static GstStateChangeReturn
3633 gst_asf_demux_change_state (GstElement * element, GstStateChange transition)
3634 {
3635 GstASFDemux *demux = GST_ASF_DEMUX (element);
3636 GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
3638 switch (transition) {
3639 case GST_STATE_CHANGE_NULL_TO_READY:{
3640 gst_segment_init (&demux->segment, GST_FORMAT_TIME);
3641 demux->need_newsegment = TRUE;
3642 demux->segment_running = FALSE;
3643 demux->adapter = gst_adapter_new ();
3644 demux->metadata = gst_caps_new_empty ();
3645 demux->global_metadata = gst_structure_empty_new ("metadata");
3646 demux->data_size = 0;
3647 demux->data_offset = 0;
3648 demux->index_offset = 0;
3649 break;
3650 }
3651 default:
3652 break;
3653 }
3655 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
3656 if (ret == GST_STATE_CHANGE_FAILURE)
3657 return ret;
3659 switch (transition) {
3660 case GST_STATE_CHANGE_PAUSED_TO_READY:
3661 case GST_STATE_CHANGE_READY_TO_NULL:
3662 gst_asf_demux_reset (demux);
3663 break;
3664 default:
3665 break;
3666 }
3668 return ret;
3669 }