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;
206 while (demux->num_streams > 0) {
207 gst_asf_demux_free_stream (demux, &demux->stream[demux->num_streams - 1]);
208 --demux->num_streams;
209 }
210 memset (demux->stream, 0, sizeof (demux->stream));
211 demux->num_audio_streams = 0;
212 demux->num_video_streams = 0;
213 demux->num_streams = 0;
214 demux->activated_streams = FALSE;
215 demux->first_ts = GST_CLOCK_TIME_NONE;
216 demux->segment_ts = GST_CLOCK_TIME_NONE;
217 demux->in_gap = 0;
218 if (!chain_reset)
219 gst_segment_init (&demux->in_segment, GST_FORMAT_UNDEFINED);
220 demux->state = GST_ASF_DEMUX_STATE_HEADER;
221 demux->seekable = FALSE;
222 demux->broadcast = FALSE;
223 demux->sidx_interval = 0;
224 demux->sidx_num_entries = 0;
225 g_free (demux->sidx_entries);
226 demux->sidx_entries = NULL;
228 demux->speed_packets = 1;
230 if (chain_reset) {
231 GST_LOG_OBJECT (demux, "Restarting");
232 gst_segment_init (&demux->segment, GST_FORMAT_TIME);
233 demux->need_newsegment = TRUE;
234 demux->segment_running = FALSE;
235 demux->accurate = FALSE;
236 demux->metadata = gst_caps_new_empty ();
237 demux->global_metadata = gst_structure_empty_new ("metadata");
238 demux->data_size = 0;
239 demux->data_offset = 0;
240 demux->index_offset = 0;
241 }
242 }
244 static void
245 gst_asf_demux_init (GstASFDemux * demux, GstASFDemuxClass * klass)
246 {
247 demux->sinkpad =
248 gst_pad_new_from_static_template (&gst_asf_demux_sink_template, "sink");
249 gst_pad_set_chain_function (demux->sinkpad,
250 GST_DEBUG_FUNCPTR (gst_asf_demux_chain));
251 gst_pad_set_event_function (demux->sinkpad,
252 GST_DEBUG_FUNCPTR (gst_asf_demux_sink_event));
253 gst_pad_set_activate_function (demux->sinkpad,
254 GST_DEBUG_FUNCPTR (gst_asf_demux_activate));
255 gst_pad_set_activatepull_function (demux->sinkpad,
256 GST_DEBUG_FUNCPTR (gst_asf_demux_activate_pull));
257 gst_pad_set_activatepush_function (demux->sinkpad,
258 GST_DEBUG_FUNCPTR (gst_asf_demux_activate_push));
259 gst_element_add_pad (GST_ELEMENT (demux), demux->sinkpad);
261 /* set initial state */
262 gst_asf_demux_reset (demux, FALSE);
263 }
265 static gboolean
266 gst_asf_demux_activate (GstPad * sinkpad)
267 {
268 if (gst_pad_check_pull_range (sinkpad)) {
269 return gst_pad_activate_pull (sinkpad, TRUE);
270 } else {
271 return gst_pad_activate_push (sinkpad, TRUE);
272 }
273 }
275 static gboolean
276 gst_asf_demux_activate_push (GstPad * sinkpad, gboolean active)
277 {
278 GstASFDemux *demux;
280 demux = GST_ASF_DEMUX (GST_OBJECT_PARENT (sinkpad));
282 demux->state = GST_ASF_DEMUX_STATE_HEADER;
283 demux->streaming = TRUE;
285 return TRUE;
286 }
288 static gboolean
289 gst_asf_demux_activate_pull (GstPad * pad, gboolean active)
290 {
291 GstASFDemux *demux;
293 demux = GST_ASF_DEMUX (GST_OBJECT_PARENT (pad));
295 if (active) {
296 demux->state = GST_ASF_DEMUX_STATE_HEADER;
297 demux->streaming = FALSE;
299 return gst_pad_start_task (pad, (GstTaskFunction) gst_asf_demux_loop,
300 demux);
301 } else {
302 return gst_pad_stop_task (pad);
303 }
304 }
307 static gboolean
308 gst_asf_demux_sink_event (GstPad * pad, GstEvent * event)
309 {
310 GstASFDemux *demux;
311 gboolean ret = TRUE;
313 demux = GST_ASF_DEMUX (gst_pad_get_parent (pad));
315 GST_LOG_OBJECT (demux, "handling %s event", GST_EVENT_TYPE_NAME (event));
316 switch (GST_EVENT_TYPE (event)) {
317 case GST_EVENT_NEWSEGMENT:{
318 GstFormat newsegment_format;
319 gint64 newsegment_start, stop, time;
320 gdouble rate, arate;
321 gboolean update;
323 gst_event_parse_new_segment_full (event, &update, &rate, &arate,
324 &newsegment_format, &newsegment_start, &stop, &time);
326 if (newsegment_format == GST_FORMAT_BYTES) {
327 if (demux->packet_size && newsegment_start > demux->data_offset)
328 demux->packet = (newsegment_start - demux->data_offset) /
329 demux->packet_size;
330 else
331 demux->packet = 0;
332 } else if (newsegment_format == GST_FORMAT_TIME) {
333 /* do not know packet position, not really a problem */
334 demux->packet = -1;
335 } else {
336 GST_WARNING_OBJECT (demux, "unsupported newsegment format, ignoring");
337 gst_event_unref (event);
338 break;
339 }
341 /* record upstream segment for interpolation */
342 if (newsegment_format != demux->in_segment.format)
343 gst_segment_init (&demux->in_segment, GST_FORMAT_UNDEFINED);
344 gst_segment_set_newsegment_full (&demux->in_segment, update, rate, arate,
345 newsegment_format, newsegment_start, stop, time);
347 /* in either case, clear some state and generate newsegment later on */
348 GST_OBJECT_LOCK (demux);
349 demux->segment_ts = GST_CLOCK_TIME_NONE;
350 demux->in_gap = GST_CLOCK_TIME_NONE;
351 demux->need_newsegment = TRUE;
352 gst_asf_demux_reset_stream_state_after_discont (demux);
353 GST_OBJECT_UNLOCK (demux);
355 gst_event_unref (event);
356 break;
357 }
358 case GST_EVENT_EOS:{
359 if (demux->state == GST_ASF_DEMUX_STATE_HEADER) {
360 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
361 (_("This stream contains no data.")),
362 ("got eos and didn't receive a complete header object"));
363 break;
364 }
365 GST_OBJECT_LOCK (demux);
366 gst_adapter_clear (demux->adapter);
367 GST_OBJECT_UNLOCK (demux);
368 gst_asf_demux_send_event_unlocked (demux, event);
369 break;
370 }
372 case GST_EVENT_FLUSH_STOP:
373 GST_OBJECT_LOCK (demux);
374 gst_asf_demux_reset_stream_state_after_discont (demux);
375 GST_OBJECT_UNLOCK (demux);
376 gst_asf_demux_send_event_unlocked (demux, event);
377 /* upon activation, latency is no longer introduced, e.g. after seek */
378 if (demux->activated_streams)
379 demux->latency = 0;
380 break;
382 default:
383 ret = gst_pad_event_default (pad, event);
384 break;
385 }
387 gst_object_unref (demux);
388 return ret;
389 }
391 static gboolean
392 gst_asf_demux_seek_index_lookup (GstASFDemux * demux, guint * packet,
393 GstClockTime seek_time, GstClockTime * p_idx_time, guint * speed)
394 {
395 GstClockTime idx_time;
396 guint idx;
398 if (G_UNLIKELY (demux->sidx_num_entries == 0 || demux->sidx_interval == 0))
399 return FALSE;
401 idx = (guint) ((seek_time + demux->preroll) / demux->sidx_interval);
403 /* FIXME: seek beyond end of file should result in immediate EOS from
404 * streaming thread instead of a failed seek */
405 if (G_UNLIKELY (idx >= demux->sidx_num_entries))
406 return FALSE;
408 *packet = demux->sidx_entries[idx].packet;
409 if (speed)
410 *speed = demux->sidx_entries[idx].count;
412 /* so we get closer to the actual time of the packet ... actually, let's not
413 * do this, since we throw away superfluous payloads before the seek position
414 * anyway; this way, our key unit seek 'snap resolution' is a bit better
415 * (ie. same as index resolution) */
416 /*
417 while (idx > 0 && demux->sidx_entries[idx-1] == demux->sidx_entries[idx])
418 --idx;
419 */
421 idx_time = demux->sidx_interval * idx;
422 if (G_LIKELY (idx_time >= demux->preroll))
423 idx_time -= demux->preroll;
425 GST_DEBUG_OBJECT (demux, "%" GST_TIME_FORMAT " => packet %u at %"
426 GST_TIME_FORMAT, GST_TIME_ARGS (seek_time), *packet,
427 GST_TIME_ARGS (idx_time));
429 if (G_LIKELY (p_idx_time))
430 *p_idx_time = idx_time;
432 return TRUE;
433 }
435 static void
436 gst_asf_demux_reset_stream_state_after_discont (GstASFDemux * demux)
437 {
438 guint n;
440 gst_adapter_clear (demux->adapter);
442 GST_DEBUG_OBJECT (demux, "reset stream state");
444 for (n = 0; n < demux->num_streams; n++) {
445 demux->stream[n].discont = TRUE;
446 demux->stream[n].last_flow = GST_FLOW_OK;
448 while (demux->stream[n].payloads->len > 0) {
449 AsfPayload *payload;
450 guint last;
452 last = demux->stream[n].payloads->len - 1;
453 payload = &g_array_index (demux->stream[n].payloads, AsfPayload, last);
454 gst_buffer_replace (&payload->buf, NULL);
455 g_array_remove_index (demux->stream[n].payloads, last);
456 }
457 }
458 }
460 static void
461 gst_asf_demux_mark_discont (GstASFDemux * demux)
462 {
463 guint n;
465 GST_DEBUG_OBJECT (demux, "Mark stream discont");
467 for (n = 0; n < demux->num_streams; n++)
468 demux->stream[n].discont = TRUE;
469 }
471 /* do a seek in push based mode */
472 static gboolean
473 gst_asf_demux_handle_seek_push (GstASFDemux * demux, GstEvent * event)
474 {
475 gdouble rate;
476 GstFormat format;
477 GstSeekFlags flags;
478 GstSeekType cur_type, stop_type;
479 gint64 cur, stop;
480 guint packet;
481 gboolean res;
483 gst_event_parse_seek (event, &rate, &format, &flags, &cur_type, &cur,
484 &stop_type, &stop);
486 stop_type = GST_SEEK_TYPE_NONE;
487 stop = -1;
489 GST_DEBUG_OBJECT (demux, "seeking to %" GST_TIME_FORMAT, GST_TIME_ARGS (cur));
491 /* determine packet, by index or by estimation */
492 if (!gst_asf_demux_seek_index_lookup (demux, &packet, cur, NULL, NULL)) {
493 packet = (guint) gst_util_uint64_scale (demux->num_packets,
494 cur, demux->play_time);
495 }
497 if (packet > demux->num_packets) {
498 GST_DEBUG_OBJECT (demux, "could not determine packet to seek to, "
499 "seek aborted.");
500 return FALSE;
501 }
503 GST_DEBUG_OBJECT (demux, "seeking to packet %d", packet);
505 cur = demux->data_offset + (packet * demux->packet_size);
507 GST_DEBUG_OBJECT (demux, "Pushing BYTE seek rate %g, "
508 "start %" G_GINT64_FORMAT ", stop %" G_GINT64_FORMAT, rate, cur, stop);
509 /* BYTE seek event */
510 event = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags, cur_type, cur,
511 stop_type, stop);
512 res = gst_pad_push_event (demux->sinkpad, event);
514 return res;
515 }
517 static gboolean
518 gst_asf_demux_handle_seek_event (GstASFDemux * demux, GstEvent * event)
519 {
520 GstClockTime idx_time;
521 GstSegment segment;
522 GstSeekFlags flags;
523 GstSeekType cur_type, stop_type;
524 GstFormat format;
525 gboolean only_need_update;
526 gboolean keyunit_sync;
527 gboolean flush;
528 gdouble rate;
529 gint64 cur, stop;
530 gint64 seek_time;
531 guint packet, speed_count = 1;
533 if (G_UNLIKELY (demux->seekable == FALSE || demux->packet_size == 0 ||
534 demux->num_packets == 0 || demux->play_time == 0)) {
535 GST_LOG_OBJECT (demux, "stream is not seekable");
536 return FALSE;
537 }
539 if (G_UNLIKELY (!demux->activated_streams)) {
540 GST_LOG_OBJECT (demux, "streams not yet activated, ignoring seek");
541 return FALSE;
542 }
544 gst_event_parse_seek (event, &rate, &format, &flags, &cur_type, &cur,
545 &stop_type, &stop);
547 if (G_UNLIKELY (format != GST_FORMAT_TIME)) {
548 GST_LOG_OBJECT (demux, "seeking is only supported in TIME format");
549 return FALSE;
550 }
552 if (G_UNLIKELY (rate <= 0.0)) {
553 GST_LOG_OBJECT (demux, "backward playback is not supported yet");
554 return FALSE;
555 }
557 flush = ((flags & GST_SEEK_FLAG_FLUSH) == GST_SEEK_FLAG_FLUSH);
558 demux->accurate =
559 ((flags & GST_SEEK_FLAG_ACCURATE) == GST_SEEK_FLAG_ACCURATE);
560 keyunit_sync = ((flags & GST_SEEK_FLAG_KEY_UNIT) == GST_SEEK_FLAG_KEY_UNIT);
562 if (G_UNLIKELY (demux->streaming)) {
563 /* support it safely needs more segment handling, e.g. closing etc */
564 if (!flush) {
565 GST_LOG_OBJECT (demux, "streaming; non-flushing seek not supported");
566 return FALSE;
567 }
568 /* we can (re)construct the start later on, but not the end */
569 if (stop_type != GST_SEEK_TYPE_NONE) {
570 GST_LOG_OBJECT (demux, "streaming; end type must be NONE");
571 return FALSE;
572 }
573 gst_event_ref (event);
574 /* upstream might handle TIME seek, e.g. mms or rtsp,
575 * or not, e.g. http, then we give it a hand */
576 if (!gst_pad_push_event (demux->sinkpad, event))
577 return gst_asf_demux_handle_seek_push (demux, event);
578 else
579 return TRUE;
580 }
582 /* unlock the streaming thread */
583 if (G_LIKELY (flush)) {
584 gst_pad_push_event (demux->sinkpad, gst_event_new_flush_start ());
585 gst_asf_demux_send_event_unlocked (demux, gst_event_new_flush_start ());
586 } else {
587 gst_pad_pause_task (demux->sinkpad);
588 }
590 /* grab the stream lock so that streaming cannot continue, for
591 * non flushing seeks when the element is in PAUSED this could block
592 * forever */
593 GST_PAD_STREAM_LOCK (demux->sinkpad);
595 /* we now can stop flushing, since we have the stream lock now */
596 gst_pad_push_event (demux->sinkpad, gst_event_new_flush_stop ());
598 if (G_LIKELY (flush))
599 gst_asf_demux_send_event_unlocked (demux, gst_event_new_flush_stop ());
601 /* operating on copy of segment until we know the seek worked */
602 segment = demux->segment;
604 if (G_UNLIKELY (demux->segment_running && !flush)) {
605 GstEvent *newseg;
607 /* create the segment event to close the current segment */
608 newseg = gst_event_new_new_segment (TRUE, segment.rate,
609 GST_FORMAT_TIME, segment.start, segment.last_stop, segment.time);
611 gst_asf_demux_send_event_unlocked (demux, newseg);
612 }
614 gst_segment_set_seek (&segment, rate, format, flags, cur_type,
615 cur, stop_type, stop, &only_need_update);
617 GST_DEBUG_OBJECT (demux, "seeking to time %" GST_TIME_FORMAT ", segment: "
618 "%" GST_SEGMENT_FORMAT, GST_TIME_ARGS (segment.start), &segment);
620 seek_time = segment.start;
622 /* FIXME: should check the KEY_UNIT flag; need to adjust last_stop to
623 * real start of data and segment_start to indexed time for key unit seek*/
624 if (G_UNLIKELY (!gst_asf_demux_seek_index_lookup (demux, &packet, seek_time,
625 &idx_time, &speed_count))) {
626 /* First try to query our source to see if it can convert for us. This is
627 the case when our source is an mms stream, notice that in this case
628 gstmms will do a time based seek to get the byte offset, this is not a
629 problem as the seek to this offset needs to happen anway. */
630 gint64 offset;
631 GstFormat dest_format = GST_FORMAT_BYTES;
633 if (gst_pad_query_peer_convert (demux->sinkpad, GST_FORMAT_TIME, seek_time,
634 &dest_format, &offset) && dest_format == GST_FORMAT_BYTES) {
635 packet = (offset - demux->data_offset) / demux->packet_size;
636 GST_LOG_OBJECT (demux, "convert %" GST_TIME_FORMAT
637 " to bytes query result: %" G_GINT64_FORMAT ", data_ofset: %"
638 G_GINT64_FORMAT ", packet_size: %u," " resulting packet: %u\n",
639 GST_TIME_ARGS (seek_time), offset, demux->data_offset,
640 demux->packet_size, packet);
641 } else {
642 /* Hackety hack, this sucks. We just seek to an earlier position
643 * and let the sinks throw away the stuff before the segment start */
644 if (flush && (demux->accurate || keyunit_sync)) {
645 seek_time -= 5 * GST_SECOND;
646 if (seek_time < 0)
647 seek_time = 0;
648 }
650 packet = (guint) gst_util_uint64_scale (demux->num_packets,
651 seek_time, demux->play_time);
653 if (packet > demux->num_packets)
654 packet = demux->num_packets;
655 }
656 } else {
657 if (G_LIKELY (keyunit_sync)) {
658 GST_DEBUG_OBJECT (demux, "key unit seek, adjust seek_time = %"
659 GST_TIME_FORMAT " to index_time = %" GST_TIME_FORMAT,
660 GST_TIME_ARGS (seek_time), GST_TIME_ARGS (idx_time));
661 segment.start = idx_time;
662 segment.last_stop = idx_time;
663 segment.time = idx_time;
664 }
665 }
667 GST_DEBUG_OBJECT (demux, "seeking to packet %u (%d)", packet, speed_count);
669 GST_OBJECT_LOCK (demux);
670 demux->segment = segment;
671 demux->packet = packet;
672 demux->need_newsegment = TRUE;
673 demux->speed_packets = speed_count;
674 gst_asf_demux_reset_stream_state_after_discont (demux);
675 GST_OBJECT_UNLOCK (demux);
677 /* restart our task since it might have been stopped when we did the flush */
678 gst_pad_start_task (demux->sinkpad, (GstTaskFunction) gst_asf_demux_loop,
679 demux);
681 /* streaming can continue now */
682 GST_PAD_STREAM_UNLOCK (demux->sinkpad);
684 return TRUE;
685 }
687 static gboolean
688 gst_asf_demux_handle_src_event (GstPad * pad, GstEvent * event)
689 {
690 GstASFDemux *demux;
691 gboolean ret;
693 demux = GST_ASF_DEMUX (gst_pad_get_parent (pad));
695 switch (GST_EVENT_TYPE (event)) {
696 case GST_EVENT_SEEK:
697 GST_LOG_OBJECT (pad, "seek event");
698 ret = gst_asf_demux_handle_seek_event (demux, event);
699 gst_event_unref (event);
700 break;
701 case GST_EVENT_QOS:
702 case GST_EVENT_NAVIGATION:
703 /* just drop these two silently */
704 gst_event_unref (event);
705 ret = FALSE;
706 break;
707 default:
708 GST_LOG_OBJECT (pad, "%s event", GST_EVENT_TYPE_NAME (event));
709 ret = gst_pad_event_default (pad, event);
710 break;
711 }
713 gst_object_unref (demux);
714 return ret;
715 }
717 static inline guint32
718 gst_asf_demux_identify_guid (const ASFGuidHash * guids, ASFGuid * guid)
719 {
720 guint32 ret;
722 ret = gst_asf_identify_guid (guids, guid);
724 GST_LOG ("%s 0x%08x-0x%08x-0x%08x-0x%08x",
725 gst_asf_get_guid_nick (guids, ret),
726 guid->v1, guid->v2, guid->v3, guid->v4);
728 return ret;
729 }
731 typedef struct
732 {
733 AsfObjectID id;
734 guint64 size;
735 } AsfObject;
738 /* expect is true when the user is expeting an object,
739 * when false, it will give no warnings if the object
740 * is not identified
741 */
742 static gboolean
743 asf_demux_peek_object (GstASFDemux * demux, const guint8 * data,
744 guint data_len, AsfObject * object, gboolean expect)
745 {
746 ASFGuid guid;
748 if (data_len < ASF_OBJECT_HEADER_SIZE)
749 return FALSE;
751 guid.v1 = GST_READ_UINT32_LE (data + 0);
752 guid.v2 = GST_READ_UINT32_LE (data + 4);
753 guid.v3 = GST_READ_UINT32_LE (data + 8);
754 guid.v4 = GST_READ_UINT32_LE (data + 12);
756 object->size = GST_READ_UINT64_LE (data + 16);
758 /* FIXME: make asf_demux_identify_object_guid() */
759 object->id = gst_asf_demux_identify_guid (asf_object_guids, &guid);
760 if (object->id == ASF_OBJ_UNDEFINED && expect) {
761 GST_WARNING_OBJECT (demux, "Unknown object %08x-%08x-%08x-%08x",
762 guid.v1, guid.v2, guid.v3, guid.v4);
763 }
765 return TRUE;
766 }
768 static GstFlowReturn
769 gst_asf_demux_chain_headers (GstASFDemux * demux)
770 {
771 GstFlowReturn flow;
772 AsfObject obj;
773 guint8 *header_data, *data = NULL;
774 const guint8 *cdata = NULL;
775 guint64 header_size;
777 cdata = (guint8 *) gst_adapter_peek (demux->adapter, ASF_OBJECT_HEADER_SIZE);
778 if (cdata == NULL)
779 goto need_more_data;
781 asf_demux_peek_object (demux, cdata, ASF_OBJECT_HEADER_SIZE, &obj, TRUE);
782 if (obj.id != ASF_OBJ_HEADER)
783 goto wrong_type;
785 GST_LOG_OBJECT (demux, "header size = %u", (guint) obj.size);
787 /* + 50 for non-packet data at beginning of ASF_OBJ_DATA */
788 if (gst_adapter_available (demux->adapter) < obj.size + 50)
789 goto need_more_data;
791 data = gst_adapter_take (demux->adapter, obj.size + 50);
793 header_data = data;
794 header_size = obj.size;
795 flow = gst_asf_demux_process_object (demux, &header_data, &header_size);
796 if (flow != GST_FLOW_OK)
797 goto parse_failed;
799 /* calculate where the packet data starts */
800 demux->data_offset = obj.size + 50;
802 /* now parse the beginning of the ASF_OBJ_DATA object */
803 if (!gst_asf_demux_parse_data_object_start (demux, data + obj.size))
804 goto wrong_type;
806 if (demux->num_streams == 0)
807 goto no_streams;
809 g_free (data);
810 return GST_FLOW_OK;
812 /* NON-FATAL */
813 need_more_data:
814 {
815 GST_LOG_OBJECT (demux, "not enough data in adapter yet");
816 return GST_FLOW_OK;
817 }
819 /* ERRORS */
820 wrong_type:
821 {
822 GST_ELEMENT_ERROR (demux, STREAM, WRONG_TYPE, (NULL),
823 ("This doesn't seem to be an ASF file"));
824 g_free (data);
825 return GST_FLOW_ERROR;
826 }
827 no_streams:
828 parse_failed:
829 {
830 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
831 ("header parsing failed, or no streams found, flow = %s",
832 gst_flow_get_name (flow)));
833 g_free (data);
834 return GST_FLOW_ERROR;
835 }
836 }
838 static GstFlowReturn
839 gst_asf_demux_aggregate_flow_return (GstASFDemux * demux)
840 {
841 int i;
842 GST_DEBUG_OBJECT (demux, "Aggregating");
844 for (i = 0; i < demux->num_streams; i++) {
845 if (demux->stream[i].active) {
846 GstFlowReturn flowret = demux->stream[i].last_flow;
847 GST_DEBUG_OBJECT (demux, "Aggregating: flow %i return %s", i,
848 gst_flow_get_name (flowret));
849 if (flowret != GST_FLOW_NOT_LINKED)
850 return flowret;
851 }
852 }
854 /* If we got here, then all our active streams are not linked */
855 return GST_FLOW_NOT_LINKED;
856 }
858 static gboolean
859 gst_asf_demux_pull_data (GstASFDemux * demux, guint64 offset, guint size,
860 GstBuffer ** p_buf, GstFlowReturn * p_flow)
861 {
862 GstFlowReturn flow;
864 GST_LOG_OBJECT (demux, "pulling buffer at %" G_GUINT64_FORMAT "+%u",
865 offset, size);
867 flow = gst_pad_pull_range (demux->sinkpad, offset, size, p_buf);
869 if (G_LIKELY (p_flow))
870 *p_flow = flow;
872 if (G_UNLIKELY (flow != GST_FLOW_OK)) {
873 GST_DEBUG_OBJECT (demux, "flow %s pulling buffer at %" G_GUINT64_FORMAT
874 "+%u", gst_flow_get_name (flow), offset, size);
875 *p_buf = NULL;
876 return FALSE;
877 }
879 g_assert (*p_buf != NULL);
881 if (G_UNLIKELY (GST_BUFFER_SIZE (*p_buf) < size)) {
882 GST_DEBUG_OBJECT (demux, "short read pulling buffer at %" G_GUINT64_FORMAT
883 "+%u (got only %u bytes)", offset, size, GST_BUFFER_SIZE (*p_buf));
884 gst_buffer_unref (*p_buf);
885 if (G_LIKELY (p_flow))
886 *p_flow = GST_FLOW_UNEXPECTED;
887 *p_buf = NULL;
888 return FALSE;
889 }
891 return TRUE;
892 }
894 static void
895 gst_asf_demux_pull_indices (GstASFDemux * demux)
896 {
897 GstBuffer *buf = NULL;
898 guint64 offset;
899 guint num_read = 0;
901 offset = demux->index_offset;
903 if (G_UNLIKELY (offset == 0)) {
904 GST_DEBUG_OBJECT (demux, "can't read indices, don't know index offset");
905 return;
906 }
908 while (gst_asf_demux_pull_data (demux, offset, 16 + 8, &buf, NULL)) {
909 GstFlowReturn flow;
910 AsfObject obj;
912 asf_demux_peek_object (demux, GST_BUFFER_DATA (buf), 16 + 8, &obj, TRUE);
913 gst_buffer_replace (&buf, NULL);
915 /* check for sanity */
916 if (G_UNLIKELY (obj.size > (5 * 1024 * 1024))) {
917 GST_DEBUG_OBJECT (demux, "implausible index object size, bailing out");
918 break;
919 }
921 if (G_UNLIKELY (!gst_asf_demux_pull_data (demux, offset, obj.size, &buf,
922 NULL)))
923 break;
925 GST_LOG_OBJECT (demux, "index object at offset 0x%" G_GINT64_MODIFIER "X"
926 ", size %u", offset, (guint) obj.size);
928 offset += obj.size; /* increase before _process_object changes it */
930 flow = gst_asf_demux_process_object (demux, &buf->data, &obj.size);
931 gst_buffer_replace (&buf, NULL);
933 if (G_UNLIKELY (flow != GST_FLOW_OK))
934 break;
936 ++num_read;
937 }
938 GST_DEBUG_OBJECT (demux, "read %u index objects", num_read);
939 }
941 static gboolean
942 gst_asf_demux_parse_data_object_start (GstASFDemux * demux, guint8 * data)
943 {
944 AsfObject obj;
946 asf_demux_peek_object (demux, data, 50, &obj, TRUE);
947 if (obj.id != ASF_OBJ_DATA) {
948 GST_WARNING_OBJECT (demux, "headers not followed by a DATA object");
949 return FALSE;
950 }
952 demux->state = GST_ASF_DEMUX_STATE_DATA;
954 if (!demux->broadcast && obj.size > 50) {
955 demux->data_size = obj.size - 50;
956 /* CHECKME: for at least one file this is off by +158 bytes?! */
957 demux->index_offset = demux->data_offset + demux->data_size;
958 } else {
959 demux->data_size = 0;
960 demux->index_offset = 0;
961 }
963 demux->packet = 0;
965 if (!demux->broadcast) {
966 /* skip object header (24 bytes) and file GUID (16 bytes) */
967 demux->num_packets = GST_READ_UINT64_LE (data + (16 + 8) + 16);
968 } else {
969 demux->num_packets = 0;
970 }
972 if (demux->num_packets == 0)
973 demux->seekable = FALSE;
975 /* fallback in the unlikely case that headers are inconsistent, can't hurt */
976 if (demux->data_size == 0 && demux->num_packets > 0) {
977 demux->data_size = demux->num_packets * demux->packet_size;
978 demux->index_offset = demux->data_offset + demux->data_size;
979 }
981 /* process pending stream objects and create pads for those */
982 gst_asf_demux_process_queued_extended_stream_objects (demux);
984 GST_INFO_OBJECT (demux, "Stream has %" G_GUINT64_FORMAT " packets, "
985 "data_offset=%" G_GINT64_FORMAT ", data_size=%" G_GINT64_FORMAT
986 ", index_offset=%" G_GUINT64_FORMAT, demux->num_packets,
987 demux->data_offset, demux->data_size, demux->index_offset);
989 return TRUE;
990 }
992 static gboolean
993 gst_asf_demux_pull_headers (GstASFDemux * demux)
994 {
995 GstFlowReturn flow;
996 AsfObject obj;
997 GstBuffer *buf = NULL;
998 guint64 size;
1000 GST_LOG_OBJECT (demux, "reading headers");
1002 /* pull HEADER object header, so we know its size */
1003 if (!gst_asf_demux_pull_data (demux, 0, 16 + 8, &buf, NULL))
1004 goto read_failed;
1006 asf_demux_peek_object (demux, GST_BUFFER_DATA (buf), 16 + 8, &obj, TRUE);
1007 gst_buffer_replace (&buf, NULL);
1009 if (obj.id != ASF_OBJ_HEADER)
1010 goto wrong_type;
1012 GST_LOG_OBJECT (demux, "header size = %u", (guint) obj.size);
1014 /* pull HEADER object */
1015 if (!gst_asf_demux_pull_data (demux, 0, obj.size, &buf, NULL))
1016 goto read_failed;
1018 size = obj.size; /* don't want obj.size changed */
1019 flow = gst_asf_demux_process_object (demux, &buf->data, &size);
1020 gst_buffer_replace (&buf, NULL);
1022 if (flow != GST_FLOW_OK) {
1023 GST_WARNING_OBJECT (demux, "process_object: %s", gst_flow_get_name (flow));
1024 goto parse_failed;
1025 }
1027 /* calculate where the packet data starts */
1028 demux->data_offset = obj.size + 50;
1030 /* now pull beginning of DATA object before packet data */
1031 if (!gst_asf_demux_pull_data (demux, obj.size, 50, &buf, NULL))
1032 goto read_failed;
1034 if (!gst_asf_demux_parse_data_object_start (demux, GST_BUFFER_DATA (buf)))
1035 goto wrong_type;
1037 if (demux->num_streams == 0)
1038 goto no_streams;
1040 gst_buffer_replace (&buf, NULL);
1041 return TRUE;
1043 /* ERRORS */
1044 wrong_type:
1045 {
1046 gst_buffer_replace (&buf, NULL);
1047 GST_ELEMENT_ERROR (demux, STREAM, WRONG_TYPE, (NULL),
1048 ("This doesn't seem to be an ASF file"));
1049 return FALSE;
1050 }
1051 no_streams:
1052 read_failed:
1053 parse_failed:
1054 {
1055 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL), (NULL));
1056 return FALSE;
1057 }
1058 }
1060 static gboolean
1061 all_streams_prerolled (GstASFDemux * demux)
1062 {
1063 GstClockTime preroll_time;
1064 guint i, num_no_data = 0;
1066 preroll_time = demux->preroll;
1068 /* returns TRUE as long as there isn't a stream which (a) has data queued
1069 * and (b) the timestamp of last piece of data queued is < demux->preroll
1070 * AND there is at least one other stream with data queued */
1071 for (i = 0; i < demux->num_streams; ++i) {
1072 AsfPayload *last_payload;
1073 AsfStream *stream;
1074 guint last_idx;
1076 stream = &demux->stream[i];
1077 if (G_UNLIKELY (stream->payloads->len == 0)) {
1078 ++num_no_data;
1079 GST_LOG_OBJECT (stream->pad, "no data queued");
1080 continue;
1081 }
1083 last_idx = stream->payloads->len - 1;
1084 last_payload = &g_array_index (stream->payloads, AsfPayload, last_idx);
1086 GST_LOG_OBJECT (stream->pad, "checking if %" GST_TIME_FORMAT " > %"
1087 GST_TIME_FORMAT, GST_TIME_ARGS (last_payload->ts),
1088 GST_TIME_ARGS (preroll_time));
1089 if (G_UNLIKELY (last_payload->ts <= preroll_time)) {
1090 GST_LOG_OBJECT (stream->pad, "not beyond preroll point yet");
1091 return FALSE;
1092 }
1093 }
1095 if (G_UNLIKELY (num_no_data == demux->num_streams))
1096 return FALSE;
1098 return TRUE;
1099 }
1101 #if 0
1102 static gboolean
1103 gst_asf_demux_have_mutually_exclusive_active_stream (GstASFDemux * demux,
1104 AsfStream * stream)
1105 {
1106 GSList *l;
1108 for (l = demux->mut_ex_streams; l != NULL; l = l->next) {
1109 guint8 *mes;
1111 /* check for each mutual exclusion group whether it affects this stream */
1112 for (mes = (guint8 *) l->data; mes != NULL && *mes != 0xff; ++mes) {
1113 if (*mes == stream->id) {
1114 /* we are in this group; let's check if we've already activated streams
1115 * that are in the same group (and hence mutually exclusive to this
1116 * one) */
1117 for (mes = (guint8 *) l->data; mes != NULL && *mes != 0xff; ++mes) {
1118 guint i;
1120 for (i = 0; i < demux->num_streams; ++i) {
1121 if (demux->stream[i].id == *mes && demux->stream[i].active) {
1122 GST_LOG_OBJECT (demux, "stream with ID %d is mutually exclusive "
1123 "to already active stream with ID %d", stream->id,
1124 demux->stream[i].id);
1125 return TRUE;
1126 }
1127 }
1128 }
1129 /* we can only be in this group once, let's break out and move on to
1130 * the next mutual exclusion group */
1131 break;
1132 }
1133 }
1134 }
1136 return FALSE;
1137 }
1138 #endif
1140 static gboolean
1141 gst_asf_demux_check_activate_streams (GstASFDemux * demux, gboolean force)
1142 {
1143 guint i;
1145 if (demux->activated_streams)
1146 return TRUE;
1148 if (!all_streams_prerolled (demux) && !force) {
1149 GST_DEBUG_OBJECT (demux, "not all streams with data beyond preroll yet");
1150 return FALSE;
1151 }
1153 for (i = 0; i < demux->num_streams; ++i) {
1154 AsfStream *stream = &demux->stream[i];
1156 if (stream->payloads->len > 0) {
1157 /* we don't check mutual exclusion stuff here; either we have data for
1158 * a stream, then we active it, or we don't, then we'll ignore it */
1159 GST_LOG_OBJECT (stream->pad, "is prerolled - activate!");
1160 gst_asf_demux_activate_stream (demux, stream);
1161 } else {
1162 GST_LOG_OBJECT (stream->pad, "no data, ignoring stream");
1163 }
1164 }
1166 demux->activated_streams = TRUE;
1167 GST_LOG_OBJECT (demux, "signalling no more pads");
1168 gst_element_no_more_pads (GST_ELEMENT (demux));
1169 return TRUE;
1170 }
1172 /* returns the stream that has a complete payload with the lowest timestamp
1173 * queued, or NULL (we push things by timestamp because during the internal
1174 * prerolling we might accumulate more data then the external queues can take,
1175 * so we'd lock up if we pushed all accumulated data for stream N in one go) */
1176 static AsfStream *
1177 gst_asf_demux_find_stream_with_complete_payload (GstASFDemux * demux)
1178 {
1179 AsfPayload *best_payload = NULL;
1180 AsfStream *best_stream = NULL;
1181 guint i;
1183 for (i = 0; i < demux->num_streams; ++i) {
1184 AsfStream *stream;
1186 stream = &demux->stream[i];
1188 /* Don't push any data until we have at least one payload that falls within
1189 * the current segment. This way we can remove out-of-segment payloads that
1190 * don't need to be decoded after a seek, sending only data from the
1191 * keyframe directly before our segment start */
1192 if (stream->payloads->len > 0) {
1193 AsfPayload *payload;
1194 guint last_idx;
1196 last_idx = stream->payloads->len - 1;
1197 payload = &g_array_index (stream->payloads, AsfPayload, last_idx);
1198 if (G_UNLIKELY (GST_CLOCK_TIME_IS_VALID (payload->ts) &&
1199 (payload->ts < demux->segment.start))) {
1200 if (G_UNLIKELY ((!demux->accurate) && payload->keyframe)) {
1201 GST_DEBUG_OBJECT (stream->pad,
1202 "Found keyframe, updating segment start to %" GST_TIME_FORMAT,
1203 GST_TIME_ARGS (payload->ts));
1204 demux->segment.start = payload->ts;
1205 demux->segment.time = payload->ts;
1206 } else {
1207 GST_DEBUG_OBJECT (stream->pad, "Last queued payload has timestamp %"
1208 GST_TIME_FORMAT " which is before our segment start %"
1209 GST_TIME_FORMAT ", not pushing yet", GST_TIME_ARGS (payload->ts),
1210 GST_TIME_ARGS (demux->segment.start));
1211 continue;
1212 }
1213 }
1215 /* Now see if there's a complete payload queued for this stream */
1217 payload = &g_array_index (stream->payloads, AsfPayload, 0);
1218 if (!gst_asf_payload_is_complete (payload))
1219 continue;
1221 /* ... and whether its timestamp is lower than the current best */
1222 if (best_stream == NULL || best_payload->ts > payload->ts) {
1223 best_stream = stream;
1224 best_payload = payload;
1225 }
1226 }
1227 }
1229 return best_stream;
1230 }
1232 static GstFlowReturn
1233 gst_asf_demux_push_complete_payloads (GstASFDemux * demux, gboolean force)
1234 {
1235 AsfStream *stream;
1237 if (G_UNLIKELY (!demux->activated_streams)) {
1238 if (!gst_asf_demux_check_activate_streams (demux, force))
1239 return GST_FLOW_OK;
1240 /* streams are now activated */
1241 }
1243 /* wait until we had a chance to "lock on" some payload's timestamp */
1244 if (G_UNLIKELY (demux->need_newsegment
1245 && !GST_CLOCK_TIME_IS_VALID (demux->segment_ts)))
1246 return GST_FLOW_OK;
1248 while ((stream = gst_asf_demux_find_stream_with_complete_payload (demux))) {
1249 AsfPayload *payload;
1251 payload = &g_array_index (stream->payloads, AsfPayload, 0);
1253 /* do we need to send a newsegment event */
1254 if ((G_UNLIKELY (demux->need_newsegment))) {
1256 /* safe default if insufficient upstream info */
1257 if (!GST_CLOCK_TIME_IS_VALID (demux->in_gap))
1258 demux->in_gap = 0;
1260 if (demux->segment.stop == GST_CLOCK_TIME_NONE &&
1261 demux->segment.duration > 0) {
1262 /* slight HACK; prevent clipping of last bit */
1263 demux->segment.stop = demux->segment.duration + demux->in_gap;
1264 }
1266 /* FIXME : only if ACCURATE ! */
1267 if (G_LIKELY (!demux->accurate
1268 && (GST_CLOCK_TIME_IS_VALID (payload->ts)))) {
1269 GST_DEBUG ("Adjusting newsegment start to %" GST_TIME_FORMAT,
1270 GST_TIME_ARGS (payload->ts));
1271 demux->segment.start = payload->ts;
1272 demux->segment.time = payload->ts;
1273 }
1275 GST_DEBUG_OBJECT (demux, "sending new-segment event %" GST_SEGMENT_FORMAT,
1276 &demux->segment);
1278 /* note: we fix up all timestamps to start from 0, so this should be ok */
1279 gst_asf_demux_send_event_unlocked (demux,
1280 gst_event_new_new_segment (FALSE, demux->segment.rate,
1281 GST_FORMAT_TIME, demux->segment.start, demux->segment.stop,
1282 demux->segment.start));
1284 /* now post any global tags we may have found */
1285 if (demux->taglist == NULL)
1286 demux->taglist = gst_tag_list_new ();
1288 gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
1289 GST_TAG_CONTAINER_FORMAT, "ASF", NULL);
1291 GST_DEBUG_OBJECT (demux, "global tags: %" GST_PTR_FORMAT, demux->taglist);
1292 gst_element_found_tags (GST_ELEMENT (demux), demux->taglist);
1293 demux->taglist = NULL;
1295 demux->need_newsegment = FALSE;
1296 demux->segment_running = TRUE;
1297 }
1299 /* Do we have tags pending for this stream? */
1300 if (G_UNLIKELY (stream->pending_tags)) {
1301 GST_LOG_OBJECT (stream->pad, "%" GST_PTR_FORMAT, stream->pending_tags);
1302 gst_element_found_tags_for_pad (GST_ELEMENT (demux), stream->pad,
1303 stream->pending_tags);
1304 stream->pending_tags = NULL;
1305 }
1307 /* We have the whole packet now so we should push the packet to
1308 * the src pad now. First though we should check if we need to do
1309 * descrambling */
1310 if (G_UNLIKELY (demux->span > 1)) {
1311 gst_asf_demux_descramble_buffer (demux, stream, &payload->buf);
1312 }
1314 payload->buf = gst_buffer_make_metadata_writable (payload->buf);
1316 if (G_LIKELY (!payload->keyframe)) {
1317 GST_BUFFER_FLAG_SET (payload->buf, GST_BUFFER_FLAG_DELTA_UNIT);
1318 }
1320 if (G_UNLIKELY (stream->discont)) {
1321 GST_DEBUG_OBJECT (stream->pad, "marking DISCONT on stream");
1322 GST_BUFFER_FLAG_SET (payload->buf, GST_BUFFER_FLAG_DISCONT);
1323 stream->discont = FALSE;
1324 }
1326 if (G_UNLIKELY (stream->is_video && payload->par_x && payload->par_y &&
1327 (payload->par_x != stream->par_x) &&
1328 (payload->par_y != stream->par_y))) {
1329 GST_DEBUG ("Updating PAR (%d/%d => %d/%d)",
1330 stream->par_x, stream->par_y, payload->par_x, payload->par_y);
1331 stream->par_x = payload->par_x;
1332 stream->par_y = payload->par_y;
1333 gst_caps_set_simple (stream->caps, "pixel-aspect-ratio",
1334 GST_TYPE_FRACTION, stream->par_x, stream->par_y, NULL);
1335 gst_pad_set_caps (stream->pad, stream->caps);
1336 }
1338 if (G_UNLIKELY (stream->interlaced != payload->interlaced)) {
1339 GST_DEBUG ("Updating interlaced status (%d => %d)", stream->interlaced,
1340 payload->interlaced);
1341 stream->interlaced = payload->interlaced;
1342 gst_caps_set_simple (stream->caps, "interlaced", G_TYPE_BOOLEAN,
1343 stream->interlaced, NULL);
1344 }
1346 gst_buffer_set_caps (payload->buf, stream->caps);
1348 /* (sort of) interpolate timestamps using upstream "frame of reference",
1349 * typically useful for live src, but might (unavoidably) mess with
1350 * position reporting if a live src is playing not so live content
1351 * (e.g. rtspsrc taking some time to fall back to tcp) */
1352 GST_BUFFER_TIMESTAMP (payload->buf) = payload->ts + demux->in_gap;
1353 if (payload->duration == GST_CLOCK_TIME_NONE)
1354 GST_BUFFER_DURATION (payload->buf) =
1355 stream->ext_props.avg_time_per_frame * 100;
1356 else
1357 GST_BUFFER_DURATION (payload->buf) = payload->duration;
1359 /* FIXME: we should really set durations on buffers if we can */
1361 GST_LOG_OBJECT (stream->pad, "pushing buffer, ts=%" GST_TIME_FORMAT
1362 ", dur=%" GST_TIME_FORMAT " size=%u",
1363 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (payload->buf)),
1364 GST_TIME_ARGS (GST_BUFFER_DURATION (payload->buf)),
1365 GST_BUFFER_SIZE (payload->buf));
1367 stream->last_flow = gst_pad_push (stream->pad, payload->buf);
1368 payload->buf = NULL;
1369 g_array_remove_index (stream->payloads, 0);
1370 }
1372 return gst_asf_demux_aggregate_flow_return (demux);
1373 }
1375 static void
1376 gst_asf_demux_loop (GstASFDemux * demux)
1377 {
1378 GstFlowReturn flow = GST_FLOW_OK;
1379 GstBuffer *buf = NULL;
1380 guint64 off;
1382 if (G_UNLIKELY (demux->state == GST_ASF_DEMUX_STATE_HEADER)) {
1383 if (!gst_asf_demux_pull_headers (demux)) {
1384 flow = GST_FLOW_ERROR;
1385 goto pause;
1386 }
1388 gst_asf_demux_pull_indices (demux);
1389 }
1391 g_assert (demux->state == GST_ASF_DEMUX_STATE_DATA);
1393 if (G_UNLIKELY (demux->num_packets != 0
1394 && demux->packet >= demux->num_packets))
1395 goto eos;
1397 GST_LOG_OBJECT (demux, "packet %u/%u", (guint) demux->packet + 1,
1398 (guint) demux->num_packets);
1400 off = demux->data_offset + (demux->packet * demux->packet_size);
1402 if (G_UNLIKELY (!gst_asf_demux_pull_data (demux, off,
1403 demux->packet_size * demux->speed_packets, &buf, &flow))) {
1404 GST_DEBUG_OBJECT (demux, "got flow %s", gst_flow_get_name (flow));
1405 if (flow == GST_FLOW_UNEXPECTED)
1406 goto eos;
1407 else if (!GST_FLOW_IS_FATAL (flow)) {
1408 GST_DEBUG_OBJECT (demux, "Not fatal");
1409 goto pause;
1410 } else
1411 goto read_failed;
1412 }
1414 if (G_LIKELY (demux->speed_packets == 1)) {
1415 /* FIXME: maybe we should just skip broken packets and error out only
1416 * after a few broken packets in a row? */
1417 if (G_UNLIKELY (!gst_asf_demux_parse_packet (demux, buf)))
1418 goto parse_error;
1420 flow = gst_asf_demux_push_complete_payloads (demux, FALSE);
1422 ++demux->packet;
1424 } else {
1425 guint n;
1426 for (n = 0; n < demux->speed_packets; n++) {
1427 GstBuffer *sub;
1429 sub =
1430 gst_buffer_create_sub (buf, n * demux->packet_size,
1431 demux->packet_size);
1432 /* FIXME: maybe we should just skip broken packets and error out only
1433 * after a few broken packets in a row? */
1434 if (G_UNLIKELY (!gst_asf_demux_parse_packet (demux, sub)))
1435 goto parse_error;
1437 gst_buffer_unref (sub);
1439 flow = gst_asf_demux_push_complete_payloads (demux, FALSE);
1441 ++demux->packet;
1443 }
1445 /* reset speed pull */
1446 demux->speed_packets = 1;
1447 }
1449 gst_buffer_unref (buf);
1451 if (G_UNLIKELY (demux->num_packets > 0
1452 && demux->packet >= demux->num_packets)) {
1453 GST_LOG_OBJECT (demux, "reached EOS");
1454 goto eos;
1455 }
1457 if (G_UNLIKELY (flow != GST_FLOW_OK)) {
1458 GST_DEBUG_OBJECT (demux, "pushing complete payloads failed");
1459 goto pause;
1460 }
1462 /* check if we're at the end of the configured segment */
1463 /* FIXME: check if segment end reached etc. */
1465 return;
1467 eos:
1468 {
1469 /* if we haven't activated our streams yet, this might be because we have
1470 * less data queued than required for preroll; force stream activation and
1471 * send any pending payloads before sending EOS */
1472 if (!demux->activated_streams)
1473 gst_asf_demux_push_complete_payloads (demux, TRUE);
1475 /* we want to push an eos or post a segment-done in any case */
1476 if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
1477 gint64 stop;
1479 /* for segment playback we need to post when (in stream time)
1480 * we stopped, this is either stop (when set) or the duration. */
1481 if ((stop = demux->segment.stop) == -1)
1482 stop = demux->segment.duration;
1484 GST_INFO_OBJECT (demux, "Posting segment-done, at end of segment");
1485 gst_element_post_message (GST_ELEMENT_CAST (demux),
1486 gst_message_new_segment_done (GST_OBJECT (demux), GST_FORMAT_TIME,
1487 stop));
1488 } else {
1489 /* normal playback, send EOS to all linked pads */
1490 GST_INFO_OBJECT (demux, "Sending EOS, at end of stream");
1491 gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
1492 }
1493 /* ... and fall through to pause */
1494 GST_DEBUG_OBJECT (demux, "EOSing");
1495 }
1496 pause:
1497 {
1498 GST_DEBUG_OBJECT (demux, "pausing task");
1499 demux->segment_running = FALSE;
1500 gst_pad_pause_task (demux->sinkpad);
1502 /* For the error cases (not EOS) */
1503 if (GST_FLOW_IS_FATAL (flow) || flow == GST_FLOW_NOT_LINKED) {
1504 /* Post an error. Hopefully something else already has, but if not... */
1505 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
1506 (_("Internal data stream error.")),
1507 ("streaming stopped, reason %s", gst_flow_get_name (flow)));
1508 }
1509 return;
1510 }
1512 /* ERRORS */
1513 read_failed:
1514 {
1515 GST_DEBUG_OBJECT (demux, "Read failed, doh");
1516 gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
1517 flow = GST_FLOW_UNEXPECTED;
1518 goto pause;
1519 }
1520 parse_error:
1521 {
1522 gst_buffer_unref (buf);
1523 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
1524 ("Error parsing ASF packet %u", (guint) demux->packet));
1525 gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
1526 flow = GST_FLOW_ERROR;
1527 goto pause;
1528 }
1529 }
1531 #define GST_ASF_DEMUX_CHECK_HEADER_YES 0
1532 #define GST_ASF_DEMUX_CHECK_HEADER_NO 1
1533 #define GST_ASF_DEMUX_CHECK_HEADER_NEED_DATA 2
1535 static gint
1536 gst_asf_demux_check_header (GstASFDemux * demux)
1537 {
1538 AsfObject obj;
1539 guint8 *cdata = (guint8 *) gst_adapter_peek (demux->adapter,
1540 ASF_OBJECT_HEADER_SIZE);
1541 if (cdata == NULL) /* need more data */
1542 return GST_ASF_DEMUX_CHECK_HEADER_NEED_DATA;
1544 asf_demux_peek_object (demux, cdata, ASF_OBJECT_HEADER_SIZE, &obj, FALSE);
1545 if (obj.id != ASF_OBJ_HEADER) {
1546 return GST_ASF_DEMUX_CHECK_HEADER_NO;
1547 } else {
1548 return GST_ASF_DEMUX_CHECK_HEADER_YES;
1549 }
1550 }
1552 static GstFlowReturn
1553 gst_asf_demux_chain (GstPad * pad, GstBuffer * buf)
1554 {
1555 GstFlowReturn ret = GST_FLOW_OK;
1556 GstASFDemux *demux;
1558 demux = GST_ASF_DEMUX (GST_PAD_PARENT (pad));
1560 GST_LOG_OBJECT (demux, "buffer: size=%u, offset=%" G_GINT64_FORMAT ", time=%"
1561 GST_TIME_FORMAT, GST_BUFFER_SIZE (buf), GST_BUFFER_OFFSET (buf),
1562 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)));
1564 if (G_UNLIKELY (GST_BUFFER_IS_DISCONT (buf))) {
1565 GST_DEBUG_OBJECT (demux, "received DISCONT");
1566 gst_asf_demux_mark_discont (demux);
1567 }
1569 if (G_UNLIKELY ((!GST_CLOCK_TIME_IS_VALID (demux->in_gap) &&
1570 GST_BUFFER_TIMESTAMP_IS_VALID (buf)))) {
1571 demux->in_gap = GST_BUFFER_TIMESTAMP (buf) - demux->in_segment.start;
1572 GST_DEBUG_OBJECT (demux, "upstream segment start %" GST_TIME_FORMAT
1573 ", interpolation gap: %" GST_TIME_FORMAT,
1574 GST_TIME_ARGS (demux->in_segment.start), GST_TIME_ARGS (demux->in_gap));
1575 }
1577 gst_adapter_push (demux->adapter, buf);
1579 switch (demux->state) {
1580 case GST_ASF_DEMUX_STATE_INDEX:{
1581 gint result = gst_asf_demux_check_header (demux);
1582 if (result == GST_ASF_DEMUX_CHECK_HEADER_NEED_DATA) /* need more data */
1583 break;
1585 if (result == GST_ASF_DEMUX_CHECK_HEADER_NO) {
1586 /* we don't care about this, probably an index */
1587 /* TODO maybe would be smarter to skip all the indices
1588 * until we got a new header or EOS to decide */
1589 GST_LOG_OBJECT (demux, "Received index object, its EOS");
1590 goto eos;
1591 } else {
1592 GST_INFO_OBJECT (demux, "Chained asf starting");
1593 /* cleanup and get ready for a chained asf */
1594 gst_asf_demux_reset (demux, TRUE);
1595 /* fall through */
1596 }
1597 }
1598 case GST_ASF_DEMUX_STATE_HEADER:{
1599 ret = gst_asf_demux_chain_headers (demux);
1600 if (demux->state != GST_ASF_DEMUX_STATE_DATA)
1601 break;
1602 /* otherwise fall through */
1603 }
1604 case GST_ASF_DEMUX_STATE_DATA:
1605 {
1606 guint64 data_size;
1608 data_size = demux->packet_size;
1610 while (gst_adapter_available (demux->adapter) >= data_size) {
1611 GstBuffer *buf;
1613 /* we don't know the length of the stream
1614 * check for a chained asf everytime */
1615 if (demux->num_packets == 0) {
1616 gint result = gst_asf_demux_check_header (demux);
1618 if (result == GST_ASF_DEMUX_CHECK_HEADER_YES) {
1619 GST_INFO_OBJECT (demux, "Chained asf starting");
1620 /* cleanup and get ready for a chained asf */
1621 gst_asf_demux_reset (demux, TRUE);
1622 break;
1623 }
1624 } else if (G_UNLIKELY (demux->num_packets != 0 && demux->packet >= 0
1625 && demux->packet >= demux->num_packets)) {
1626 /* do not overshoot data section when streaming */
1627 break;
1628 }
1630 buf = gst_adapter_take_buffer (demux->adapter, data_size);
1632 /* FIXME: maybe we should just skip broken packets and error out only
1633 * after a few broken packets in a row? */
1634 if (G_UNLIKELY (!gst_asf_demux_parse_packet (demux, buf))) {
1635 GST_WARNING_OBJECT (demux, "Parse error");
1636 }
1638 gst_buffer_unref (buf);
1640 ret = gst_asf_demux_push_complete_payloads (demux, FALSE);
1642 if (demux->packet >= 0)
1643 ++demux->packet;
1644 }
1645 if (G_UNLIKELY (demux->num_packets != 0 && demux->packet >= 0
1646 && demux->packet >= demux->num_packets)) {
1647 demux->state = GST_ASF_DEMUX_STATE_INDEX;
1648 }
1649 break;
1650 }
1651 default:
1652 g_assert_not_reached ();
1653 }
1655 done:
1656 if (ret != GST_FLOW_OK)
1657 GST_DEBUG_OBJECT (demux, "flow: %s", gst_flow_get_name (ret));
1659 return ret;
1661 eos:
1662 {
1663 GST_DEBUG_OBJECT (demux, "Handled last packet, setting EOS");
1664 ret = GST_FLOW_UNEXPECTED;
1665 goto done;
1666 }
1667 }
1669 static inline gboolean
1670 gst_asf_demux_skip_bytes (guint num_bytes, guint8 ** p_data, guint64 * p_size)
1671 {
1672 if (*p_size < num_bytes)
1673 return FALSE;
1675 *p_data += num_bytes;
1676 *p_size -= num_bytes;
1677 return TRUE;
1678 }
1680 static inline guint8
1681 gst_asf_demux_get_uint8 (guint8 ** p_data, guint64 * p_size)
1682 {
1683 guint8 ret;
1685 g_assert (*p_size >= 1);
1686 ret = GST_READ_UINT8 (*p_data);
1687 *p_data += sizeof (guint8);
1688 *p_size -= sizeof (guint8);
1689 return ret;
1690 }
1692 static inline guint16
1693 gst_asf_demux_get_uint16 (guint8 ** p_data, guint64 * p_size)
1694 {
1695 guint16 ret;
1697 g_assert (*p_size >= 2);
1698 ret = GST_READ_UINT16_LE (*p_data);
1699 *p_data += sizeof (guint16);
1700 *p_size -= sizeof (guint16);
1701 return ret;
1702 }
1704 static inline guint32
1705 gst_asf_demux_get_uint32 (guint8 ** p_data, guint64 * p_size)
1706 {
1707 guint32 ret;
1709 g_assert (*p_size >= 4);
1710 ret = GST_READ_UINT32_LE (*p_data);
1711 *p_data += sizeof (guint32);
1712 *p_size -= sizeof (guint32);
1713 return ret;
1714 }
1716 static inline guint64
1717 gst_asf_demux_get_uint64 (guint8 ** p_data, guint64 * p_size)
1718 {
1719 guint64 ret;
1721 g_assert (*p_size >= 8);
1722 ret = GST_READ_UINT64_LE (*p_data);
1723 *p_data += sizeof (guint64);
1724 *p_size -= sizeof (guint64);
1725 return ret;
1726 }
1728 static inline guint32
1729 gst_asf_demux_get_var_length (guint8 type, guint8 ** p_data, guint64 * p_size)
1730 {
1731 switch (type) {
1732 case 0:
1733 return 0;
1735 case 1:
1736 g_assert (*p_size >= 1);
1737 return gst_asf_demux_get_uint8 (p_data, p_size);
1739 case 2:
1740 g_assert (*p_size >= 2);
1741 return gst_asf_demux_get_uint16 (p_data, p_size);
1743 case 3:
1744 g_assert (*p_size >= 4);
1745 return gst_asf_demux_get_uint32 (p_data, p_size);
1747 default:
1748 break;
1749 }
1751 g_assert_not_reached ();
1752 }
1754 static gboolean
1755 gst_asf_demux_get_buffer (GstBuffer ** p_buf, guint num_bytes_to_read,
1756 guint8 ** p_data, guint64 * p_size)
1757 {
1758 *p_buf = NULL;
1760 if (*p_size < num_bytes_to_read)
1761 return FALSE;
1763 *p_buf = gst_buffer_new_and_alloc (num_bytes_to_read);
1764 memcpy (GST_BUFFER_DATA (*p_buf), *p_data, num_bytes_to_read);
1765 *p_data += num_bytes_to_read;
1766 *p_size -= num_bytes_to_read;
1767 return TRUE;
1768 }
1770 static gboolean
1771 gst_asf_demux_get_bytes (guint8 ** p_buf, guint num_bytes_to_read,
1772 guint8 ** p_data, guint64 * p_size)
1773 {
1774 *p_buf = NULL;
1776 if (*p_size < num_bytes_to_read)
1777 return FALSE;
1779 *p_buf = g_memdup (*p_data, num_bytes_to_read);
1780 *p_data += num_bytes_to_read;
1781 *p_size -= num_bytes_to_read;
1782 return TRUE;
1783 }
1785 static gboolean
1786 gst_asf_demux_get_string (gchar ** p_str, guint16 * p_strlen,
1787 guint8 ** p_data, guint64 * p_size)
1788 {
1789 guint16 s_length;
1790 guint8 *s;
1792 *p_str = NULL;
1794 if (*p_size < 2)
1795 return FALSE;
1797 s_length = gst_asf_demux_get_uint16 (p_data, p_size);
1799 if (p_strlen)
1800 *p_strlen = s_length;
1802 if (s_length == 0) {
1803 GST_WARNING ("zero-length string");
1804 *p_str = g_strdup ("");
1805 return TRUE;
1806 }
1808 if (!gst_asf_demux_get_bytes (&s, s_length, p_data, p_size))
1809 return FALSE;
1811 g_assert (s != NULL);
1813 /* just because They don't exist doesn't
1814 * mean They are not out to get you ... */
1815 if (s[s_length - 1] != '\0') {
1816 s = g_realloc (s, s_length + 1);
1817 s[s_length] = '\0';
1818 }
1820 *p_str = (gchar *) s;
1821 return TRUE;
1822 }
1825 static void
1826 gst_asf_demux_get_guid (ASFGuid * guid, guint8 ** p_data, guint64 * p_size)
1827 {
1828 g_assert (*p_size >= 4 * sizeof (guint32));
1830 guid->v1 = gst_asf_demux_get_uint32 (p_data, p_size);
1831 guid->v2 = gst_asf_demux_get_uint32 (p_data, p_size);
1832 guid->v3 = gst_asf_demux_get_uint32 (p_data, p_size);
1833 guid->v4 = gst_asf_demux_get_uint32 (p_data, p_size);
1834 }
1836 static gboolean
1837 gst_asf_demux_get_stream_audio (asf_stream_audio * audio, guint8 ** p_data,
1838 guint64 * p_size)
1839 {
1840 if (*p_size < (2 + 2 + 4 + 4 + 2 + 2 + 2))
1841 return FALSE;
1843 /* WAVEFORMATEX Structure */
1844 audio->codec_tag = gst_asf_demux_get_uint16 (p_data, p_size);
1845 audio->channels = gst_asf_demux_get_uint16 (p_data, p_size);
1846 audio->sample_rate = gst_asf_demux_get_uint32 (p_data, p_size);
1847 audio->byte_rate = gst_asf_demux_get_uint32 (p_data, p_size);
1848 audio->block_align = gst_asf_demux_get_uint16 (p_data, p_size);
1849 audio->word_size = gst_asf_demux_get_uint16 (p_data, p_size);
1850 /* Codec specific data size */
1851 audio->size = gst_asf_demux_get_uint16 (p_data, p_size);
1852 return TRUE;
1853 }
1855 static gboolean
1856 gst_asf_demux_get_stream_video (asf_stream_video * video, guint8 ** p_data,
1857 guint64 * p_size)
1858 {
1859 if (*p_size < (4 + 4 + 1 + 2))
1860 return FALSE;
1862 video->width = gst_asf_demux_get_uint32 (p_data, p_size);
1863 video->height = gst_asf_demux_get_uint32 (p_data, p_size);
1864 video->unknown = gst_asf_demux_get_uint8 (p_data, p_size);
1865 video->size = gst_asf_demux_get_uint16 (p_data, p_size);
1866 return TRUE;
1867 }
1869 static gboolean
1870 gst_asf_demux_get_stream_video_format (asf_stream_video_format * fmt,
1871 guint8 ** p_data, guint64 * p_size)
1872 {
1873 if (*p_size < (4 + 4 + 4 + 2 + 2 + 4 + 4 + 4 + 4 + 4 + 4))
1874 return FALSE;
1876 fmt->size = gst_asf_demux_get_uint32 (p_data, p_size);
1877 fmt->width = gst_asf_demux_get_uint32 (p_data, p_size);
1878 fmt->height = gst_asf_demux_get_uint32 (p_data, p_size);
1879 fmt->planes = gst_asf_demux_get_uint16 (p_data, p_size);
1880 fmt->depth = gst_asf_demux_get_uint16 (p_data, p_size);
1881 fmt->tag = gst_asf_demux_get_uint32 (p_data, p_size);
1882 fmt->image_size = gst_asf_demux_get_uint32 (p_data, p_size);
1883 fmt->xpels_meter = gst_asf_demux_get_uint32 (p_data, p_size);
1884 fmt->ypels_meter = gst_asf_demux_get_uint32 (p_data, p_size);
1885 fmt->num_colors = gst_asf_demux_get_uint32 (p_data, p_size);
1886 fmt->imp_colors = gst_asf_demux_get_uint32 (p_data, p_size);
1887 return TRUE;
1888 }
1890 AsfStream *
1891 gst_asf_demux_get_stream (GstASFDemux * demux, guint16 id)
1892 {
1893 guint i;
1895 for (i = 0; i < demux->num_streams; i++) {
1896 if (demux->stream[i].id == id)
1897 return &demux->stream[i];
1898 }
1900 GST_WARNING ("Segment found for undefined stream: (%d)", id);
1901 return NULL;
1902 }
1904 static void
1905 gst_asf_demux_setup_pad (GstASFDemux * demux, GstPad * src_pad,
1906 GstCaps * caps, guint16 id, gboolean is_video, GstTagList * tags)
1907 {
1908 AsfStream *stream;
1910 gst_pad_use_fixed_caps (src_pad);
1911 gst_pad_set_caps (src_pad, caps);
1913 gst_pad_set_event_function (src_pad,
1914 GST_DEBUG_FUNCPTR (gst_asf_demux_handle_src_event));
1915 gst_pad_set_query_type_function (src_pad,
1916 GST_DEBUG_FUNCPTR (gst_asf_demux_get_src_query_types));
1917 gst_pad_set_query_function (src_pad,
1918 GST_DEBUG_FUNCPTR (gst_asf_demux_handle_src_query));
1920 stream = &demux->stream[demux->num_streams];
1921 stream->caps = caps;
1922 stream->pad = src_pad;
1923 stream->id = id;
1924 stream->fps_known = !is_video; /* bit hacky for audio */
1925 stream->is_video = is_video;
1926 stream->pending_tags = tags;
1927 stream->discont = TRUE;
1928 if (is_video) {
1929 GstStructure *st;
1930 gint par_x, par_y;
1931 st = gst_caps_get_structure (caps, 0);
1932 if (gst_structure_get_fraction (st, "pixel-aspect-ratio", &par_x, &par_y) &&
1933 par_x > 0 && par_y > 0) {
1934 GST_DEBUG ("PAR %d/%d", par_x, par_y);
1935 stream->par_x = par_x;
1936 stream->par_y = par_y;
1937 }
1938 }
1940 stream->payloads = g_array_new (FALSE, FALSE, sizeof (AsfPayload));
1942 GST_INFO ("Created pad %s for stream %u with caps %" GST_PTR_FORMAT,
1943 GST_PAD_NAME (src_pad), demux->num_streams, caps);
1945 ++demux->num_streams;
1947 stream->active = FALSE;
1948 }
1950 static void
1951 gst_asf_demux_add_audio_stream (GstASFDemux * demux,
1952 asf_stream_audio * audio, guint16 id, guint8 ** p_data, guint64 * p_size)
1953 {
1954 GstTagList *tags = NULL;
1955 GstBuffer *extradata = NULL;
1956 GstPad *src_pad;
1957 GstCaps *caps;
1958 guint16 size_left = 0;
1959 gchar *codec_name = NULL;
1960 gchar *name = NULL;
1962 size_left = audio->size;
1964 /* Create the audio pad */
1965 name = g_strdup_printf ("audio_%02d", demux->num_audio_streams);
1967 src_pad = gst_pad_new_from_static_template (&audio_src_template, name);
1968 g_free (name);
1970 /* Swallow up any left over data and set up the
1971 * standard properties from the header info */
1972 if (size_left) {
1973 GST_INFO_OBJECT (demux, "Audio header contains %d bytes of "
1974 "codec specific data", size_left);
1976 g_assert (size_left <= *p_size);
1977 gst_asf_demux_get_buffer (&extradata, size_left, p_data, p_size);
1978 }
1980 /* asf_stream_audio is the same as gst_riff_strf_auds, but with an
1981 * additional two bytes indicating extradata. */
1982 caps = gst_riff_create_audio_caps (audio->codec_tag, NULL,
1983 (gst_riff_strf_auds *) audio, extradata, NULL, &codec_name);
1985 if (caps == NULL) {
1986 caps = gst_caps_new_simple ("audio/x-asf-unknown", "codec_id",
1987 G_TYPE_INT, (gint) audio->codec_tag, NULL);
1988 }
1990 /* Informing about that audio format we just added */
1991 if (codec_name) {
1992 tags = gst_tag_list_new ();
1993 gst_tag_list_add (tags, GST_TAG_MERGE_APPEND, GST_TAG_AUDIO_CODEC,
1994 codec_name, NULL);
1995 g_free (codec_name);
1996 }
1998 if (extradata)
1999 gst_buffer_unref (extradata);
2001 GST_INFO ("Adding audio stream #%u, id %u codec %u (0x%04x), tags=%"
2002 GST_PTR_FORMAT, demux->num_audio_streams, id, audio->codec_tag,
2003 audio->codec_tag, tags);
2005 ++demux->num_audio_streams;
2007 gst_asf_demux_setup_pad (demux, src_pad, caps, id, FALSE, tags);
2008 }
2010 static void
2011 gst_asf_demux_add_video_stream (GstASFDemux * demux,
2012 asf_stream_video_format * video, guint16 id,
2013 guint8 ** p_data, guint64 * p_size)
2014 {
2015 GstTagList *tags = NULL;
2016 GstBuffer *extradata = NULL;
2017 GstPad *src_pad;
2018 GstCaps *caps;
2019 gchar *name = NULL;
2020 gchar *codec_name = NULL;
2021 gint size_left = video->size - 40;
2023 /* Create the video pad */
2024 name = g_strdup_printf ("video_%02d", demux->num_video_streams);
2025 src_pad = gst_pad_new_from_static_template (&video_src_template, name);
2026 g_free (name);
2028 /* Now try some gstreamer formatted MIME types (from gst_avi_demux_strf_vids) */
2029 if (size_left) {
2030 GST_LOG ("Video header has %d bytes of codec specific data", size_left);
2031 g_assert (size_left <= *p_size);
2032 gst_asf_demux_get_buffer (&extradata, size_left, p_data, p_size);
2033 }
2035 GST_DEBUG ("video codec %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (video->tag));
2037 /* yes, asf_stream_video_format and gst_riff_strf_vids are the same */
2038 caps = gst_riff_create_video_caps (video->tag, NULL,
2039 (gst_riff_strf_vids *) video, extradata, NULL, &codec_name);
2041 if (caps == NULL) {
2042 caps = gst_caps_new_simple ("video/x-asf-unknown", "fourcc",
2043 GST_TYPE_FOURCC, video->tag, NULL);
2044 } else {
2045 GstStructure *s;
2046 gint ax, ay;
2048 s = gst_asf_demux_get_metadata_for_stream (demux, id);
2049 if (gst_structure_get_int (s, "AspectRatioX", &ax) &&
2050 gst_structure_get_int (s, "AspectRatioY", &ay) && (ax > 0 && ay > 0)) {
2051 gst_caps_set_simple (caps, "pixel-aspect-ratio", GST_TYPE_FRACTION,
2052 ax, ay, NULL);
2054 } else {
2055 guint ax, ay;
2056 /* retry with the global metadata */
2057 GST_DEBUG ("Retrying with global metadata %" GST_PTR_FORMAT,
2058 demux->global_metadata);
2059 s = demux->global_metadata;
2060 if (gst_structure_get_uint (s, "AspectRatioX", &ax) &&
2061 gst_structure_get_uint (s, "AspectRatioY", &ay)) {
2062 GST_DEBUG ("ax:%d, ay:%d", ax, ay);
2063 if (ax > 0 && ay > 0)
2064 gst_caps_set_simple (caps, "pixel-aspect-ratio", GST_TYPE_FRACTION,
2065 ax, ay, NULL);
2066 }
2067 }
2068 s = gst_caps_get_structure (caps, 0);
2069 gst_structure_remove_field (s, "framerate");
2070 }
2072 /* add fourcc format to caps, some proprietary decoders seem to need it */
2073 gst_caps_set_simple (caps, "format", GST_TYPE_FOURCC, video->tag, NULL);
2075 if (codec_name) {
2076 tags = gst_tag_list_new ();
2077 gst_tag_list_add (tags, GST_TAG_MERGE_APPEND, GST_TAG_VIDEO_CODEC,
2078 codec_name, NULL);
2079 g_free (codec_name);
2080 }
2082 if (extradata)
2083 gst_buffer_unref (extradata);
2085 GST_INFO ("Adding video stream #%u, id %u, codec %"
2086 GST_FOURCC_FORMAT " (0x%08x)", demux->num_video_streams, id,
2087 GST_FOURCC_ARGS (video->tag), video->tag);
2089 ++demux->num_video_streams;
2091 gst_asf_demux_setup_pad (demux, src_pad, caps, id, TRUE, tags);
2092 }
2094 static void
2095 gst_asf_demux_activate_stream (GstASFDemux * demux, AsfStream * stream)
2096 {
2097 if (!stream->active) {
2098 GST_INFO_OBJECT (demux, "Activating stream %2u, pad %s, caps %"
2099 GST_PTR_FORMAT, stream->id, GST_PAD_NAME (stream->pad), stream->caps);
2100 gst_pad_set_active (stream->pad, TRUE);
2101 gst_element_add_pad (GST_ELEMENT_CAST (demux), stream->pad);
2102 stream->active = TRUE;
2103 }
2104 }
2106 static AsfStream *
2107 gst_asf_demux_parse_stream_object (GstASFDemux * demux, guint8 * data,
2108 guint64 size)
2109 {
2110 AsfCorrectionType correction_type;
2111 AsfStreamType stream_type;
2112 GstClockTime time_offset;
2113 gboolean is_encrypted;
2114 guint16 stream_id;
2115 guint16 flags;
2116 ASFGuid guid;
2117 guint stream_specific_size;
2118 guint type_specific_size;
2119 guint unknown;
2121 /* Get the rest of the header's header */
2122 if (size < (16 + 16 + 8 + 4 + 4 + 2 + 4))
2123 goto not_enough_data;
2125 gst_asf_demux_get_guid (&guid, &data, &size);
2126 stream_type = gst_asf_demux_identify_guid (asf_stream_guids, &guid);
2128 gst_asf_demux_get_guid (&guid, &data, &size);
2129 correction_type = gst_asf_demux_identify_guid (asf_correction_guids, &guid);
2131 time_offset = gst_asf_demux_get_uint64 (&data, &size) * 100;
2133 type_specific_size = gst_asf_demux_get_uint32 (&data, &size);
2134 stream_specific_size = gst_asf_demux_get_uint32 (&data, &size);
2136 flags = gst_asf_demux_get_uint16 (&data, &size);
2137 stream_id = flags & 0x7f;
2138 is_encrypted = !!((flags & 0x8000) << 15);
2139 unknown = gst_asf_demux_get_uint32 (&data, &size);
2141 GST_DEBUG_OBJECT (demux, "Found stream %u, time_offset=%" GST_TIME_FORMAT,
2142 stream_id, GST_TIME_ARGS (time_offset));
2144 switch (stream_type) {
2145 case ASF_STREAM_AUDIO:{
2146 asf_stream_audio audio_object;
2148 if (!gst_asf_demux_get_stream_audio (&audio_object, &data, &size))
2149 goto not_enough_data;
2151 GST_INFO ("Object is an audio stream with %u bytes of additional data",
2152 audio_object.size);
2154 gst_asf_demux_add_audio_stream (demux, &audio_object, stream_id,
2155 &data, &size);
2157 switch (correction_type) {
2158 case ASF_CORRECTION_ON:{
2159 guint span, packet_size, chunk_size, data_size, silence_data;
2161 GST_INFO ("Using error correction");
2163 if (size < (1 + 2 + 2 + 2 + 1))
2164 goto not_enough_data;
2166 span = gst_asf_demux_get_uint8 (&data, &size);
2167 packet_size = gst_asf_demux_get_uint16 (&data, &size);
2168 chunk_size = gst_asf_demux_get_uint16 (&data, &size);
2169 data_size = gst_asf_demux_get_uint16 (&data, &size);
2170 silence_data = gst_asf_demux_get_uint8 (&data, &size);
2172 /* FIXME: shouldn't this be per-stream? */
2173 demux->span = span;
2175 GST_DEBUG_OBJECT (demux, "Descrambling ps:%u cs:%u ds:%u s:%u sd:%u",
2176 packet_size, chunk_size, data_size, span, silence_data);
2178 if (demux->span > 1) {
2179 if (chunk_size == 0 || ((packet_size / chunk_size) <= 1)) {
2180 /* Disable descrambling */
2181 demux->span = 0;
2182 } else {
2183 /* FIXME: this else branch was added for
2184 * weird_al_yankovic - the saga begins.asf */
2185 demux->ds_packet_size = packet_size;
2186 demux->ds_chunk_size = chunk_size;
2187 }
2188 } else {
2189 /* Descambling is enabled */
2190 demux->ds_packet_size = packet_size;
2191 demux->ds_chunk_size = chunk_size;
2192 }
2193 #if 0
2194 /* Now skip the rest of the silence data */
2195 if (data_size > 1)
2196 gst_bytestream_flush (demux->bs, data_size - 1);
2197 #else
2198 /* FIXME: CHECKME. And why -1? */
2199 if (data_size > 1) {
2200 if (!gst_asf_demux_skip_bytes (data_size - 1, &data, &size)) {
2201 goto not_enough_data;
2202 }
2203 }
2204 #endif
2205 break;
2206 }
2207 case ASF_CORRECTION_OFF:{
2208 GST_INFO ("Error correction off");
2209 if (!gst_asf_demux_skip_bytes (stream_specific_size, &data, &size))
2210 goto not_enough_data;
2211 break;
2212 }
2213 default:
2214 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
2215 ("Audio stream using unknown error correction"));
2216 return NULL;
2217 }
2219 break;
2220 }
2222 case ASF_STREAM_VIDEO:{
2223 asf_stream_video_format video_format_object;
2224 asf_stream_video video_object;
2225 guint16 vsize;
2227 if (!gst_asf_demux_get_stream_video (&video_object, &data, &size))
2228 goto not_enough_data;
2230 vsize = video_object.size - 40; /* Byte order gets offset by single byte */
2232 GST_INFO ("object is a video stream with %u bytes of "
2233 "additional data", vsize);
2235 if (!gst_asf_demux_get_stream_video_format (&video_format_object,
2236 &data, &size)) {
2237 goto not_enough_data;
2238 }
2240 gst_asf_demux_add_video_stream (demux, &video_format_object, stream_id,
2241 &data, &size);
2243 break;
2244 }
2246 default:
2247 GST_WARNING_OBJECT (demux, "Unknown stream type for stream %u",
2248 stream_id);
2249 break;
2250 }
2252 return gst_asf_demux_get_stream (demux, stream_id);
2254 not_enough_data:
2255 {
2256 GST_WARNING_OBJECT (demux, "Unexpected end of data parsing stream object");
2257 /* we'll error out later if we found no streams */
2258 return NULL;
2259 }
2260 }
2262 static const gchar *
2263 gst_asf_demux_get_gst_tag_from_tag_name (const gchar * name_utf8)
2264 {
2265 const struct
2266 {
2267 const gchar *asf_name;
2268 const gchar *gst_name;
2269 } tags[] = {
2270 {
2271 "WM/Genre", GST_TAG_GENRE}, {
2272 "WM/AlbumTitle", GST_TAG_ALBUM}, {
2273 "WM/AlbumArtist", GST_TAG_ARTIST}, {
2274 "WM/Picture", GST_TAG_IMAGE}, {
2275 "WM/Track", GST_TAG_TRACK_NUMBER}, {
2276 "WM/TrackNumber", GST_TAG_TRACK_NUMBER}, {
2277 "WM/Year", GST_TAG_DATE}
2278 /* { "WM/Composer", GST_TAG_COMPOSER } */
2279 };
2280 gsize out = strlen (name_utf8);
2281 guint i;
2283 if (name_utf8 == NULL) {
2284 GST_WARNING ("Failed to convert name to UTF8, skipping");
2285 return NULL;
2286 }
2288 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
2289 if (strncmp (tags[i].asf_name, name_utf8, out) == 0) {
2290 GST_LOG ("map tagname '%s' -> '%s'", name_utf8, tags[i].gst_name);
2291 return tags[i].gst_name;
2292 }
2293 }
2295 return NULL;
2296 }
2298 /* gst_asf_demux_add_global_tags() takes ownership of taglist! */
2299 static void
2300 gst_asf_demux_add_global_tags (GstASFDemux * demux, GstTagList * taglist)
2301 {
2302 GstTagList *t;
2304 GST_DEBUG_OBJECT (demux, "adding global tags: %" GST_PTR_FORMAT, taglist);
2306 if (taglist == NULL)
2307 return;
2309 if (gst_tag_list_is_empty (taglist)) {
2310 gst_tag_list_free (taglist);
2311 return;
2312 }
2314 t = gst_tag_list_merge (demux->taglist, taglist, GST_TAG_MERGE_APPEND);
2315 if (demux->taglist)
2316 gst_tag_list_free (demux->taglist);
2317 gst_tag_list_free (taglist);
2318 demux->taglist = t;
2319 GST_LOG_OBJECT (demux, "global tags now: %" GST_PTR_FORMAT, demux->taglist);
2320 }
2322 #define ASF_DEMUX_DATA_TYPE_UTF16LE_STRING 0
2323 #define ASF_DEMUX_DATA_TYPE_BYTE_ARRAY 1
2324 #define ASF_DEMUX_DATA_TYPE_DWORD 3
2326 static void
2327 asf_demux_parse_picture_tag (GstTagList * tags, const guint8 * tag_data,
2328 guint tag_data_len)
2329 {
2330 GstByteReader r;
2331 const guint8 *img_data = NULL;
2332 guint32 img_data_len = 0;
2333 guint8 pic_type = 0;
2335 gst_byte_reader_init (&r, tag_data, tag_data_len);
2337 /* skip mime type string (we don't trust it and do our own typefinding),
2338 * and also skip the description string, since we don't use it */
2339 if (!gst_byte_reader_get_uint8 (&r, &pic_type) ||
2340 !gst_byte_reader_get_uint32_le (&r, &img_data_len) ||
2341 !gst_byte_reader_skip_string_utf16 (&r) ||
2342 !gst_byte_reader_skip_string_utf16 (&r) ||
2343 !gst_byte_reader_get_data (&r, img_data_len, &img_data)) {
2344 goto not_enough_data;
2345 }
2348 if (!gst_tag_list_add_id3_image (tags, img_data, img_data_len, pic_type))
2349 GST_DEBUG ("failed to add image extracted from WM/Picture tag to taglist");
2351 return;
2353 not_enough_data:
2354 {
2355 GST_DEBUG ("Failed to read WM/Picture tag: not enough data");
2356 GST_MEMDUMP ("WM/Picture data", tag_data, tag_data_len);
2357 return;
2358 }
2359 }
2361 /* Extended Content Description Object */
2362 static GstFlowReturn
2363 gst_asf_demux_process_ext_content_desc (GstASFDemux * demux, guint8 * data,
2364 guint64 size)
2365 {
2366 /* Other known (and unused) 'text/unicode' metadata available :
2367 *
2368 * WM/Lyrics =
2369 * WM/MediaPrimaryClassID = {D1607DBC-E323-4BE2-86A1-48A42A28441E}
2370 * WMFSDKVersion = 9.00.00.2980
2371 * WMFSDKNeeded = 0.0.0.0000
2372 * WM/UniqueFileIdentifier = AMGa_id=R 15334;AMGp_id=P 5149;AMGt_id=T 2324984
2373 * WM/Publisher = 4AD
2374 * WM/Provider = AMG
2375 * WM/ProviderRating = 8
2376 * WM/ProviderStyle = Rock (similar to WM/Genre)
2377 * WM/GenreID (similar to WM/Genre)
2378 * WM/TrackNumber (same as WM/Track but as a string)
2379 *
2380 * Other known (and unused) 'non-text' metadata available :
2381 *
2382 * WM/EncodingTime
2383 * WM/MCDI
2384 * IsVBR
2385 *
2386 * We might want to read WM/TrackNumber and use atoi() if we don't have
2387 * WM/Track
2388 */
2390 GstTagList *taglist;
2391 guint16 blockcount, i;
2393 GST_INFO_OBJECT (demux, "object is an extended content description");
2395 taglist = gst_tag_list_new ();
2397 /* Content Descriptor Count */
2398 if (size < 2)
2399 goto not_enough_data;
2401 blockcount = gst_asf_demux_get_uint16 (&data, &size);
2403 for (i = 1; i <= blockcount; ++i) {
2404 const gchar *gst_tag_name;
2405 guint16 datatype;
2406 guint16 value_len;
2407 guint16 name_len;
2408 GValue tag_value = { 0, };
2409 gsize in, out;
2410 gchar *name;
2411 gchar *name_utf8 = NULL;
2412 gchar *value;
2414 /* Descriptor */
2415 if (!gst_asf_demux_get_string (&name, &name_len, &data, &size))
2416 goto not_enough_data;
2418 if (size < 2) {
2419 g_free (name);
2420 goto not_enough_data;
2421 }
2422 /* Descriptor Value Data Type */
2423 datatype = gst_asf_demux_get_uint16 (&data, &size);
2425 /* Descriptor Value (not really a string, but same thing reading-wise) */
2426 if (!gst_asf_demux_get_string (&value, &value_len, &data, &size)) {
2427 g_free (name);
2428 goto not_enough_data;
2429 }
2431 name_utf8 =
2432 g_convert (name, name_len, "UTF-8", "UTF-16LE", &in, &out, NULL);
2434 GST_DEBUG ("Found tag/metadata %s", name_utf8);
2436 gst_tag_name = gst_asf_demux_get_gst_tag_from_tag_name (name_utf8);
2438 GST_DEBUG ("gst_tag_name %s", gst_tag_name);
2440 if (name_utf8 != NULL) {
2441 switch (datatype) {
2442 case ASF_DEMUX_DATA_TYPE_UTF16LE_STRING:{
2443 gchar *value_utf8;
2445 value_utf8 = g_convert (value, value_len, "UTF-8", "UTF-16LE",
2446 &in, &out, NULL);
2448 GST_DEBUG ("string value %s", value_utf8);
2450 /* get rid of tags with empty value */
2451 if (value_utf8 != NULL && *value_utf8 != '\0') {
2452 value_utf8[out] = '\0';
2454 if (gst_tag_name != NULL) {
2455 if (strcmp (gst_tag_name, GST_TAG_DATE) == 0) {
2456 guint year = atoi (value_utf8);
2458 if (year > 0) {
2459 GDate *date = g_date_new_dmy (1, 1, year);
2461 g_value_init (&tag_value, GST_TYPE_DATE);
2462 gst_value_set_date (&tag_value, date);
2463 g_date_free (date);
2464 }
2465 } else if (strcmp (gst_tag_name, GST_TAG_GENRE) == 0) {
2466 guint id3v1_genre_id;
2467 const gchar *genre_str;
2469 if (sscanf (value_utf8, "(%u)", &id3v1_genre_id) == 1 &&
2470 ((genre_str = gst_tag_id3_genre_get (id3v1_genre_id)))) {
2471 GST_DEBUG ("Genre: %s -> %s", value_utf8, genre_str);
2472 g_free (value_utf8);
2473 value_utf8 = g_strdup (genre_str);
2474 }
2475 } else {
2476 GType tag_type;
2478 /* convert tag from string to other type if required */
2479 tag_type = gst_tag_get_type (gst_tag_name);
2480 g_value_init (&tag_value, tag_type);
2481 if (!gst_value_deserialize (&tag_value, value_utf8)) {
2482 GValue from_val = { 0, };
2484 g_value_init (&from_val, G_TYPE_STRING);
2485 g_value_set_string (&from_val, value_utf8);
2486 if (!g_value_transform (&from_val, &tag_value)) {
2487 GST_WARNING_OBJECT (demux,
2488 "Could not transform string tag to " "%s tag type %s",
2489 gst_tag_name, g_type_name (tag_type));
2490 g_value_unset (&tag_value);
2491 }
2492 g_value_unset (&from_val);
2493 }
2494 }
2495 } else {
2496 /* metadata ! */
2497 GST_DEBUG ("Setting metadata");
2498 g_value_init (&tag_value, G_TYPE_STRING);
2499 g_value_set_string (&tag_value, value_utf8);
2500 }
2501 } else if (value_utf8 == NULL) {
2502 GST_WARNING ("Failed to convert string value to UTF8, skipping");
2503 } else {
2504 GST_DEBUG ("Skipping empty string value for %s", gst_tag_name);
2505 }
2506 g_free (value_utf8);
2507 break;
2508 }
2509 case ASF_DEMUX_DATA_TYPE_BYTE_ARRAY:{
2510 if (gst_tag_name) {
2511 if (!g_str_equal (gst_tag_name, GST_TAG_IMAGE)) {
2512 GST_FIXME ("Unhandled byte array tag %s", gst_tag_name);
2513 break;
2514 } else {
2515 asf_demux_parse_picture_tag (taglist, (guint8 *) value,
2516 value_len);
2517 }
2518 }
2519 break;
2520 }
2521 case ASF_DEMUX_DATA_TYPE_DWORD:{
2522 guint uint_val = GST_READ_UINT32_LE (value);
2524 /* this is the track number */
2525 g_value_init (&tag_value, G_TYPE_UINT);
2527 /* WM/Track counts from 0 */
2528 if (!strcmp (name_utf8, "WM/Track"))
2529 ++uint_val;
2531 g_value_set_uint (&tag_value, uint_val);
2532 break;
2533 }
2534 default:{
2535 GST_DEBUG ("Skipping tag %s of type %d", gst_tag_name, datatype);
2536 break;
2537 }
2538 }
2540 if (G_IS_VALUE (&tag_value)) {
2541 if (gst_tag_name) {
2542 GstTagMergeMode merge_mode = GST_TAG_MERGE_APPEND;
2544 /* WM/TrackNumber is more reliable than WM/Track, since the latter
2545 * is supposed to have a 0 base but is often wrongly written to start
2546 * from 1 as well, so prefer WM/TrackNumber when we have it: either
2547 * replace the value added earlier from WM/Track or put it first in
2548 * the list, so that it will get picked up by _get_uint() */
2549 if (strcmp (name_utf8, "WM/TrackNumber") == 0)
2550 merge_mode = GST_TAG_MERGE_REPLACE;
2552 gst_tag_list_add_values (taglist, merge_mode, gst_tag_name,
2553 &tag_value, NULL);
2554 } else {
2555 GST_DEBUG ("Setting global metadata %s", name_utf8);
2556 gst_structure_set_value (demux->global_metadata, name_utf8,
2557 &tag_value);
2558 }
2560 g_value_unset (&tag_value);
2561 }
2562 }
2564 g_free (name);
2565 g_free (value);
2566 g_free (name_utf8);
2567 }
2569 gst_asf_demux_add_global_tags (demux, taglist);
2571 return GST_FLOW_OK;
2573 /* Errors */
2574 not_enough_data:
2575 {
2576 GST_WARNING ("Unexpected end of data parsing ext content desc object");
2577 gst_tag_list_free (taglist);
2578 return GST_FLOW_OK; /* not really fatal */
2579 }
2580 }
2582 static GstStructure *
2583 gst_asf_demux_get_metadata_for_stream (GstASFDemux * demux, guint stream_num)
2584 {
2585 gchar sname[32];
2586 guint i;
2588 g_snprintf (sname, sizeof (sname), "stream-%u", stream_num);
2590 for (i = 0; i < gst_caps_get_size (demux->metadata); ++i) {
2591 GstStructure *s;
2593 s = gst_caps_get_structure (demux->metadata, i);
2594 if (gst_structure_has_name (s, sname))
2595 return s;
2596 }
2598 gst_caps_append_structure (demux->metadata, gst_structure_empty_new (sname));
2600 /* try lookup again; demux->metadata took ownership of the structure, so we
2601 * can't really make any assumptions about what happened to it, so we can't
2602 * just return it directly after appending it */
2603 return gst_asf_demux_get_metadata_for_stream (demux, stream_num);
2604 }
2606 static GstFlowReturn
2607 gst_asf_demux_process_metadata (GstASFDemux * demux, guint8 * data,
2608 guint64 size)
2609 {
2610 guint16 blockcount, i;
2612 GST_INFO_OBJECT (demux, "object is a metadata object");
2614 /* Content Descriptor Count */
2615 if (size < 2)
2616 goto not_enough_data;
2618 blockcount = gst_asf_demux_get_uint16 (&data, &size);
2620 for (i = 0; i < blockcount; ++i) {
2621 GstStructure *s;
2622 guint16 lang_idx, stream_num, name_len, data_type;
2623 guint32 data_len, ival;
2624 gchar *name_utf8;
2626 if (size < (2 + 2 + 2 + 2 + 4))
2627 goto not_enough_data;
2629 lang_idx = gst_asf_demux_get_uint16 (&data, &size);
2630 stream_num = gst_asf_demux_get_uint16 (&data, &size);
2631 name_len = gst_asf_demux_get_uint16 (&data, &size);
2632 data_type = gst_asf_demux_get_uint16 (&data, &size);
2633 data_len = gst_asf_demux_get_uint32 (&data, &size);
2635 if (size < name_len + data_len)
2636 goto not_enough_data;
2638 /* convert name to UTF-8 */
2639 name_utf8 = g_convert ((gchar *) data, name_len, "UTF-8", "UTF-16LE",
2640 NULL, NULL, NULL);
2641 gst_asf_demux_skip_bytes (name_len, &data, &size);
2643 if (name_utf8 == NULL) {
2644 GST_WARNING ("Failed to convert value name to UTF8, skipping");
2645 gst_asf_demux_skip_bytes (data_len, &data, &size);
2646 continue;
2647 }
2649 if (data_type != ASF_DEMUX_DATA_TYPE_DWORD) {
2650 gst_asf_demux_skip_bytes (data_len, &data, &size);
2651 g_free (name_utf8);
2652 continue;
2653 }
2655 /* read DWORD */
2656 if (size < 4) {
2657 g_free (name_utf8);
2658 goto not_enough_data;
2659 }
2661 ival = gst_asf_demux_get_uint32 (&data, &size);
2663 /* skip anything else there may be, just in case */
2664 gst_asf_demux_skip_bytes (data_len - 4, &data, &size);
2666 s = gst_asf_demux_get_metadata_for_stream (demux, stream_num);
2667 gst_structure_set (s, name_utf8, G_TYPE_INT, ival, NULL);
2668 g_free (name_utf8);
2669 }
2671 GST_INFO_OBJECT (demux, "metadata = %" GST_PTR_FORMAT, demux->metadata);
2672 return GST_FLOW_OK;
2674 /* Errors */
2675 not_enough_data:
2676 {
2677 GST_WARNING ("Unexpected end of data parsing metadata object");
2678 return GST_FLOW_OK; /* not really fatal */
2679 }
2680 }
2682 static GstFlowReturn
2683 gst_asf_demux_process_header (GstASFDemux * demux, guint8 * data, guint64 size)
2684 {
2685 GstFlowReturn ret = GST_FLOW_OK;
2686 guint32 i, num_objects;
2687 guint8 unknown;
2689 /* Get the rest of the header's header */
2690 if (size < (4 + 1 + 1))
2691 goto not_enough_data;
2693 num_objects = gst_asf_demux_get_uint32 (&data, &size);
2694 unknown = gst_asf_demux_get_uint8 (&data, &size);
2695 unknown = gst_asf_demux_get_uint8 (&data, &size);
2697 GST_INFO_OBJECT (demux, "object is a header with %u parts", num_objects);
2699 /* Loop through the header's objects, processing those */
2700 for (i = 0; i < num_objects; ++i) {
2701 GST_INFO_OBJECT (demux, "reading header part %u", i);
2702 ret = gst_asf_demux_process_object (demux, &data, &size);
2703 if (ret != GST_FLOW_OK) {
2704 GST_WARNING ("process_object returned %s", gst_asf_get_flow_name (ret));
2705 break;
2706 }
2707 }
2709 return ret;
2711 not_enough_data:
2712 {
2713 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
2714 ("short read parsing HEADER object"));
2715 return GST_FLOW_ERROR;
2716 }
2717 }
2719 static GstFlowReturn
2720 gst_asf_demux_process_file (GstASFDemux * demux, guint8 * data, guint64 size)
2721 {
2722 guint64 file_size, creation_time, packets_count;
2723 guint64 play_time, send_time, preroll;
2724 guint32 flags, min_pktsize, max_pktsize, min_bitrate;
2726 if (size < (16 + 8 + 8 + 8 + 8 + 8 + 8 + 4 + 4 + 4 + 4))
2727 goto not_enough_data;
2729 gst_asf_demux_skip_bytes (16, &data, &size); /* skip GUID */
2730 file_size = gst_asf_demux_get_uint64 (&data, &size);
2731 creation_time = gst_asf_demux_get_uint64 (&data, &size);
2732 packets_count = gst_asf_demux_get_uint64 (&data, &size);
2733 play_time = gst_asf_demux_get_uint64 (&data, &size);
2734 send_time = gst_asf_demux_get_uint64 (&data, &size);
2735 preroll = gst_asf_demux_get_uint64 (&data, &size);
2736 flags = gst_asf_demux_get_uint32 (&data, &size);
2737 min_pktsize = gst_asf_demux_get_uint32 (&data, &size);
2738 max_pktsize = gst_asf_demux_get_uint32 (&data, &size);
2739 min_bitrate = gst_asf_demux_get_uint32 (&data, &size);
2741 demux->broadcast = !!(flags & 0x01);
2742 demux->seekable = !!(flags & 0x02);
2744 GST_DEBUG_OBJECT (demux, "min_pktsize = %u", min_pktsize);
2745 GST_DEBUG_OBJECT (demux, "flags::broadcast = %d", demux->broadcast);
2746 GST_DEBUG_OBJECT (demux, "flags::seekable = %d", demux->seekable);
2748 if (demux->broadcast) {
2749 /* these fields are invalid if the broadcast flag is set */
2750 play_time = 0;
2751 file_size = 0;
2752 }
2754 if (min_pktsize != max_pktsize)
2755 goto non_fixed_packet_size;
2757 demux->packet_size = max_pktsize;
2759 /* FIXME: do we need send_time as well? what is it? */
2760 if ((play_time * 100) >= (preroll * GST_MSECOND))
2761 demux->play_time = (play_time * 100) - (preroll * GST_MSECOND);
2762 else
2763 demux->play_time = 0;
2765 demux->preroll = preroll * GST_MSECOND;
2767 /* initial latency */
2768 demux->latency = demux->preroll;
2770 if (demux->play_time == 0)
2771 demux->seekable = FALSE;
2773 GST_DEBUG_OBJECT (demux, "play_time %" GST_TIME_FORMAT,
2774 GST_TIME_ARGS (demux->play_time));
2775 GST_DEBUG_OBJECT (demux, "preroll %" GST_TIME_FORMAT,
2776 GST_TIME_ARGS (demux->preroll));
2778 if (demux->play_time > 0) {
2779 gst_segment_set_duration (&demux->segment, GST_FORMAT_TIME,
2780 demux->play_time);
2781 }
2783 GST_INFO ("object is a file with %" G_GUINT64_FORMAT " data packets",
2784 packets_count);
2785 GST_INFO ("preroll = %" G_GUINT64_FORMAT, demux->preroll);
2787 return GST_FLOW_OK;
2789 /* ERRORS */
2790 non_fixed_packet_size:
2791 {
2792 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
2793 ("packet size must be fixed"));
2794 return GST_FLOW_ERROR;
2795 }
2796 not_enough_data:
2797 {
2798 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
2799 ("short read parsing FILE object"));
2800 return GST_FLOW_ERROR;
2801 }
2802 }
2804 /* Content Description Object */
2805 static GstFlowReturn
2806 gst_asf_demux_process_comment (GstASFDemux * demux, guint8 * data, guint64 size)
2807 {
2808 struct
2809 {
2810 const gchar *gst_tag;
2811 guint16 val_length;
2812 gchar *val_utf8;
2813 } tags[5] = {
2814 {
2815 GST_TAG_TITLE, 0, NULL}, {
2816 GST_TAG_ARTIST, 0, NULL}, {
2817 GST_TAG_COPYRIGHT, 0, NULL}, {
2818 GST_TAG_DESCRIPTION, 0, NULL}, {
2819 GST_TAG_COMMENT, 0, NULL}
2820 };
2821 GstTagList *taglist;
2822 GValue value = { 0 };
2823 gsize in, out;
2824 gint i = -1;
2826 GST_INFO_OBJECT (demux, "object is a comment");
2828 if (size < (2 + 2 + 2 + 2 + 2))
2829 goto not_enough_data;
2831 tags[0].val_length = gst_asf_demux_get_uint16 (&data, &size);
2832 tags[1].val_length = gst_asf_demux_get_uint16 (&data, &size);
2833 tags[2].val_length = gst_asf_demux_get_uint16 (&data, &size);
2834 tags[3].val_length = gst_asf_demux_get_uint16 (&data, &size);
2835 tags[4].val_length = gst_asf_demux_get_uint16 (&data, &size);
2837 GST_DEBUG_OBJECT (demux, "Comment lengths: title=%d author=%d copyright=%d "
2838 "description=%d rating=%d", tags[0].val_length, tags[1].val_length,
2839 tags[2].val_length, tags[3].val_length, tags[4].val_length);
2841 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
2842 if (size < tags[i].val_length)
2843 goto not_enough_data;
2845 /* might be just '/0', '/0'... */
2846 if (tags[i].val_length > 2 && tags[i].val_length % 2 == 0) {
2847 /* convert to UTF-8 */
2848 tags[i].val_utf8 = g_convert ((gchar *) data, tags[i].val_length,
2849 "UTF-8", "UTF-16LE", &in, &out, NULL);
2850 }
2851 gst_asf_demux_skip_bytes (tags[i].val_length, &data, &size);
2852 }
2854 /* parse metadata into taglist */
2855 taglist = gst_tag_list_new ();
2856 g_value_init (&value, G_TYPE_STRING);
2857 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
2858 if (tags[i].val_utf8 && strlen (tags[i].val_utf8) > 0 && tags[i].gst_tag) {
2859 g_value_set_string (&value, tags[i].val_utf8);
2860 gst_tag_list_add_values (taglist, GST_TAG_MERGE_APPEND,
2861 tags[i].gst_tag, &value, NULL);
2862 }
2863 }
2864 g_value_unset (&value);
2866 gst_asf_demux_add_global_tags (demux, taglist);
2868 for (i = 0; i < G_N_ELEMENTS (tags); ++i)
2869 g_free (tags[i].val_utf8);
2871 return GST_FLOW_OK;
2873 not_enough_data:
2874 {
2875 GST_WARNING_OBJECT (demux, "unexpectedly short of data while processing "
2876 "comment tag section %d, skipping comment object", i);
2877 for (i = 0; i < G_N_ELEMENTS (tags); i++)
2878 g_free (tags[i].val_utf8);
2879 return GST_FLOW_OK; /* not really fatal */
2880 }
2881 }
2883 static GstFlowReturn
2884 gst_asf_demux_process_bitrate_props_object (GstASFDemux * demux, guint8 * data,
2885 guint64 size)
2886 {
2887 guint16 num_streams, i;
2889 if (size < 2)
2890 goto not_enough_data;
2892 num_streams = gst_asf_demux_get_uint16 (&data, &size);
2894 GST_INFO ("object is a bitrate properties object with %u streams",
2895 num_streams);
2897 if (size < (num_streams * (2 + 4)))
2898 goto not_enough_data;
2900 for (i = 0; i < num_streams; ++i) {
2901 guint32 bitrate;
2902 guint16 stream_id;
2904 stream_id = gst_asf_demux_get_uint16 (&data, &size);
2905 bitrate = gst_asf_demux_get_uint32 (&data, &size);
2907 if (stream_id < GST_ASF_DEMUX_NUM_STREAM_IDS) {
2908 demux->bitrate[stream_id] = bitrate;
2909 GST_DEBUG ("bitrate[%u] = %u", stream_id, bitrate);
2910 } else {
2911 GST_WARNING ("stream id %u is too large", stream_id);
2912 }
2913 }
2915 return GST_FLOW_OK;
2917 not_enough_data:
2918 {
2919 GST_WARNING_OBJECT (demux, "short read parsing bitrate props object!");
2920 return GST_FLOW_OK; /* not really fatal */
2921 }
2922 }
2924 static GstFlowReturn
2925 gst_asf_demux_process_header_ext (GstASFDemux * demux, guint8 * data,
2926 guint64 size)
2927 {
2928 GstFlowReturn ret = GST_FLOW_OK;
2929 guint64 hdr_size;
2931 /* Get the rest of the header's header */
2932 if (size < (16 + 2 + 4))
2933 goto not_enough_data;
2935 /* skip GUID and two other bytes */
2936 gst_asf_demux_skip_bytes (16 + 2, &data, &size);
2937 hdr_size = gst_asf_demux_get_uint32 (&data, &size);
2939 GST_INFO ("extended header object with a size of %u bytes", (guint) size);
2941 /* FIXME: does data_size include the rest of the header that we have read? */
2942 if (hdr_size > size)
2943 goto not_enough_data;
2945 while (hdr_size > 0) {
2946 ret = gst_asf_demux_process_object (demux, &data, &hdr_size);
2947 if (ret != GST_FLOW_OK)
2948 break;
2949 }
2951 return ret;
2953 not_enough_data:
2954 {
2955 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
2956 ("short read parsing extended header object"));
2957 return GST_FLOW_ERROR;
2958 }
2959 }
2961 static GstFlowReturn
2962 gst_asf_demux_process_language_list (GstASFDemux * demux, guint8 * data,
2963 guint64 size)
2964 {
2965 guint i;
2967 if (size < 2)
2968 goto not_enough_data;
2970 if (demux->languages) {
2971 GST_WARNING ("More than one LANGUAGE_LIST object in stream");
2972 g_strfreev (demux->languages);
2973 demux->languages = NULL;
2974 demux->num_languages = 0;
2975 }
2977 demux->num_languages = gst_asf_demux_get_uint16 (&data, &size);
2978 GST_LOG ("%u languages:", demux->num_languages);
2980 demux->languages = g_new0 (gchar *, demux->num_languages + 1);
2981 for (i = 0; i < demux->num_languages; ++i) {
2982 guint8 len, *lang_data = NULL;
2984 if (size < 1)
2985 goto not_enough_data;
2986 len = gst_asf_demux_get_uint8 (&data, &size);
2987 if (gst_asf_demux_get_bytes (&lang_data, len, &data, &size)) {
2988 gchar *utf8;
2990 utf8 = g_convert ((gchar *) lang_data, len, "UTF-8", "UTF-16LE", NULL,
2991 NULL, NULL);
2993 /* truncate "en-us" etc. to just "en" */
2994 if (utf8 && strlen (utf8) >= 5 && (utf8[2] == '-' || utf8[2] == '_')) {
2995 utf8[2] = '\0';
2996 }
2997 GST_DEBUG ("[%u] %s", i, GST_STR_NULL (utf8));
2998 demux->languages[i] = utf8;
2999 g_free (lang_data);
3000 } else {
3001 goto not_enough_data;
3002 }
3003 }
3005 return GST_FLOW_OK;
3007 not_enough_data:
3008 {
3009 GST_WARNING_OBJECT (demux, "short read parsing language list object!");
3010 g_free (demux->languages);
3011 demux->languages = NULL;
3012 return GST_FLOW_OK; /* not fatal */
3013 }
3014 }
3016 static GstFlowReturn
3017 gst_asf_demux_process_simple_index (GstASFDemux * demux, guint8 * data,
3018 guint64 size)
3019 {
3020 GstClockTime interval;
3021 guint32 x, count, i;
3023 if (size < (16 + 8 + 4 + 4))
3024 goto not_enough_data;
3026 /* skip file id */
3027 gst_asf_demux_skip_bytes (16, &data, &size);
3028 interval = gst_asf_demux_get_uint64 (&data, &size) * (GstClockTime) 100;
3029 x = gst_asf_demux_get_uint32 (&data, &size);
3030 count = gst_asf_demux_get_uint32 (&data, &size);
3031 if (count > 0) {
3032 demux->sidx_interval = interval;
3033 demux->sidx_num_entries = count;
3034 g_free (demux->sidx_entries);
3035 demux->sidx_entries = g_new0 (AsfSimpleIndexEntry, count);
3037 for (i = 0; i < count; ++i) {
3038 if (G_UNLIKELY (size <= 6))
3039 break;
3040 demux->sidx_entries[i].packet = gst_asf_demux_get_uint32 (&data, &size);
3041 demux->sidx_entries[i].count = gst_asf_demux_get_uint16 (&data, &size);
3042 GST_LOG_OBJECT (demux, "%" GST_TIME_FORMAT " = packet %4u count : %2d",
3043 GST_TIME_ARGS (i * interval), demux->sidx_entries[i].packet,
3044 demux->sidx_entries[i].count);
3045 }
3046 } else {
3047 GST_DEBUG_OBJECT (demux, "simple index object with 0 entries");
3048 }
3050 return GST_FLOW_OK;
3052 not_enough_data:
3053 {
3054 GST_WARNING_OBJECT (demux, "short read parsing simple index object!");
3055 return GST_FLOW_OK; /* not fatal */
3056 }
3057 }
3059 static GstFlowReturn
3060 gst_asf_demux_process_advanced_mutual_exclusion (GstASFDemux * demux,
3061 guint8 * data, guint64 size)
3062 {
3063 ASFGuid guid;
3064 guint16 num, i;
3065 guint8 *mes;
3067 if (size < 16 + 2 + (2 * 2))
3068 goto not_enough_data;
3070 gst_asf_demux_get_guid (&guid, &data, &size);
3071 num = gst_asf_demux_get_uint16 (&data, &size);
3073 if (num < 2) {
3074 GST_WARNING_OBJECT (demux, "nonsensical mutually exclusive streams count");
3075 return GST_FLOW_OK;
3076 }
3078 if (size < (num * sizeof (guint16)))
3079 goto not_enough_data;
3081 /* read mutually exclusive stream numbers */
3082 mes = g_new (guint8, num + 1);
3083 for (i = 0; i < num; ++i) {
3084 mes[i] = gst_asf_demux_get_uint16 (&data, &size) & 0x7f;
3085 GST_LOG_OBJECT (demux, "mutually exclusive: stream #%d", mes[i]);
3086 }
3088 /* add terminator so we can easily get the count or know when to stop */
3089 mes[i] = (guint8) - 1;
3091 demux->mut_ex_streams = g_slist_append (demux->mut_ex_streams, mes);
3093 return GST_FLOW_OK;
3095 /* Errors */
3096 not_enough_data:
3097 {
3098 GST_WARNING_OBJECT (demux, "short read parsing advanced mutual exclusion");
3099 return GST_FLOW_OK; /* not absolutely fatal */
3100 }
3101 }
3103 static GstFlowReturn
3104 gst_asf_demux_process_ext_stream_props (GstASFDemux * demux, guint8 * data,
3105 guint64 size)
3106 {
3107 AsfStreamExtProps esp;
3108 AsfStream *stream = NULL;
3109 AsfObject stream_obj;
3110 guint16 stream_name_count;
3111 guint16 num_payload_ext;
3112 guint64 len;
3113 guint8 *stream_obj_data = NULL;
3114 guint8 *data_start;
3115 guint obj_size;
3116 guint i, stream_num;
3118 data_start = data;
3119 obj_size = (guint) size;
3121 if (size < 64)
3122 goto not_enough_data;
3124 esp.valid = TRUE;
3125 esp.start_time = gst_asf_demux_get_uint64 (&data, &size) * GST_MSECOND;
3126 esp.end_time = gst_asf_demux_get_uint64 (&data, &size) * GST_MSECOND;
3127 esp.data_bitrate = gst_asf_demux_get_uint32 (&data, &size);
3128 esp.buffer_size = gst_asf_demux_get_uint32 (&data, &size);
3129 esp.intial_buf_fullness = gst_asf_demux_get_uint32 (&data, &size);
3130 esp.data_bitrate2 = gst_asf_demux_get_uint32 (&data, &size);
3131 esp.buffer_size2 = gst_asf_demux_get_uint32 (&data, &size);
3132 esp.intial_buf_fullness2 = gst_asf_demux_get_uint32 (&data, &size);
3133 esp.max_obj_size = gst_asf_demux_get_uint32 (&data, &size);
3134 esp.flags = gst_asf_demux_get_uint32 (&data, &size);
3135 stream_num = gst_asf_demux_get_uint16 (&data, &size);
3136 esp.lang_idx = gst_asf_demux_get_uint16 (&data, &size);
3137 esp.avg_time_per_frame = gst_asf_demux_get_uint64 (&data, &size);
3138 stream_name_count = gst_asf_demux_get_uint16 (&data, &size);
3139 num_payload_ext = gst_asf_demux_get_uint16 (&data, &size);
3141 GST_INFO ("start_time = %" GST_TIME_FORMAT,
3142 GST_TIME_ARGS (esp.start_time));
3143 GST_INFO ("end_time = %" GST_TIME_FORMAT,
3144 GST_TIME_ARGS (esp.end_time));
3145 GST_INFO ("flags = %08x", esp.flags);
3146 GST_INFO ("average time per frame = %" GST_TIME_FORMAT,
3147 GST_TIME_ARGS (esp.avg_time_per_frame * 100));
3148 GST_INFO ("stream number = %u", stream_num);
3149 GST_INFO ("stream language ID idx = %u (%s)", esp.lang_idx,
3150 (esp.lang_idx < demux->num_languages) ?
3151 GST_STR_NULL (demux->languages[esp.lang_idx]) : "??");
3152 GST_INFO ("stream name count = %u", stream_name_count);
3154 /* read stream names */
3155 for (i = 0; i < stream_name_count; ++i) {
3156 guint16 stream_lang_idx;
3157 gchar *stream_name = NULL;
3159 if (size < 2)
3160 goto not_enough_data;
3161 stream_lang_idx = gst_asf_demux_get_uint16 (&data, &size);
3162 if (!gst_asf_demux_get_string (&stream_name, NULL, &data, &size))
3163 goto not_enough_data;
3164 GST_INFO ("stream name %d: %s", i, GST_STR_NULL (stream_name));
3165 g_free (stream_name); /* TODO: store names in struct */
3166 }
3168 /* read payload extension systems stuff */
3169 GST_LOG ("payload extension systems count = %u", num_payload_ext);
3171 if (num_payload_ext > 0)
3172 esp.payload_extensions = g_new0 (AsfPayloadExtension, num_payload_ext + 1);
3173 else
3174 esp.payload_extensions = NULL;
3176 for (i = 0; i < num_payload_ext; ++i) {
3177 AsfPayloadExtension ext;
3178 ASFGuid ext_guid;
3179 guint32 sys_info_len;
3181 if (size < 16 + 2 + 4)
3182 goto not_enough_data;
3184 gst_asf_demux_get_guid (&ext_guid, &data, &size);
3185 ext.id = gst_asf_demux_identify_guid (asf_payload_ext_guids, &ext_guid);
3186 ext.len = gst_asf_demux_get_uint16 (&data, &size);
3188 sys_info_len = gst_asf_demux_get_uint32 (&data, &size);
3189 GST_LOG ("payload systems info len = %u", sys_info_len);
3190 if (!gst_asf_demux_skip_bytes (sys_info_len, &data, &size))
3191 goto not_enough_data;
3193 esp.payload_extensions[i] = ext;
3194 }
3196 GST_LOG ("bytes read: %u/%u", (guint) (data - data_start), obj_size);
3198 /* there might be an optional STREAM_INFO object here now; if not, we
3199 * should have parsed the corresponding stream info object already (since
3200 * we are parsing the extended stream properties objects delayed) */
3201 if (size == 0) {
3202 stream = gst_asf_demux_get_stream (demux, stream_num);
3203 goto done;
3204 }
3206 /* get size of the stream object */
3207 if (!asf_demux_peek_object (demux, data, size, &stream_obj, TRUE))
3208 goto not_enough_data;
3210 if (stream_obj.id != ASF_OBJ_STREAM)
3211 goto expected_stream_object;
3213 if (stream_obj.size < ASF_OBJECT_HEADER_SIZE ||
3214 stream_obj.size > (10 * 1024 * 1024))
3215 goto not_enough_data;
3217 gst_asf_demux_skip_bytes (ASF_OBJECT_HEADER_SIZE, &data, &size);
3219 /* process this stream object later after all the other 'normal' ones
3220 * have been processed (since the others are more important/non-hidden) */
3221 len = stream_obj.size - ASF_OBJECT_HEADER_SIZE;
3222 if (!gst_asf_demux_get_bytes (&stream_obj_data, len, &data, &size))
3223 goto not_enough_data;
3225 /* parse stream object */
3226 stream = gst_asf_demux_parse_stream_object (demux, stream_obj_data, len);
3227 g_free (stream_obj_data);
3229 done:
3231 if (stream) {
3232 stream->ext_props = esp;
3234 /* try to set the framerate */
3235 if (stream->is_video && stream->caps) {
3236 GValue framerate = { 0 };
3237 GstStructure *s;
3238 gint num, denom;
3240 g_value_init (&framerate, GST_TYPE_FRACTION);
3242 num = GST_SECOND / 100;
3243 denom = esp.avg_time_per_frame;
3244 if (denom == 0) {
3245 /* avoid division by 0, assume 25/1 framerate */
3246 denom = GST_SECOND / 2500;
3247 }
3249 gst_value_set_fraction (&framerate, num, denom);
3251 stream->caps = gst_caps_make_writable (stream->caps);
3252 s = gst_caps_get_structure (stream->caps, 0);
3253 gst_structure_set_value (s, "framerate", &framerate);
3254 g_value_unset (&framerate);
3255 GST_DEBUG_OBJECT (demux, "setting framerate of %d/%d = %f",
3256 num, denom, ((gdouble) num) / denom);
3257 }
3259 /* add language info now if we have it */
3260 if (stream->ext_props.lang_idx < demux->num_languages) {
3261 if (stream->pending_tags == NULL)
3262 stream->pending_tags = gst_tag_list_new ();
3263 GST_LOG_OBJECT (demux, "stream %u has language '%s'", stream->id,
3264 demux->languages[stream->ext_props.lang_idx]);
3265 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_APPEND,
3266 GST_TAG_LANGUAGE_CODE, demux->languages[stream->ext_props.lang_idx],
3267 NULL);
3268 }
3269 } else {
3270 GST_WARNING_OBJECT (demux, "Ext. stream properties for unknown stream");
3271 }
3273 return GST_FLOW_OK;
3275 /* Errors */
3276 not_enough_data:
3277 {
3278 GST_WARNING_OBJECT (demux, "short read parsing ext stream props object!");
3279 return GST_FLOW_OK; /* not absolutely fatal */
3280 }
3281 expected_stream_object:
3282 {
3283 GST_WARNING_OBJECT (demux, "error parsing extended stream properties "
3284 "object: expected embedded stream object, but got %s object instead!",
3285 gst_asf_get_guid_nick (asf_object_guids, stream_obj.id));
3286 return GST_FLOW_OK; /* not absolutely fatal */
3287 }
3288 }
3290 static const gchar *
3291 gst_asf_demux_push_obj (GstASFDemux * demux, guint32 obj_id)
3292 {
3293 const gchar *nick;
3295 nick = gst_asf_get_guid_nick (asf_object_guids, obj_id);
3296 if (g_str_has_prefix (nick, "ASF_OBJ_"))
3297 nick += strlen ("ASF_OBJ_");
3299 if (demux->objpath == NULL) {
3300 demux->objpath = g_strdup (nick);
3301 } else {
3302 gchar *newpath;
3304 newpath = g_strdup_printf ("%s/%s", demux->objpath, nick);
3305 g_free (demux->objpath);
3306 demux->objpath = newpath;
3307 }
3309 return (const gchar *) demux->objpath;
3310 }
3312 static void
3313 gst_asf_demux_pop_obj (GstASFDemux * demux)
3314 {
3315 gchar *s;
3317 if ((s = g_strrstr (demux->objpath, "/"))) {
3318 *s = '\0';
3319 } else {
3320 g_free (demux->objpath);
3321 demux->objpath = NULL;
3322 }
3323 }
3325 static void
3326 gst_asf_demux_process_queued_extended_stream_objects (GstASFDemux * demux)
3327 {
3328 GSList *l;
3329 guint i;
3331 /* Parse the queued extended stream property objects and add the info
3332 * to the existing streams or add the new embedded streams, but without
3333 * activating them yet */
3334 GST_LOG_OBJECT (demux, "%u queued extended stream properties objects",
3335 g_slist_length (demux->ext_stream_props));
3337 for (l = demux->ext_stream_props, i = 0; l != NULL; l = l->next, ++i) {
3338 GstBuffer *buf = GST_BUFFER (l->data);
3340 GST_LOG_OBJECT (demux, "parsing ext. stream properties object #%u", i);
3341 gst_asf_demux_process_ext_stream_props (demux, GST_BUFFER_DATA (buf),
3342 GST_BUFFER_SIZE (buf));
3343 gst_buffer_unref (buf);
3344 }
3345 g_slist_free (demux->ext_stream_props);
3346 demux->ext_stream_props = NULL;
3347 }
3349 #if 0
3350 static void
3351 gst_asf_demux_activate_ext_props_streams (GstASFDemux * demux)
3352 {
3353 guint i, j;
3355 for (i = 0; i < demux->num_streams; ++i) {
3356 AsfStream *stream;
3357 gboolean is_hidden;
3358 GSList *x;
3360 stream = &demux->stream[i];
3362 GST_LOG_OBJECT (demux, "checking stream %2u", stream->id);
3364 if (stream->active) {
3365 GST_LOG_OBJECT (demux, "stream %2u is already activated", stream->id);
3366 continue;
3367 }
3369 is_hidden = FALSE;
3370 for (x = demux->mut_ex_streams; x != NULL; x = x->next) {
3371 guint8 *mes;
3373 /* check for each mutual exclusion whether it affects this stream */
3374 for (mes = (guint8 *) x->data; mes != NULL && *mes != 0xff; ++mes) {
3375 if (*mes == stream->id) {
3376 /* if yes, check if we've already added streams that are mutually
3377 * exclusive with the stream we're about to add */
3378 for (mes = (guint8 *) x->data; mes != NULL && *mes != 0xff; ++mes) {
3379 for (j = 0; j < demux->num_streams; ++j) {
3380 /* if the broadcast flag is set, assume the hidden streams aren't
3381 * actually streamed and hide them (or playbin won't work right),
3382 * otherwise assume their data is available */
3383 if (demux->stream[j].id == *mes && demux->broadcast) {
3384 is_hidden = TRUE;
3385 GST_LOG_OBJECT (demux, "broadcast stream ID %d to be added is "
3386 "mutually exclusive with already existing stream ID %d, "
3387 "hiding stream", stream->id, demux->stream[j].id);
3388 goto next;
3389 }
3390 }
3391 }
3392 break;
3393 }
3394 }
3395 }
3397 next:
3399 /* FIXME: we should do stream activation based on preroll data in
3400 * streaming mode too */
3401 if (demux->streaming && !is_hidden)
3402 gst_asf_demux_activate_stream (demux, stream);
3403 }
3404 }
3405 #endif
3407 static GstFlowReturn
3408 gst_asf_demux_process_object (GstASFDemux * demux, guint8 ** p_data,
3409 guint64 * p_size)
3410 {
3411 GstFlowReturn ret = GST_FLOW_OK;
3412 AsfObject obj;
3413 guint64 obj_data_size;
3415 if (*p_size < ASF_OBJECT_HEADER_SIZE)
3416 return ASF_FLOW_NEED_MORE_DATA;
3418 asf_demux_peek_object (demux, *p_data, ASF_OBJECT_HEADER_SIZE, &obj, TRUE);
3419 gst_asf_demux_skip_bytes (ASF_OBJECT_HEADER_SIZE, p_data, p_size);
3421 obj_data_size = obj.size - ASF_OBJECT_HEADER_SIZE;
3423 if (*p_size < obj_data_size)
3424 return ASF_FLOW_NEED_MORE_DATA;
3426 gst_asf_demux_push_obj (demux, obj.id);
3428 GST_INFO ("%s: size %" G_GUINT64_FORMAT, demux->objpath, obj.size);
3430 switch (obj.id) {
3431 case ASF_OBJ_STREAM:{
3432 AsfStream *stream;
3434 stream =
3435 gst_asf_demux_parse_stream_object (demux, *p_data, obj_data_size);
3437 ret = GST_FLOW_OK;
3438 break;
3439 }
3440 case ASF_OBJ_FILE:
3441 ret = gst_asf_demux_process_file (demux, *p_data, obj_data_size);
3442 break;
3443 case ASF_OBJ_HEADER:
3444 ret = gst_asf_demux_process_header (demux, *p_data, obj_data_size);
3445 break;
3446 case ASF_OBJ_COMMENT:
3447 ret = gst_asf_demux_process_comment (demux, *p_data, obj_data_size);
3448 break;
3449 case ASF_OBJ_HEAD1:
3450 ret = gst_asf_demux_process_header_ext (demux, *p_data, obj_data_size);
3451 break;
3452 case ASF_OBJ_BITRATE_PROPS:
3453 ret =
3454 gst_asf_demux_process_bitrate_props_object (demux, *p_data,
3455 obj_data_size);
3456 break;
3457 case ASF_OBJ_EXT_CONTENT_DESC:
3458 ret =
3459 gst_asf_demux_process_ext_content_desc (demux, *p_data,
3460 obj_data_size);
3461 break;
3462 case ASF_OBJ_METADATA_OBJECT:
3463 ret = gst_asf_demux_process_metadata (demux, *p_data, obj_data_size);
3464 break;
3465 case ASF_OBJ_EXTENDED_STREAM_PROPS:{
3466 GstBuffer *buf;
3468 /* process these later, we might not have parsed the corresponding
3469 * stream object yet */
3470 GST_LOG ("%s: queued for later parsing", demux->objpath);
3471 buf = gst_buffer_new_and_alloc (obj_data_size);
3472 memcpy (GST_BUFFER_DATA (buf), *p_data, obj_data_size);
3473 demux->ext_stream_props = g_slist_append (demux->ext_stream_props, buf);
3474 ret = GST_FLOW_OK;
3475 break;
3476 }
3477 case ASF_OBJ_LANGUAGE_LIST:
3478 ret = gst_asf_demux_process_language_list (demux, *p_data, obj_data_size);
3479 break;
3480 case ASF_OBJ_ADVANCED_MUTUAL_EXCLUSION:
3481 ret = gst_asf_demux_process_advanced_mutual_exclusion (demux, *p_data,
3482 obj_data_size);
3483 break;
3484 case ASF_OBJ_SIMPLE_INDEX:
3485 ret = gst_asf_demux_process_simple_index (demux, *p_data, obj_data_size);
3486 break;
3487 case ASF_OBJ_CONTENT_ENCRYPTION:
3488 case ASF_OBJ_EXT_CONTENT_ENCRYPTION:
3489 case ASF_OBJ_DIGITAL_SIGNATURE_OBJECT:
3490 goto error_encrypted;
3491 case ASF_OBJ_CONCEAL_NONE:
3492 case ASF_OBJ_HEAD2:
3493 case ASF_OBJ_UNDEFINED:
3494 case ASF_OBJ_CODEC_COMMENT:
3495 case ASF_OBJ_INDEX:
3496 case ASF_OBJ_PADDING:
3497 case ASF_OBJ_BITRATE_MUTEX:
3498 case ASF_OBJ_COMPATIBILITY:
3499 case ASF_OBJ_INDEX_PLACEHOLDER:
3500 case ASF_OBJ_INDEX_PARAMETERS:
3501 case ASF_OBJ_STREAM_PRIORITIZATION:
3502 case ASF_OBJ_SCRIPT_COMMAND:
3503 default:
3504 /* Unknown/unhandled object, skip it and hope for the best */
3505 GST_INFO ("%s: skipping object", demux->objpath);
3506 ret = GST_FLOW_OK;
3507 break;
3508 }
3510 /* this can't fail, we checked the number of bytes available before */
3511 gst_asf_demux_skip_bytes (obj_data_size, p_data, p_size);
3513 GST_LOG ("%s: ret = %s", demux->objpath, gst_asf_get_flow_name (ret));
3515 gst_asf_demux_pop_obj (demux);
3517 return ret;
3519 /* ERRORS */
3520 error_encrypted:
3521 {
3522 GST_ELEMENT_ERROR (demux, STREAM, DECRYPT, (NULL), (NULL));
3523 return GST_FLOW_ERROR;
3524 }
3525 }
3527 static void
3528 gst_asf_demux_descramble_buffer (GstASFDemux * demux, AsfStream * stream,
3529 GstBuffer ** p_buffer)
3530 {
3531 GstBuffer *descrambled_buffer;
3532 GstBuffer *scrambled_buffer;
3533 GstBuffer *sub_buffer;
3534 guint offset;
3535 guint off;
3536 guint row;
3537 guint col;
3538 guint idx;
3540 /* descrambled_buffer is initialised in the first iteration */
3541 descrambled_buffer = NULL;
3542 scrambled_buffer = *p_buffer;
3544 if (GST_BUFFER_SIZE (scrambled_buffer) < demux->ds_packet_size * demux->span)
3545 return;
3547 for (offset = 0; offset < GST_BUFFER_SIZE (scrambled_buffer);
3548 offset += demux->ds_chunk_size) {
3549 off = offset / demux->ds_chunk_size;
3550 row = off / demux->span;
3551 col = off % demux->span;
3552 idx = row + col * demux->ds_packet_size / demux->ds_chunk_size;
3553 GST_DEBUG ("idx=%u, row=%u, col=%u, off=%u, ds_chunk_size=%u", idx, row,
3554 col, off, demux->ds_chunk_size);
3555 GST_DEBUG ("scrambled buffer size=%u, span=%u, packet_size=%u",
3556 GST_BUFFER_SIZE (scrambled_buffer), demux->span, demux->ds_packet_size);
3557 GST_DEBUG ("GST_BUFFER_SIZE (scrambled_buffer) = %u",
3558 GST_BUFFER_SIZE (scrambled_buffer));
3559 sub_buffer =
3560 gst_buffer_create_sub (scrambled_buffer, idx * demux->ds_chunk_size,
3561 demux->ds_chunk_size);
3562 if (!offset) {
3563 descrambled_buffer = sub_buffer;
3564 } else {
3565 descrambled_buffer = gst_buffer_join (descrambled_buffer, sub_buffer);
3566 }
3567 }
3569 gst_buffer_copy_metadata (descrambled_buffer, scrambled_buffer,
3570 GST_BUFFER_COPY_TIMESTAMPS);
3572 /* FIXME/CHECK: do we need to transfer buffer flags here too? */
3574 gst_buffer_unref (scrambled_buffer);
3575 *p_buffer = descrambled_buffer;
3576 }
3578 static gboolean
3579 gst_asf_demux_element_send_event (GstElement * element, GstEvent * event)
3580 {
3581 GstASFDemux *demux = GST_ASF_DEMUX (element);
3582 gint i;
3584 GST_DEBUG ("handling element event of type %s", GST_EVENT_TYPE_NAME (event));
3586 for (i = 0; i < demux->num_streams; ++i) {
3587 gst_event_ref (event);
3588 if (gst_asf_demux_handle_src_event (demux->stream[i].pad, event)) {
3589 gst_event_unref (event);
3590 return TRUE;
3591 }
3592 }
3594 gst_event_unref (event);
3595 return FALSE;
3596 }
3598 /* takes ownership of the passed event */
3599 static gboolean
3600 gst_asf_demux_send_event_unlocked (GstASFDemux * demux, GstEvent * event)
3601 {
3602 gboolean ret = TRUE;
3603 gint i;
3605 GST_DEBUG_OBJECT (demux, "sending %s event to all source pads",
3606 GST_EVENT_TYPE_NAME (event));
3608 for (i = 0; i < demux->num_streams; ++i) {
3609 gst_event_ref (event);
3610 ret &= gst_pad_push_event (demux->stream[i].pad, event);
3611 }
3612 gst_event_unref (event);
3613 return ret;
3614 }
3616 static const GstQueryType *
3617 gst_asf_demux_get_src_query_types (GstPad * pad)
3618 {
3619 static const GstQueryType types[] = {
3620 GST_QUERY_POSITION,
3621 GST_QUERY_DURATION,
3622 GST_QUERY_SEEKING,
3623 0
3624 };
3626 return types;
3627 }
3629 static gboolean
3630 gst_asf_demux_handle_src_query (GstPad * pad, GstQuery * query)
3631 {
3632 GstASFDemux *demux;
3633 gboolean res = FALSE;
3635 demux = GST_ASF_DEMUX (gst_pad_get_parent (pad));
3637 GST_DEBUG ("handling %s query",
3638 gst_query_type_get_name (GST_QUERY_TYPE (query)));
3640 switch (GST_QUERY_TYPE (query)) {
3641 case GST_QUERY_DURATION:
3642 {
3643 GstFormat format;
3645 gst_query_parse_duration (query, &format, NULL);
3647 if (format != GST_FORMAT_TIME) {
3648 GST_LOG ("only support duration queries in TIME format");
3649 break;
3650 }
3652 GST_OBJECT_LOCK (demux);
3654 if (demux->segment.duration != GST_CLOCK_TIME_NONE) {
3655 GST_LOG ("returning duration: %" GST_TIME_FORMAT,
3656 GST_TIME_ARGS (demux->segment.duration));
3658 gst_query_set_duration (query, GST_FORMAT_TIME,
3659 demux->segment.duration);
3661 res = TRUE;
3662 } else {
3663 GST_LOG ("duration not known yet");
3664 }
3666 GST_OBJECT_UNLOCK (demux);
3667 break;
3668 }
3670 case GST_QUERY_POSITION:{
3671 GstFormat format;
3673 gst_query_parse_position (query, &format, NULL);
3675 if (format != GST_FORMAT_TIME) {
3676 GST_LOG ("only support position queries in TIME format");
3677 break;
3678 }
3680 GST_OBJECT_LOCK (demux);
3682 if (demux->segment.last_stop != GST_CLOCK_TIME_NONE) {
3683 GST_LOG ("returning position: %" GST_TIME_FORMAT,
3684 GST_TIME_ARGS (demux->segment.last_stop));
3686 gst_query_set_position (query, GST_FORMAT_TIME,
3687 demux->segment.last_stop);
3689 res = TRUE;
3690 } else {
3691 GST_LOG ("position not known yet");
3692 }
3694 GST_OBJECT_UNLOCK (demux);
3695 break;
3696 }
3698 case GST_QUERY_SEEKING:{
3699 GstFormat format;
3701 gst_query_parse_seeking (query, &format, NULL, NULL, NULL);
3702 if (format == GST_FORMAT_TIME) {
3703 gint64 duration;
3705 GST_OBJECT_LOCK (demux);
3706 duration = demux->segment.duration;
3707 GST_OBJECT_UNLOCK (demux);
3709 if (!demux->streaming || !demux->seekable) {
3710 gst_query_set_seeking (query, GST_FORMAT_TIME, demux->seekable, 0,
3711 duration);
3712 res = TRUE;
3713 } else {
3714 GstFormat fmt;
3715 gboolean seekable;
3717 /* try downstream first in TIME */
3718 res = gst_pad_query_default (pad, query);
3720 gst_query_parse_seeking (query, &fmt, &seekable, NULL, NULL);
3721 GST_LOG_OBJECT (demux, "upstream %s seekable %d",
3722 GST_STR_NULL (gst_format_get_name (fmt)), seekable);
3723 /* if no luck, maybe in BYTES */
3724 if (!seekable || fmt != GST_FORMAT_TIME) {
3725 GstQuery *q;
3727 q = gst_query_new_seeking (GST_FORMAT_BYTES);
3728 if ((res = gst_pad_peer_query (demux->sinkpad, q))) {
3729 gst_query_parse_seeking (q, &fmt, &seekable, NULL, NULL);
3730 GST_LOG_OBJECT (demux, "upstream %s seekable %d",
3731 GST_STR_NULL (gst_format_get_name (fmt)), seekable);
3732 if (fmt != GST_FORMAT_BYTES)
3733 seekable = FALSE;
3734 }
3735 gst_query_unref (q);
3736 gst_query_set_seeking (query, GST_FORMAT_TIME, seekable, 0,
3737 duration);
3738 res = TRUE;
3739 }
3740 }
3741 } else
3742 GST_LOG_OBJECT (demux, "only support seeking in TIME format");
3743 break;
3744 }
3746 case GST_QUERY_LATENCY:
3747 {
3748 gboolean live;
3749 GstClockTime min, max;
3751 /* preroll delay does not matter in non-live pipeline,
3752 * but we might end up in a live (rtsp) one ... */
3754 /* first forward */
3755 res = gst_pad_query_default (pad, query);
3756 if (!res)
3757 break;
3759 gst_query_parse_latency (query, &live, &min, &max);
3761 GST_DEBUG_OBJECT (demux, "Peer latency: live %d, min %"
3762 GST_TIME_FORMAT " max %" GST_TIME_FORMAT, live,
3763 GST_TIME_ARGS (min), GST_TIME_ARGS (max));
3765 GST_OBJECT_LOCK (demux);
3766 if (min != -1)
3767 min += demux->latency;
3768 if (max != -1)
3769 max += demux->latency;
3770 GST_OBJECT_UNLOCK (demux);
3772 gst_query_set_latency (query, live, min, max);
3773 break;
3774 }
3775 default:
3776 res = gst_pad_query_default (pad, query);
3777 break;
3778 }
3780 gst_object_unref (demux);
3781 return res;
3782 }
3784 static GstStateChangeReturn
3785 gst_asf_demux_change_state (GstElement * element, GstStateChange transition)
3786 {
3787 GstASFDemux *demux = GST_ASF_DEMUX (element);
3788 GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
3790 switch (transition) {
3791 case GST_STATE_CHANGE_NULL_TO_READY:{
3792 gst_segment_init (&demux->segment, GST_FORMAT_TIME);
3793 demux->need_newsegment = TRUE;
3794 demux->segment_running = FALSE;
3795 demux->accurate = FALSE;
3796 demux->adapter = gst_adapter_new ();
3797 demux->metadata = gst_caps_new_empty ();
3798 demux->global_metadata = gst_structure_empty_new ("metadata");
3799 demux->data_size = 0;
3800 demux->data_offset = 0;
3801 demux->index_offset = 0;
3802 break;
3803 }
3804 default:
3805 break;
3806 }
3808 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
3809 if (ret == GST_STATE_CHANGE_FAILURE)
3810 return ret;
3812 switch (transition) {
3813 case GST_STATE_CHANGE_PAUSED_TO_READY:
3814 case GST_STATE_CHANGE_READY_TO_NULL:
3815 gst_asf_demux_reset (demux, FALSE);
3816 break;
3817 default:
3818 break;
3819 }
3821 return ret;
3822 }