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 <stdio.h>
41 #include <stdlib.h>
42 #include <string.h>
44 #include "gstasfdemux.h"
45 #include "asfheaders.h"
46 #include "asfpacket.h"
48 static GstStaticPadTemplate gst_asf_demux_sink_template =
49 GST_STATIC_PAD_TEMPLATE ("sink",
50 GST_PAD_SINK,
51 GST_PAD_ALWAYS,
52 GST_STATIC_CAPS ("video/x-ms-asf")
53 );
55 static GstStaticPadTemplate audio_src_template =
56 GST_STATIC_PAD_TEMPLATE ("audio_%02d",
57 GST_PAD_SRC,
58 GST_PAD_SOMETIMES,
59 GST_STATIC_CAPS_ANY);
61 static GstStaticPadTemplate video_src_template =
62 GST_STATIC_PAD_TEMPLATE ("video_%02d",
63 GST_PAD_SRC,
64 GST_PAD_SOMETIMES,
65 GST_STATIC_CAPS_ANY);
67 /* size of an ASF object header, ie. GUID (16 bytes) + object size (8 bytes) */
68 #define ASF_OBJECT_HEADER_SIZE (16+8)
70 /* FIXME: get rid of this */
71 /* abuse this GstFlowReturn enum for internal usage */
72 #define ASF_FLOW_NEED_MORE_DATA 99
74 #define gst_asf_get_flow_name(flow) \
75 (flow == ASF_FLOW_NEED_MORE_DATA) ? \
76 "need-more-data" : gst_flow_get_name (flow)
78 GST_DEBUG_CATEGORY (asfdemux_dbg);
80 static GstStateChangeReturn gst_asf_demux_change_state (GstElement * element,
81 GstStateChange transition);
82 static gboolean gst_asf_demux_element_send_event (GstElement * element,
83 GstEvent * event);
84 static gboolean gst_asf_demux_send_event_unlocked (GstASFDemux * demux,
85 GstEvent * event);
86 static gboolean gst_asf_demux_handle_src_query (GstPad * pad, GstQuery * query);
87 static const GstQueryType *gst_asf_demux_get_src_query_types (GstPad * pad);
88 static GstFlowReturn gst_asf_demux_chain (GstPad * pad, GstBuffer * buf);
89 static gboolean gst_asf_demux_sink_event (GstPad * pad, GstEvent * event);
90 static GstFlowReturn gst_asf_demux_process_object (GstASFDemux * demux,
91 guint8 ** p_data, guint64 * p_size);
92 static gboolean gst_asf_demux_activate (GstPad * sinkpad);
93 static gboolean gst_asf_demux_activate_push (GstPad * sinkpad, gboolean active);
94 static gboolean gst_asf_demux_activate_pull (GstPad * sinkpad, gboolean active);
95 static void gst_asf_demux_loop (GstASFDemux * demux);
96 static void
97 gst_asf_demux_process_queued_extended_stream_objects (GstASFDemux * demux);
98 static gboolean gst_asf_demux_pull_headers (GstASFDemux * demux);
99 static void gst_asf_demux_pull_indices (GstASFDemux * demux);
100 static void gst_asf_demux_reset_stream_state_after_discont (GstASFDemux * asf);
101 static gboolean
102 gst_asf_demux_parse_data_object_start (GstASFDemux * demux, guint8 * data);
103 static void gst_asf_demux_descramble_buffer (GstASFDemux * demux,
104 AsfStream * stream, GstBuffer ** p_buffer);
105 static void gst_asf_demux_activate_stream (GstASFDemux * demux,
106 AsfStream * stream);
107 static GstStructure *gst_asf_demux_get_metadata_for_stream (GstASFDemux * d,
108 guint stream_num);
110 GST_BOILERPLATE (GstASFDemux, gst_asf_demux, GstElement, GST_TYPE_ELEMENT);
112 static void
113 gst_asf_demux_base_init (gpointer g_class)
114 {
115 GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
116 static GstElementDetails gst_asf_demux_details = {
117 "ASF Demuxer",
118 "Codec/Demuxer",
119 "Demultiplexes ASF Streams",
120 "Owen Fraser-Green <owen@discobabe.net>"
121 };
123 gst_element_class_add_pad_template (element_class,
124 gst_static_pad_template_get (&audio_src_template));
125 gst_element_class_add_pad_template (element_class,
126 gst_static_pad_template_get (&video_src_template));
127 gst_element_class_add_pad_template (element_class,
128 gst_static_pad_template_get (&gst_asf_demux_sink_template));
130 gst_element_class_set_details (element_class, &gst_asf_demux_details);
131 }
133 static void
134 gst_asf_demux_class_init (GstASFDemuxClass * klass)
135 {
136 GstElementClass *gstelement_class;
138 gstelement_class = (GstElementClass *) klass;
140 gstelement_class->change_state =
141 GST_DEBUG_FUNCPTR (gst_asf_demux_change_state);
142 gstelement_class->send_event =
143 GST_DEBUG_FUNCPTR (gst_asf_demux_element_send_event);
144 }
146 static void
147 gst_asf_demux_free_stream (GstASFDemux * demux, AsfStream * stream)
148 {
149 gst_caps_replace (&stream->caps, NULL);
150 if (stream->pending_tags) {
151 gst_tag_list_free (stream->pending_tags);
152 stream->pending_tags = NULL;
153 }
154 if (stream->pad) {
155 if (stream->active)
156 gst_element_remove_pad (GST_ELEMENT_CAST (demux), stream->pad);
157 else
158 gst_object_unref (stream->pad);
159 stream->pad = NULL;
160 }
161 if (stream->payloads) {
162 g_array_free (stream->payloads, TRUE);
163 stream->payloads = NULL;
164 }
165 if (stream->ext_props.valid) {
166 g_free (stream->ext_props.payload_extensions);
167 stream->ext_props.payload_extensions = NULL;
168 }
169 }
171 static void
172 gst_asf_demux_reset (GstASFDemux * demux, gboolean chain_reset)
173 {
174 GST_LOG_OBJECT (demux, "resetting");
176 gst_segment_init (&demux->segment, GST_FORMAT_UNDEFINED);
177 demux->segment_running = FALSE;
178 if (demux->adapter && !chain_reset) {
179 gst_adapter_clear (demux->adapter);
180 g_object_unref (demux->adapter);
181 demux->adapter = NULL;
182 }
183 if (demux->taglist) {
184 gst_tag_list_free (demux->taglist);
185 demux->taglist = NULL;
186 }
187 if (demux->metadata) {
188 gst_caps_unref (demux->metadata);
189 demux->metadata = NULL;
190 }
191 if (demux->global_metadata) {
192 gst_structure_free (demux->global_metadata);
193 demux->global_metadata = NULL;
194 }
196 demux->state = GST_ASF_DEMUX_STATE_HEADER;
197 g_free (demux->objpath);
198 demux->objpath = NULL;
199 g_strfreev (demux->languages);
200 demux->languages = NULL;
201 demux->num_languages = 0;
202 g_slist_foreach (demux->ext_stream_props, (GFunc) gst_mini_object_unref,
203 NULL);
204 g_slist_free (demux->ext_stream_props);
205 demux->ext_stream_props = NULL;
207 while (demux->old_num_streams > 0) {
208 gst_asf_demux_free_stream (demux,
209 &demux->old_stream[demux->old_num_streams - 1]);
210 --demux->old_num_streams;
211 }
212 memset (demux->old_stream, 0, sizeof (demux->old_stream));
213 demux->old_num_streams = 0;
215 /* when resetting for a new chained asf, we don't want to remove the pads
216 * before adding the new ones */
217 if (chain_reset) {
218 memcpy (demux->old_stream, demux->stream, sizeof (demux->stream));
219 demux->old_num_streams = demux->num_streams;
220 demux->num_streams = 0;
221 }
223 while (demux->num_streams > 0) {
224 gst_asf_demux_free_stream (demux, &demux->stream[demux->num_streams - 1]);
225 --demux->num_streams;
226 }
227 memset (demux->stream, 0, sizeof (demux->stream));
228 if (!chain_reset) {
229 /* do not remove those for not adding pads with same name */
230 demux->num_audio_streams = 0;
231 demux->num_video_streams = 0;
232 }
233 demux->num_streams = 0;
234 demux->activated_streams = FALSE;
235 demux->first_ts = GST_CLOCK_TIME_NONE;
236 demux->segment_ts = GST_CLOCK_TIME_NONE;
237 demux->in_gap = 0;
238 if (!chain_reset)
239 gst_segment_init (&demux->in_segment, GST_FORMAT_UNDEFINED);
240 demux->state = GST_ASF_DEMUX_STATE_HEADER;
241 demux->seekable = FALSE;
242 demux->broadcast = FALSE;
243 demux->sidx_interval = 0;
244 demux->sidx_num_entries = 0;
245 g_free (demux->sidx_entries);
246 demux->sidx_entries = NULL;
248 demux->speed_packets = 1;
250 if (chain_reset) {
251 GST_LOG_OBJECT (demux, "Restarting");
252 gst_segment_init (&demux->segment, GST_FORMAT_TIME);
253 demux->need_newsegment = TRUE;
254 demux->segment_running = FALSE;
255 demux->accurate = FALSE;
256 demux->metadata = gst_caps_new_empty ();
257 demux->global_metadata = gst_structure_empty_new ("metadata");
258 demux->data_size = 0;
259 demux->data_offset = 0;
260 demux->index_offset = 0;
261 } else {
262 demux->base_offset = 0;
263 }
264 }
266 static void
267 gst_asf_demux_init (GstASFDemux * demux, GstASFDemuxClass * klass)
268 {
269 demux->sinkpad =
270 gst_pad_new_from_static_template (&gst_asf_demux_sink_template, "sink");
271 gst_pad_set_chain_function (demux->sinkpad,
272 GST_DEBUG_FUNCPTR (gst_asf_demux_chain));
273 gst_pad_set_event_function (demux->sinkpad,
274 GST_DEBUG_FUNCPTR (gst_asf_demux_sink_event));
275 gst_pad_set_activate_function (demux->sinkpad,
276 GST_DEBUG_FUNCPTR (gst_asf_demux_activate));
277 gst_pad_set_activatepull_function (demux->sinkpad,
278 GST_DEBUG_FUNCPTR (gst_asf_demux_activate_pull));
279 gst_pad_set_activatepush_function (demux->sinkpad,
280 GST_DEBUG_FUNCPTR (gst_asf_demux_activate_push));
281 gst_element_add_pad (GST_ELEMENT (demux), demux->sinkpad);
283 /* set initial state */
284 gst_asf_demux_reset (demux, FALSE);
285 }
287 static gboolean
288 gst_asf_demux_activate (GstPad * sinkpad)
289 {
290 if (gst_pad_check_pull_range (sinkpad)) {
291 return gst_pad_activate_pull (sinkpad, TRUE);
292 } else {
293 return gst_pad_activate_push (sinkpad, TRUE);
294 }
295 }
297 static gboolean
298 gst_asf_demux_activate_push (GstPad * sinkpad, gboolean active)
299 {
300 GstASFDemux *demux;
302 demux = GST_ASF_DEMUX (GST_OBJECT_PARENT (sinkpad));
304 demux->state = GST_ASF_DEMUX_STATE_HEADER;
305 demux->streaming = TRUE;
307 return TRUE;
308 }
310 static gboolean
311 gst_asf_demux_activate_pull (GstPad * pad, gboolean active)
312 {
313 GstASFDemux *demux;
315 demux = GST_ASF_DEMUX (GST_OBJECT_PARENT (pad));
317 if (active) {
318 demux->state = GST_ASF_DEMUX_STATE_HEADER;
319 demux->streaming = FALSE;
321 return gst_pad_start_task (pad, (GstTaskFunction) gst_asf_demux_loop,
322 demux);
323 } else {
324 return gst_pad_stop_task (pad);
325 }
326 }
329 static gboolean
330 gst_asf_demux_sink_event (GstPad * pad, GstEvent * event)
331 {
332 GstASFDemux *demux;
333 gboolean ret = TRUE;
335 demux = GST_ASF_DEMUX (gst_pad_get_parent (pad));
337 GST_LOG_OBJECT (demux, "handling %s event", GST_EVENT_TYPE_NAME (event));
338 switch (GST_EVENT_TYPE (event)) {
339 case GST_EVENT_NEWSEGMENT:{
340 GstFormat newsegment_format;
341 gint64 newsegment_start, stop, time;
342 gdouble rate, arate;
343 gboolean update;
345 gst_event_parse_new_segment_full (event, &update, &rate, &arate,
346 &newsegment_format, &newsegment_start, &stop, &time);
348 if (newsegment_format == GST_FORMAT_BYTES) {
349 if (demux->packet_size && newsegment_start > demux->data_offset)
350 demux->packet = (newsegment_start - demux->data_offset) /
351 demux->packet_size;
352 else
353 demux->packet = 0;
354 } else if (newsegment_format == GST_FORMAT_TIME) {
355 /* do not know packet position, not really a problem */
356 demux->packet = -1;
357 } else {
358 GST_WARNING_OBJECT (demux, "unsupported newsegment format, ignoring");
359 gst_event_unref (event);
360 break;
361 }
363 /* record upstream segment for interpolation */
364 if (newsegment_format != demux->in_segment.format)
365 gst_segment_init (&demux->in_segment, GST_FORMAT_UNDEFINED);
366 gst_segment_set_newsegment_full (&demux->in_segment, update, rate, arate,
367 newsegment_format, newsegment_start, stop, time);
369 /* in either case, clear some state and generate newsegment later on */
370 GST_OBJECT_LOCK (demux);
371 demux->segment_ts = GST_CLOCK_TIME_NONE;
372 demux->in_gap = GST_CLOCK_TIME_NONE;
373 demux->need_newsegment = TRUE;
374 gst_asf_demux_reset_stream_state_after_discont (demux);
375 GST_OBJECT_UNLOCK (demux);
377 gst_event_unref (event);
378 break;
379 }
380 case GST_EVENT_EOS:{
381 if (demux->state == GST_ASF_DEMUX_STATE_HEADER) {
382 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
383 (_("This stream contains no data.")),
384 ("got eos and didn't receive a complete header object"));
385 break;
386 }
387 GST_OBJECT_LOCK (demux);
388 gst_adapter_clear (demux->adapter);
389 GST_OBJECT_UNLOCK (demux);
390 gst_asf_demux_send_event_unlocked (demux, event);
391 break;
392 }
394 case GST_EVENT_FLUSH_STOP:
395 GST_OBJECT_LOCK (demux);
396 gst_asf_demux_reset_stream_state_after_discont (demux);
397 GST_OBJECT_UNLOCK (demux);
398 gst_asf_demux_send_event_unlocked (demux, event);
399 /* upon activation, latency is no longer introduced, e.g. after seek */
400 if (demux->activated_streams)
401 demux->latency = 0;
402 break;
404 default:
405 ret = gst_pad_event_default (pad, event);
406 break;
407 }
409 gst_object_unref (demux);
410 return ret;
411 }
413 static gboolean
414 gst_asf_demux_seek_index_lookup (GstASFDemux * demux, guint * packet,
415 GstClockTime seek_time, GstClockTime * p_idx_time, guint * speed)
416 {
417 GstClockTime idx_time;
418 guint idx;
420 if (G_UNLIKELY (demux->sidx_num_entries == 0 || demux->sidx_interval == 0))
421 return FALSE;
423 idx = (guint) ((seek_time + demux->preroll) / demux->sidx_interval);
425 /* FIXME: seek beyond end of file should result in immediate EOS from
426 * streaming thread instead of a failed seek */
427 if (G_UNLIKELY (idx >= demux->sidx_num_entries))
428 return FALSE;
430 *packet = demux->sidx_entries[idx].packet;
431 if (speed)
432 *speed = demux->sidx_entries[idx].count;
434 /* so we get closer to the actual time of the packet ... actually, let's not
435 * do this, since we throw away superfluous payloads before the seek position
436 * anyway; this way, our key unit seek 'snap resolution' is a bit better
437 * (ie. same as index resolution) */
438 /*
439 while (idx > 0 && demux->sidx_entries[idx-1] == demux->sidx_entries[idx])
440 --idx;
441 */
443 idx_time = demux->sidx_interval * idx;
444 if (G_LIKELY (idx_time >= demux->preroll))
445 idx_time -= demux->preroll;
447 GST_DEBUG_OBJECT (demux, "%" GST_TIME_FORMAT " => packet %u at %"
448 GST_TIME_FORMAT, GST_TIME_ARGS (seek_time), *packet,
449 GST_TIME_ARGS (idx_time));
451 if (G_LIKELY (p_idx_time))
452 *p_idx_time = idx_time;
454 return TRUE;
455 }
457 static void
458 gst_asf_demux_reset_stream_state_after_discont (GstASFDemux * demux)
459 {
460 guint n;
462 gst_adapter_clear (demux->adapter);
464 GST_DEBUG_OBJECT (demux, "reset stream state");
466 for (n = 0; n < demux->num_streams; n++) {
467 demux->stream[n].discont = TRUE;
468 demux->stream[n].last_flow = GST_FLOW_OK;
470 while (demux->stream[n].payloads->len > 0) {
471 AsfPayload *payload;
472 guint last;
474 last = demux->stream[n].payloads->len - 1;
475 payload = &g_array_index (demux->stream[n].payloads, AsfPayload, last);
476 gst_buffer_replace (&payload->buf, NULL);
477 g_array_remove_index (demux->stream[n].payloads, last);
478 }
479 }
480 }
482 static void
483 gst_asf_demux_mark_discont (GstASFDemux * demux)
484 {
485 guint n;
487 GST_DEBUG_OBJECT (demux, "Mark stream discont");
489 for (n = 0; n < demux->num_streams; n++)
490 demux->stream[n].discont = TRUE;
491 }
493 /* do a seek in push based mode */
494 static gboolean
495 gst_asf_demux_handle_seek_push (GstASFDemux * demux, GstEvent * event)
496 {
497 gdouble rate;
498 GstFormat format;
499 GstSeekFlags flags;
500 GstSeekType cur_type, stop_type;
501 gint64 cur, stop;
502 guint packet;
503 gboolean res;
505 gst_event_parse_seek (event, &rate, &format, &flags, &cur_type, &cur,
506 &stop_type, &stop);
508 stop_type = GST_SEEK_TYPE_NONE;
509 stop = -1;
511 GST_DEBUG_OBJECT (demux, "seeking to %" GST_TIME_FORMAT, GST_TIME_ARGS (cur));
513 /* determine packet, by index or by estimation */
514 if (!gst_asf_demux_seek_index_lookup (demux, &packet, cur, NULL, NULL)) {
515 packet = (guint) gst_util_uint64_scale (demux->num_packets,
516 cur, demux->play_time);
517 }
519 if (packet > demux->num_packets) {
520 GST_DEBUG_OBJECT (demux, "could not determine packet to seek to, "
521 "seek aborted.");
522 return FALSE;
523 }
525 GST_DEBUG_OBJECT (demux, "seeking to packet %d", packet);
527 cur = demux->data_offset + (packet * demux->packet_size);
529 GST_DEBUG_OBJECT (demux, "Pushing BYTE seek rate %g, "
530 "start %" G_GINT64_FORMAT ", stop %" G_GINT64_FORMAT, rate, cur, stop);
531 /* BYTE seek event */
532 event = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags, cur_type, cur,
533 stop_type, stop);
534 res = gst_pad_push_event (demux->sinkpad, event);
536 return res;
537 }
539 static gboolean
540 gst_asf_demux_handle_seek_event (GstASFDemux * demux, GstEvent * event)
541 {
542 GstClockTime idx_time;
543 GstSegment segment;
544 GstSeekFlags flags;
545 GstSeekType cur_type, stop_type;
546 GstFormat format;
547 gboolean only_need_update;
548 gboolean keyunit_sync;
549 gboolean flush;
550 gdouble rate;
551 gint64 cur, stop;
552 gint64 seek_time;
553 guint packet, speed_count = 1;
555 if (G_UNLIKELY (demux->seekable == FALSE || demux->packet_size == 0 ||
556 demux->num_packets == 0 || demux->play_time == 0)) {
557 GST_LOG_OBJECT (demux, "stream is not seekable");
558 return FALSE;
559 }
561 if (G_UNLIKELY (!demux->activated_streams)) {
562 GST_LOG_OBJECT (demux, "streams not yet activated, ignoring seek");
563 return FALSE;
564 }
566 gst_event_parse_seek (event, &rate, &format, &flags, &cur_type, &cur,
567 &stop_type, &stop);
569 if (G_UNLIKELY (format != GST_FORMAT_TIME)) {
570 GST_LOG_OBJECT (demux, "seeking is only supported in TIME format");
571 return FALSE;
572 }
574 if (G_UNLIKELY (rate <= 0.0)) {
575 GST_LOG_OBJECT (demux, "backward playback is not supported yet");
576 return FALSE;
577 }
579 flush = ((flags & GST_SEEK_FLAG_FLUSH) == GST_SEEK_FLAG_FLUSH);
580 demux->accurate =
581 ((flags & GST_SEEK_FLAG_ACCURATE) == GST_SEEK_FLAG_ACCURATE);
582 keyunit_sync = ((flags & GST_SEEK_FLAG_KEY_UNIT) == GST_SEEK_FLAG_KEY_UNIT);
584 if (G_UNLIKELY (demux->streaming)) {
585 /* support it safely needs more segment handling, e.g. closing etc */
586 if (!flush) {
587 GST_LOG_OBJECT (demux, "streaming; non-flushing seek not supported");
588 return FALSE;
589 }
590 /* we can (re)construct the start later on, but not the end */
591 if (stop_type != GST_SEEK_TYPE_NONE) {
592 GST_LOG_OBJECT (demux, "streaming; end type must be NONE");
593 return FALSE;
594 }
595 gst_event_ref (event);
596 /* upstream might handle TIME seek, e.g. mms or rtsp,
597 * or not, e.g. http, then we give it a hand */
598 if (!gst_pad_push_event (demux->sinkpad, event))
599 return gst_asf_demux_handle_seek_push (demux, event);
600 else
601 return TRUE;
602 }
604 /* unlock the streaming thread */
605 if (G_LIKELY (flush)) {
606 gst_pad_push_event (demux->sinkpad, gst_event_new_flush_start ());
607 gst_asf_demux_send_event_unlocked (demux, gst_event_new_flush_start ());
608 } else {
609 gst_pad_pause_task (demux->sinkpad);
610 }
612 /* grab the stream lock so that streaming cannot continue, for
613 * non flushing seeks when the element is in PAUSED this could block
614 * forever */
615 GST_PAD_STREAM_LOCK (demux->sinkpad);
617 /* we now can stop flushing, since we have the stream lock now */
618 gst_pad_push_event (demux->sinkpad, gst_event_new_flush_stop ());
620 if (G_LIKELY (flush))
621 gst_asf_demux_send_event_unlocked (demux, gst_event_new_flush_stop ());
623 /* operating on copy of segment until we know the seek worked */
624 segment = demux->segment;
626 if (G_UNLIKELY (demux->segment_running && !flush)) {
627 GstEvent *newseg;
629 /* create the segment event to close the current segment */
630 newseg = gst_event_new_new_segment (TRUE, segment.rate,
631 GST_FORMAT_TIME, segment.start, segment.last_stop, segment.time);
633 gst_asf_demux_send_event_unlocked (demux, newseg);
634 }
636 gst_segment_set_seek (&segment, rate, format, flags, cur_type,
637 cur, stop_type, stop, &only_need_update);
639 GST_DEBUG_OBJECT (demux, "seeking to time %" GST_TIME_FORMAT ", segment: "
640 "%" GST_SEGMENT_FORMAT, GST_TIME_ARGS (segment.start), &segment);
642 seek_time = segment.start;
644 /* FIXME: should check the KEY_UNIT flag; need to adjust last_stop to
645 * real start of data and segment_start to indexed time for key unit seek*/
646 if (G_UNLIKELY (!gst_asf_demux_seek_index_lookup (demux, &packet, seek_time,
647 &idx_time, &speed_count))) {
648 /* First try to query our source to see if it can convert for us. This is
649 the case when our source is an mms stream, notice that in this case
650 gstmms will do a time based seek to get the byte offset, this is not a
651 problem as the seek to this offset needs to happen anway. */
652 gint64 offset;
653 GstFormat dest_format = GST_FORMAT_BYTES;
655 if (gst_pad_query_peer_convert (demux->sinkpad, GST_FORMAT_TIME, seek_time,
656 &dest_format, &offset) && dest_format == GST_FORMAT_BYTES) {
657 packet = (offset - demux->data_offset) / demux->packet_size;
658 GST_LOG_OBJECT (demux, "convert %" GST_TIME_FORMAT
659 " to bytes query result: %" G_GINT64_FORMAT ", data_ofset: %"
660 G_GINT64_FORMAT ", packet_size: %u," " resulting packet: %u\n",
661 GST_TIME_ARGS (seek_time), offset, demux->data_offset,
662 demux->packet_size, packet);
663 } else {
664 /* Hackety hack, this sucks. We just seek to an earlier position
665 * and let the sinks throw away the stuff before the segment start */
666 if (flush && (demux->accurate || keyunit_sync)) {
667 seek_time -= 5 * GST_SECOND;
668 if (seek_time < 0)
669 seek_time = 0;
670 }
672 packet = (guint) gst_util_uint64_scale (demux->num_packets,
673 seek_time, demux->play_time);
675 if (packet > demux->num_packets)
676 packet = demux->num_packets;
677 }
678 } else {
679 if (G_LIKELY (keyunit_sync)) {
680 GST_DEBUG_OBJECT (demux, "key unit seek, adjust seek_time = %"
681 GST_TIME_FORMAT " to index_time = %" GST_TIME_FORMAT,
682 GST_TIME_ARGS (seek_time), GST_TIME_ARGS (idx_time));
683 segment.start = idx_time;
684 segment.last_stop = idx_time;
685 segment.time = idx_time;
686 }
687 }
689 GST_DEBUG_OBJECT (demux, "seeking to packet %u (%d)", packet, speed_count);
691 GST_OBJECT_LOCK (demux);
692 demux->segment = segment;
693 demux->packet = packet;
694 demux->need_newsegment = TRUE;
695 demux->speed_packets = speed_count;
696 gst_asf_demux_reset_stream_state_after_discont (demux);
697 GST_OBJECT_UNLOCK (demux);
699 /* restart our task since it might have been stopped when we did the flush */
700 gst_pad_start_task (demux->sinkpad, (GstTaskFunction) gst_asf_demux_loop,
701 demux);
703 /* streaming can continue now */
704 GST_PAD_STREAM_UNLOCK (demux->sinkpad);
706 return TRUE;
707 }
709 static gboolean
710 gst_asf_demux_handle_src_event (GstPad * pad, GstEvent * event)
711 {
712 GstASFDemux *demux;
713 gboolean ret;
715 demux = GST_ASF_DEMUX (gst_pad_get_parent (pad));
717 switch (GST_EVENT_TYPE (event)) {
718 case GST_EVENT_SEEK:
719 GST_LOG_OBJECT (pad, "seek event");
720 ret = gst_asf_demux_handle_seek_event (demux, event);
721 gst_event_unref (event);
722 break;
723 case GST_EVENT_QOS:
724 case GST_EVENT_NAVIGATION:
725 /* just drop these two silently */
726 gst_event_unref (event);
727 ret = FALSE;
728 break;
729 default:
730 GST_LOG_OBJECT (pad, "%s event", GST_EVENT_TYPE_NAME (event));
731 ret = gst_pad_event_default (pad, event);
732 break;
733 }
735 gst_object_unref (demux);
736 return ret;
737 }
739 static inline guint32
740 gst_asf_demux_identify_guid (const ASFGuidHash * guids, ASFGuid * guid)
741 {
742 guint32 ret;
744 ret = gst_asf_identify_guid (guids, guid);
746 GST_LOG ("%s 0x%08x-0x%08x-0x%08x-0x%08x",
747 gst_asf_get_guid_nick (guids, ret),
748 guid->v1, guid->v2, guid->v3, guid->v4);
750 return ret;
751 }
753 typedef struct
754 {
755 AsfObjectID id;
756 guint64 size;
757 } AsfObject;
760 /* expect is true when the user is expeting an object,
761 * when false, it will give no warnings if the object
762 * is not identified
763 */
764 static gboolean
765 asf_demux_peek_object (GstASFDemux * demux, const guint8 * data,
766 guint data_len, AsfObject * object, gboolean expect)
767 {
768 ASFGuid guid;
770 if (data_len < ASF_OBJECT_HEADER_SIZE)
771 return FALSE;
773 guid.v1 = GST_READ_UINT32_LE (data + 0);
774 guid.v2 = GST_READ_UINT32_LE (data + 4);
775 guid.v3 = GST_READ_UINT32_LE (data + 8);
776 guid.v4 = GST_READ_UINT32_LE (data + 12);
778 object->size = GST_READ_UINT64_LE (data + 16);
780 /* FIXME: make asf_demux_identify_object_guid() */
781 object->id = gst_asf_demux_identify_guid (asf_object_guids, &guid);
782 if (object->id == ASF_OBJ_UNDEFINED && expect) {
783 GST_WARNING_OBJECT (demux, "Unknown object %08x-%08x-%08x-%08x",
784 guid.v1, guid.v2, guid.v3, guid.v4);
785 }
787 return TRUE;
788 }
790 static void
791 gst_asf_demux_release_old_pads (GstASFDemux * demux)
792 {
793 GST_DEBUG_OBJECT (demux, "Releasing old pads");
795 while (demux->old_num_streams > 0) {
796 gst_pad_push_event (demux->old_stream[demux->old_num_streams - 1].pad,
797 gst_event_new_eos ());
798 gst_asf_demux_free_stream (demux,
799 &demux->old_stream[demux->old_num_streams - 1]);
800 --demux->old_num_streams;
801 }
802 memset (demux->old_stream, 0, sizeof (demux->old_stream));
803 demux->old_num_streams = 0;
804 }
806 static GstFlowReturn
807 gst_asf_demux_chain_headers (GstASFDemux * demux)
808 {
809 GstFlowReturn flow;
810 AsfObject obj;
811 guint8 *header_data, *data = NULL;
812 const guint8 *cdata = NULL;
813 guint64 header_size;
815 cdata = (guint8 *) gst_adapter_peek (demux->adapter, ASF_OBJECT_HEADER_SIZE);
816 if (cdata == NULL)
817 goto need_more_data;
819 asf_demux_peek_object (demux, cdata, ASF_OBJECT_HEADER_SIZE, &obj, TRUE);
820 if (obj.id != ASF_OBJ_HEADER)
821 goto wrong_type;
823 GST_LOG_OBJECT (demux, "header size = %u", (guint) obj.size);
825 /* + 50 for non-packet data at beginning of ASF_OBJ_DATA */
826 if (gst_adapter_available (demux->adapter) < obj.size + 50)
827 goto need_more_data;
829 data = gst_adapter_take (demux->adapter, obj.size + 50);
831 header_data = data;
832 header_size = obj.size;
833 flow = gst_asf_demux_process_object (demux, &header_data, &header_size);
834 if (flow != GST_FLOW_OK)
835 goto parse_failed;
837 /* calculate where the packet data starts */
838 demux->data_offset = obj.size + 50;
840 /* now parse the beginning of the ASF_OBJ_DATA object */
841 if (!gst_asf_demux_parse_data_object_start (demux, data + obj.size))
842 goto wrong_type;
844 if (demux->num_streams == 0)
845 goto no_streams;
847 g_free (data);
848 return GST_FLOW_OK;
850 /* NON-FATAL */
851 need_more_data:
852 {
853 GST_LOG_OBJECT (demux, "not enough data in adapter yet");
854 return GST_FLOW_OK;
855 }
857 /* ERRORS */
858 wrong_type:
859 {
860 GST_ELEMENT_ERROR (demux, STREAM, WRONG_TYPE, (NULL),
861 ("This doesn't seem to be an ASF file"));
862 g_free (data);
863 return GST_FLOW_ERROR;
864 }
865 no_streams:
866 parse_failed:
867 {
868 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
869 ("header parsing failed, or no streams found, flow = %s",
870 gst_flow_get_name (flow)));
871 g_free (data);
872 return GST_FLOW_ERROR;
873 }
874 }
876 static GstFlowReturn
877 gst_asf_demux_aggregate_flow_return (GstASFDemux * demux)
878 {
879 int i;
880 GST_DEBUG_OBJECT (demux, "Aggregating");
882 for (i = 0; i < demux->num_streams; i++) {
883 if (demux->stream[i].active) {
884 GstFlowReturn flowret = demux->stream[i].last_flow;
885 GST_DEBUG_OBJECT (demux, "Aggregating: flow %i return %s", i,
886 gst_flow_get_name (flowret));
887 if (flowret != GST_FLOW_NOT_LINKED)
888 return flowret;
889 }
890 }
892 /* If we got here, then all our active streams are not linked */
893 return GST_FLOW_NOT_LINKED;
894 }
896 static gboolean
897 gst_asf_demux_pull_data (GstASFDemux * demux, guint64 offset, guint size,
898 GstBuffer ** p_buf, GstFlowReturn * p_flow)
899 {
900 GstFlowReturn flow;
902 GST_LOG_OBJECT (demux, "pulling buffer at %" G_GUINT64_FORMAT "+%u",
903 offset, size);
905 flow = gst_pad_pull_range (demux->sinkpad, offset, size, p_buf);
907 if (G_LIKELY (p_flow))
908 *p_flow = flow;
910 if (G_UNLIKELY (flow != GST_FLOW_OK)) {
911 GST_DEBUG_OBJECT (demux, "flow %s pulling buffer at %" G_GUINT64_FORMAT
912 "+%u", gst_flow_get_name (flow), offset, size);
913 *p_buf = NULL;
914 return FALSE;
915 }
917 g_assert (*p_buf != NULL);
919 if (G_UNLIKELY (GST_BUFFER_SIZE (*p_buf) < size)) {
920 GST_DEBUG_OBJECT (demux, "short read pulling buffer at %" G_GUINT64_FORMAT
921 "+%u (got only %u bytes)", offset, size, GST_BUFFER_SIZE (*p_buf));
922 gst_buffer_unref (*p_buf);
923 if (G_LIKELY (p_flow))
924 *p_flow = GST_FLOW_UNEXPECTED;
925 *p_buf = NULL;
926 return FALSE;
927 }
929 return TRUE;
930 }
932 static void
933 gst_asf_demux_pull_indices (GstASFDemux * demux)
934 {
935 GstBuffer *buf = NULL;
936 guint64 offset;
937 guint num_read = 0;
939 offset = demux->index_offset;
941 if (G_UNLIKELY (offset == 0)) {
942 GST_DEBUG_OBJECT (demux, "can't read indices, don't know index offset");
943 return;
944 }
946 while (gst_asf_demux_pull_data (demux, offset, 16 + 8, &buf, NULL)) {
947 GstFlowReturn flow;
948 AsfObject obj;
950 asf_demux_peek_object (demux, GST_BUFFER_DATA (buf), 16 + 8, &obj, TRUE);
951 gst_buffer_replace (&buf, NULL);
953 /* check for sanity */
954 if (G_UNLIKELY (obj.size > (5 * 1024 * 1024))) {
955 GST_DEBUG_OBJECT (demux, "implausible index object size, bailing out");
956 break;
957 }
959 if (G_UNLIKELY (!gst_asf_demux_pull_data (demux, offset, obj.size, &buf,
960 NULL)))
961 break;
963 GST_LOG_OBJECT (demux, "index object at offset 0x%" G_GINT64_MODIFIER "X"
964 ", size %u", offset, (guint) obj.size);
966 offset += obj.size; /* increase before _process_object changes it */
968 flow = gst_asf_demux_process_object (demux, &buf->data, &obj.size);
969 gst_buffer_replace (&buf, NULL);
971 if (G_UNLIKELY (flow != GST_FLOW_OK))
972 break;
974 ++num_read;
975 }
976 GST_DEBUG_OBJECT (demux, "read %u index objects", num_read);
977 }
979 static gboolean
980 gst_asf_demux_parse_data_object_start (GstASFDemux * demux, guint8 * data)
981 {
982 AsfObject obj;
984 asf_demux_peek_object (demux, data, 50, &obj, TRUE);
985 if (obj.id != ASF_OBJ_DATA) {
986 GST_WARNING_OBJECT (demux, "headers not followed by a DATA object");
987 return FALSE;
988 }
990 demux->state = GST_ASF_DEMUX_STATE_DATA;
992 if (!demux->broadcast && obj.size > 50) {
993 demux->data_size = obj.size - 50;
994 /* CHECKME: for at least one file this is off by +158 bytes?! */
995 demux->index_offset = demux->data_offset + demux->data_size;
996 } else {
997 demux->data_size = 0;
998 demux->index_offset = 0;
999 }
1001 demux->packet = 0;
1003 if (!demux->broadcast) {
1004 /* skip object header (24 bytes) and file GUID (16 bytes) */
1005 demux->num_packets = GST_READ_UINT64_LE (data + (16 + 8) + 16);
1006 } else {
1007 demux->num_packets = 0;
1008 }
1010 if (demux->num_packets == 0)
1011 demux->seekable = FALSE;
1013 /* fallback in the unlikely case that headers are inconsistent, can't hurt */
1014 if (demux->data_size == 0 && demux->num_packets > 0) {
1015 demux->data_size = demux->num_packets * demux->packet_size;
1016 demux->index_offset = demux->data_offset + demux->data_size;
1017 }
1019 /* process pending stream objects and create pads for those */
1020 gst_asf_demux_process_queued_extended_stream_objects (demux);
1022 GST_INFO_OBJECT (demux, "Stream has %" G_GUINT64_FORMAT " packets, "
1023 "data_offset=%" G_GINT64_FORMAT ", data_size=%" G_GINT64_FORMAT
1024 ", index_offset=%" G_GUINT64_FORMAT, demux->num_packets,
1025 demux->data_offset, demux->data_size, demux->index_offset);
1027 return TRUE;
1028 }
1030 static gboolean
1031 gst_asf_demux_pull_headers (GstASFDemux * demux)
1032 {
1033 GstFlowReturn flow;
1034 AsfObject obj;
1035 GstBuffer *buf = NULL;
1036 guint64 size;
1038 GST_LOG_OBJECT (demux, "reading headers");
1040 /* pull HEADER object header, so we know its size */
1041 if (!gst_asf_demux_pull_data (demux, demux->base_offset, 16 + 8, &buf, NULL))
1042 goto read_failed;
1044 asf_demux_peek_object (demux, GST_BUFFER_DATA (buf), 16 + 8, &obj, TRUE);
1045 gst_buffer_replace (&buf, NULL);
1047 if (obj.id != ASF_OBJ_HEADER)
1048 goto wrong_type;
1050 GST_LOG_OBJECT (demux, "header size = %u", (guint) obj.size);
1052 /* pull HEADER object */
1053 if (!gst_asf_demux_pull_data (demux, demux->base_offset, obj.size, &buf,
1054 NULL))
1055 goto read_failed;
1057 size = obj.size; /* don't want obj.size changed */
1058 flow = gst_asf_demux_process_object (demux, &buf->data, &size);
1059 gst_buffer_replace (&buf, NULL);
1061 if (flow != GST_FLOW_OK) {
1062 GST_WARNING_OBJECT (demux, "process_object: %s", gst_flow_get_name (flow));
1063 goto parse_failed;
1064 }
1066 /* calculate where the packet data starts */
1067 demux->data_offset = demux->base_offset + obj.size + 50;
1069 /* now pull beginning of DATA object before packet data */
1070 if (!gst_asf_demux_pull_data (demux, demux->base_offset + obj.size, 50, &buf,
1071 NULL))
1072 goto read_failed;
1074 if (!gst_asf_demux_parse_data_object_start (demux, GST_BUFFER_DATA (buf)))
1075 goto wrong_type;
1077 if (demux->num_streams == 0)
1078 goto no_streams;
1080 gst_buffer_replace (&buf, NULL);
1081 return TRUE;
1083 /* ERRORS */
1084 wrong_type:
1085 {
1086 gst_buffer_replace (&buf, NULL);
1087 GST_ELEMENT_ERROR (demux, STREAM, WRONG_TYPE, (NULL),
1088 ("This doesn't seem to be an ASF file"));
1089 return FALSE;
1090 }
1091 no_streams:
1092 read_failed:
1093 parse_failed:
1094 {
1095 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL), (NULL));
1096 return FALSE;
1097 }
1098 }
1100 static gboolean
1101 all_streams_prerolled (GstASFDemux * demux)
1102 {
1103 GstClockTime preroll_time;
1104 guint i, num_no_data = 0;
1106 preroll_time = demux->preroll;
1108 /* returns TRUE as long as there isn't a stream which (a) has data queued
1109 * and (b) the timestamp of last piece of data queued is < demux->preroll
1110 * AND there is at least one other stream with data queued */
1111 for (i = 0; i < demux->num_streams; ++i) {
1112 AsfPayload *last_payload;
1113 AsfStream *stream;
1114 guint last_idx;
1116 stream = &demux->stream[i];
1117 if (G_UNLIKELY (stream->payloads->len == 0)) {
1118 ++num_no_data;
1119 GST_LOG_OBJECT (stream->pad, "no data queued");
1120 continue;
1121 }
1123 last_idx = stream->payloads->len - 1;
1124 last_payload = &g_array_index (stream->payloads, AsfPayload, last_idx);
1126 GST_LOG_OBJECT (stream->pad, "checking if %" GST_TIME_FORMAT " > %"
1127 GST_TIME_FORMAT, GST_TIME_ARGS (last_payload->ts),
1128 GST_TIME_ARGS (preroll_time));
1129 if (G_UNLIKELY (last_payload->ts <= preroll_time)) {
1130 GST_LOG_OBJECT (stream->pad, "not beyond preroll point yet");
1131 return FALSE;
1132 }
1133 }
1135 if (G_UNLIKELY (num_no_data == demux->num_streams))
1136 return FALSE;
1138 return TRUE;
1139 }
1141 #if 0
1142 static gboolean
1143 gst_asf_demux_have_mutually_exclusive_active_stream (GstASFDemux * demux,
1144 AsfStream * stream)
1145 {
1146 GSList *l;
1148 for (l = demux->mut_ex_streams; l != NULL; l = l->next) {
1149 guint8 *mes;
1151 /* check for each mutual exclusion group whether it affects this stream */
1152 for (mes = (guint8 *) l->data; mes != NULL && *mes != 0xff; ++mes) {
1153 if (*mes == stream->id) {
1154 /* we are in this group; let's check if we've already activated streams
1155 * that are in the same group (and hence mutually exclusive to this
1156 * one) */
1157 for (mes = (guint8 *) l->data; mes != NULL && *mes != 0xff; ++mes) {
1158 guint i;
1160 for (i = 0; i < demux->num_streams; ++i) {
1161 if (demux->stream[i].id == *mes && demux->stream[i].active) {
1162 GST_LOG_OBJECT (demux, "stream with ID %d is mutually exclusive "
1163 "to already active stream with ID %d", stream->id,
1164 demux->stream[i].id);
1165 return TRUE;
1166 }
1167 }
1168 }
1169 /* we can only be in this group once, let's break out and move on to
1170 * the next mutual exclusion group */
1171 break;
1172 }
1173 }
1174 }
1176 return FALSE;
1177 }
1178 #endif
1180 static gboolean
1181 gst_asf_demux_check_activate_streams (GstASFDemux * demux, gboolean force)
1182 {
1183 guint i;
1185 if (demux->activated_streams)
1186 return TRUE;
1188 if (!all_streams_prerolled (demux) && !force) {
1189 GST_DEBUG_OBJECT (demux, "not all streams with data beyond preroll yet");
1190 return FALSE;
1191 }
1193 for (i = 0; i < demux->num_streams; ++i) {
1194 AsfStream *stream = &demux->stream[i];
1196 if (stream->payloads->len > 0) {
1197 /* we don't check mutual exclusion stuff here; either we have data for
1198 * a stream, then we active it, or we don't, then we'll ignore it */
1199 GST_LOG_OBJECT (stream->pad, "is prerolled - activate!");
1200 gst_asf_demux_activate_stream (demux, stream);
1201 } else {
1202 GST_LOG_OBJECT (stream->pad, "no data, ignoring stream");
1203 }
1204 }
1206 gst_asf_demux_release_old_pads (demux);
1208 demux->activated_streams = TRUE;
1209 GST_LOG_OBJECT (demux, "signalling no more pads");
1210 gst_element_no_more_pads (GST_ELEMENT (demux));
1211 return TRUE;
1212 }
1214 /* returns the stream that has a complete payload with the lowest timestamp
1215 * queued, or NULL (we push things by timestamp because during the internal
1216 * prerolling we might accumulate more data then the external queues can take,
1217 * so we'd lock up if we pushed all accumulated data for stream N in one go) */
1218 static AsfStream *
1219 gst_asf_demux_find_stream_with_complete_payload (GstASFDemux * demux)
1220 {
1221 AsfPayload *best_payload = NULL;
1222 AsfStream *best_stream = NULL;
1223 guint i;
1225 for (i = 0; i < demux->num_streams; ++i) {
1226 AsfStream *stream;
1228 stream = &demux->stream[i];
1230 /* Don't push any data until we have at least one payload that falls within
1231 * the current segment. This way we can remove out-of-segment payloads that
1232 * don't need to be decoded after a seek, sending only data from the
1233 * keyframe directly before our segment start */
1234 if (stream->payloads->len > 0) {
1235 AsfPayload *payload;
1236 guint last_idx;
1238 last_idx = stream->payloads->len - 1;
1239 payload = &g_array_index (stream->payloads, AsfPayload, last_idx);
1240 if (G_UNLIKELY (GST_CLOCK_TIME_IS_VALID (payload->ts) &&
1241 (payload->ts < demux->segment.start))) {
1242 if (G_UNLIKELY ((!demux->accurate) && payload->keyframe)) {
1243 GST_DEBUG_OBJECT (stream->pad,
1244 "Found keyframe, updating segment start to %" GST_TIME_FORMAT,
1245 GST_TIME_ARGS (payload->ts));
1246 demux->segment.start = payload->ts;
1247 demux->segment.time = payload->ts;
1248 } else {
1249 GST_DEBUG_OBJECT (stream->pad, "Last queued payload has timestamp %"
1250 GST_TIME_FORMAT " which is before our segment start %"
1251 GST_TIME_FORMAT ", not pushing yet", GST_TIME_ARGS (payload->ts),
1252 GST_TIME_ARGS (demux->segment.start));
1253 continue;
1254 }
1255 }
1257 /* Now see if there's a complete payload queued for this stream */
1259 payload = &g_array_index (stream->payloads, AsfPayload, 0);
1260 if (!gst_asf_payload_is_complete (payload))
1261 continue;
1263 /* ... and whether its timestamp is lower than the current best */
1264 if (best_stream == NULL || best_payload->ts > payload->ts) {
1265 best_stream = stream;
1266 best_payload = payload;
1267 }
1268 }
1269 }
1271 return best_stream;
1272 }
1274 static GstFlowReturn
1275 gst_asf_demux_push_complete_payloads (GstASFDemux * demux, gboolean force)
1276 {
1277 AsfStream *stream;
1279 if (G_UNLIKELY (!demux->activated_streams)) {
1280 if (!gst_asf_demux_check_activate_streams (demux, force))
1281 return GST_FLOW_OK;
1282 /* streams are now activated */
1283 }
1285 /* wait until we had a chance to "lock on" some payload's timestamp */
1286 if (G_UNLIKELY (demux->need_newsegment
1287 && !GST_CLOCK_TIME_IS_VALID (demux->segment_ts)))
1288 return GST_FLOW_OK;
1290 while ((stream = gst_asf_demux_find_stream_with_complete_payload (demux))) {
1291 AsfPayload *payload;
1293 payload = &g_array_index (stream->payloads, AsfPayload, 0);
1295 /* do we need to send a newsegment event */
1296 if ((G_UNLIKELY (demux->need_newsegment))) {
1298 /* safe default if insufficient upstream info */
1299 if (!GST_CLOCK_TIME_IS_VALID (demux->in_gap))
1300 demux->in_gap = 0;
1302 if (demux->segment.stop == GST_CLOCK_TIME_NONE &&
1303 demux->segment.duration > 0) {
1304 /* slight HACK; prevent clipping of last bit */
1305 demux->segment.stop = demux->segment.duration + demux->in_gap;
1306 }
1308 /* FIXME : only if ACCURATE ! */
1309 if (G_LIKELY (!demux->accurate
1310 && (GST_CLOCK_TIME_IS_VALID (payload->ts)))) {
1311 GST_DEBUG ("Adjusting newsegment start to %" GST_TIME_FORMAT,
1312 GST_TIME_ARGS (payload->ts));
1313 demux->segment.start = payload->ts;
1314 demux->segment.time = payload->ts;
1315 }
1317 GST_DEBUG_OBJECT (demux, "sending new-segment event %" GST_SEGMENT_FORMAT,
1318 &demux->segment);
1320 /* note: we fix up all timestamps to start from 0, so this should be ok */
1321 gst_asf_demux_send_event_unlocked (demux,
1322 gst_event_new_new_segment (FALSE, demux->segment.rate,
1323 GST_FORMAT_TIME, demux->segment.start, demux->segment.stop,
1324 demux->segment.start));
1326 /* now post any global tags we may have found */
1327 if (demux->taglist == NULL)
1328 demux->taglist = gst_tag_list_new ();
1330 gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
1331 GST_TAG_CONTAINER_FORMAT, "ASF", NULL);
1333 GST_DEBUG_OBJECT (demux, "global tags: %" GST_PTR_FORMAT, demux->taglist);
1334 gst_element_found_tags (GST_ELEMENT (demux), demux->taglist);
1335 demux->taglist = NULL;
1337 demux->need_newsegment = FALSE;
1338 demux->segment_running = TRUE;
1339 }
1341 /* Do we have tags pending for this stream? */
1342 if (G_UNLIKELY (stream->pending_tags)) {
1343 GST_LOG_OBJECT (stream->pad, "%" GST_PTR_FORMAT, stream->pending_tags);
1344 gst_element_found_tags_for_pad (GST_ELEMENT (demux), stream->pad,
1345 stream->pending_tags);
1346 stream->pending_tags = NULL;
1347 }
1349 /* We have the whole packet now so we should push the packet to
1350 * the src pad now. First though we should check if we need to do
1351 * descrambling */
1352 if (G_UNLIKELY (demux->span > 1)) {
1353 gst_asf_demux_descramble_buffer (demux, stream, &payload->buf);
1354 }
1356 payload->buf = gst_buffer_make_metadata_writable (payload->buf);
1358 if (G_LIKELY (!payload->keyframe)) {
1359 GST_BUFFER_FLAG_SET (payload->buf, GST_BUFFER_FLAG_DELTA_UNIT);
1360 }
1362 if (G_UNLIKELY (stream->discont)) {
1363 GST_DEBUG_OBJECT (stream->pad, "marking DISCONT on stream");
1364 GST_BUFFER_FLAG_SET (payload->buf, GST_BUFFER_FLAG_DISCONT);
1365 stream->discont = FALSE;
1366 }
1368 if (G_UNLIKELY (stream->is_video && payload->par_x && payload->par_y &&
1369 (payload->par_x != stream->par_x) &&
1370 (payload->par_y != stream->par_y))) {
1371 GST_DEBUG ("Updating PAR (%d/%d => %d/%d)",
1372 stream->par_x, stream->par_y, payload->par_x, payload->par_y);
1373 stream->par_x = payload->par_x;
1374 stream->par_y = payload->par_y;
1375 gst_caps_set_simple (stream->caps, "pixel-aspect-ratio",
1376 GST_TYPE_FRACTION, stream->par_x, stream->par_y, NULL);
1377 gst_pad_set_caps (stream->pad, stream->caps);
1378 }
1380 if (G_UNLIKELY (stream->interlaced != payload->interlaced)) {
1381 GST_DEBUG ("Updating interlaced status (%d => %d)", stream->interlaced,
1382 payload->interlaced);
1383 stream->interlaced = payload->interlaced;
1384 gst_caps_set_simple (stream->caps, "interlaced", G_TYPE_BOOLEAN,
1385 stream->interlaced, NULL);
1386 }
1388 gst_buffer_set_caps (payload->buf, stream->caps);
1390 /* (sort of) interpolate timestamps using upstream "frame of reference",
1391 * typically useful for live src, but might (unavoidably) mess with
1392 * position reporting if a live src is playing not so live content
1393 * (e.g. rtspsrc taking some time to fall back to tcp) */
1394 GST_BUFFER_TIMESTAMP (payload->buf) = payload->ts + demux->in_gap;
1395 if (payload->duration == GST_CLOCK_TIME_NONE)
1396 GST_BUFFER_DURATION (payload->buf) =
1397 stream->ext_props.avg_time_per_frame * 100;
1398 else
1399 GST_BUFFER_DURATION (payload->buf) = payload->duration;
1401 /* FIXME: we should really set durations on buffers if we can */
1403 GST_LOG_OBJECT (stream->pad, "pushing buffer, ts=%" GST_TIME_FORMAT
1404 ", dur=%" GST_TIME_FORMAT " size=%u",
1405 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (payload->buf)),
1406 GST_TIME_ARGS (GST_BUFFER_DURATION (payload->buf)),
1407 GST_BUFFER_SIZE (payload->buf));
1409 stream->last_flow = gst_pad_push (stream->pad, payload->buf);
1410 payload->buf = NULL;
1411 g_array_remove_index (stream->payloads, 0);
1412 }
1414 return gst_asf_demux_aggregate_flow_return (demux);
1415 }
1417 static gboolean
1418 gst_asf_demux_check_buffer_is_header (GstASFDemux * demux, GstBuffer * buf)
1419 {
1420 AsfObject obj;
1421 g_assert (buf != NULL);
1423 GST_LOG_OBJECT (demux, "Checking if buffer is a header");
1425 /* we return false on buffer too small */
1426 if (GST_BUFFER_SIZE (buf) < ASF_OBJECT_HEADER_SIZE)
1427 return FALSE;
1429 /* check if it is a header */
1430 asf_demux_peek_object (demux, GST_BUFFER_DATA (buf),
1431 ASF_OBJECT_HEADER_SIZE, &obj, TRUE);
1432 if (obj.id == ASF_OBJ_HEADER) {
1433 return TRUE;
1434 }
1435 return FALSE;
1436 }
1438 static gboolean
1439 gst_asf_demux_check_chained_asf (GstASFDemux * demux)
1440 {
1441 guint64 off = demux->data_offset + (demux->packet * demux->packet_size);
1442 GstFlowReturn ret = GST_FLOW_OK;
1443 GstBuffer *buf = NULL;
1444 gboolean header = FALSE;
1446 /* TODO maybe we should skip index objects after the data and look
1447 * further for a new header */
1448 if (gst_asf_demux_pull_data (demux, off, ASF_OBJECT_HEADER_SIZE, &buf, &ret)) {
1449 g_assert (buf != NULL);
1450 /* check if it is a header */
1451 if (gst_asf_demux_check_buffer_is_header (demux, buf)) {
1452 GST_DEBUG_OBJECT (demux, "new base offset: %" G_GUINT64_FORMAT, off);
1453 demux->base_offset = off;
1454 header = TRUE;
1455 }
1457 gst_buffer_unref (buf);
1458 }
1460 return header;
1461 }
1463 static void
1464 gst_asf_demux_loop (GstASFDemux * demux)
1465 {
1466 GstFlowReturn flow = GST_FLOW_OK;
1467 GstBuffer *buf = NULL;
1468 guint64 off;
1470 if (G_UNLIKELY (demux->state == GST_ASF_DEMUX_STATE_HEADER)) {
1471 if (!gst_asf_demux_pull_headers (demux)) {
1472 flow = GST_FLOW_ERROR;
1473 goto pause;
1474 }
1476 gst_asf_demux_pull_indices (demux);
1477 }
1479 g_assert (demux->state == GST_ASF_DEMUX_STATE_DATA);
1481 if (G_UNLIKELY (demux->num_packets != 0
1482 && demux->packet >= demux->num_packets))
1483 goto eos;
1485 GST_LOG_OBJECT (demux, "packet %u/%u", (guint) demux->packet + 1,
1486 (guint) demux->num_packets);
1488 off = demux->data_offset + (demux->packet * demux->packet_size);
1490 if (G_UNLIKELY (!gst_asf_demux_pull_data (demux, off,
1491 demux->packet_size * demux->speed_packets, &buf, &flow))) {
1492 GST_DEBUG_OBJECT (demux, "got flow %s", gst_flow_get_name (flow));
1493 if (flow == GST_FLOW_UNEXPECTED)
1494 goto eos;
1495 else if (!GST_FLOW_IS_FATAL (flow)) {
1496 GST_DEBUG_OBJECT (demux, "Not fatal");
1497 goto pause;
1498 } else
1499 goto read_failed;
1500 }
1502 if (G_LIKELY (demux->speed_packets == 1)) {
1503 /* FIXME: maybe we should just skip broken packets and error out only
1504 * after a few broken packets in a row? */
1505 if (G_UNLIKELY (!gst_asf_demux_parse_packet (demux, buf))) {
1506 /* when we don't know when the data object ends, we should check
1507 * for a chained asf */
1508 if (demux->num_packets == 0) {
1509 if (gst_asf_demux_check_buffer_is_header (demux, buf)) {
1510 GST_INFO_OBJECT (demux, "Chained asf found");
1511 demux->base_offset = off;
1512 gst_asf_demux_reset (demux, TRUE);
1513 gst_buffer_unref (buf);
1514 return;
1515 }
1516 }
1517 goto parse_error;
1518 }
1520 flow = gst_asf_demux_push_complete_payloads (demux, FALSE);
1522 ++demux->packet;
1524 } else {
1525 guint n;
1526 for (n = 0; n < demux->speed_packets; n++) {
1527 GstBuffer *sub;
1529 sub =
1530 gst_buffer_create_sub (buf, n * demux->packet_size,
1531 demux->packet_size);
1532 /* FIXME: maybe we should just skip broken packets and error out only
1533 * after a few broken packets in a row? */
1534 if (G_UNLIKELY (!gst_asf_demux_parse_packet (demux, sub))) {
1535 /* when we don't know when the data object ends, we should check
1536 * for a chained asf */
1537 if (demux->num_packets == 0) {
1538 if (gst_asf_demux_check_buffer_is_header (demux, sub)) {
1539 GST_INFO_OBJECT (demux, "Chained asf found");
1540 demux->base_offset = off + n * demux->packet_size;
1541 gst_asf_demux_reset (demux, TRUE);
1542 gst_buffer_unref (sub);
1543 gst_buffer_unref (buf);
1544 return;
1545 }
1546 }
1547 goto parse_error;
1548 }
1550 gst_buffer_unref (sub);
1552 flow = gst_asf_demux_push_complete_payloads (demux, FALSE);
1554 ++demux->packet;
1556 }
1558 /* reset speed pull */
1559 demux->speed_packets = 1;
1560 }
1562 gst_buffer_unref (buf);
1564 if (G_UNLIKELY (demux->num_packets > 0
1565 && demux->packet >= demux->num_packets)) {
1566 GST_LOG_OBJECT (demux, "reached EOS");
1567 goto eos;
1568 }
1570 if (G_UNLIKELY (flow != GST_FLOW_OK)) {
1571 GST_DEBUG_OBJECT (demux, "pushing complete payloads failed");
1572 goto pause;
1573 }
1575 /* check if we're at the end of the configured segment */
1576 /* FIXME: check if segment end reached etc. */
1578 return;
1580 eos:
1581 {
1582 /* if we haven't activated our streams yet, this might be because we have
1583 * less data queued than required for preroll; force stream activation and
1584 * send any pending payloads before sending EOS */
1585 if (!demux->activated_streams)
1586 gst_asf_demux_push_complete_payloads (demux, TRUE);
1588 /* we want to push an eos or post a segment-done in any case */
1589 if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
1590 gint64 stop;
1592 /* for segment playback we need to post when (in stream time)
1593 * we stopped, this is either stop (when set) or the duration. */
1594 if ((stop = demux->segment.stop) == -1)
1595 stop = demux->segment.duration;
1597 GST_INFO_OBJECT (demux, "Posting segment-done, at end of segment");
1598 gst_element_post_message (GST_ELEMENT_CAST (demux),
1599 gst_message_new_segment_done (GST_OBJECT (demux), GST_FORMAT_TIME,
1600 stop));
1601 } else if (flow != GST_FLOW_UNEXPECTED) {
1602 /* check if we have a chained asf, in case, we don't eos yet */
1603 if (gst_asf_demux_check_chained_asf (demux)) {
1604 GST_INFO_OBJECT (demux, "Chained ASF starting");
1605 gst_asf_demux_reset (demux, TRUE);
1606 return;
1607 }
1608 /* normal playback, send EOS to all linked pads */
1609 GST_INFO_OBJECT (demux, "Sending EOS, at end of stream");
1610 gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
1611 }
1612 /* ... and fall through to pause */
1613 GST_DEBUG_OBJECT (demux, "EOSing");
1614 }
1615 pause:
1616 {
1617 GST_DEBUG_OBJECT (demux, "pausing task");
1618 demux->segment_running = FALSE;
1619 gst_pad_pause_task (demux->sinkpad);
1621 /* For the error cases (not EOS) */
1622 if (GST_FLOW_IS_FATAL (flow) || flow == GST_FLOW_NOT_LINKED) {
1623 /* Post an error. Hopefully something else already has, but if not... */
1624 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
1625 (_("Internal data stream error.")),
1626 ("streaming stopped, reason %s", gst_flow_get_name (flow)));
1627 }
1628 return;
1629 }
1631 /* ERRORS */
1632 read_failed:
1633 {
1634 GST_DEBUG_OBJECT (demux, "Read failed, doh");
1635 gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
1636 flow = GST_FLOW_UNEXPECTED;
1637 goto pause;
1638 }
1639 parse_error:
1640 {
1641 gst_buffer_unref (buf);
1642 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
1643 ("Error parsing ASF packet %u", (guint) demux->packet));
1644 gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
1645 flow = GST_FLOW_ERROR;
1646 goto pause;
1647 }
1648 }
1650 #define GST_ASF_DEMUX_CHECK_HEADER_YES 0
1651 #define GST_ASF_DEMUX_CHECK_HEADER_NO 1
1652 #define GST_ASF_DEMUX_CHECK_HEADER_NEED_DATA 2
1654 static gint
1655 gst_asf_demux_check_header (GstASFDemux * demux)
1656 {
1657 AsfObject obj;
1658 guint8 *cdata = (guint8 *) gst_adapter_peek (demux->adapter,
1659 ASF_OBJECT_HEADER_SIZE);
1660 if (cdata == NULL) /* need more data */
1661 return GST_ASF_DEMUX_CHECK_HEADER_NEED_DATA;
1663 asf_demux_peek_object (demux, cdata, ASF_OBJECT_HEADER_SIZE, &obj, FALSE);
1664 if (obj.id != ASF_OBJ_HEADER) {
1665 return GST_ASF_DEMUX_CHECK_HEADER_NO;
1666 } else {
1667 return GST_ASF_DEMUX_CHECK_HEADER_YES;
1668 }
1669 }
1671 static GstFlowReturn
1672 gst_asf_demux_chain (GstPad * pad, GstBuffer * buf)
1673 {
1674 GstFlowReturn ret = GST_FLOW_OK;
1675 GstASFDemux *demux;
1677 demux = GST_ASF_DEMUX (GST_PAD_PARENT (pad));
1679 GST_LOG_OBJECT (demux, "buffer: size=%u, offset=%" G_GINT64_FORMAT ", time=%"
1680 GST_TIME_FORMAT, GST_BUFFER_SIZE (buf), GST_BUFFER_OFFSET (buf),
1681 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)));
1683 if (G_UNLIKELY (GST_BUFFER_IS_DISCONT (buf))) {
1684 GST_DEBUG_OBJECT (demux, "received DISCONT");
1685 gst_asf_demux_mark_discont (demux);
1686 }
1688 if (G_UNLIKELY ((!GST_CLOCK_TIME_IS_VALID (demux->in_gap) &&
1689 GST_BUFFER_TIMESTAMP_IS_VALID (buf)))) {
1690 demux->in_gap = GST_BUFFER_TIMESTAMP (buf) - demux->in_segment.start;
1691 GST_DEBUG_OBJECT (demux, "upstream segment start %" GST_TIME_FORMAT
1692 ", interpolation gap: %" GST_TIME_FORMAT,
1693 GST_TIME_ARGS (demux->in_segment.start), GST_TIME_ARGS (demux->in_gap));
1694 }
1696 gst_adapter_push (demux->adapter, buf);
1698 switch (demux->state) {
1699 case GST_ASF_DEMUX_STATE_INDEX:{
1700 gint result = gst_asf_demux_check_header (demux);
1701 if (result == GST_ASF_DEMUX_CHECK_HEADER_NEED_DATA) /* need more data */
1702 break;
1704 if (result == GST_ASF_DEMUX_CHECK_HEADER_NO) {
1705 /* we don't care about this, probably an index */
1706 /* TODO maybe would be smarter to skip all the indices
1707 * until we got a new header or EOS to decide */
1708 GST_LOG_OBJECT (demux, "Received index object, its EOS");
1709 goto eos;
1710 } else {
1711 GST_INFO_OBJECT (demux, "Chained asf starting");
1712 /* cleanup and get ready for a chained asf */
1713 gst_asf_demux_reset (demux, TRUE);
1714 /* fall through */
1715 }
1716 }
1717 case GST_ASF_DEMUX_STATE_HEADER:{
1718 ret = gst_asf_demux_chain_headers (demux);
1719 if (demux->state != GST_ASF_DEMUX_STATE_DATA)
1720 break;
1721 /* otherwise fall through */
1722 }
1723 case GST_ASF_DEMUX_STATE_DATA:
1724 {
1725 guint64 data_size;
1727 data_size = demux->packet_size;
1729 while (gst_adapter_available (demux->adapter) >= data_size) {
1730 GstBuffer *buf;
1732 /* we don't know the length of the stream
1733 * check for a chained asf everytime */
1734 if (demux->num_packets == 0) {
1735 gint result = gst_asf_demux_check_header (demux);
1737 if (result == GST_ASF_DEMUX_CHECK_HEADER_YES) {
1738 GST_INFO_OBJECT (demux, "Chained asf starting");
1739 /* cleanup and get ready for a chained asf */
1740 gst_asf_demux_reset (demux, TRUE);
1741 break;
1742 }
1743 } else if (G_UNLIKELY (demux->num_packets != 0 && demux->packet >= 0
1744 && demux->packet >= demux->num_packets)) {
1745 /* do not overshoot data section when streaming */
1746 break;
1747 }
1749 buf = gst_adapter_take_buffer (demux->adapter, data_size);
1751 /* FIXME: maybe we should just skip broken packets and error out only
1752 * after a few broken packets in a row? */
1753 if (G_UNLIKELY (!gst_asf_demux_parse_packet (demux, buf))) {
1754 GST_WARNING_OBJECT (demux, "Parse error");
1755 }
1757 gst_buffer_unref (buf);
1759 ret = gst_asf_demux_push_complete_payloads (demux, FALSE);
1761 if (demux->packet >= 0)
1762 ++demux->packet;
1763 }
1764 if (G_UNLIKELY (demux->num_packets != 0 && demux->packet >= 0
1765 && demux->packet >= demux->num_packets)) {
1766 demux->state = GST_ASF_DEMUX_STATE_INDEX;
1767 }
1768 break;
1769 }
1770 default:
1771 g_assert_not_reached ();
1772 }
1774 done:
1775 if (ret != GST_FLOW_OK)
1776 GST_DEBUG_OBJECT (demux, "flow: %s", gst_flow_get_name (ret));
1778 return ret;
1780 eos:
1781 {
1782 GST_DEBUG_OBJECT (demux, "Handled last packet, setting EOS");
1783 ret = GST_FLOW_UNEXPECTED;
1784 goto done;
1785 }
1786 }
1788 static inline gboolean
1789 gst_asf_demux_skip_bytes (guint num_bytes, guint8 ** p_data, guint64 * p_size)
1790 {
1791 if (*p_size < num_bytes)
1792 return FALSE;
1794 *p_data += num_bytes;
1795 *p_size -= num_bytes;
1796 return TRUE;
1797 }
1799 static inline guint8
1800 gst_asf_demux_get_uint8 (guint8 ** p_data, guint64 * p_size)
1801 {
1802 guint8 ret;
1804 g_assert (*p_size >= 1);
1805 ret = GST_READ_UINT8 (*p_data);
1806 *p_data += sizeof (guint8);
1807 *p_size -= sizeof (guint8);
1808 return ret;
1809 }
1811 static inline guint16
1812 gst_asf_demux_get_uint16 (guint8 ** p_data, guint64 * p_size)
1813 {
1814 guint16 ret;
1816 g_assert (*p_size >= 2);
1817 ret = GST_READ_UINT16_LE (*p_data);
1818 *p_data += sizeof (guint16);
1819 *p_size -= sizeof (guint16);
1820 return ret;
1821 }
1823 static inline guint32
1824 gst_asf_demux_get_uint32 (guint8 ** p_data, guint64 * p_size)
1825 {
1826 guint32 ret;
1828 g_assert (*p_size >= 4);
1829 ret = GST_READ_UINT32_LE (*p_data);
1830 *p_data += sizeof (guint32);
1831 *p_size -= sizeof (guint32);
1832 return ret;
1833 }
1835 static inline guint64
1836 gst_asf_demux_get_uint64 (guint8 ** p_data, guint64 * p_size)
1837 {
1838 guint64 ret;
1840 g_assert (*p_size >= 8);
1841 ret = GST_READ_UINT64_LE (*p_data);
1842 *p_data += sizeof (guint64);
1843 *p_size -= sizeof (guint64);
1844 return ret;
1845 }
1847 static inline guint32
1848 gst_asf_demux_get_var_length (guint8 type, guint8 ** p_data, guint64 * p_size)
1849 {
1850 switch (type) {
1851 case 0:
1852 return 0;
1854 case 1:
1855 g_assert (*p_size >= 1);
1856 return gst_asf_demux_get_uint8 (p_data, p_size);
1858 case 2:
1859 g_assert (*p_size >= 2);
1860 return gst_asf_demux_get_uint16 (p_data, p_size);
1862 case 3:
1863 g_assert (*p_size >= 4);
1864 return gst_asf_demux_get_uint32 (p_data, p_size);
1866 default:
1867 break;
1868 }
1870 g_assert_not_reached ();
1871 }
1873 static gboolean
1874 gst_asf_demux_get_buffer (GstBuffer ** p_buf, guint num_bytes_to_read,
1875 guint8 ** p_data, guint64 * p_size)
1876 {
1877 *p_buf = NULL;
1879 if (*p_size < num_bytes_to_read)
1880 return FALSE;
1882 *p_buf = gst_buffer_new_and_alloc (num_bytes_to_read);
1883 memcpy (GST_BUFFER_DATA (*p_buf), *p_data, num_bytes_to_read);
1884 *p_data += num_bytes_to_read;
1885 *p_size -= num_bytes_to_read;
1886 return TRUE;
1887 }
1889 static gboolean
1890 gst_asf_demux_get_bytes (guint8 ** p_buf, guint num_bytes_to_read,
1891 guint8 ** p_data, guint64 * p_size)
1892 {
1893 *p_buf = NULL;
1895 if (*p_size < num_bytes_to_read)
1896 return FALSE;
1898 *p_buf = g_memdup (*p_data, num_bytes_to_read);
1899 *p_data += num_bytes_to_read;
1900 *p_size -= num_bytes_to_read;
1901 return TRUE;
1902 }
1904 static gboolean
1905 gst_asf_demux_get_string (gchar ** p_str, guint16 * p_strlen,
1906 guint8 ** p_data, guint64 * p_size)
1907 {
1908 guint16 s_length;
1909 guint8 *s;
1911 *p_str = NULL;
1913 if (*p_size < 2)
1914 return FALSE;
1916 s_length = gst_asf_demux_get_uint16 (p_data, p_size);
1918 if (p_strlen)
1919 *p_strlen = s_length;
1921 if (s_length == 0) {
1922 GST_WARNING ("zero-length string");
1923 *p_str = g_strdup ("");
1924 return TRUE;
1925 }
1927 if (!gst_asf_demux_get_bytes (&s, s_length, p_data, p_size))
1928 return FALSE;
1930 g_assert (s != NULL);
1932 /* just because They don't exist doesn't
1933 * mean They are not out to get you ... */
1934 if (s[s_length - 1] != '\0') {
1935 s = g_realloc (s, s_length + 1);
1936 s[s_length] = '\0';
1937 }
1939 *p_str = (gchar *) s;
1940 return TRUE;
1941 }
1944 static void
1945 gst_asf_demux_get_guid (ASFGuid * guid, guint8 ** p_data, guint64 * p_size)
1946 {
1947 g_assert (*p_size >= 4 * sizeof (guint32));
1949 guid->v1 = gst_asf_demux_get_uint32 (p_data, p_size);
1950 guid->v2 = gst_asf_demux_get_uint32 (p_data, p_size);
1951 guid->v3 = gst_asf_demux_get_uint32 (p_data, p_size);
1952 guid->v4 = gst_asf_demux_get_uint32 (p_data, p_size);
1953 }
1955 static gboolean
1956 gst_asf_demux_get_stream_audio (asf_stream_audio * audio, guint8 ** p_data,
1957 guint64 * p_size)
1958 {
1959 if (*p_size < (2 + 2 + 4 + 4 + 2 + 2 + 2))
1960 return FALSE;
1962 /* WAVEFORMATEX Structure */
1963 audio->codec_tag = gst_asf_demux_get_uint16 (p_data, p_size);
1964 audio->channels = gst_asf_demux_get_uint16 (p_data, p_size);
1965 audio->sample_rate = gst_asf_demux_get_uint32 (p_data, p_size);
1966 audio->byte_rate = gst_asf_demux_get_uint32 (p_data, p_size);
1967 audio->block_align = gst_asf_demux_get_uint16 (p_data, p_size);
1968 audio->word_size = gst_asf_demux_get_uint16 (p_data, p_size);
1969 /* Codec specific data size */
1970 audio->size = gst_asf_demux_get_uint16 (p_data, p_size);
1971 return TRUE;
1972 }
1974 static gboolean
1975 gst_asf_demux_get_stream_video (asf_stream_video * video, guint8 ** p_data,
1976 guint64 * p_size)
1977 {
1978 if (*p_size < (4 + 4 + 1 + 2))
1979 return FALSE;
1981 video->width = gst_asf_demux_get_uint32 (p_data, p_size);
1982 video->height = gst_asf_demux_get_uint32 (p_data, p_size);
1983 video->unknown = gst_asf_demux_get_uint8 (p_data, p_size);
1984 video->size = gst_asf_demux_get_uint16 (p_data, p_size);
1985 return TRUE;
1986 }
1988 static gboolean
1989 gst_asf_demux_get_stream_video_format (asf_stream_video_format * fmt,
1990 guint8 ** p_data, guint64 * p_size)
1991 {
1992 if (*p_size < (4 + 4 + 4 + 2 + 2 + 4 + 4 + 4 + 4 + 4 + 4))
1993 return FALSE;
1995 fmt->size = gst_asf_demux_get_uint32 (p_data, p_size);
1996 fmt->width = gst_asf_demux_get_uint32 (p_data, p_size);
1997 fmt->height = gst_asf_demux_get_uint32 (p_data, p_size);
1998 fmt->planes = gst_asf_demux_get_uint16 (p_data, p_size);
1999 fmt->depth = gst_asf_demux_get_uint16 (p_data, p_size);
2000 fmt->tag = gst_asf_demux_get_uint32 (p_data, p_size);
2001 fmt->image_size = gst_asf_demux_get_uint32 (p_data, p_size);
2002 fmt->xpels_meter = gst_asf_demux_get_uint32 (p_data, p_size);
2003 fmt->ypels_meter = gst_asf_demux_get_uint32 (p_data, p_size);
2004 fmt->num_colors = gst_asf_demux_get_uint32 (p_data, p_size);
2005 fmt->imp_colors = gst_asf_demux_get_uint32 (p_data, p_size);
2006 return TRUE;
2007 }
2009 AsfStream *
2010 gst_asf_demux_get_stream (GstASFDemux * demux, guint16 id)
2011 {
2012 guint i;
2014 for (i = 0; i < demux->num_streams; i++) {
2015 if (demux->stream[i].id == id)
2016 return &demux->stream[i];
2017 }
2019 GST_WARNING ("Segment found for undefined stream: (%d)", id);
2020 return NULL;
2021 }
2023 static void
2024 gst_asf_demux_setup_pad (GstASFDemux * demux, GstPad * src_pad,
2025 GstCaps * caps, guint16 id, gboolean is_video, GstTagList * tags)
2026 {
2027 AsfStream *stream;
2029 gst_pad_use_fixed_caps (src_pad);
2030 gst_pad_set_caps (src_pad, caps);
2032 gst_pad_set_event_function (src_pad,
2033 GST_DEBUG_FUNCPTR (gst_asf_demux_handle_src_event));
2034 gst_pad_set_query_type_function (src_pad,
2035 GST_DEBUG_FUNCPTR (gst_asf_demux_get_src_query_types));
2036 gst_pad_set_query_function (src_pad,
2037 GST_DEBUG_FUNCPTR (gst_asf_demux_handle_src_query));
2039 stream = &demux->stream[demux->num_streams];
2040 stream->caps = caps;
2041 stream->pad = src_pad;
2042 stream->id = id;
2043 stream->fps_known = !is_video; /* bit hacky for audio */
2044 stream->is_video = is_video;
2045 stream->pending_tags = tags;
2046 stream->discont = TRUE;
2047 if (is_video) {
2048 GstStructure *st;
2049 gint par_x, par_y;
2050 st = gst_caps_get_structure (caps, 0);
2051 if (gst_structure_get_fraction (st, "pixel-aspect-ratio", &par_x, &par_y) &&
2052 par_x > 0 && par_y > 0) {
2053 GST_DEBUG ("PAR %d/%d", par_x, par_y);
2054 stream->par_x = par_x;
2055 stream->par_y = par_y;
2056 }
2057 }
2059 stream->payloads = g_array_new (FALSE, FALSE, sizeof (AsfPayload));
2061 GST_INFO ("Created pad %s for stream %u with caps %" GST_PTR_FORMAT,
2062 GST_PAD_NAME (src_pad), demux->num_streams, caps);
2064 ++demux->num_streams;
2066 stream->active = FALSE;
2067 }
2069 static void
2070 gst_asf_demux_add_audio_stream (GstASFDemux * demux,
2071 asf_stream_audio * audio, guint16 id, guint8 ** p_data, guint64 * p_size)
2072 {
2073 GstTagList *tags = NULL;
2074 GstBuffer *extradata = NULL;
2075 GstPad *src_pad;
2076 GstCaps *caps;
2077 guint16 size_left = 0;
2078 gchar *codec_name = NULL;
2079 gchar *name = NULL;
2081 size_left = audio->size;
2083 /* Create the audio pad */
2084 name = g_strdup_printf ("audio_%02d", demux->num_audio_streams);
2086 src_pad = gst_pad_new_from_static_template (&audio_src_template, name);
2087 g_free (name);
2089 /* Swallow up any left over data and set up the
2090 * standard properties from the header info */
2091 if (size_left) {
2092 GST_INFO_OBJECT (demux, "Audio header contains %d bytes of "
2093 "codec specific data", size_left);
2095 g_assert (size_left <= *p_size);
2096 gst_asf_demux_get_buffer (&extradata, size_left, p_data, p_size);
2097 }
2099 /* asf_stream_audio is the same as gst_riff_strf_auds, but with an
2100 * additional two bytes indicating extradata. */
2101 caps = gst_riff_create_audio_caps (audio->codec_tag, NULL,
2102 (gst_riff_strf_auds *) audio, extradata, NULL, &codec_name);
2104 if (caps == NULL) {
2105 caps = gst_caps_new_simple ("audio/x-asf-unknown", "codec_id",
2106 G_TYPE_INT, (gint) audio->codec_tag, NULL);
2107 }
2109 /* Informing about that audio format we just added */
2110 if (codec_name) {
2111 tags = gst_tag_list_new ();
2112 gst_tag_list_add (tags, GST_TAG_MERGE_APPEND, GST_TAG_AUDIO_CODEC,
2113 codec_name, NULL);
2114 g_free (codec_name);
2115 }
2117 if (extradata)
2118 gst_buffer_unref (extradata);
2120 GST_INFO ("Adding audio stream #%u, id %u codec %u (0x%04x), tags=%"
2121 GST_PTR_FORMAT, demux->num_audio_streams, id, audio->codec_tag,
2122 audio->codec_tag, tags);
2124 ++demux->num_audio_streams;
2126 gst_asf_demux_setup_pad (demux, src_pad, caps, id, FALSE, tags);
2127 }
2129 static void
2130 gst_asf_demux_add_video_stream (GstASFDemux * demux,
2131 asf_stream_video_format * video, guint16 id,
2132 guint8 ** p_data, guint64 * p_size)
2133 {
2134 GstTagList *tags = NULL;
2135 GstBuffer *extradata = NULL;
2136 GstPad *src_pad;
2137 GstCaps *caps;
2138 gchar *name = NULL;
2139 gchar *codec_name = NULL;
2140 gint size_left = video->size - 40;
2142 /* Create the video pad */
2143 name = g_strdup_printf ("video_%02d", demux->num_video_streams);
2144 src_pad = gst_pad_new_from_static_template (&video_src_template, name);
2145 g_free (name);
2147 /* Now try some gstreamer formatted MIME types (from gst_avi_demux_strf_vids) */
2148 if (size_left) {
2149 GST_LOG ("Video header has %d bytes of codec specific data", size_left);
2150 g_assert (size_left <= *p_size);
2151 gst_asf_demux_get_buffer (&extradata, size_left, p_data, p_size);
2152 }
2154 GST_DEBUG ("video codec %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (video->tag));
2156 /* yes, asf_stream_video_format and gst_riff_strf_vids are the same */
2157 caps = gst_riff_create_video_caps (video->tag, NULL,
2158 (gst_riff_strf_vids *) video, extradata, NULL, &codec_name);
2160 if (caps == NULL) {
2161 caps = gst_caps_new_simple ("video/x-asf-unknown", "fourcc",
2162 GST_TYPE_FOURCC, video->tag, NULL);
2163 } else {
2164 GstStructure *s;
2165 gint ax, ay;
2167 s = gst_asf_demux_get_metadata_for_stream (demux, id);
2168 if (gst_structure_get_int (s, "AspectRatioX", &ax) &&
2169 gst_structure_get_int (s, "AspectRatioY", &ay) && (ax > 0 && ay > 0)) {
2170 gst_caps_set_simple (caps, "pixel-aspect-ratio", GST_TYPE_FRACTION,
2171 ax, ay, NULL);
2173 } else {
2174 guint ax, ay;
2175 /* retry with the global metadata */
2176 GST_DEBUG ("Retrying with global metadata %" GST_PTR_FORMAT,
2177 demux->global_metadata);
2178 s = demux->global_metadata;
2179 if (gst_structure_get_uint (s, "AspectRatioX", &ax) &&
2180 gst_structure_get_uint (s, "AspectRatioY", &ay)) {
2181 GST_DEBUG ("ax:%d, ay:%d", ax, ay);
2182 if (ax > 0 && ay > 0)
2183 gst_caps_set_simple (caps, "pixel-aspect-ratio", GST_TYPE_FRACTION,
2184 ax, ay, NULL);
2185 }
2186 }
2187 s = gst_caps_get_structure (caps, 0);
2188 gst_structure_remove_field (s, "framerate");
2189 }
2191 /* add fourcc format to caps, some proprietary decoders seem to need it */
2192 gst_caps_set_simple (caps, "format", GST_TYPE_FOURCC, video->tag, NULL);
2194 if (codec_name) {
2195 tags = gst_tag_list_new ();
2196 gst_tag_list_add (tags, GST_TAG_MERGE_APPEND, GST_TAG_VIDEO_CODEC,
2197 codec_name, NULL);
2198 g_free (codec_name);
2199 }
2201 if (extradata)
2202 gst_buffer_unref (extradata);
2204 GST_INFO ("Adding video stream #%u, id %u, codec %"
2205 GST_FOURCC_FORMAT " (0x%08x)", demux->num_video_streams, id,
2206 GST_FOURCC_ARGS (video->tag), video->tag);
2208 ++demux->num_video_streams;
2210 gst_asf_demux_setup_pad (demux, src_pad, caps, id, TRUE, tags);
2211 }
2213 static void
2214 gst_asf_demux_activate_stream (GstASFDemux * demux, AsfStream * stream)
2215 {
2216 if (!stream->active) {
2217 GST_INFO_OBJECT (demux, "Activating stream %2u, pad %s, caps %"
2218 GST_PTR_FORMAT, stream->id, GST_PAD_NAME (stream->pad), stream->caps);
2219 gst_pad_set_active (stream->pad, TRUE);
2220 gst_element_add_pad (GST_ELEMENT_CAST (demux), stream->pad);
2221 stream->active = TRUE;
2222 }
2223 }
2225 static AsfStream *
2226 gst_asf_demux_parse_stream_object (GstASFDemux * demux, guint8 * data,
2227 guint64 size)
2228 {
2229 AsfCorrectionType correction_type;
2230 AsfStreamType stream_type;
2231 GstClockTime time_offset;
2232 gboolean is_encrypted;
2233 guint16 stream_id;
2234 guint16 flags;
2235 ASFGuid guid;
2236 guint stream_specific_size;
2237 guint type_specific_size;
2238 guint unknown;
2240 /* Get the rest of the header's header */
2241 if (size < (16 + 16 + 8 + 4 + 4 + 2 + 4))
2242 goto not_enough_data;
2244 gst_asf_demux_get_guid (&guid, &data, &size);
2245 stream_type = gst_asf_demux_identify_guid (asf_stream_guids, &guid);
2247 gst_asf_demux_get_guid (&guid, &data, &size);
2248 correction_type = gst_asf_demux_identify_guid (asf_correction_guids, &guid);
2250 time_offset = gst_asf_demux_get_uint64 (&data, &size) * 100;
2252 type_specific_size = gst_asf_demux_get_uint32 (&data, &size);
2253 stream_specific_size = gst_asf_demux_get_uint32 (&data, &size);
2255 flags = gst_asf_demux_get_uint16 (&data, &size);
2256 stream_id = flags & 0x7f;
2257 is_encrypted = !!((flags & 0x8000) << 15);
2258 unknown = gst_asf_demux_get_uint32 (&data, &size);
2260 GST_DEBUG_OBJECT (demux, "Found stream %u, time_offset=%" GST_TIME_FORMAT,
2261 stream_id, GST_TIME_ARGS (time_offset));
2263 switch (stream_type) {
2264 case ASF_STREAM_AUDIO:{
2265 asf_stream_audio audio_object;
2267 if (!gst_asf_demux_get_stream_audio (&audio_object, &data, &size))
2268 goto not_enough_data;
2270 GST_INFO ("Object is an audio stream with %u bytes of additional data",
2271 audio_object.size);
2273 gst_asf_demux_add_audio_stream (demux, &audio_object, stream_id,
2274 &data, &size);
2276 switch (correction_type) {
2277 case ASF_CORRECTION_ON:{
2278 guint span, packet_size, chunk_size, data_size, silence_data;
2280 GST_INFO ("Using error correction");
2282 if (size < (1 + 2 + 2 + 2 + 1))
2283 goto not_enough_data;
2285 span = gst_asf_demux_get_uint8 (&data, &size);
2286 packet_size = gst_asf_demux_get_uint16 (&data, &size);
2287 chunk_size = gst_asf_demux_get_uint16 (&data, &size);
2288 data_size = gst_asf_demux_get_uint16 (&data, &size);
2289 silence_data = gst_asf_demux_get_uint8 (&data, &size);
2291 /* FIXME: shouldn't this be per-stream? */
2292 demux->span = span;
2294 GST_DEBUG_OBJECT (demux, "Descrambling ps:%u cs:%u ds:%u s:%u sd:%u",
2295 packet_size, chunk_size, data_size, span, silence_data);
2297 if (demux->span > 1) {
2298 if (chunk_size == 0 || ((packet_size / chunk_size) <= 1)) {
2299 /* Disable descrambling */
2300 demux->span = 0;
2301 } else {
2302 /* FIXME: this else branch was added for
2303 * weird_al_yankovic - the saga begins.asf */
2304 demux->ds_packet_size = packet_size;
2305 demux->ds_chunk_size = chunk_size;
2306 }
2307 } else {
2308 /* Descambling is enabled */
2309 demux->ds_packet_size = packet_size;
2310 demux->ds_chunk_size = chunk_size;
2311 }
2312 #if 0
2313 /* Now skip the rest of the silence data */
2314 if (data_size > 1)
2315 gst_bytestream_flush (demux->bs, data_size - 1);
2316 #else
2317 /* FIXME: CHECKME. And why -1? */
2318 if (data_size > 1) {
2319 if (!gst_asf_demux_skip_bytes (data_size - 1, &data, &size)) {
2320 goto not_enough_data;
2321 }
2322 }
2323 #endif
2324 break;
2325 }
2326 case ASF_CORRECTION_OFF:{
2327 GST_INFO ("Error correction off");
2328 if (!gst_asf_demux_skip_bytes (stream_specific_size, &data, &size))
2329 goto not_enough_data;
2330 break;
2331 }
2332 default:
2333 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
2334 ("Audio stream using unknown error correction"));
2335 return NULL;
2336 }
2338 break;
2339 }
2341 case ASF_STREAM_VIDEO:{
2342 asf_stream_video_format video_format_object;
2343 asf_stream_video video_object;
2344 guint16 vsize;
2346 if (!gst_asf_demux_get_stream_video (&video_object, &data, &size))
2347 goto not_enough_data;
2349 vsize = video_object.size - 40; /* Byte order gets offset by single byte */
2351 GST_INFO ("object is a video stream with %u bytes of "
2352 "additional data", vsize);
2354 if (!gst_asf_demux_get_stream_video_format (&video_format_object,
2355 &data, &size)) {
2356 goto not_enough_data;
2357 }
2359 gst_asf_demux_add_video_stream (demux, &video_format_object, stream_id,
2360 &data, &size);
2362 break;
2363 }
2365 default:
2366 GST_WARNING_OBJECT (demux, "Unknown stream type for stream %u",
2367 stream_id);
2368 break;
2369 }
2371 return gst_asf_demux_get_stream (demux, stream_id);
2373 not_enough_data:
2374 {
2375 GST_WARNING_OBJECT (demux, "Unexpected end of data parsing stream object");
2376 /* we'll error out later if we found no streams */
2377 return NULL;
2378 }
2379 }
2381 static const gchar *
2382 gst_asf_demux_get_gst_tag_from_tag_name (const gchar * name_utf8)
2383 {
2384 const struct
2385 {
2386 const gchar *asf_name;
2387 const gchar *gst_name;
2388 } tags[] = {
2389 {
2390 "WM/Genre", GST_TAG_GENRE}, {
2391 "WM/AlbumTitle", GST_TAG_ALBUM}, {
2392 "WM/AlbumArtist", GST_TAG_ARTIST}, {
2393 "WM/Picture", GST_TAG_IMAGE}, {
2394 "WM/Track", GST_TAG_TRACK_NUMBER}, {
2395 "WM/TrackNumber", GST_TAG_TRACK_NUMBER}, {
2396 "WM/Year", GST_TAG_DATE}
2397 /* { "WM/Composer", GST_TAG_COMPOSER } */
2398 };
2399 gsize out;
2400 guint i;
2402 if (name_utf8 == NULL) {
2403 GST_WARNING ("Failed to convert name to UTF8, skipping");
2404 return NULL;
2405 }
2407 out = strlen (name_utf8);
2409 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
2410 if (strncmp (tags[i].asf_name, name_utf8, out) == 0) {
2411 GST_LOG ("map tagname '%s' -> '%s'", name_utf8, tags[i].gst_name);
2412 return tags[i].gst_name;
2413 }
2414 }
2416 return NULL;
2417 }
2419 /* gst_asf_demux_add_global_tags() takes ownership of taglist! */
2420 static void
2421 gst_asf_demux_add_global_tags (GstASFDemux * demux, GstTagList * taglist)
2422 {
2423 GstTagList *t;
2425 GST_DEBUG_OBJECT (demux, "adding global tags: %" GST_PTR_FORMAT, taglist);
2427 if (taglist == NULL)
2428 return;
2430 if (gst_tag_list_is_empty (taglist)) {
2431 gst_tag_list_free (taglist);
2432 return;
2433 }
2435 t = gst_tag_list_merge (demux->taglist, taglist, GST_TAG_MERGE_APPEND);
2436 if (demux->taglist)
2437 gst_tag_list_free (demux->taglist);
2438 gst_tag_list_free (taglist);
2439 demux->taglist = t;
2440 GST_LOG_OBJECT (demux, "global tags now: %" GST_PTR_FORMAT, demux->taglist);
2441 }
2443 #define ASF_DEMUX_DATA_TYPE_UTF16LE_STRING 0
2444 #define ASF_DEMUX_DATA_TYPE_BYTE_ARRAY 1
2445 #define ASF_DEMUX_DATA_TYPE_DWORD 3
2447 static void
2448 asf_demux_parse_picture_tag (GstTagList * tags, const guint8 * tag_data,
2449 guint tag_data_len)
2450 {
2451 GstByteReader r;
2452 const guint8 *img_data = NULL;
2453 guint32 img_data_len = 0;
2454 guint8 pic_type = 0;
2456 gst_byte_reader_init (&r, tag_data, tag_data_len);
2458 /* skip mime type string (we don't trust it and do our own typefinding),
2459 * and also skip the description string, since we don't use it */
2460 if (!gst_byte_reader_get_uint8 (&r, &pic_type) ||
2461 !gst_byte_reader_get_uint32_le (&r, &img_data_len) ||
2462 !gst_byte_reader_skip_string_utf16 (&r) ||
2463 !gst_byte_reader_skip_string_utf16 (&r) ||
2464 !gst_byte_reader_get_data (&r, img_data_len, &img_data)) {
2465 goto not_enough_data;
2466 }
2469 if (!gst_tag_list_add_id3_image (tags, img_data, img_data_len, pic_type))
2470 GST_DEBUG ("failed to add image extracted from WM/Picture tag to taglist");
2472 return;
2474 not_enough_data:
2475 {
2476 GST_DEBUG ("Failed to read WM/Picture tag: not enough data");
2477 GST_MEMDUMP ("WM/Picture data", tag_data, tag_data_len);
2478 return;
2479 }
2480 }
2482 /* Extended Content Description Object */
2483 static GstFlowReturn
2484 gst_asf_demux_process_ext_content_desc (GstASFDemux * demux, guint8 * data,
2485 guint64 size)
2486 {
2487 /* Other known (and unused) 'text/unicode' metadata available :
2488 *
2489 * WM/Lyrics =
2490 * WM/MediaPrimaryClassID = {D1607DBC-E323-4BE2-86A1-48A42A28441E}
2491 * WMFSDKVersion = 9.00.00.2980
2492 * WMFSDKNeeded = 0.0.0.0000
2493 * WM/UniqueFileIdentifier = AMGa_id=R 15334;AMGp_id=P 5149;AMGt_id=T 2324984
2494 * WM/Publisher = 4AD
2495 * WM/Provider = AMG
2496 * WM/ProviderRating = 8
2497 * WM/ProviderStyle = Rock (similar to WM/Genre)
2498 * WM/GenreID (similar to WM/Genre)
2499 * WM/TrackNumber (same as WM/Track but as a string)
2500 *
2501 * Other known (and unused) 'non-text' metadata available :
2502 *
2503 * WM/EncodingTime
2504 * WM/MCDI
2505 * IsVBR
2506 *
2507 * We might want to read WM/TrackNumber and use atoi() if we don't have
2508 * WM/Track
2509 */
2511 GstTagList *taglist;
2512 guint16 blockcount, i;
2514 GST_INFO_OBJECT (demux, "object is an extended content description");
2516 taglist = gst_tag_list_new ();
2518 /* Content Descriptor Count */
2519 if (size < 2)
2520 goto not_enough_data;
2522 blockcount = gst_asf_demux_get_uint16 (&data, &size);
2524 for (i = 1; i <= blockcount; ++i) {
2525 const gchar *gst_tag_name;
2526 guint16 datatype;
2527 guint16 value_len;
2528 guint16 name_len;
2529 GValue tag_value = { 0, };
2530 gsize in, out;
2531 gchar *name;
2532 gchar *name_utf8 = NULL;
2533 gchar *value;
2535 /* Descriptor */
2536 if (!gst_asf_demux_get_string (&name, &name_len, &data, &size))
2537 goto not_enough_data;
2539 if (size < 2) {
2540 g_free (name);
2541 goto not_enough_data;
2542 }
2543 /* Descriptor Value Data Type */
2544 datatype = gst_asf_demux_get_uint16 (&data, &size);
2546 /* Descriptor Value (not really a string, but same thing reading-wise) */
2547 if (!gst_asf_demux_get_string (&value, &value_len, &data, &size)) {
2548 g_free (name);
2549 goto not_enough_data;
2550 }
2552 name_utf8 =
2553 g_convert (name, name_len, "UTF-8", "UTF-16LE", &in, &out, NULL);
2555 if (name_utf8 != NULL) {
2556 GST_DEBUG ("Found tag/metadata %s", name_utf8);
2558 gst_tag_name = gst_asf_demux_get_gst_tag_from_tag_name (name_utf8);
2559 GST_DEBUG ("gst_tag_name %s", GST_STR_NULL (gst_tag_name));
2561 switch (datatype) {
2562 case ASF_DEMUX_DATA_TYPE_UTF16LE_STRING:{
2563 gchar *value_utf8;
2565 value_utf8 = g_convert (value, value_len, "UTF-8", "UTF-16LE",
2566 &in, &out, NULL);
2568 /* get rid of tags with empty value */
2569 if (value_utf8 != NULL && *value_utf8 != '\0') {
2570 GST_DEBUG ("string value %s", value_utf8);
2572 value_utf8[out] = '\0';
2574 if (gst_tag_name != NULL) {
2575 if (strcmp (gst_tag_name, GST_TAG_DATE) == 0) {
2576 guint year = atoi (value_utf8);
2578 if (year > 0) {
2579 GDate *date = g_date_new_dmy (1, 1, year);
2581 g_value_init (&tag_value, GST_TYPE_DATE);
2582 gst_value_set_date (&tag_value, date);
2583 g_date_free (date);
2584 }
2585 } else if (strcmp (gst_tag_name, GST_TAG_GENRE) == 0) {
2586 guint id3v1_genre_id;
2587 const gchar *genre_str;
2589 if (sscanf (value_utf8, "(%u)", &id3v1_genre_id) == 1 &&
2590 ((genre_str = gst_tag_id3_genre_get (id3v1_genre_id)))) {
2591 GST_DEBUG ("Genre: %s -> %s", value_utf8, genre_str);
2592 g_free (value_utf8);
2593 value_utf8 = g_strdup (genre_str);
2594 }
2595 } else {
2596 GType tag_type;
2598 /* convert tag from string to other type if required */
2599 tag_type = gst_tag_get_type (gst_tag_name);
2600 g_value_init (&tag_value, tag_type);
2601 if (!gst_value_deserialize (&tag_value, value_utf8)) {
2602 GValue from_val = { 0, };
2604 g_value_init (&from_val, G_TYPE_STRING);
2605 g_value_set_string (&from_val, value_utf8);
2606 if (!g_value_transform (&from_val, &tag_value)) {
2607 GST_WARNING_OBJECT (demux,
2608 "Could not transform string tag to " "%s tag type %s",
2609 gst_tag_name, g_type_name (tag_type));
2610 g_value_unset (&tag_value);
2611 }
2612 g_value_unset (&from_val);
2613 }
2614 }
2615 } else {
2616 /* metadata ! */
2617 GST_DEBUG ("Setting metadata");
2618 g_value_init (&tag_value, G_TYPE_STRING);
2619 g_value_set_string (&tag_value, value_utf8);
2620 }
2621 } else if (value_utf8 == NULL) {
2622 GST_WARNING ("Failed to convert string value to UTF8, skipping");
2623 } else {
2624 GST_DEBUG ("Skipping empty string value for %s",
2625 GST_STR_NULL (gst_tag_name));
2626 }
2627 g_free (value_utf8);
2628 break;
2629 }
2630 case ASF_DEMUX_DATA_TYPE_BYTE_ARRAY:{
2631 if (gst_tag_name) {
2632 if (!g_str_equal (gst_tag_name, GST_TAG_IMAGE)) {
2633 GST_FIXME ("Unhandled byte array tag %s",
2634 GST_STR_NULL (gst_tag_name));
2635 break;
2636 } else {
2637 asf_demux_parse_picture_tag (taglist, (guint8 *) value,
2638 value_len);
2639 }
2640 }
2641 break;
2642 }
2643 case ASF_DEMUX_DATA_TYPE_DWORD:{
2644 guint uint_val = GST_READ_UINT32_LE (value);
2646 /* this is the track number */
2647 g_value_init (&tag_value, G_TYPE_UINT);
2649 /* WM/Track counts from 0 */
2650 if (!strcmp (name_utf8, "WM/Track"))
2651 ++uint_val;
2653 g_value_set_uint (&tag_value, uint_val);
2654 break;
2655 }
2656 default:{
2657 GST_DEBUG ("Skipping tag %s of type %d", gst_tag_name, datatype);
2658 break;
2659 }
2660 }
2662 if (G_IS_VALUE (&tag_value)) {
2663 if (gst_tag_name) {
2664 GstTagMergeMode merge_mode = GST_TAG_MERGE_APPEND;
2666 /* WM/TrackNumber is more reliable than WM/Track, since the latter
2667 * is supposed to have a 0 base but is often wrongly written to start
2668 * from 1 as well, so prefer WM/TrackNumber when we have it: either
2669 * replace the value added earlier from WM/Track or put it first in
2670 * the list, so that it will get picked up by _get_uint() */
2671 if (strcmp (name_utf8, "WM/TrackNumber") == 0)
2672 merge_mode = GST_TAG_MERGE_REPLACE;
2674 gst_tag_list_add_values (taglist, merge_mode, gst_tag_name,
2675 &tag_value, NULL);
2676 } else {
2677 GST_DEBUG ("Setting global metadata %s", name_utf8);
2678 gst_structure_set_value (demux->global_metadata, name_utf8,
2679 &tag_value);
2680 }
2682 g_value_unset (&tag_value);
2683 }
2684 }
2686 g_free (name);
2687 g_free (value);
2688 g_free (name_utf8);
2689 }
2691 gst_asf_demux_add_global_tags (demux, taglist);
2693 return GST_FLOW_OK;
2695 /* Errors */
2696 not_enough_data:
2697 {
2698 GST_WARNING ("Unexpected end of data parsing ext content desc object");
2699 gst_tag_list_free (taglist);
2700 return GST_FLOW_OK; /* not really fatal */
2701 }
2702 }
2704 static GstStructure *
2705 gst_asf_demux_get_metadata_for_stream (GstASFDemux * demux, guint stream_num)
2706 {
2707 gchar sname[32];
2708 guint i;
2710 g_snprintf (sname, sizeof (sname), "stream-%u", stream_num);
2712 for (i = 0; i < gst_caps_get_size (demux->metadata); ++i) {
2713 GstStructure *s;
2715 s = gst_caps_get_structure (demux->metadata, i);
2716 if (gst_structure_has_name (s, sname))
2717 return s;
2718 }
2720 gst_caps_append_structure (demux->metadata, gst_structure_empty_new (sname));
2722 /* try lookup again; demux->metadata took ownership of the structure, so we
2723 * can't really make any assumptions about what happened to it, so we can't
2724 * just return it directly after appending it */
2725 return gst_asf_demux_get_metadata_for_stream (demux, stream_num);
2726 }
2728 static GstFlowReturn
2729 gst_asf_demux_process_metadata (GstASFDemux * demux, guint8 * data,
2730 guint64 size)
2731 {
2732 guint16 blockcount, i;
2734 GST_INFO_OBJECT (demux, "object is a metadata object");
2736 /* Content Descriptor Count */
2737 if (size < 2)
2738 goto not_enough_data;
2740 blockcount = gst_asf_demux_get_uint16 (&data, &size);
2742 for (i = 0; i < blockcount; ++i) {
2743 GstStructure *s;
2744 guint16 lang_idx, stream_num, name_len, data_type;
2745 guint32 data_len, ival;
2746 gchar *name_utf8;
2748 if (size < (2 + 2 + 2 + 2 + 4))
2749 goto not_enough_data;
2751 lang_idx = gst_asf_demux_get_uint16 (&data, &size);
2752 stream_num = gst_asf_demux_get_uint16 (&data, &size);
2753 name_len = gst_asf_demux_get_uint16 (&data, &size);
2754 data_type = gst_asf_demux_get_uint16 (&data, &size);
2755 data_len = gst_asf_demux_get_uint32 (&data, &size);
2757 if (size < name_len + data_len)
2758 goto not_enough_data;
2760 /* convert name to UTF-8 */
2761 name_utf8 = g_convert ((gchar *) data, name_len, "UTF-8", "UTF-16LE",
2762 NULL, NULL, NULL);
2763 gst_asf_demux_skip_bytes (name_len, &data, &size);
2765 if (name_utf8 == NULL) {
2766 GST_WARNING ("Failed to convert value name to UTF8, skipping");
2767 gst_asf_demux_skip_bytes (data_len, &data, &size);
2768 continue;
2769 }
2771 if (data_type != ASF_DEMUX_DATA_TYPE_DWORD) {
2772 gst_asf_demux_skip_bytes (data_len, &data, &size);
2773 g_free (name_utf8);
2774 continue;
2775 }
2777 /* read DWORD */
2778 if (size < 4) {
2779 g_free (name_utf8);
2780 goto not_enough_data;
2781 }
2783 ival = gst_asf_demux_get_uint32 (&data, &size);
2785 /* skip anything else there may be, just in case */
2786 gst_asf_demux_skip_bytes (data_len - 4, &data, &size);
2788 s = gst_asf_demux_get_metadata_for_stream (demux, stream_num);
2789 gst_structure_set (s, name_utf8, G_TYPE_INT, ival, NULL);
2790 g_free (name_utf8);
2791 }
2793 GST_INFO_OBJECT (demux, "metadata = %" GST_PTR_FORMAT, demux->metadata);
2794 return GST_FLOW_OK;
2796 /* Errors */
2797 not_enough_data:
2798 {
2799 GST_WARNING ("Unexpected end of data parsing metadata object");
2800 return GST_FLOW_OK; /* not really fatal */
2801 }
2802 }
2804 static GstFlowReturn
2805 gst_asf_demux_process_header (GstASFDemux * demux, guint8 * data, guint64 size)
2806 {
2807 GstFlowReturn ret = GST_FLOW_OK;
2808 guint32 i, num_objects;
2809 guint8 unknown;
2811 /* Get the rest of the header's header */
2812 if (size < (4 + 1 + 1))
2813 goto not_enough_data;
2815 num_objects = gst_asf_demux_get_uint32 (&data, &size);
2816 unknown = gst_asf_demux_get_uint8 (&data, &size);
2817 unknown = gst_asf_demux_get_uint8 (&data, &size);
2819 GST_INFO_OBJECT (demux, "object is a header with %u parts", num_objects);
2821 /* Loop through the header's objects, processing those */
2822 for (i = 0; i < num_objects; ++i) {
2823 GST_INFO_OBJECT (demux, "reading header part %u", i);
2824 ret = gst_asf_demux_process_object (demux, &data, &size);
2825 if (ret != GST_FLOW_OK) {
2826 GST_WARNING ("process_object returned %s", gst_asf_get_flow_name (ret));
2827 break;
2828 }
2829 }
2831 return ret;
2833 not_enough_data:
2834 {
2835 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
2836 ("short read parsing HEADER object"));
2837 return GST_FLOW_ERROR;
2838 }
2839 }
2841 static GstFlowReturn
2842 gst_asf_demux_process_file (GstASFDemux * demux, guint8 * data, guint64 size)
2843 {
2844 guint64 file_size, creation_time, packets_count;
2845 guint64 play_time, send_time, preroll;
2846 guint32 flags, min_pktsize, max_pktsize, min_bitrate;
2848 if (size < (16 + 8 + 8 + 8 + 8 + 8 + 8 + 4 + 4 + 4 + 4))
2849 goto not_enough_data;
2851 gst_asf_demux_skip_bytes (16, &data, &size); /* skip GUID */
2852 file_size = gst_asf_demux_get_uint64 (&data, &size);
2853 creation_time = gst_asf_demux_get_uint64 (&data, &size);
2854 packets_count = gst_asf_demux_get_uint64 (&data, &size);
2855 play_time = gst_asf_demux_get_uint64 (&data, &size);
2856 send_time = gst_asf_demux_get_uint64 (&data, &size);
2857 preroll = gst_asf_demux_get_uint64 (&data, &size);
2858 flags = gst_asf_demux_get_uint32 (&data, &size);
2859 min_pktsize = gst_asf_demux_get_uint32 (&data, &size);
2860 max_pktsize = gst_asf_demux_get_uint32 (&data, &size);
2861 min_bitrate = gst_asf_demux_get_uint32 (&data, &size);
2863 demux->broadcast = !!(flags & 0x01);
2864 demux->seekable = !!(flags & 0x02);
2866 GST_DEBUG_OBJECT (demux, "min_pktsize = %u", min_pktsize);
2867 GST_DEBUG_OBJECT (demux, "flags::broadcast = %d", demux->broadcast);
2868 GST_DEBUG_OBJECT (demux, "flags::seekable = %d", demux->seekable);
2870 if (demux->broadcast) {
2871 /* these fields are invalid if the broadcast flag is set */
2872 play_time = 0;
2873 file_size = 0;
2874 }
2876 if (min_pktsize != max_pktsize)
2877 goto non_fixed_packet_size;
2879 demux->packet_size = max_pktsize;
2881 /* FIXME: do we need send_time as well? what is it? */
2882 if ((play_time * 100) >= (preroll * GST_MSECOND))
2883 demux->play_time = (play_time * 100) - (preroll * GST_MSECOND);
2884 else
2885 demux->play_time = 0;
2887 demux->preroll = preroll * GST_MSECOND;
2889 /* initial latency */
2890 demux->latency = demux->preroll;
2892 if (demux->play_time == 0)
2893 demux->seekable = FALSE;
2895 GST_DEBUG_OBJECT (demux, "play_time %" GST_TIME_FORMAT,
2896 GST_TIME_ARGS (demux->play_time));
2897 GST_DEBUG_OBJECT (demux, "preroll %" GST_TIME_FORMAT,
2898 GST_TIME_ARGS (demux->preroll));
2900 if (demux->play_time > 0) {
2901 gst_segment_set_duration (&demux->segment, GST_FORMAT_TIME,
2902 demux->play_time);
2903 }
2905 GST_INFO ("object is a file with %" G_GUINT64_FORMAT " data packets",
2906 packets_count);
2907 GST_INFO ("preroll = %" G_GUINT64_FORMAT, demux->preroll);
2909 return GST_FLOW_OK;
2911 /* ERRORS */
2912 non_fixed_packet_size:
2913 {
2914 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
2915 ("packet size must be fixed"));
2916 return GST_FLOW_ERROR;
2917 }
2918 not_enough_data:
2919 {
2920 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
2921 ("short read parsing FILE object"));
2922 return GST_FLOW_ERROR;
2923 }
2924 }
2926 /* Content Description Object */
2927 static GstFlowReturn
2928 gst_asf_demux_process_comment (GstASFDemux * demux, guint8 * data, guint64 size)
2929 {
2930 struct
2931 {
2932 const gchar *gst_tag;
2933 guint16 val_length;
2934 gchar *val_utf8;
2935 } tags[5] = {
2936 {
2937 GST_TAG_TITLE, 0, NULL}, {
2938 GST_TAG_ARTIST, 0, NULL}, {
2939 GST_TAG_COPYRIGHT, 0, NULL}, {
2940 GST_TAG_DESCRIPTION, 0, NULL}, {
2941 GST_TAG_COMMENT, 0, NULL}
2942 };
2943 GstTagList *taglist;
2944 GValue value = { 0 };
2945 gsize in, out;
2946 gint i = -1;
2948 GST_INFO_OBJECT (demux, "object is a comment");
2950 if (size < (2 + 2 + 2 + 2 + 2))
2951 goto not_enough_data;
2953 tags[0].val_length = gst_asf_demux_get_uint16 (&data, &size);
2954 tags[1].val_length = gst_asf_demux_get_uint16 (&data, &size);
2955 tags[2].val_length = gst_asf_demux_get_uint16 (&data, &size);
2956 tags[3].val_length = gst_asf_demux_get_uint16 (&data, &size);
2957 tags[4].val_length = gst_asf_demux_get_uint16 (&data, &size);
2959 GST_DEBUG_OBJECT (demux, "Comment lengths: title=%d author=%d copyright=%d "
2960 "description=%d rating=%d", tags[0].val_length, tags[1].val_length,
2961 tags[2].val_length, tags[3].val_length, tags[4].val_length);
2963 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
2964 if (size < tags[i].val_length)
2965 goto not_enough_data;
2967 /* might be just '/0', '/0'... */
2968 if (tags[i].val_length > 2 && tags[i].val_length % 2 == 0) {
2969 /* convert to UTF-8 */
2970 tags[i].val_utf8 = g_convert ((gchar *) data, tags[i].val_length,
2971 "UTF-8", "UTF-16LE", &in, &out, NULL);
2972 }
2973 gst_asf_demux_skip_bytes (tags[i].val_length, &data, &size);
2974 }
2976 /* parse metadata into taglist */
2977 taglist = gst_tag_list_new ();
2978 g_value_init (&value, G_TYPE_STRING);
2979 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
2980 if (tags[i].val_utf8 && strlen (tags[i].val_utf8) > 0 && tags[i].gst_tag) {
2981 g_value_set_string (&value, tags[i].val_utf8);
2982 gst_tag_list_add_values (taglist, GST_TAG_MERGE_APPEND,
2983 tags[i].gst_tag, &value, NULL);
2984 }
2985 }
2986 g_value_unset (&value);
2988 gst_asf_demux_add_global_tags (demux, taglist);
2990 for (i = 0; i < G_N_ELEMENTS (tags); ++i)
2991 g_free (tags[i].val_utf8);
2993 return GST_FLOW_OK;
2995 not_enough_data:
2996 {
2997 GST_WARNING_OBJECT (demux, "unexpectedly short of data while processing "
2998 "comment tag section %d, skipping comment object", i);
2999 for (i = 0; i < G_N_ELEMENTS (tags); i++)
3000 g_free (tags[i].val_utf8);
3001 return GST_FLOW_OK; /* not really fatal */
3002 }
3003 }
3005 static GstFlowReturn
3006 gst_asf_demux_process_bitrate_props_object (GstASFDemux * demux, guint8 * data,
3007 guint64 size)
3008 {
3009 guint16 num_streams, i;
3010 AsfStream *stream;
3012 if (size < 2)
3013 goto not_enough_data;
3015 num_streams = gst_asf_demux_get_uint16 (&data, &size);
3017 GST_INFO ("object is a bitrate properties object with %u streams",
3018 num_streams);
3020 if (size < (num_streams * (2 + 4)))
3021 goto not_enough_data;
3023 for (i = 0; i < num_streams; ++i) {
3024 guint32 bitrate;
3025 guint16 stream_id;
3027 stream_id = gst_asf_demux_get_uint16 (&data, &size);
3028 bitrate = gst_asf_demux_get_uint32 (&data, &size);
3030 if (stream_id < GST_ASF_DEMUX_NUM_STREAM_IDS) {
3031 GST_DEBUG_OBJECT (demux, "bitrate of stream %u = %u", stream_id, bitrate);
3032 stream = gst_asf_demux_get_stream (demux, stream_id);
3033 if (stream) {
3034 if (stream->pending_tags == NULL)
3035 stream->pending_tags = gst_tag_list_new ();
3036 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
3037 GST_TAG_BITRATE, bitrate, NULL);
3038 } else {
3039 GST_WARNING_OBJECT (demux, "Stream id %u wasn't found", stream_id);
3040 }
3041 } else {
3042 GST_WARNING ("stream id %u is too large", stream_id);
3043 }
3044 }
3046 return GST_FLOW_OK;
3048 not_enough_data:
3049 {
3050 GST_WARNING_OBJECT (demux, "short read parsing bitrate props object!");
3051 return GST_FLOW_OK; /* not really fatal */
3052 }
3053 }
3055 static GstFlowReturn
3056 gst_asf_demux_process_header_ext (GstASFDemux * demux, guint8 * data,
3057 guint64 size)
3058 {
3059 GstFlowReturn ret = GST_FLOW_OK;
3060 guint64 hdr_size;
3062 /* Get the rest of the header's header */
3063 if (size < (16 + 2 + 4))
3064 goto not_enough_data;
3066 /* skip GUID and two other bytes */
3067 gst_asf_demux_skip_bytes (16 + 2, &data, &size);
3068 hdr_size = gst_asf_demux_get_uint32 (&data, &size);
3070 GST_INFO ("extended header object with a size of %u bytes", (guint) size);
3072 /* FIXME: does data_size include the rest of the header that we have read? */
3073 if (hdr_size > size)
3074 goto not_enough_data;
3076 while (hdr_size > 0) {
3077 ret = gst_asf_demux_process_object (demux, &data, &hdr_size);
3078 if (ret != GST_FLOW_OK)
3079 break;
3080 }
3082 return ret;
3084 not_enough_data:
3085 {
3086 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3087 ("short read parsing extended header object"));
3088 return GST_FLOW_ERROR;
3089 }
3090 }
3092 static GstFlowReturn
3093 gst_asf_demux_process_language_list (GstASFDemux * demux, guint8 * data,
3094 guint64 size)
3095 {
3096 guint i;
3098 if (size < 2)
3099 goto not_enough_data;
3101 if (demux->languages) {
3102 GST_WARNING ("More than one LANGUAGE_LIST object in stream");
3103 g_strfreev (demux->languages);
3104 demux->languages = NULL;
3105 demux->num_languages = 0;
3106 }
3108 demux->num_languages = gst_asf_demux_get_uint16 (&data, &size);
3109 GST_LOG ("%u languages:", demux->num_languages);
3111 demux->languages = g_new0 (gchar *, demux->num_languages + 1);
3112 for (i = 0; i < demux->num_languages; ++i) {
3113 guint8 len, *lang_data = NULL;
3115 if (size < 1)
3116 goto not_enough_data;
3117 len = gst_asf_demux_get_uint8 (&data, &size);
3118 if (gst_asf_demux_get_bytes (&lang_data, len, &data, &size)) {
3119 gchar *utf8;
3121 utf8 = g_convert ((gchar *) lang_data, len, "UTF-8", "UTF-16LE", NULL,
3122 NULL, NULL);
3124 /* truncate "en-us" etc. to just "en" */
3125 if (utf8 && strlen (utf8) >= 5 && (utf8[2] == '-' || utf8[2] == '_')) {
3126 utf8[2] = '\0';
3127 }
3128 GST_DEBUG ("[%u] %s", i, GST_STR_NULL (utf8));
3129 demux->languages[i] = utf8;
3130 g_free (lang_data);
3131 } else {
3132 goto not_enough_data;
3133 }
3134 }
3136 return GST_FLOW_OK;
3138 not_enough_data:
3139 {
3140 GST_WARNING_OBJECT (demux, "short read parsing language list object!");
3141 g_free (demux->languages);
3142 demux->languages = NULL;
3143 return GST_FLOW_OK; /* not fatal */
3144 }
3145 }
3147 static GstFlowReturn
3148 gst_asf_demux_process_simple_index (GstASFDemux * demux, guint8 * data,
3149 guint64 size)
3150 {
3151 GstClockTime interval;
3152 guint32 x, count, i;
3154 if (size < (16 + 8 + 4 + 4))
3155 goto not_enough_data;
3157 /* skip file id */
3158 gst_asf_demux_skip_bytes (16, &data, &size);
3159 interval = gst_asf_demux_get_uint64 (&data, &size) * (GstClockTime) 100;
3160 x = gst_asf_demux_get_uint32 (&data, &size);
3161 count = gst_asf_demux_get_uint32 (&data, &size);
3162 if (count > 0) {
3163 demux->sidx_interval = interval;
3164 demux->sidx_num_entries = count;
3165 g_free (demux->sidx_entries);
3166 demux->sidx_entries = g_new0 (AsfSimpleIndexEntry, count);
3168 for (i = 0; i < count; ++i) {
3169 if (G_UNLIKELY (size <= 6))
3170 break;
3171 demux->sidx_entries[i].packet = gst_asf_demux_get_uint32 (&data, &size);
3172 demux->sidx_entries[i].count = gst_asf_demux_get_uint16 (&data, &size);
3173 GST_LOG_OBJECT (demux, "%" GST_TIME_FORMAT " = packet %4u count : %2d",
3174 GST_TIME_ARGS (i * interval), demux->sidx_entries[i].packet,
3175 demux->sidx_entries[i].count);
3176 }
3177 } else {
3178 GST_DEBUG_OBJECT (demux, "simple index object with 0 entries");
3179 }
3181 return GST_FLOW_OK;
3183 not_enough_data:
3184 {
3185 GST_WARNING_OBJECT (demux, "short read parsing simple index object!");
3186 return GST_FLOW_OK; /* not fatal */
3187 }
3188 }
3190 static GstFlowReturn
3191 gst_asf_demux_process_advanced_mutual_exclusion (GstASFDemux * demux,
3192 guint8 * data, guint64 size)
3193 {
3194 ASFGuid guid;
3195 guint16 num, i;
3196 guint8 *mes;
3198 if (size < 16 + 2 + (2 * 2))
3199 goto not_enough_data;
3201 gst_asf_demux_get_guid (&guid, &data, &size);
3202 num = gst_asf_demux_get_uint16 (&data, &size);
3204 if (num < 2) {
3205 GST_WARNING_OBJECT (demux, "nonsensical mutually exclusive streams count");
3206 return GST_FLOW_OK;
3207 }
3209 if (size < (num * sizeof (guint16)))
3210 goto not_enough_data;
3212 /* read mutually exclusive stream numbers */
3213 mes = g_new (guint8, num + 1);
3214 for (i = 0; i < num; ++i) {
3215 mes[i] = gst_asf_demux_get_uint16 (&data, &size) & 0x7f;
3216 GST_LOG_OBJECT (demux, "mutually exclusive: stream #%d", mes[i]);
3217 }
3219 /* add terminator so we can easily get the count or know when to stop */
3220 mes[i] = (guint8) - 1;
3222 demux->mut_ex_streams = g_slist_append (demux->mut_ex_streams, mes);
3224 return GST_FLOW_OK;
3226 /* Errors */
3227 not_enough_data:
3228 {
3229 GST_WARNING_OBJECT (demux, "short read parsing advanced mutual exclusion");
3230 return GST_FLOW_OK; /* not absolutely fatal */
3231 }
3232 }
3234 static GstFlowReturn
3235 gst_asf_demux_process_ext_stream_props (GstASFDemux * demux, guint8 * data,
3236 guint64 size)
3237 {
3238 AsfStreamExtProps esp;
3239 AsfStream *stream = NULL;
3240 AsfObject stream_obj;
3241 guint16 stream_name_count;
3242 guint16 num_payload_ext;
3243 guint64 len;
3244 guint8 *stream_obj_data = NULL;
3245 guint8 *data_start;
3246 guint obj_size;
3247 guint i, stream_num;
3249 data_start = data;
3250 obj_size = (guint) size;
3252 if (size < 64)
3253 goto not_enough_data;
3255 esp.valid = TRUE;
3256 esp.start_time = gst_asf_demux_get_uint64 (&data, &size) * GST_MSECOND;
3257 esp.end_time = gst_asf_demux_get_uint64 (&data, &size) * GST_MSECOND;
3258 esp.data_bitrate = gst_asf_demux_get_uint32 (&data, &size);
3259 esp.buffer_size = gst_asf_demux_get_uint32 (&data, &size);
3260 esp.intial_buf_fullness = gst_asf_demux_get_uint32 (&data, &size);
3261 esp.data_bitrate2 = gst_asf_demux_get_uint32 (&data, &size);
3262 esp.buffer_size2 = gst_asf_demux_get_uint32 (&data, &size);
3263 esp.intial_buf_fullness2 = gst_asf_demux_get_uint32 (&data, &size);
3264 esp.max_obj_size = gst_asf_demux_get_uint32 (&data, &size);
3265 esp.flags = gst_asf_demux_get_uint32 (&data, &size);
3266 stream_num = gst_asf_demux_get_uint16 (&data, &size);
3267 esp.lang_idx = gst_asf_demux_get_uint16 (&data, &size);
3268 esp.avg_time_per_frame = gst_asf_demux_get_uint64 (&data, &size);
3269 stream_name_count = gst_asf_demux_get_uint16 (&data, &size);
3270 num_payload_ext = gst_asf_demux_get_uint16 (&data, &size);
3272 GST_INFO ("start_time = %" GST_TIME_FORMAT,
3273 GST_TIME_ARGS (esp.start_time));
3274 GST_INFO ("end_time = %" GST_TIME_FORMAT,
3275 GST_TIME_ARGS (esp.end_time));
3276 GST_INFO ("flags = %08x", esp.flags);
3277 GST_INFO ("average time per frame = %" GST_TIME_FORMAT,
3278 GST_TIME_ARGS (esp.avg_time_per_frame * 100));
3279 GST_INFO ("stream number = %u", stream_num);
3280 GST_INFO ("stream language ID idx = %u (%s)", esp.lang_idx,
3281 (esp.lang_idx < demux->num_languages) ?
3282 GST_STR_NULL (demux->languages[esp.lang_idx]) : "??");
3283 GST_INFO ("stream name count = %u", stream_name_count);
3285 /* read stream names */
3286 for (i = 0; i < stream_name_count; ++i) {
3287 guint16 stream_lang_idx;
3288 gchar *stream_name = NULL;
3290 if (size < 2)
3291 goto not_enough_data;
3292 stream_lang_idx = gst_asf_demux_get_uint16 (&data, &size);
3293 if (!gst_asf_demux_get_string (&stream_name, NULL, &data, &size))
3294 goto not_enough_data;
3295 GST_INFO ("stream name %d: %s", i, GST_STR_NULL (stream_name));
3296 g_free (stream_name); /* TODO: store names in struct */
3297 }
3299 /* read payload extension systems stuff */
3300 GST_LOG ("payload extension systems count = %u", num_payload_ext);
3302 if (num_payload_ext > 0)
3303 esp.payload_extensions = g_new0 (AsfPayloadExtension, num_payload_ext + 1);
3304 else
3305 esp.payload_extensions = NULL;
3307 for (i = 0; i < num_payload_ext; ++i) {
3308 AsfPayloadExtension ext;
3309 ASFGuid ext_guid;
3310 guint32 sys_info_len;
3312 if (size < 16 + 2 + 4)
3313 goto not_enough_data;
3315 gst_asf_demux_get_guid (&ext_guid, &data, &size);
3316 ext.id = gst_asf_demux_identify_guid (asf_payload_ext_guids, &ext_guid);
3317 ext.len = gst_asf_demux_get_uint16 (&data, &size);
3319 sys_info_len = gst_asf_demux_get_uint32 (&data, &size);
3320 GST_LOG ("payload systems info len = %u", sys_info_len);
3321 if (!gst_asf_demux_skip_bytes (sys_info_len, &data, &size))
3322 goto not_enough_data;
3324 esp.payload_extensions[i] = ext;
3325 }
3327 GST_LOG ("bytes read: %u/%u", (guint) (data - data_start), obj_size);
3329 /* there might be an optional STREAM_INFO object here now; if not, we
3330 * should have parsed the corresponding stream info object already (since
3331 * we are parsing the extended stream properties objects delayed) */
3332 if (size == 0) {
3333 stream = gst_asf_demux_get_stream (demux, stream_num);
3334 goto done;
3335 }
3337 /* get size of the stream object */
3338 if (!asf_demux_peek_object (demux, data, size, &stream_obj, TRUE))
3339 goto not_enough_data;
3341 if (stream_obj.id != ASF_OBJ_STREAM)
3342 goto expected_stream_object;
3344 if (stream_obj.size < ASF_OBJECT_HEADER_SIZE ||
3345 stream_obj.size > (10 * 1024 * 1024))
3346 goto not_enough_data;
3348 gst_asf_demux_skip_bytes (ASF_OBJECT_HEADER_SIZE, &data, &size);
3350 /* process this stream object later after all the other 'normal' ones
3351 * have been processed (since the others are more important/non-hidden) */
3352 len = stream_obj.size - ASF_OBJECT_HEADER_SIZE;
3353 if (!gst_asf_demux_get_bytes (&stream_obj_data, len, &data, &size))
3354 goto not_enough_data;
3356 /* parse stream object */
3357 stream = gst_asf_demux_parse_stream_object (demux, stream_obj_data, len);
3358 g_free (stream_obj_data);
3360 done:
3362 if (stream) {
3363 stream->ext_props = esp;
3365 /* try to set the framerate */
3366 if (stream->is_video && stream->caps) {
3367 GValue framerate = { 0 };
3368 GstStructure *s;
3369 gint num, denom;
3371 g_value_init (&framerate, GST_TYPE_FRACTION);
3373 num = GST_SECOND / 100;
3374 denom = esp.avg_time_per_frame;
3375 if (denom == 0) {
3376 /* avoid division by 0, assume 25/1 framerate */
3377 denom = GST_SECOND / 2500;
3378 }
3380 gst_value_set_fraction (&framerate, num, denom);
3382 stream->caps = gst_caps_make_writable (stream->caps);
3383 s = gst_caps_get_structure (stream->caps, 0);
3384 gst_structure_set_value (s, "framerate", &framerate);
3385 g_value_unset (&framerate);
3386 GST_DEBUG_OBJECT (demux, "setting framerate of %d/%d = %f",
3387 num, denom, ((gdouble) num) / denom);
3388 }
3390 /* add language info now if we have it */
3391 if (stream->ext_props.lang_idx < demux->num_languages) {
3392 if (stream->pending_tags == NULL)
3393 stream->pending_tags = gst_tag_list_new ();
3394 GST_LOG_OBJECT (demux, "stream %u has language '%s'", stream->id,
3395 demux->languages[stream->ext_props.lang_idx]);
3396 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_APPEND,
3397 GST_TAG_LANGUAGE_CODE, demux->languages[stream->ext_props.lang_idx],
3398 NULL);
3399 }
3400 } else {
3401 GST_WARNING_OBJECT (demux, "Ext. stream properties for unknown stream");
3402 }
3404 return GST_FLOW_OK;
3406 /* Errors */
3407 not_enough_data:
3408 {
3409 GST_WARNING_OBJECT (demux, "short read parsing ext stream props object!");
3410 return GST_FLOW_OK; /* not absolutely fatal */
3411 }
3412 expected_stream_object:
3413 {
3414 GST_WARNING_OBJECT (demux, "error parsing extended stream properties "
3415 "object: expected embedded stream object, but got %s object instead!",
3416 gst_asf_get_guid_nick (asf_object_guids, stream_obj.id));
3417 return GST_FLOW_OK; /* not absolutely fatal */
3418 }
3419 }
3421 static const gchar *
3422 gst_asf_demux_push_obj (GstASFDemux * demux, guint32 obj_id)
3423 {
3424 const gchar *nick;
3426 nick = gst_asf_get_guid_nick (asf_object_guids, obj_id);
3427 if (g_str_has_prefix (nick, "ASF_OBJ_"))
3428 nick += strlen ("ASF_OBJ_");
3430 if (demux->objpath == NULL) {
3431 demux->objpath = g_strdup (nick);
3432 } else {
3433 gchar *newpath;
3435 newpath = g_strdup_printf ("%s/%s", demux->objpath, nick);
3436 g_free (demux->objpath);
3437 demux->objpath = newpath;
3438 }
3440 return (const gchar *) demux->objpath;
3441 }
3443 static void
3444 gst_asf_demux_pop_obj (GstASFDemux * demux)
3445 {
3446 gchar *s;
3448 if ((s = g_strrstr (demux->objpath, "/"))) {
3449 *s = '\0';
3450 } else {
3451 g_free (demux->objpath);
3452 demux->objpath = NULL;
3453 }
3454 }
3456 static void
3457 gst_asf_demux_process_queued_extended_stream_objects (GstASFDemux * demux)
3458 {
3459 GSList *l;
3460 guint i;
3462 /* Parse the queued extended stream property objects and add the info
3463 * to the existing streams or add the new embedded streams, but without
3464 * activating them yet */
3465 GST_LOG_OBJECT (demux, "%u queued extended stream properties objects",
3466 g_slist_length (demux->ext_stream_props));
3468 for (l = demux->ext_stream_props, i = 0; l != NULL; l = l->next, ++i) {
3469 GstBuffer *buf = GST_BUFFER (l->data);
3471 GST_LOG_OBJECT (demux, "parsing ext. stream properties object #%u", i);
3472 gst_asf_demux_process_ext_stream_props (demux, GST_BUFFER_DATA (buf),
3473 GST_BUFFER_SIZE (buf));
3474 gst_buffer_unref (buf);
3475 }
3476 g_slist_free (demux->ext_stream_props);
3477 demux->ext_stream_props = NULL;
3478 }
3480 #if 0
3481 static void
3482 gst_asf_demux_activate_ext_props_streams (GstASFDemux * demux)
3483 {
3484 guint i, j;
3486 for (i = 0; i < demux->num_streams; ++i) {
3487 AsfStream *stream;
3488 gboolean is_hidden;
3489 GSList *x;
3491 stream = &demux->stream[i];
3493 GST_LOG_OBJECT (demux, "checking stream %2u", stream->id);
3495 if (stream->active) {
3496 GST_LOG_OBJECT (demux, "stream %2u is already activated", stream->id);
3497 continue;
3498 }
3500 is_hidden = FALSE;
3501 for (x = demux->mut_ex_streams; x != NULL; x = x->next) {
3502 guint8 *mes;
3504 /* check for each mutual exclusion whether it affects this stream */
3505 for (mes = (guint8 *) x->data; mes != NULL && *mes != 0xff; ++mes) {
3506 if (*mes == stream->id) {
3507 /* if yes, check if we've already added streams that are mutually
3508 * exclusive with the stream we're about to add */
3509 for (mes = (guint8 *) x->data; mes != NULL && *mes != 0xff; ++mes) {
3510 for (j = 0; j < demux->num_streams; ++j) {
3511 /* if the broadcast flag is set, assume the hidden streams aren't
3512 * actually streamed and hide them (or playbin won't work right),
3513 * otherwise assume their data is available */
3514 if (demux->stream[j].id == *mes && demux->broadcast) {
3515 is_hidden = TRUE;
3516 GST_LOG_OBJECT (demux, "broadcast stream ID %d to be added is "
3517 "mutually exclusive with already existing stream ID %d, "
3518 "hiding stream", stream->id, demux->stream[j].id);
3519 goto next;
3520 }
3521 }
3522 }
3523 break;
3524 }
3525 }
3526 }
3528 next:
3530 /* FIXME: we should do stream activation based on preroll data in
3531 * streaming mode too */
3532 if (demux->streaming && !is_hidden)
3533 gst_asf_demux_activate_stream (demux, stream);
3534 }
3535 }
3536 #endif
3538 static GstFlowReturn
3539 gst_asf_demux_process_object (GstASFDemux * demux, guint8 ** p_data,
3540 guint64 * p_size)
3541 {
3542 GstFlowReturn ret = GST_FLOW_OK;
3543 AsfObject obj;
3544 guint64 obj_data_size;
3546 if (*p_size < ASF_OBJECT_HEADER_SIZE)
3547 return ASF_FLOW_NEED_MORE_DATA;
3549 asf_demux_peek_object (demux, *p_data, ASF_OBJECT_HEADER_SIZE, &obj, TRUE);
3550 gst_asf_demux_skip_bytes (ASF_OBJECT_HEADER_SIZE, p_data, p_size);
3552 obj_data_size = obj.size - ASF_OBJECT_HEADER_SIZE;
3554 if (*p_size < obj_data_size)
3555 return ASF_FLOW_NEED_MORE_DATA;
3557 gst_asf_demux_push_obj (demux, obj.id);
3559 GST_INFO ("%s: size %" G_GUINT64_FORMAT, demux->objpath, obj.size);
3561 switch (obj.id) {
3562 case ASF_OBJ_STREAM:{
3563 AsfStream *stream;
3565 stream =
3566 gst_asf_demux_parse_stream_object (demux, *p_data, obj_data_size);
3568 ret = GST_FLOW_OK;
3569 break;
3570 }
3571 case ASF_OBJ_FILE:
3572 ret = gst_asf_demux_process_file (demux, *p_data, obj_data_size);
3573 break;
3574 case ASF_OBJ_HEADER:
3575 ret = gst_asf_demux_process_header (demux, *p_data, obj_data_size);
3576 break;
3577 case ASF_OBJ_COMMENT:
3578 ret = gst_asf_demux_process_comment (demux, *p_data, obj_data_size);
3579 break;
3580 case ASF_OBJ_HEAD1:
3581 ret = gst_asf_demux_process_header_ext (demux, *p_data, obj_data_size);
3582 break;
3583 case ASF_OBJ_BITRATE_PROPS:
3584 ret =
3585 gst_asf_demux_process_bitrate_props_object (demux, *p_data,
3586 obj_data_size);
3587 break;
3588 case ASF_OBJ_EXT_CONTENT_DESC:
3589 ret =
3590 gst_asf_demux_process_ext_content_desc (demux, *p_data,
3591 obj_data_size);
3592 break;
3593 case ASF_OBJ_METADATA_OBJECT:
3594 ret = gst_asf_demux_process_metadata (demux, *p_data, obj_data_size);
3595 break;
3596 case ASF_OBJ_EXTENDED_STREAM_PROPS:{
3597 GstBuffer *buf;
3599 /* process these later, we might not have parsed the corresponding
3600 * stream object yet */
3601 GST_LOG ("%s: queued for later parsing", demux->objpath);
3602 buf = gst_buffer_new_and_alloc (obj_data_size);
3603 memcpy (GST_BUFFER_DATA (buf), *p_data, obj_data_size);
3604 demux->ext_stream_props = g_slist_append (demux->ext_stream_props, buf);
3605 ret = GST_FLOW_OK;
3606 break;
3607 }
3608 case ASF_OBJ_LANGUAGE_LIST:
3609 ret = gst_asf_demux_process_language_list (demux, *p_data, obj_data_size);
3610 break;
3611 case ASF_OBJ_ADVANCED_MUTUAL_EXCLUSION:
3612 ret = gst_asf_demux_process_advanced_mutual_exclusion (demux, *p_data,
3613 obj_data_size);
3614 break;
3615 case ASF_OBJ_SIMPLE_INDEX:
3616 ret = gst_asf_demux_process_simple_index (demux, *p_data, obj_data_size);
3617 break;
3618 case ASF_OBJ_CONTENT_ENCRYPTION:
3619 case ASF_OBJ_EXT_CONTENT_ENCRYPTION:
3620 case ASF_OBJ_DIGITAL_SIGNATURE_OBJECT:
3621 goto error_encrypted;
3622 case ASF_OBJ_CONCEAL_NONE:
3623 case ASF_OBJ_HEAD2:
3624 case ASF_OBJ_UNDEFINED:
3625 case ASF_OBJ_CODEC_COMMENT:
3626 case ASF_OBJ_INDEX:
3627 case ASF_OBJ_PADDING:
3628 case ASF_OBJ_BITRATE_MUTEX:
3629 case ASF_OBJ_COMPATIBILITY:
3630 case ASF_OBJ_INDEX_PLACEHOLDER:
3631 case ASF_OBJ_INDEX_PARAMETERS:
3632 case ASF_OBJ_STREAM_PRIORITIZATION:
3633 case ASF_OBJ_SCRIPT_COMMAND:
3634 default:
3635 /* Unknown/unhandled object, skip it and hope for the best */
3636 GST_INFO ("%s: skipping object", demux->objpath);
3637 ret = GST_FLOW_OK;
3638 break;
3639 }
3641 /* this can't fail, we checked the number of bytes available before */
3642 gst_asf_demux_skip_bytes (obj_data_size, p_data, p_size);
3644 GST_LOG ("%s: ret = %s", demux->objpath, gst_asf_get_flow_name (ret));
3646 gst_asf_demux_pop_obj (demux);
3648 return ret;
3650 /* ERRORS */
3651 error_encrypted:
3652 {
3653 GST_ELEMENT_ERROR (demux, STREAM, DECRYPT, (NULL), (NULL));
3654 return GST_FLOW_ERROR;
3655 }
3656 }
3658 static void
3659 gst_asf_demux_descramble_buffer (GstASFDemux * demux, AsfStream * stream,
3660 GstBuffer ** p_buffer)
3661 {
3662 GstBuffer *descrambled_buffer;
3663 GstBuffer *scrambled_buffer;
3664 GstBuffer *sub_buffer;
3665 guint offset;
3666 guint off;
3667 guint row;
3668 guint col;
3669 guint idx;
3671 /* descrambled_buffer is initialised in the first iteration */
3672 descrambled_buffer = NULL;
3673 scrambled_buffer = *p_buffer;
3675 if (GST_BUFFER_SIZE (scrambled_buffer) < demux->ds_packet_size * demux->span)
3676 return;
3678 for (offset = 0; offset < GST_BUFFER_SIZE (scrambled_buffer);
3679 offset += demux->ds_chunk_size) {
3680 off = offset / demux->ds_chunk_size;
3681 row = off / demux->span;
3682 col = off % demux->span;
3683 idx = row + col * demux->ds_packet_size / demux->ds_chunk_size;
3684 GST_DEBUG ("idx=%u, row=%u, col=%u, off=%u, ds_chunk_size=%u", idx, row,
3685 col, off, demux->ds_chunk_size);
3686 GST_DEBUG ("scrambled buffer size=%u, span=%u, packet_size=%u",
3687 GST_BUFFER_SIZE (scrambled_buffer), demux->span, demux->ds_packet_size);
3688 GST_DEBUG ("GST_BUFFER_SIZE (scrambled_buffer) = %u",
3689 GST_BUFFER_SIZE (scrambled_buffer));
3690 sub_buffer =
3691 gst_buffer_create_sub (scrambled_buffer, idx * demux->ds_chunk_size,
3692 demux->ds_chunk_size);
3693 if (!offset) {
3694 descrambled_buffer = sub_buffer;
3695 } else {
3696 descrambled_buffer = gst_buffer_join (descrambled_buffer, sub_buffer);
3697 }
3698 }
3700 gst_buffer_copy_metadata (descrambled_buffer, scrambled_buffer,
3701 GST_BUFFER_COPY_TIMESTAMPS);
3703 /* FIXME/CHECK: do we need to transfer buffer flags here too? */
3705 gst_buffer_unref (scrambled_buffer);
3706 *p_buffer = descrambled_buffer;
3707 }
3709 static gboolean
3710 gst_asf_demux_element_send_event (GstElement * element, GstEvent * event)
3711 {
3712 GstASFDemux *demux = GST_ASF_DEMUX (element);
3713 gint i;
3715 GST_DEBUG ("handling element event of type %s", GST_EVENT_TYPE_NAME (event));
3717 for (i = 0; i < demux->num_streams; ++i) {
3718 gst_event_ref (event);
3719 if (gst_asf_demux_handle_src_event (demux->stream[i].pad, event)) {
3720 gst_event_unref (event);
3721 return TRUE;
3722 }
3723 }
3725 gst_event_unref (event);
3726 return FALSE;
3727 }
3729 /* takes ownership of the passed event */
3730 static gboolean
3731 gst_asf_demux_send_event_unlocked (GstASFDemux * demux, GstEvent * event)
3732 {
3733 gboolean ret = TRUE;
3734 gint i;
3736 GST_DEBUG_OBJECT (demux, "sending %s event to all source pads",
3737 GST_EVENT_TYPE_NAME (event));
3739 for (i = 0; i < demux->num_streams; ++i) {
3740 gst_event_ref (event);
3741 ret &= gst_pad_push_event (demux->stream[i].pad, event);
3742 }
3743 gst_event_unref (event);
3744 return ret;
3745 }
3747 static const GstQueryType *
3748 gst_asf_demux_get_src_query_types (GstPad * pad)
3749 {
3750 static const GstQueryType types[] = {
3751 GST_QUERY_POSITION,
3752 GST_QUERY_DURATION,
3753 GST_QUERY_SEEKING,
3754 0
3755 };
3757 return types;
3758 }
3760 static gboolean
3761 gst_asf_demux_handle_src_query (GstPad * pad, GstQuery * query)
3762 {
3763 GstASFDemux *demux;
3764 gboolean res = FALSE;
3766 demux = GST_ASF_DEMUX (gst_pad_get_parent (pad));
3768 GST_DEBUG ("handling %s query",
3769 gst_query_type_get_name (GST_QUERY_TYPE (query)));
3771 switch (GST_QUERY_TYPE (query)) {
3772 case GST_QUERY_DURATION:
3773 {
3774 GstFormat format;
3776 gst_query_parse_duration (query, &format, NULL);
3778 if (format != GST_FORMAT_TIME) {
3779 GST_LOG ("only support duration queries in TIME format");
3780 break;
3781 }
3783 GST_OBJECT_LOCK (demux);
3785 if (demux->segment.duration != GST_CLOCK_TIME_NONE) {
3786 GST_LOG ("returning duration: %" GST_TIME_FORMAT,
3787 GST_TIME_ARGS (demux->segment.duration));
3789 gst_query_set_duration (query, GST_FORMAT_TIME,
3790 demux->segment.duration);
3792 res = TRUE;
3793 } else {
3794 GST_LOG ("duration not known yet");
3795 }
3797 GST_OBJECT_UNLOCK (demux);
3798 break;
3799 }
3801 case GST_QUERY_POSITION:{
3802 GstFormat format;
3804 gst_query_parse_position (query, &format, NULL);
3806 if (format != GST_FORMAT_TIME) {
3807 GST_LOG ("only support position queries in TIME format");
3808 break;
3809 }
3811 GST_OBJECT_LOCK (demux);
3813 if (demux->segment.last_stop != GST_CLOCK_TIME_NONE) {
3814 GST_LOG ("returning position: %" GST_TIME_FORMAT,
3815 GST_TIME_ARGS (demux->segment.last_stop));
3817 gst_query_set_position (query, GST_FORMAT_TIME,
3818 demux->segment.last_stop);
3820 res = TRUE;
3821 } else {
3822 GST_LOG ("position not known yet");
3823 }
3825 GST_OBJECT_UNLOCK (demux);
3826 break;
3827 }
3829 case GST_QUERY_SEEKING:{
3830 GstFormat format;
3832 gst_query_parse_seeking (query, &format, NULL, NULL, NULL);
3833 if (format == GST_FORMAT_TIME) {
3834 gint64 duration;
3836 GST_OBJECT_LOCK (demux);
3837 duration = demux->segment.duration;
3838 GST_OBJECT_UNLOCK (demux);
3840 if (!demux->streaming || !demux->seekable) {
3841 gst_query_set_seeking (query, GST_FORMAT_TIME, demux->seekable, 0,
3842 duration);
3843 res = TRUE;
3844 } else {
3845 GstFormat fmt;
3846 gboolean seekable;
3848 /* try downstream first in TIME */
3849 res = gst_pad_query_default (pad, query);
3851 gst_query_parse_seeking (query, &fmt, &seekable, NULL, NULL);
3852 GST_LOG_OBJECT (demux, "upstream %s seekable %d",
3853 GST_STR_NULL (gst_format_get_name (fmt)), seekable);
3854 /* if no luck, maybe in BYTES */
3855 if (!seekable || fmt != GST_FORMAT_TIME) {
3856 GstQuery *q;
3858 q = gst_query_new_seeking (GST_FORMAT_BYTES);
3859 if ((res = gst_pad_peer_query (demux->sinkpad, q))) {
3860 gst_query_parse_seeking (q, &fmt, &seekable, NULL, NULL);
3861 GST_LOG_OBJECT (demux, "upstream %s seekable %d",
3862 GST_STR_NULL (gst_format_get_name (fmt)), seekable);
3863 if (fmt != GST_FORMAT_BYTES)
3864 seekable = FALSE;
3865 }
3866 gst_query_unref (q);
3867 gst_query_set_seeking (query, GST_FORMAT_TIME, seekable, 0,
3868 duration);
3869 res = TRUE;
3870 }
3871 }
3872 } else
3873 GST_LOG_OBJECT (demux, "only support seeking in TIME format");
3874 break;
3875 }
3877 case GST_QUERY_LATENCY:
3878 {
3879 gboolean live;
3880 GstClockTime min, max;
3882 /* preroll delay does not matter in non-live pipeline,
3883 * but we might end up in a live (rtsp) one ... */
3885 /* first forward */
3886 res = gst_pad_query_default (pad, query);
3887 if (!res)
3888 break;
3890 gst_query_parse_latency (query, &live, &min, &max);
3892 GST_DEBUG_OBJECT (demux, "Peer latency: live %d, min %"
3893 GST_TIME_FORMAT " max %" GST_TIME_FORMAT, live,
3894 GST_TIME_ARGS (min), GST_TIME_ARGS (max));
3896 GST_OBJECT_LOCK (demux);
3897 if (min != -1)
3898 min += demux->latency;
3899 if (max != -1)
3900 max += demux->latency;
3901 GST_OBJECT_UNLOCK (demux);
3903 gst_query_set_latency (query, live, min, max);
3904 break;
3905 }
3906 default:
3907 res = gst_pad_query_default (pad, query);
3908 break;
3909 }
3911 gst_object_unref (demux);
3912 return res;
3913 }
3915 static GstStateChangeReturn
3916 gst_asf_demux_change_state (GstElement * element, GstStateChange transition)
3917 {
3918 GstASFDemux *demux = GST_ASF_DEMUX (element);
3919 GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
3921 switch (transition) {
3922 case GST_STATE_CHANGE_NULL_TO_READY:{
3923 gst_segment_init (&demux->segment, GST_FORMAT_TIME);
3924 demux->need_newsegment = TRUE;
3925 demux->segment_running = FALSE;
3926 demux->accurate = FALSE;
3927 demux->adapter = gst_adapter_new ();
3928 demux->metadata = gst_caps_new_empty ();
3929 demux->global_metadata = gst_structure_empty_new ("metadata");
3930 demux->data_size = 0;
3931 demux->data_offset = 0;
3932 demux->index_offset = 0;
3933 demux->base_offset = 0;
3934 break;
3935 }
3936 default:
3937 break;
3938 }
3940 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
3941 if (ret == GST_STATE_CHANGE_FAILURE)
3942 return ret;
3944 switch (transition) {
3945 case GST_STATE_CHANGE_PAUSED_TO_READY:
3946 case GST_STATE_CHANGE_READY_TO_NULL:
3947 gst_asf_demux_reset (demux, FALSE);
3948 break;
3949 default:
3950 break;
3951 }
3953 return ret;
3954 }