743e432a2b42ebc35229b9ba89abe28375a2ce19
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 /* FIXME 0.11: suppress warnings for deprecated API such as GStaticRecMutex
36 * with newer GLib versions (>= 2.31.0) */
37 #define GLIB_DISABLE_DEPRECATION_WARNINGS
39 #include <gst/gstutils.h>
40 #include <gst/base/gstbytereader.h>
41 #include <gst/riff/riff-media.h>
42 #include <gst/tag/tag.h>
43 #include <gst/gst-i18n-plugin.h>
44 #include <stdio.h>
45 #include <stdlib.h>
46 #include <string.h>
48 #include "gstasfdemux.h"
49 #include "asfheaders.h"
50 #include "asfpacket.h"
52 static GstStaticPadTemplate gst_asf_demux_sink_template =
53 GST_STATIC_PAD_TEMPLATE ("sink",
54 GST_PAD_SINK,
55 GST_PAD_ALWAYS,
56 GST_STATIC_CAPS ("video/x-ms-asf")
57 );
59 static GstStaticPadTemplate audio_src_template =
60 GST_STATIC_PAD_TEMPLATE ("audio_%02d",
61 GST_PAD_SRC,
62 GST_PAD_SOMETIMES,
63 GST_STATIC_CAPS_ANY);
65 static GstStaticPadTemplate video_src_template =
66 GST_STATIC_PAD_TEMPLATE ("video_%02d",
67 GST_PAD_SRC,
68 GST_PAD_SOMETIMES,
69 GST_STATIC_CAPS_ANY);
71 /* size of an ASF object header, ie. GUID (16 bytes) + object size (8 bytes) */
72 #define ASF_OBJECT_HEADER_SIZE (16+8)
74 /* FIXME: get rid of this */
75 /* abuse this GstFlowReturn enum for internal usage */
76 #define ASF_FLOW_NEED_MORE_DATA 99
78 #define gst_asf_get_flow_name(flow) \
79 (flow == ASF_FLOW_NEED_MORE_DATA) ? \
80 "need-more-data" : gst_flow_get_name (flow)
82 GST_DEBUG_CATEGORY (asfdemux_dbg);
84 static GstStateChangeReturn gst_asf_demux_change_state (GstElement * element,
85 GstStateChange transition);
86 static gboolean gst_asf_demux_element_send_event (GstElement * element,
87 GstEvent * event);
88 static gboolean gst_asf_demux_send_event_unlocked (GstASFDemux * demux,
89 GstEvent * event);
90 static gboolean gst_asf_demux_handle_src_query (GstPad * pad, GstQuery * query);
91 static const GstQueryType *gst_asf_demux_get_src_query_types (GstPad * pad);
92 static GstFlowReturn gst_asf_demux_chain (GstPad * pad, GstBuffer * buf);
93 static gboolean gst_asf_demux_sink_event (GstPad * pad, GstEvent * event);
94 static GstFlowReturn gst_asf_demux_process_object (GstASFDemux * demux,
95 guint8 ** p_data, guint64 * p_size);
96 static gboolean gst_asf_demux_activate (GstPad * sinkpad);
97 static gboolean gst_asf_demux_activate_push (GstPad * sinkpad, gboolean active);
98 static gboolean gst_asf_demux_activate_pull (GstPad * sinkpad, gboolean active);
99 static void gst_asf_demux_loop (GstASFDemux * demux);
100 static void
101 gst_asf_demux_process_queued_extended_stream_objects (GstASFDemux * demux);
102 static gboolean gst_asf_demux_pull_headers (GstASFDemux * demux);
103 static void gst_asf_demux_pull_indices (GstASFDemux * demux);
104 static void gst_asf_demux_reset_stream_state_after_discont (GstASFDemux * asf);
105 static gboolean
106 gst_asf_demux_parse_data_object_start (GstASFDemux * demux, guint8 * data);
107 static void gst_asf_demux_descramble_buffer (GstASFDemux * demux,
108 AsfStream * stream, GstBuffer ** p_buffer);
109 static void gst_asf_demux_activate_stream (GstASFDemux * demux,
110 AsfStream * stream);
111 static GstStructure *gst_asf_demux_get_metadata_for_stream (GstASFDemux * d,
112 guint stream_num);
113 static GstFlowReturn gst_asf_demux_push_complete_payloads (GstASFDemux * demux,
114 gboolean force);
116 GST_BOILERPLATE (GstASFDemux, gst_asf_demux, GstElement, GST_TYPE_ELEMENT);
118 static void
119 gst_asf_demux_base_init (gpointer g_class)
120 {
121 GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
123 gst_element_class_add_static_pad_template (element_class,
124 &audio_src_template);
125 gst_element_class_add_static_pad_template (element_class,
126 &video_src_template);
127 gst_element_class_add_static_pad_template (element_class,
128 &gst_asf_demux_sink_template);
130 gst_element_class_set_details_simple (element_class, "ASF Demuxer",
131 "Codec/Demuxer",
132 "Demultiplexes ASF Streams", "Owen Fraser-Green <owen@discobabe.net>");
133 }
135 static void
136 gst_asf_demux_class_init (GstASFDemuxClass * klass)
137 {
138 GstElementClass *gstelement_class;
140 gstelement_class = (GstElementClass *) klass;
142 gstelement_class->change_state =
143 GST_DEBUG_FUNCPTR (gst_asf_demux_change_state);
144 gstelement_class->send_event =
145 GST_DEBUG_FUNCPTR (gst_asf_demux_element_send_event);
146 }
148 static void
149 gst_asf_demux_free_stream (GstASFDemux * demux, AsfStream * stream)
150 {
151 gst_caps_replace (&stream->caps, NULL);
152 if (stream->pending_tags) {
153 gst_tag_list_free (stream->pending_tags);
154 stream->pending_tags = NULL;
155 }
156 if (stream->pad) {
157 if (stream->active)
158 gst_element_remove_pad (GST_ELEMENT_CAST (demux), stream->pad);
159 else
160 gst_object_unref (stream->pad);
161 stream->pad = NULL;
162 }
164 while (stream->payloads->len > 0) {
165 AsfPayload *payload;
166 guint last;
168 last = stream->payloads->len - 1;
169 payload = &g_array_index (stream->payloads, AsfPayload, last);
170 gst_buffer_replace (&payload->buf, NULL);
171 g_array_remove_index (stream->payloads, last);
172 }
173 if (stream->payloads) {
174 g_array_free (stream->payloads, TRUE);
175 stream->payloads = NULL;
176 }
177 if (stream->ext_props.valid) {
178 g_free (stream->ext_props.payload_extensions);
179 stream->ext_props.payload_extensions = NULL;
180 }
181 }
183 static void
184 gst_asf_demux_reset (GstASFDemux * demux, gboolean chain_reset)
185 {
186 GST_LOG_OBJECT (demux, "resetting");
188 gst_segment_init (&demux->segment, GST_FORMAT_UNDEFINED);
189 demux->segment_running = FALSE;
190 if (demux->adapter && !chain_reset) {
191 gst_adapter_clear (demux->adapter);
192 g_object_unref (demux->adapter);
193 demux->adapter = NULL;
194 }
195 if (demux->taglist) {
196 gst_tag_list_free (demux->taglist);
197 demux->taglist = NULL;
198 }
199 if (demux->metadata) {
200 gst_caps_unref (demux->metadata);
201 demux->metadata = NULL;
202 }
203 if (demux->global_metadata) {
204 gst_structure_free (demux->global_metadata);
205 demux->global_metadata = NULL;
206 }
208 demux->state = GST_ASF_DEMUX_STATE_HEADER;
209 g_free (demux->objpath);
210 demux->objpath = NULL;
211 g_strfreev (demux->languages);
212 demux->languages = NULL;
213 demux->num_languages = 0;
214 g_slist_foreach (demux->ext_stream_props, (GFunc) gst_mini_object_unref,
215 NULL);
216 g_slist_free (demux->ext_stream_props);
217 demux->ext_stream_props = NULL;
219 while (demux->old_num_streams > 0) {
220 gst_asf_demux_free_stream (demux,
221 &demux->old_stream[demux->old_num_streams - 1]);
222 --demux->old_num_streams;
223 }
224 memset (demux->old_stream, 0, sizeof (demux->old_stream));
225 demux->old_num_streams = 0;
227 /* when resetting for a new chained asf, we don't want to remove the pads
228 * before adding the new ones */
229 if (chain_reset) {
230 memcpy (demux->old_stream, demux->stream, sizeof (demux->stream));
231 demux->old_num_streams = demux->num_streams;
232 demux->num_streams = 0;
233 }
235 while (demux->num_streams > 0) {
236 gst_asf_demux_free_stream (demux, &demux->stream[demux->num_streams - 1]);
237 --demux->num_streams;
238 }
239 memset (demux->stream, 0, sizeof (demux->stream));
240 if (!chain_reset) {
241 /* do not remove those for not adding pads with same name */
242 demux->num_audio_streams = 0;
243 demux->num_video_streams = 0;
244 }
245 demux->num_streams = 0;
246 demux->activated_streams = FALSE;
247 demux->first_ts = GST_CLOCK_TIME_NONE;
248 demux->segment_ts = GST_CLOCK_TIME_NONE;
249 demux->in_gap = 0;
250 if (!chain_reset)
251 gst_segment_init (&demux->in_segment, GST_FORMAT_UNDEFINED);
252 demux->state = GST_ASF_DEMUX_STATE_HEADER;
253 demux->seekable = FALSE;
254 demux->broadcast = FALSE;
255 demux->sidx_interval = 0;
256 demux->sidx_num_entries = 0;
257 g_free (demux->sidx_entries);
258 demux->sidx_entries = NULL;
260 demux->speed_packets = 1;
262 if (chain_reset) {
263 GST_LOG_OBJECT (demux, "Restarting");
264 gst_segment_init (&demux->segment, GST_FORMAT_TIME);
265 demux->need_newsegment = TRUE;
266 demux->segment_running = FALSE;
267 demux->accurate = FALSE;
268 demux->metadata = gst_caps_new_empty ();
269 demux->global_metadata = gst_structure_empty_new ("metadata");
270 demux->data_size = 0;
271 demux->data_offset = 0;
272 demux->index_offset = 0;
273 } else {
274 demux->base_offset = 0;
275 }
276 }
278 static void
279 gst_asf_demux_init (GstASFDemux * demux, GstASFDemuxClass * klass)
280 {
281 demux->sinkpad =
282 gst_pad_new_from_static_template (&gst_asf_demux_sink_template, "sink");
283 gst_pad_set_chain_function (demux->sinkpad,
284 GST_DEBUG_FUNCPTR (gst_asf_demux_chain));
285 gst_pad_set_event_function (demux->sinkpad,
286 GST_DEBUG_FUNCPTR (gst_asf_demux_sink_event));
287 gst_pad_set_activate_function (demux->sinkpad,
288 GST_DEBUG_FUNCPTR (gst_asf_demux_activate));
289 gst_pad_set_activatepull_function (demux->sinkpad,
290 GST_DEBUG_FUNCPTR (gst_asf_demux_activate_pull));
291 gst_pad_set_activatepush_function (demux->sinkpad,
292 GST_DEBUG_FUNCPTR (gst_asf_demux_activate_push));
293 gst_element_add_pad (GST_ELEMENT (demux), demux->sinkpad);
295 /* set initial state */
296 gst_asf_demux_reset (demux, FALSE);
297 }
299 static gboolean
300 gst_asf_demux_activate (GstPad * sinkpad)
301 {
302 if (gst_pad_check_pull_range (sinkpad)) {
303 return gst_pad_activate_pull (sinkpad, TRUE);
304 } else {
305 return gst_pad_activate_push (sinkpad, TRUE);
306 }
307 }
309 static gboolean
310 gst_asf_demux_activate_push (GstPad * sinkpad, gboolean active)
311 {
312 GstASFDemux *demux;
314 demux = GST_ASF_DEMUX (GST_OBJECT_PARENT (sinkpad));
316 demux->state = GST_ASF_DEMUX_STATE_HEADER;
317 demux->streaming = TRUE;
319 return TRUE;
320 }
322 static gboolean
323 gst_asf_demux_activate_pull (GstPad * pad, gboolean active)
324 {
325 GstASFDemux *demux;
327 demux = GST_ASF_DEMUX (GST_OBJECT_PARENT (pad));
329 if (active) {
330 demux->state = GST_ASF_DEMUX_STATE_HEADER;
331 demux->streaming = FALSE;
333 return gst_pad_start_task (pad, (GstTaskFunction) gst_asf_demux_loop,
334 demux);
335 } else {
336 return gst_pad_stop_task (pad);
337 }
338 }
341 static gboolean
342 gst_asf_demux_sink_event (GstPad * pad, GstEvent * event)
343 {
344 GstASFDemux *demux;
345 gboolean ret = TRUE;
347 demux = GST_ASF_DEMUX (gst_pad_get_parent (pad));
349 GST_LOG_OBJECT (demux, "handling %s event", GST_EVENT_TYPE_NAME (event));
350 switch (GST_EVENT_TYPE (event)) {
351 case GST_EVENT_NEWSEGMENT:{
352 GstFormat newsegment_format;
353 gint64 newsegment_start, stop, time;
354 gdouble rate, arate;
355 gboolean update;
357 gst_event_parse_new_segment_full (event, &update, &rate, &arate,
358 &newsegment_format, &newsegment_start, &stop, &time);
360 if (newsegment_format == GST_FORMAT_BYTES) {
361 if (demux->packet_size && newsegment_start > demux->data_offset)
362 demux->packet = (newsegment_start - demux->data_offset) /
363 demux->packet_size;
364 else
365 demux->packet = 0;
366 } else if (newsegment_format == GST_FORMAT_TIME) {
367 /* do not know packet position, not really a problem */
368 demux->packet = -1;
369 } else {
370 GST_WARNING_OBJECT (demux, "unsupported newsegment format, ignoring");
371 gst_event_unref (event);
372 break;
373 }
375 /* record upstream segment for interpolation */
376 if (newsegment_format != demux->in_segment.format)
377 gst_segment_init (&demux->in_segment, GST_FORMAT_UNDEFINED);
378 gst_segment_set_newsegment_full (&demux->in_segment, update, rate, arate,
379 newsegment_format, newsegment_start, stop, time);
381 /* in either case, clear some state and generate newsegment later on */
382 GST_OBJECT_LOCK (demux);
383 demux->segment_ts = GST_CLOCK_TIME_NONE;
384 demux->in_gap = GST_CLOCK_TIME_NONE;
385 demux->need_newsegment = TRUE;
386 gst_asf_demux_reset_stream_state_after_discont (demux);
387 GST_OBJECT_UNLOCK (demux);
389 gst_event_unref (event);
390 break;
391 }
392 case GST_EVENT_EOS:{
393 GstFlowReturn flow;
395 if (demux->state == GST_ASF_DEMUX_STATE_HEADER) {
396 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
397 (_("This stream contains no data.")),
398 ("got eos and didn't receive a complete header object"));
399 break;
400 }
401 flow = gst_asf_demux_push_complete_payloads (demux, TRUE);
402 if (flow < GST_FLOW_UNEXPECTED || flow == GST_FLOW_NOT_LINKED) {
403 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
404 (_("Internal data stream error.")),
405 ("streaming stopped, reason %s", gst_flow_get_name (flow)));
406 break;
407 }
409 GST_OBJECT_LOCK (demux);
410 gst_adapter_clear (demux->adapter);
411 GST_OBJECT_UNLOCK (demux);
412 gst_asf_demux_send_event_unlocked (demux, event);
413 break;
414 }
416 case GST_EVENT_FLUSH_STOP:
417 GST_OBJECT_LOCK (demux);
418 gst_asf_demux_reset_stream_state_after_discont (demux);
419 GST_OBJECT_UNLOCK (demux);
420 gst_asf_demux_send_event_unlocked (demux, event);
421 /* upon activation, latency is no longer introduced, e.g. after seek */
422 if (demux->activated_streams)
423 demux->latency = 0;
424 break;
426 default:
427 ret = gst_pad_event_default (pad, event);
428 break;
429 }
431 gst_object_unref (demux);
432 return ret;
433 }
435 static gboolean
436 gst_asf_demux_seek_index_lookup (GstASFDemux * demux, guint * packet,
437 GstClockTime seek_time, GstClockTime * p_idx_time, guint * speed)
438 {
439 GstClockTime idx_time;
440 guint idx;
442 if (G_UNLIKELY (demux->sidx_num_entries == 0 || demux->sidx_interval == 0))
443 return FALSE;
445 idx = (guint) ((seek_time + demux->preroll) / demux->sidx_interval);
447 /* FIXME: seek beyond end of file should result in immediate EOS from
448 * streaming thread instead of a failed seek */
449 if (G_UNLIKELY (idx >= demux->sidx_num_entries))
450 return FALSE;
452 *packet = demux->sidx_entries[idx].packet;
453 if (speed)
454 *speed = demux->sidx_entries[idx].count;
456 /* so we get closer to the actual time of the packet ... actually, let's not
457 * do this, since we throw away superfluous payloads before the seek position
458 * anyway; this way, our key unit seek 'snap resolution' is a bit better
459 * (ie. same as index resolution) */
460 /*
461 while (idx > 0 && demux->sidx_entries[idx-1] == demux->sidx_entries[idx])
462 --idx;
463 */
465 idx_time = demux->sidx_interval * idx;
466 if (G_LIKELY (idx_time >= demux->preroll))
467 idx_time -= demux->preroll;
469 GST_DEBUG_OBJECT (demux, "%" GST_TIME_FORMAT " => packet %u at %"
470 GST_TIME_FORMAT, GST_TIME_ARGS (seek_time), *packet,
471 GST_TIME_ARGS (idx_time));
473 if (G_LIKELY (p_idx_time))
474 *p_idx_time = idx_time;
476 return TRUE;
477 }
479 static void
480 gst_asf_demux_reset_stream_state_after_discont (GstASFDemux * demux)
481 {
482 guint n;
484 gst_adapter_clear (demux->adapter);
486 GST_DEBUG_OBJECT (demux, "reset stream state");
488 for (n = 0; n < demux->num_streams; n++) {
489 demux->stream[n].discont = TRUE;
490 demux->stream[n].last_flow = GST_FLOW_OK;
492 while (demux->stream[n].payloads->len > 0) {
493 AsfPayload *payload;
494 guint last;
496 last = demux->stream[n].payloads->len - 1;
497 payload = &g_array_index (demux->stream[n].payloads, AsfPayload, last);
498 gst_buffer_replace (&payload->buf, NULL);
499 g_array_remove_index (demux->stream[n].payloads, last);
500 }
501 }
502 }
504 static void
505 gst_asf_demux_mark_discont (GstASFDemux * demux)
506 {
507 guint n;
509 GST_DEBUG_OBJECT (demux, "Mark stream discont");
511 for (n = 0; n < demux->num_streams; n++)
512 demux->stream[n].discont = TRUE;
513 }
515 /* do a seek in push based mode */
516 static gboolean
517 gst_asf_demux_handle_seek_push (GstASFDemux * demux, GstEvent * event)
518 {
519 gdouble rate;
520 GstFormat format;
521 GstSeekFlags flags;
522 GstSeekType cur_type, stop_type;
523 gint64 cur, stop;
524 guint packet;
525 gboolean res;
527 gst_event_parse_seek (event, &rate, &format, &flags, &cur_type, &cur,
528 &stop_type, &stop);
530 stop_type = GST_SEEK_TYPE_NONE;
531 stop = -1;
533 GST_DEBUG_OBJECT (demux, "seeking to %" GST_TIME_FORMAT, GST_TIME_ARGS (cur));
535 /* determine packet, by index or by estimation */
536 if (!gst_asf_demux_seek_index_lookup (demux, &packet, cur, NULL, NULL)) {
537 packet = (guint) gst_util_uint64_scale (demux->num_packets,
538 cur, demux->play_time);
539 }
541 if (packet > demux->num_packets) {
542 GST_DEBUG_OBJECT (demux, "could not determine packet to seek to, "
543 "seek aborted.");
544 return FALSE;
545 }
547 GST_DEBUG_OBJECT (demux, "seeking to packet %d", packet);
549 cur = demux->data_offset + (packet * demux->packet_size);
551 GST_DEBUG_OBJECT (demux, "Pushing BYTE seek rate %g, "
552 "start %" G_GINT64_FORMAT ", stop %" G_GINT64_FORMAT, rate, cur, stop);
553 /* BYTE seek event */
554 event = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags, cur_type, cur,
555 stop_type, stop);
556 res = gst_pad_push_event (demux->sinkpad, event);
558 return res;
559 }
561 static gboolean
562 gst_asf_demux_handle_seek_event (GstASFDemux * demux, GstEvent * event)
563 {
564 GstClockTime idx_time;
565 GstSegment segment;
566 GstSeekFlags flags;
567 GstSeekType cur_type, stop_type;
568 GstFormat format;
569 gboolean only_need_update;
570 gboolean keyunit_sync;
571 gboolean flush;
572 gdouble rate;
573 gint64 cur, stop;
574 gint64 seek_time;
575 guint packet, speed_count = 1;
577 if (G_UNLIKELY (demux->seekable == FALSE || demux->packet_size == 0 ||
578 demux->num_packets == 0 || demux->play_time == 0)) {
579 GST_LOG_OBJECT (demux, "stream is not seekable");
580 return FALSE;
581 }
583 if (G_UNLIKELY (!demux->activated_streams)) {
584 GST_LOG_OBJECT (demux, "streams not yet activated, ignoring seek");
585 return FALSE;
586 }
588 gst_event_parse_seek (event, &rate, &format, &flags, &cur_type, &cur,
589 &stop_type, &stop);
591 if (G_UNLIKELY (format != GST_FORMAT_TIME)) {
592 GST_LOG_OBJECT (demux, "seeking is only supported in TIME format");
593 return FALSE;
594 }
596 if (G_UNLIKELY (rate <= 0.0)) {
597 GST_LOG_OBJECT (demux, "backward playback is not supported yet");
598 return FALSE;
599 }
601 flush = ((flags & GST_SEEK_FLAG_FLUSH) == GST_SEEK_FLAG_FLUSH);
602 demux->accurate =
603 ((flags & GST_SEEK_FLAG_ACCURATE) == GST_SEEK_FLAG_ACCURATE);
604 keyunit_sync = ((flags & GST_SEEK_FLAG_KEY_UNIT) == GST_SEEK_FLAG_KEY_UNIT);
606 if (G_UNLIKELY (demux->streaming)) {
607 /* support it safely needs more segment handling, e.g. closing etc */
608 if (!flush) {
609 GST_LOG_OBJECT (demux, "streaming; non-flushing seek not supported");
610 return FALSE;
611 }
612 /* we can (re)construct the start later on, but not the end */
613 if (stop_type != GST_SEEK_TYPE_NONE) {
614 GST_LOG_OBJECT (demux, "streaming; end type must be NONE");
615 return FALSE;
616 }
617 gst_event_ref (event);
618 /* upstream might handle TIME seek, e.g. mms or rtsp,
619 * or not, e.g. http, then we give it a hand */
620 if (!gst_pad_push_event (demux->sinkpad, event))
621 return gst_asf_demux_handle_seek_push (demux, event);
622 else
623 return TRUE;
624 }
626 /* unlock the streaming thread */
627 if (G_LIKELY (flush)) {
628 gst_pad_push_event (demux->sinkpad, gst_event_new_flush_start ());
629 gst_asf_demux_send_event_unlocked (demux, gst_event_new_flush_start ());
630 } else {
631 gst_pad_pause_task (demux->sinkpad);
632 }
634 /* grab the stream lock so that streaming cannot continue, for
635 * non flushing seeks when the element is in PAUSED this could block
636 * forever */
637 GST_PAD_STREAM_LOCK (demux->sinkpad);
639 /* we now can stop flushing, since we have the stream lock now */
640 gst_pad_push_event (demux->sinkpad, gst_event_new_flush_stop ());
642 if (G_LIKELY (flush))
643 gst_asf_demux_send_event_unlocked (demux, gst_event_new_flush_stop ());
645 /* operating on copy of segment until we know the seek worked */
646 segment = demux->segment;
648 if (G_UNLIKELY (demux->segment_running && !flush)) {
649 GstEvent *newseg;
651 /* create the segment event to close the current segment */
652 newseg = gst_event_new_new_segment (TRUE, segment.rate,
653 GST_FORMAT_TIME, segment.start, segment.last_stop, segment.time);
655 gst_asf_demux_send_event_unlocked (demux, newseg);
656 }
658 gst_segment_set_seek (&segment, rate, format, flags, cur_type,
659 cur, stop_type, stop, &only_need_update);
661 GST_DEBUG_OBJECT (demux, "seeking to time %" GST_TIME_FORMAT ", segment: "
662 "%" GST_SEGMENT_FORMAT, GST_TIME_ARGS (segment.start), &segment);
664 seek_time = segment.start;
666 /* FIXME: should check the KEY_UNIT flag; need to adjust last_stop to
667 * real start of data and segment_start to indexed time for key unit seek*/
668 if (G_UNLIKELY (!gst_asf_demux_seek_index_lookup (demux, &packet, seek_time,
669 &idx_time, &speed_count))) {
670 /* First try to query our source to see if it can convert for us. This is
671 the case when our source is an mms stream, notice that in this case
672 gstmms will do a time based seek to get the byte offset, this is not a
673 problem as the seek to this offset needs to happen anway. */
674 gint64 offset;
675 GstFormat dest_format = GST_FORMAT_BYTES;
677 if (gst_pad_query_peer_convert (demux->sinkpad, GST_FORMAT_TIME, seek_time,
678 &dest_format, &offset) && dest_format == GST_FORMAT_BYTES) {
679 packet = (offset - demux->data_offset) / demux->packet_size;
680 GST_LOG_OBJECT (demux, "convert %" GST_TIME_FORMAT
681 " to bytes query result: %" G_GINT64_FORMAT ", data_ofset: %"
682 G_GINT64_FORMAT ", packet_size: %u," " resulting packet: %u\n",
683 GST_TIME_ARGS (seek_time), offset, demux->data_offset,
684 demux->packet_size, packet);
685 } else {
686 /* FIXME: For streams containing video, seek to an earlier position in
687 * the hope of hitting a keyframe and let the sinks throw away the stuff
688 * before the segment start. For audio-only this is unnecessary as every
689 * frame is 'key'. */
690 if (flush && (demux->accurate || keyunit_sync)
691 && demux->num_video_streams > 0) {
692 seek_time -= 5 * GST_SECOND;
693 if (seek_time < 0)
694 seek_time = 0;
695 }
697 packet = (guint) gst_util_uint64_scale (demux->num_packets,
698 seek_time, demux->play_time);
700 if (packet > demux->num_packets)
701 packet = demux->num_packets;
702 }
703 } else {
704 if (G_LIKELY (keyunit_sync)) {
705 GST_DEBUG_OBJECT (demux, "key unit seek, adjust seek_time = %"
706 GST_TIME_FORMAT " to index_time = %" GST_TIME_FORMAT,
707 GST_TIME_ARGS (seek_time), GST_TIME_ARGS (idx_time));
708 segment.start = idx_time;
709 segment.last_stop = idx_time;
710 segment.time = idx_time;
711 }
712 }
714 GST_DEBUG_OBJECT (demux, "seeking to packet %u (%d)", packet, speed_count);
716 GST_OBJECT_LOCK (demux);
717 demux->segment = segment;
718 demux->packet = packet;
719 demux->need_newsegment = TRUE;
720 demux->speed_packets = speed_count;
721 gst_asf_demux_reset_stream_state_after_discont (demux);
722 GST_OBJECT_UNLOCK (demux);
724 /* restart our task since it might have been stopped when we did the flush */
725 gst_pad_start_task (demux->sinkpad, (GstTaskFunction) gst_asf_demux_loop,
726 demux);
728 /* streaming can continue now */
729 GST_PAD_STREAM_UNLOCK (demux->sinkpad);
731 return TRUE;
732 }
734 static gboolean
735 gst_asf_demux_handle_src_event (GstPad * pad, GstEvent * event)
736 {
737 GstASFDemux *demux;
738 gboolean ret;
740 demux = GST_ASF_DEMUX (gst_pad_get_parent (pad));
742 switch (GST_EVENT_TYPE (event)) {
743 case GST_EVENT_SEEK:
744 GST_LOG_OBJECT (pad, "seek event");
745 ret = gst_asf_demux_handle_seek_event (demux, event);
746 gst_event_unref (event);
747 break;
748 case GST_EVENT_QOS:
749 case GST_EVENT_NAVIGATION:
750 /* just drop these two silently */
751 gst_event_unref (event);
752 ret = FALSE;
753 break;
754 default:
755 GST_LOG_OBJECT (pad, "%s event", GST_EVENT_TYPE_NAME (event));
756 ret = gst_pad_event_default (pad, event);
757 break;
758 }
760 gst_object_unref (demux);
761 return ret;
762 }
764 static inline guint32
765 gst_asf_demux_identify_guid (const ASFGuidHash * guids, ASFGuid * guid)
766 {
767 guint32 ret;
769 ret = gst_asf_identify_guid (guids, guid);
771 GST_LOG ("%s 0x%08x-0x%08x-0x%08x-0x%08x",
772 gst_asf_get_guid_nick (guids, ret),
773 guid->v1, guid->v2, guid->v3, guid->v4);
775 return ret;
776 }
778 typedef struct
779 {
780 AsfObjectID id;
781 guint64 size;
782 } AsfObject;
785 /* expect is true when the user is expeting an object,
786 * when false, it will give no warnings if the object
787 * is not identified
788 */
789 static gboolean
790 asf_demux_peek_object (GstASFDemux * demux, const guint8 * data,
791 guint data_len, AsfObject * object, gboolean expect)
792 {
793 ASFGuid guid;
795 if (data_len < ASF_OBJECT_HEADER_SIZE)
796 return FALSE;
798 guid.v1 = GST_READ_UINT32_LE (data + 0);
799 guid.v2 = GST_READ_UINT32_LE (data + 4);
800 guid.v3 = GST_READ_UINT32_LE (data + 8);
801 guid.v4 = GST_READ_UINT32_LE (data + 12);
803 object->size = GST_READ_UINT64_LE (data + 16);
805 /* FIXME: make asf_demux_identify_object_guid() */
806 object->id = gst_asf_demux_identify_guid (asf_object_guids, &guid);
807 if (object->id == ASF_OBJ_UNDEFINED && expect) {
808 GST_WARNING_OBJECT (demux, "Unknown object %08x-%08x-%08x-%08x",
809 guid.v1, guid.v2, guid.v3, guid.v4);
810 }
812 return TRUE;
813 }
815 static void
816 gst_asf_demux_release_old_pads (GstASFDemux * demux)
817 {
818 GST_DEBUG_OBJECT (demux, "Releasing old pads");
820 while (demux->old_num_streams > 0) {
821 gst_pad_push_event (demux->old_stream[demux->old_num_streams - 1].pad,
822 gst_event_new_eos ());
823 gst_asf_demux_free_stream (demux,
824 &demux->old_stream[demux->old_num_streams - 1]);
825 --demux->old_num_streams;
826 }
827 memset (demux->old_stream, 0, sizeof (demux->old_stream));
828 demux->old_num_streams = 0;
829 }
831 static GstFlowReturn
832 gst_asf_demux_chain_headers (GstASFDemux * demux)
833 {
834 GstFlowReturn flow;
835 AsfObject obj;
836 guint8 *header_data, *data = NULL;
837 const guint8 *cdata = NULL;
838 guint64 header_size;
840 cdata = (guint8 *) gst_adapter_peek (demux->adapter, ASF_OBJECT_HEADER_SIZE);
841 if (cdata == NULL)
842 goto need_more_data;
844 asf_demux_peek_object (demux, cdata, ASF_OBJECT_HEADER_SIZE, &obj, TRUE);
845 if (obj.id != ASF_OBJ_HEADER)
846 goto wrong_type;
848 GST_LOG_OBJECT (demux, "header size = %u", (guint) obj.size);
850 /* + 50 for non-packet data at beginning of ASF_OBJ_DATA */
851 if (gst_adapter_available (demux->adapter) < obj.size + 50)
852 goto need_more_data;
854 data = gst_adapter_take (demux->adapter, obj.size + 50);
856 header_data = data;
857 header_size = obj.size;
858 flow = gst_asf_demux_process_object (demux, &header_data, &header_size);
859 if (flow != GST_FLOW_OK)
860 goto parse_failed;
862 /* calculate where the packet data starts */
863 demux->data_offset = obj.size + 50;
865 /* now parse the beginning of the ASF_OBJ_DATA object */
866 if (!gst_asf_demux_parse_data_object_start (demux, data + obj.size))
867 goto wrong_type;
869 if (demux->num_streams == 0)
870 goto no_streams;
872 g_free (data);
873 return GST_FLOW_OK;
875 /* NON-FATAL */
876 need_more_data:
877 {
878 GST_LOG_OBJECT (demux, "not enough data in adapter yet");
879 return GST_FLOW_OK;
880 }
882 /* ERRORS */
883 wrong_type:
884 {
885 GST_ELEMENT_ERROR (demux, STREAM, WRONG_TYPE, (NULL),
886 ("This doesn't seem to be an ASF file"));
887 g_free (data);
888 return GST_FLOW_ERROR;
889 }
890 no_streams:
891 parse_failed:
892 {
893 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
894 ("header parsing failed, or no streams found, flow = %s",
895 gst_flow_get_name (flow)));
896 g_free (data);
897 return GST_FLOW_ERROR;
898 }
899 }
901 static GstFlowReturn
902 gst_asf_demux_aggregate_flow_return (GstASFDemux * demux, AsfStream * stream,
903 GstFlowReturn flow)
904 {
905 int i;
907 GST_DEBUG_OBJECT (demux, "Aggregating");
909 /* Store the value */
910 stream->last_flow = flow;
912 /* any other error that is not not-linked can be returned right away */
913 if (flow != GST_FLOW_NOT_LINKED)
914 goto done;
916 for (i = 0; i < demux->num_streams; i++) {
917 if (demux->stream[i].active) {
918 flow = demux->stream[i].last_flow;
919 GST_DEBUG_OBJECT (demux, "Aggregating: flow %i return %s", i,
920 gst_flow_get_name (flow));
921 if (flow != GST_FLOW_NOT_LINKED)
922 goto done;
923 }
924 }
926 /* If we got here, then all our active streams are not linked */
927 done:
928 return flow;
929 }
931 static gboolean
932 gst_asf_demux_pull_data (GstASFDemux * demux, guint64 offset, guint size,
933 GstBuffer ** p_buf, GstFlowReturn * p_flow)
934 {
935 GstFlowReturn flow;
937 GST_LOG_OBJECT (demux, "pulling buffer at %" G_GUINT64_FORMAT "+%u",
938 offset, size);
940 flow = gst_pad_pull_range (demux->sinkpad, offset, size, p_buf);
942 if (G_LIKELY (p_flow))
943 *p_flow = flow;
945 if (G_UNLIKELY (flow != GST_FLOW_OK)) {
946 GST_DEBUG_OBJECT (demux, "flow %s pulling buffer at %" G_GUINT64_FORMAT
947 "+%u", gst_flow_get_name (flow), offset, size);
948 *p_buf = NULL;
949 return FALSE;
950 }
952 g_assert (*p_buf != NULL);
954 if (G_UNLIKELY (GST_BUFFER_SIZE (*p_buf) < size)) {
955 GST_DEBUG_OBJECT (demux, "short read pulling buffer at %" G_GUINT64_FORMAT
956 "+%u (got only %u bytes)", offset, size, GST_BUFFER_SIZE (*p_buf));
957 gst_buffer_unref (*p_buf);
958 if (G_LIKELY (p_flow))
959 *p_flow = GST_FLOW_UNEXPECTED;
960 *p_buf = NULL;
961 return FALSE;
962 }
964 return TRUE;
965 }
967 static void
968 gst_asf_demux_pull_indices (GstASFDemux * demux)
969 {
970 GstBuffer *buf = NULL;
971 guint64 offset;
972 guint num_read = 0;
974 offset = demux->index_offset;
976 if (G_UNLIKELY (offset == 0)) {
977 GST_DEBUG_OBJECT (demux, "can't read indices, don't know index offset");
978 return;
979 }
981 while (gst_asf_demux_pull_data (demux, offset, 16 + 8, &buf, NULL)) {
982 GstFlowReturn flow;
983 AsfObject obj;
985 asf_demux_peek_object (demux, GST_BUFFER_DATA (buf), 16 + 8, &obj, TRUE);
986 gst_buffer_replace (&buf, NULL);
988 /* check for sanity */
989 if (G_UNLIKELY (obj.size > (5 * 1024 * 1024))) {
990 GST_DEBUG_OBJECT (demux, "implausible index object size, bailing out");
991 break;
992 }
994 if (G_UNLIKELY (!gst_asf_demux_pull_data (demux, offset, obj.size, &buf,
995 NULL)))
996 break;
998 GST_LOG_OBJECT (demux, "index object at offset 0x%" G_GINT64_MODIFIER "X"
999 ", size %u", offset, (guint) obj.size);
1001 offset += obj.size; /* increase before _process_object changes it */
1003 flow = gst_asf_demux_process_object (demux, &buf->data, &obj.size);
1004 gst_buffer_replace (&buf, NULL);
1006 if (G_UNLIKELY (flow != GST_FLOW_OK))
1007 break;
1009 ++num_read;
1010 }
1011 GST_DEBUG_OBJECT (demux, "read %u index objects", num_read);
1012 }
1014 static gboolean
1015 gst_asf_demux_parse_data_object_start (GstASFDemux * demux, guint8 * data)
1016 {
1017 AsfObject obj;
1019 asf_demux_peek_object (demux, data, 50, &obj, TRUE);
1020 if (obj.id != ASF_OBJ_DATA) {
1021 GST_WARNING_OBJECT (demux, "headers not followed by a DATA object");
1022 return FALSE;
1023 }
1025 demux->state = GST_ASF_DEMUX_STATE_DATA;
1027 if (!demux->broadcast && obj.size > 50) {
1028 demux->data_size = obj.size - 50;
1029 /* CHECKME: for at least one file this is off by +158 bytes?! */
1030 demux->index_offset = demux->data_offset + demux->data_size;
1031 } else {
1032 demux->data_size = 0;
1033 demux->index_offset = 0;
1034 }
1036 demux->packet = 0;
1038 if (!demux->broadcast) {
1039 /* skip object header (24 bytes) and file GUID (16 bytes) */
1040 demux->num_packets = GST_READ_UINT64_LE (data + (16 + 8) + 16);
1041 } else {
1042 demux->num_packets = 0;
1043 }
1045 if (demux->num_packets == 0)
1046 demux->seekable = FALSE;
1048 /* fallback in the unlikely case that headers are inconsistent, can't hurt */
1049 if (demux->data_size == 0 && demux->num_packets > 0) {
1050 demux->data_size = demux->num_packets * demux->packet_size;
1051 demux->index_offset = demux->data_offset + demux->data_size;
1052 }
1054 /* process pending stream objects and create pads for those */
1055 gst_asf_demux_process_queued_extended_stream_objects (demux);
1057 GST_INFO_OBJECT (demux, "Stream has %" G_GUINT64_FORMAT " packets, "
1058 "data_offset=%" G_GINT64_FORMAT ", data_size=%" G_GINT64_FORMAT
1059 ", index_offset=%" G_GUINT64_FORMAT, demux->num_packets,
1060 demux->data_offset, demux->data_size, demux->index_offset);
1062 return TRUE;
1063 }
1065 static gboolean
1066 gst_asf_demux_pull_headers (GstASFDemux * demux)
1067 {
1068 GstFlowReturn flow;
1069 AsfObject obj;
1070 GstBuffer *buf = NULL;
1071 guint64 size;
1073 GST_LOG_OBJECT (demux, "reading headers");
1075 /* pull HEADER object header, so we know its size */
1076 if (!gst_asf_demux_pull_data (demux, demux->base_offset, 16 + 8, &buf, NULL))
1077 goto read_failed;
1079 asf_demux_peek_object (demux, GST_BUFFER_DATA (buf), 16 + 8, &obj, TRUE);
1080 gst_buffer_replace (&buf, NULL);
1082 if (obj.id != ASF_OBJ_HEADER)
1083 goto wrong_type;
1085 GST_LOG_OBJECT (demux, "header size = %u", (guint) obj.size);
1087 /* pull HEADER object */
1088 if (!gst_asf_demux_pull_data (demux, demux->base_offset, obj.size, &buf,
1089 NULL))
1090 goto read_failed;
1092 size = obj.size; /* don't want obj.size changed */
1093 flow = gst_asf_demux_process_object (demux, &buf->data, &size);
1094 gst_buffer_replace (&buf, NULL);
1096 if (flow != GST_FLOW_OK) {
1097 GST_WARNING_OBJECT (demux, "process_object: %s", gst_flow_get_name (flow));
1098 goto parse_failed;
1099 }
1101 /* calculate where the packet data starts */
1102 demux->data_offset = demux->base_offset + obj.size + 50;
1104 /* now pull beginning of DATA object before packet data */
1105 if (!gst_asf_demux_pull_data (demux, demux->base_offset + obj.size, 50, &buf,
1106 NULL))
1107 goto read_failed;
1109 if (!gst_asf_demux_parse_data_object_start (demux, GST_BUFFER_DATA (buf)))
1110 goto wrong_type;
1112 if (demux->num_streams == 0)
1113 goto no_streams;
1115 gst_buffer_replace (&buf, NULL);
1116 return TRUE;
1118 /* ERRORS */
1119 wrong_type:
1120 {
1121 gst_buffer_replace (&buf, NULL);
1122 GST_ELEMENT_ERROR (demux, STREAM, WRONG_TYPE, (NULL),
1123 ("This doesn't seem to be an ASF file"));
1124 return FALSE;
1125 }
1126 no_streams:
1127 read_failed:
1128 parse_failed:
1129 {
1130 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL), (NULL));
1131 return FALSE;
1132 }
1133 }
1135 static gboolean
1136 all_streams_prerolled (GstASFDemux * demux)
1137 {
1138 GstClockTime preroll_time;
1139 guint i, num_no_data = 0;
1141 /* Allow at least 500ms of preroll_time */
1142 preroll_time = MAX (demux->preroll, 500 * GST_MSECOND);
1144 /* returns TRUE as long as there isn't a stream which (a) has data queued
1145 * and (b) the timestamp of last piece of data queued is < demux->preroll
1146 * AND there is at least one other stream with data queued */
1147 for (i = 0; i < demux->num_streams; ++i) {
1148 AsfPayload *last_payload;
1149 AsfStream *stream;
1150 guint last_idx;
1152 stream = &demux->stream[i];
1153 if (G_UNLIKELY (stream->payloads->len == 0)) {
1154 ++num_no_data;
1155 GST_LOG_OBJECT (stream->pad, "no data queued");
1156 continue;
1157 }
1159 last_idx = stream->payloads->len - 1;
1160 last_payload = &g_array_index (stream->payloads, AsfPayload, last_idx);
1162 GST_LOG_OBJECT (stream->pad, "checking if %" GST_TIME_FORMAT " > %"
1163 GST_TIME_FORMAT, GST_TIME_ARGS (last_payload->ts),
1164 GST_TIME_ARGS (preroll_time));
1165 if (G_UNLIKELY (last_payload->ts <= preroll_time)) {
1166 GST_LOG_OBJECT (stream->pad, "not beyond preroll point yet");
1167 return FALSE;
1168 }
1169 }
1171 if (G_UNLIKELY (num_no_data == demux->num_streams))
1172 return FALSE;
1174 return TRUE;
1175 }
1177 #if 0
1178 static gboolean
1179 gst_asf_demux_have_mutually_exclusive_active_stream (GstASFDemux * demux,
1180 AsfStream * stream)
1181 {
1182 GSList *l;
1184 for (l = demux->mut_ex_streams; l != NULL; l = l->next) {
1185 guint8 *mes;
1187 /* check for each mutual exclusion group whether it affects this stream */
1188 for (mes = (guint8 *) l->data; mes != NULL && *mes != 0xff; ++mes) {
1189 if (*mes == stream->id) {
1190 /* we are in this group; let's check if we've already activated streams
1191 * that are in the same group (and hence mutually exclusive to this
1192 * one) */
1193 for (mes = (guint8 *) l->data; mes != NULL && *mes != 0xff; ++mes) {
1194 guint i;
1196 for (i = 0; i < demux->num_streams; ++i) {
1197 if (demux->stream[i].id == *mes && demux->stream[i].active) {
1198 GST_LOG_OBJECT (demux, "stream with ID %d is mutually exclusive "
1199 "to already active stream with ID %d", stream->id,
1200 demux->stream[i].id);
1201 return TRUE;
1202 }
1203 }
1204 }
1205 /* we can only be in this group once, let's break out and move on to
1206 * the next mutual exclusion group */
1207 break;
1208 }
1209 }
1210 }
1212 return FALSE;
1213 }
1214 #endif
1216 static gboolean
1217 gst_asf_demux_check_activate_streams (GstASFDemux * demux, gboolean force)
1218 {
1219 guint i;
1221 if (demux->activated_streams)
1222 return TRUE;
1224 if (!all_streams_prerolled (demux) && !force) {
1225 GST_DEBUG_OBJECT (demux, "not all streams with data beyond preroll yet");
1226 return FALSE;
1227 }
1229 for (i = 0; i < demux->num_streams; ++i) {
1230 AsfStream *stream = &demux->stream[i];
1232 if (stream->payloads->len > 0) {
1233 /* we don't check mutual exclusion stuff here; either we have data for
1234 * a stream, then we active it, or we don't, then we'll ignore it */
1235 GST_LOG_OBJECT (stream->pad, "is prerolled - activate!");
1236 gst_asf_demux_activate_stream (demux, stream);
1237 } else {
1238 GST_LOG_OBJECT (stream->pad, "no data, ignoring stream");
1239 }
1240 }
1242 gst_asf_demux_release_old_pads (demux);
1244 demux->activated_streams = TRUE;
1245 GST_LOG_OBJECT (demux, "signalling no more pads");
1246 gst_element_no_more_pads (GST_ELEMENT (demux));
1247 return TRUE;
1248 }
1250 /* returns the stream that has a complete payload with the lowest timestamp
1251 * queued, or NULL (we push things by timestamp because during the internal
1252 * prerolling we might accumulate more data then the external queues can take,
1253 * so we'd lock up if we pushed all accumulated data for stream N in one go) */
1254 static AsfStream *
1255 gst_asf_demux_find_stream_with_complete_payload (GstASFDemux * demux)
1256 {
1257 AsfPayload *best_payload = NULL;
1258 AsfStream *best_stream = NULL;
1259 guint i;
1261 for (i = 0; i < demux->num_streams; ++i) {
1262 AsfStream *stream;
1264 stream = &demux->stream[i];
1266 /* Don't push any data until we have at least one payload that falls within
1267 * the current segment. This way we can remove out-of-segment payloads that
1268 * don't need to be decoded after a seek, sending only data from the
1269 * keyframe directly before our segment start */
1270 if (stream->payloads->len > 0) {
1271 AsfPayload *payload;
1272 guint last_idx;
1274 last_idx = stream->payloads->len - 1;
1275 payload = &g_array_index (stream->payloads, AsfPayload, last_idx);
1276 if (G_UNLIKELY (GST_CLOCK_TIME_IS_VALID (payload->ts) &&
1277 (payload->ts < demux->segment.start))) {
1278 if (G_UNLIKELY ((!demux->accurate) && payload->keyframe)) {
1279 GST_DEBUG_OBJECT (stream->pad,
1280 "Found keyframe, updating segment start to %" GST_TIME_FORMAT,
1281 GST_TIME_ARGS (payload->ts));
1282 demux->segment.start = payload->ts;
1283 demux->segment.time = payload->ts;
1284 } else {
1285 GST_DEBUG_OBJECT (stream->pad, "Last queued payload has timestamp %"
1286 GST_TIME_FORMAT " which is before our segment start %"
1287 GST_TIME_FORMAT ", not pushing yet", GST_TIME_ARGS (payload->ts),
1288 GST_TIME_ARGS (demux->segment.start));
1289 continue;
1290 }
1291 }
1293 /* Now see if there's a complete payload queued for this stream */
1295 payload = &g_array_index (stream->payloads, AsfPayload, 0);
1296 if (!gst_asf_payload_is_complete (payload))
1297 continue;
1299 /* ... and whether its timestamp is lower than the current best */
1300 if (best_stream == NULL || best_payload->ts > payload->ts) {
1301 best_stream = stream;
1302 best_payload = payload;
1303 }
1304 }
1305 }
1307 return best_stream;
1308 }
1310 static GstFlowReturn
1311 gst_asf_demux_push_complete_payloads (GstASFDemux * demux, gboolean force)
1312 {
1313 AsfStream *stream;
1314 GstFlowReturn ret = GST_FLOW_OK;
1316 if (G_UNLIKELY (!demux->activated_streams)) {
1317 if (!gst_asf_demux_check_activate_streams (demux, force))
1318 return GST_FLOW_OK;
1319 /* streams are now activated */
1320 }
1322 /* wait until we had a chance to "lock on" some payload's timestamp */
1323 if (G_UNLIKELY (demux->need_newsegment
1324 && !GST_CLOCK_TIME_IS_VALID (demux->segment_ts)))
1325 return GST_FLOW_OK;
1327 while ((stream = gst_asf_demux_find_stream_with_complete_payload (demux))) {
1328 AsfPayload *payload;
1330 payload = &g_array_index (stream->payloads, AsfPayload, 0);
1332 /* do we need to send a newsegment event */
1333 if ((G_UNLIKELY (demux->need_newsegment))) {
1335 /* safe default if insufficient upstream info */
1336 if (!GST_CLOCK_TIME_IS_VALID (demux->in_gap))
1337 demux->in_gap = 0;
1339 if (demux->segment.stop == GST_CLOCK_TIME_NONE &&
1340 demux->segment.duration > 0) {
1341 /* slight HACK; prevent clipping of last bit */
1342 demux->segment.stop = demux->segment.duration + demux->in_gap;
1343 }
1345 /* FIXME : only if ACCURATE ! */
1346 if (G_LIKELY (!demux->accurate
1347 && (GST_CLOCK_TIME_IS_VALID (payload->ts)))) {
1348 GST_DEBUG ("Adjusting newsegment start to %" GST_TIME_FORMAT,
1349 GST_TIME_ARGS (payload->ts));
1350 demux->segment.start = payload->ts;
1351 demux->segment.time = payload->ts;
1352 }
1354 GST_DEBUG_OBJECT (demux, "sending new-segment event %" GST_SEGMENT_FORMAT,
1355 &demux->segment);
1357 /* note: we fix up all timestamps to start from 0, so this should be ok */
1358 gst_asf_demux_send_event_unlocked (demux,
1359 gst_event_new_new_segment (FALSE, demux->segment.rate,
1360 GST_FORMAT_TIME, demux->segment.start, demux->segment.stop,
1361 demux->segment.start));
1363 /* now post any global tags we may have found */
1364 if (demux->taglist == NULL)
1365 demux->taglist = gst_tag_list_new ();
1367 gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
1368 GST_TAG_CONTAINER_FORMAT, "ASF", NULL);
1370 GST_DEBUG_OBJECT (demux, "global tags: %" GST_PTR_FORMAT, demux->taglist);
1371 gst_element_found_tags (GST_ELEMENT (demux), demux->taglist);
1372 demux->taglist = NULL;
1374 demux->need_newsegment = FALSE;
1375 demux->segment_running = TRUE;
1376 }
1378 /* Do we have tags pending for this stream? */
1379 if (G_UNLIKELY (stream->pending_tags)) {
1380 GST_LOG_OBJECT (stream->pad, "%" GST_PTR_FORMAT, stream->pending_tags);
1381 gst_element_found_tags_for_pad (GST_ELEMENT (demux), stream->pad,
1382 stream->pending_tags);
1383 stream->pending_tags = NULL;
1384 }
1386 /* We have the whole packet now so we should push the packet to
1387 * the src pad now. First though we should check if we need to do
1388 * descrambling */
1389 if (G_UNLIKELY (demux->span > 1)) {
1390 gst_asf_demux_descramble_buffer (demux, stream, &payload->buf);
1391 }
1393 payload->buf = gst_buffer_make_metadata_writable (payload->buf);
1395 if (G_LIKELY (!payload->keyframe)) {
1396 GST_BUFFER_FLAG_SET (payload->buf, GST_BUFFER_FLAG_DELTA_UNIT);
1397 }
1399 if (G_UNLIKELY (stream->discont)) {
1400 GST_DEBUG_OBJECT (stream->pad, "marking DISCONT on stream");
1401 GST_BUFFER_FLAG_SET (payload->buf, GST_BUFFER_FLAG_DISCONT);
1402 stream->discont = FALSE;
1403 }
1405 if (G_UNLIKELY (stream->is_video && payload->par_x && payload->par_y &&
1406 (payload->par_x != stream->par_x) &&
1407 (payload->par_y != stream->par_y))) {
1408 GST_DEBUG ("Updating PAR (%d/%d => %d/%d)",
1409 stream->par_x, stream->par_y, payload->par_x, payload->par_y);
1410 stream->par_x = payload->par_x;
1411 stream->par_y = payload->par_y;
1412 gst_caps_set_simple (stream->caps, "pixel-aspect-ratio",
1413 GST_TYPE_FRACTION, stream->par_x, stream->par_y, NULL);
1414 gst_pad_set_caps (stream->pad, stream->caps);
1415 }
1417 if (G_UNLIKELY (stream->interlaced != payload->interlaced)) {
1418 GST_DEBUG ("Updating interlaced status (%d => %d)", stream->interlaced,
1419 payload->interlaced);
1420 stream->interlaced = payload->interlaced;
1421 gst_caps_set_simple (stream->caps, "interlaced", G_TYPE_BOOLEAN,
1422 stream->interlaced, NULL);
1423 }
1425 gst_buffer_set_caps (payload->buf, stream->caps);
1427 /* (sort of) interpolate timestamps using upstream "frame of reference",
1428 * typically useful for live src, but might (unavoidably) mess with
1429 * position reporting if a live src is playing not so live content
1430 * (e.g. rtspsrc taking some time to fall back to tcp) */
1431 GST_BUFFER_TIMESTAMP (payload->buf) = payload->ts + demux->in_gap;
1432 if (payload->duration == GST_CLOCK_TIME_NONE
1433 && stream->ext_props.avg_time_per_frame != 0)
1434 GST_BUFFER_DURATION (payload->buf) =
1435 stream->ext_props.avg_time_per_frame * 100;
1436 else
1437 GST_BUFFER_DURATION (payload->buf) = payload->duration;
1439 /* FIXME: we should really set durations on buffers if we can */
1441 GST_LOG_OBJECT (stream->pad, "pushing buffer, ts=%" GST_TIME_FORMAT
1442 ", dur=%" GST_TIME_FORMAT " size=%u",
1443 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (payload->buf)),
1444 GST_TIME_ARGS (GST_BUFFER_DURATION (payload->buf)),
1445 GST_BUFFER_SIZE (payload->buf));
1447 ret = gst_pad_push (stream->pad, payload->buf);
1448 ret = gst_asf_demux_aggregate_flow_return (demux, stream, ret);
1449 payload->buf = NULL;
1450 g_array_remove_index (stream->payloads, 0);
1452 /* Break out as soon as we have an issue */
1453 if (G_UNLIKELY (ret != GST_FLOW_OK))
1454 break;
1455 }
1457 return ret;
1458 }
1460 static gboolean
1461 gst_asf_demux_check_buffer_is_header (GstASFDemux * demux, GstBuffer * buf)
1462 {
1463 AsfObject obj;
1464 g_assert (buf != NULL);
1466 GST_LOG_OBJECT (demux, "Checking if buffer is a header");
1468 /* we return false on buffer too small */
1469 if (GST_BUFFER_SIZE (buf) < ASF_OBJECT_HEADER_SIZE)
1470 return FALSE;
1472 /* check if it is a header */
1473 asf_demux_peek_object (demux, GST_BUFFER_DATA (buf),
1474 ASF_OBJECT_HEADER_SIZE, &obj, TRUE);
1475 if (obj.id == ASF_OBJ_HEADER) {
1476 return TRUE;
1477 }
1478 return FALSE;
1479 }
1481 static gboolean
1482 gst_asf_demux_check_chained_asf (GstASFDemux * demux)
1483 {
1484 guint64 off = demux->data_offset + (demux->packet * demux->packet_size);
1485 GstFlowReturn ret = GST_FLOW_OK;
1486 GstBuffer *buf = NULL;
1487 gboolean header = FALSE;
1489 /* TODO maybe we should skip index objects after the data and look
1490 * further for a new header */
1491 if (gst_asf_demux_pull_data (demux, off, ASF_OBJECT_HEADER_SIZE, &buf, &ret)) {
1492 g_assert (buf != NULL);
1493 /* check if it is a header */
1494 if (gst_asf_demux_check_buffer_is_header (demux, buf)) {
1495 GST_DEBUG_OBJECT (demux, "new base offset: %" G_GUINT64_FORMAT, off);
1496 demux->base_offset = off;
1497 header = TRUE;
1498 }
1500 gst_buffer_unref (buf);
1501 }
1503 return header;
1504 }
1506 static void
1507 gst_asf_demux_loop (GstASFDemux * demux)
1508 {
1509 GstFlowReturn flow = GST_FLOW_OK;
1510 GstBuffer *buf = NULL;
1511 guint64 off;
1512 gboolean sent_eos = FALSE;
1514 if (G_UNLIKELY (demux->state == GST_ASF_DEMUX_STATE_HEADER)) {
1515 if (!gst_asf_demux_pull_headers (demux)) {
1516 flow = GST_FLOW_ERROR;
1517 goto pause;
1518 }
1520 gst_asf_demux_pull_indices (demux);
1521 }
1523 g_assert (demux->state == GST_ASF_DEMUX_STATE_DATA);
1525 if (G_UNLIKELY (demux->num_packets != 0
1526 && demux->packet >= demux->num_packets))
1527 goto eos;
1529 GST_LOG_OBJECT (demux, "packet %u/%u", (guint) demux->packet + 1,
1530 (guint) demux->num_packets);
1532 off = demux->data_offset + (demux->packet * demux->packet_size);
1534 if (G_UNLIKELY (!gst_asf_demux_pull_data (demux, off,
1535 demux->packet_size * demux->speed_packets, &buf, &flow))) {
1536 GST_DEBUG_OBJECT (demux, "got flow %s", gst_flow_get_name (flow));
1537 if (flow == GST_FLOW_UNEXPECTED)
1538 goto eos;
1539 else if (flow == GST_FLOW_WRONG_STATE) {
1540 GST_DEBUG_OBJECT (demux, "Not fatal");
1541 goto pause;
1542 } else
1543 goto read_failed;
1544 }
1546 if (G_LIKELY (demux->speed_packets == 1)) {
1547 /* FIXME: maybe we should just skip broken packets and error out only
1548 * after a few broken packets in a row? */
1549 if (G_UNLIKELY (!gst_asf_demux_parse_packet (demux, buf))) {
1550 /* when we don't know when the data object ends, we should check
1551 * for a chained asf */
1552 if (demux->num_packets == 0) {
1553 if (gst_asf_demux_check_buffer_is_header (demux, buf)) {
1554 GST_INFO_OBJECT (demux, "Chained asf found");
1555 demux->base_offset = off;
1556 gst_asf_demux_reset (demux, TRUE);
1557 gst_buffer_unref (buf);
1558 return;
1559 }
1560 }
1561 goto parse_error;
1562 }
1564 flow = gst_asf_demux_push_complete_payloads (demux, FALSE);
1566 ++demux->packet;
1568 } else {
1569 guint n;
1570 for (n = 0; n < demux->speed_packets; n++) {
1571 GstBuffer *sub;
1573 sub =
1574 gst_buffer_create_sub (buf, n * demux->packet_size,
1575 demux->packet_size);
1576 /* FIXME: maybe we should just skip broken packets and error out only
1577 * after a few broken packets in a row? */
1578 if (G_UNLIKELY (!gst_asf_demux_parse_packet (demux, sub))) {
1579 /* when we don't know when the data object ends, we should check
1580 * for a chained asf */
1581 if (demux->num_packets == 0) {
1582 if (gst_asf_demux_check_buffer_is_header (demux, sub)) {
1583 GST_INFO_OBJECT (demux, "Chained asf found");
1584 demux->base_offset = off + n * demux->packet_size;
1585 gst_asf_demux_reset (demux, TRUE);
1586 gst_buffer_unref (sub);
1587 gst_buffer_unref (buf);
1588 return;
1589 }
1590 }
1591 goto parse_error;
1592 }
1594 gst_buffer_unref (sub);
1596 flow = gst_asf_demux_push_complete_payloads (demux, FALSE);
1598 ++demux->packet;
1600 }
1602 /* reset speed pull */
1603 demux->speed_packets = 1;
1604 }
1606 gst_buffer_unref (buf);
1608 if (G_UNLIKELY (demux->num_packets > 0
1609 && demux->packet >= demux->num_packets)) {
1610 GST_LOG_OBJECT (demux, "reached EOS");
1611 goto eos;
1612 }
1614 if (G_UNLIKELY (flow != GST_FLOW_OK)) {
1615 GST_DEBUG_OBJECT (demux, "pushing complete payloads failed");
1616 goto pause;
1617 }
1619 /* check if we're at the end of the configured segment */
1620 /* FIXME: check if segment end reached etc. */
1622 return;
1624 eos:
1625 {
1626 /* if we haven't activated our streams yet, this might be because we have
1627 * less data queued than required for preroll; force stream activation and
1628 * send any pending payloads before sending EOS */
1629 if (!demux->activated_streams)
1630 gst_asf_demux_push_complete_payloads (demux, TRUE);
1632 /* we want to push an eos or post a segment-done in any case */
1633 if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
1634 gint64 stop;
1636 /* for segment playback we need to post when (in stream time)
1637 * we stopped, this is either stop (when set) or the duration. */
1638 if ((stop = demux->segment.stop) == -1)
1639 stop = demux->segment.duration;
1641 GST_INFO_OBJECT (demux, "Posting segment-done, at end of segment");
1642 gst_element_post_message (GST_ELEMENT_CAST (demux),
1643 gst_message_new_segment_done (GST_OBJECT (demux), GST_FORMAT_TIME,
1644 stop));
1645 } else if (flow != GST_FLOW_UNEXPECTED) {
1646 /* check if we have a chained asf, in case, we don't eos yet */
1647 if (gst_asf_demux_check_chained_asf (demux)) {
1648 GST_INFO_OBJECT (demux, "Chained ASF starting");
1649 gst_asf_demux_reset (demux, TRUE);
1650 return;
1651 }
1652 }
1653 /* normal playback, send EOS to all linked pads */
1654 GST_INFO_OBJECT (demux, "Sending EOS, at end of stream");
1655 gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
1656 sent_eos = TRUE;
1657 /* ... and fall through to pause */
1658 }
1659 pause:
1660 {
1661 GST_DEBUG_OBJECT (demux, "pausing task, flow return: %s",
1662 gst_flow_get_name (flow));
1663 demux->segment_running = FALSE;
1664 gst_pad_pause_task (demux->sinkpad);
1666 /* For the error cases (not EOS) */
1667 if (!sent_eos) {
1668 if (flow == GST_FLOW_UNEXPECTED)
1669 gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
1670 else if (flow < GST_FLOW_UNEXPECTED || flow == GST_FLOW_NOT_LINKED) {
1671 /* Post an error. Hopefully something else already has, but if not... */
1672 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
1673 (_("Internal data stream error.")),
1674 ("streaming stopped, reason %s", gst_flow_get_name (flow)));
1675 }
1676 }
1677 return;
1678 }
1680 /* ERRORS */
1681 read_failed:
1682 {
1683 GST_DEBUG_OBJECT (demux, "Read failed, doh");
1684 gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
1685 flow = GST_FLOW_UNEXPECTED;
1686 goto pause;
1687 }
1688 parse_error:
1689 {
1690 gst_buffer_unref (buf);
1691 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
1692 ("Error parsing ASF packet %u", (guint) demux->packet));
1693 gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
1694 flow = GST_FLOW_ERROR;
1695 goto pause;
1696 }
1697 }
1699 #define GST_ASF_DEMUX_CHECK_HEADER_YES 0
1700 #define GST_ASF_DEMUX_CHECK_HEADER_NO 1
1701 #define GST_ASF_DEMUX_CHECK_HEADER_NEED_DATA 2
1703 static gint
1704 gst_asf_demux_check_header (GstASFDemux * demux)
1705 {
1706 AsfObject obj;
1707 guint8 *cdata = (guint8 *) gst_adapter_peek (demux->adapter,
1708 ASF_OBJECT_HEADER_SIZE);
1709 if (cdata == NULL) /* need more data */
1710 return GST_ASF_DEMUX_CHECK_HEADER_NEED_DATA;
1712 asf_demux_peek_object (demux, cdata, ASF_OBJECT_HEADER_SIZE, &obj, FALSE);
1713 if (obj.id != ASF_OBJ_HEADER) {
1714 return GST_ASF_DEMUX_CHECK_HEADER_NO;
1715 } else {
1716 return GST_ASF_DEMUX_CHECK_HEADER_YES;
1717 }
1718 }
1720 static GstFlowReturn
1721 gst_asf_demux_chain (GstPad * pad, GstBuffer * buf)
1722 {
1723 GstFlowReturn ret = GST_FLOW_OK;
1724 GstASFDemux *demux;
1726 demux = GST_ASF_DEMUX (GST_PAD_PARENT (pad));
1728 GST_LOG_OBJECT (demux, "buffer: size=%u, offset=%" G_GINT64_FORMAT ", time=%"
1729 GST_TIME_FORMAT, GST_BUFFER_SIZE (buf), GST_BUFFER_OFFSET (buf),
1730 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)));
1732 if (G_UNLIKELY (GST_BUFFER_IS_DISCONT (buf))) {
1733 GST_DEBUG_OBJECT (demux, "received DISCONT");
1734 gst_asf_demux_mark_discont (demux);
1735 }
1737 if (G_UNLIKELY ((!GST_CLOCK_TIME_IS_VALID (demux->in_gap) &&
1738 GST_BUFFER_TIMESTAMP_IS_VALID (buf)))) {
1739 demux->in_gap = GST_BUFFER_TIMESTAMP (buf) - demux->in_segment.start;
1740 GST_DEBUG_OBJECT (demux, "upstream segment start %" GST_TIME_FORMAT
1741 ", interpolation gap: %" GST_TIME_FORMAT,
1742 GST_TIME_ARGS (demux->in_segment.start), GST_TIME_ARGS (demux->in_gap));
1743 }
1745 gst_adapter_push (demux->adapter, buf);
1747 switch (demux->state) {
1748 case GST_ASF_DEMUX_STATE_INDEX:{
1749 gint result = gst_asf_demux_check_header (demux);
1750 if (result == GST_ASF_DEMUX_CHECK_HEADER_NEED_DATA) /* need more data */
1751 break;
1753 if (result == GST_ASF_DEMUX_CHECK_HEADER_NO) {
1754 /* we don't care about this, probably an index */
1755 /* TODO maybe would be smarter to skip all the indices
1756 * until we got a new header or EOS to decide */
1757 GST_LOG_OBJECT (demux, "Received index object, its EOS");
1758 goto eos;
1759 } else {
1760 GST_INFO_OBJECT (demux, "Chained asf starting");
1761 /* cleanup and get ready for a chained asf */
1762 gst_asf_demux_reset (demux, TRUE);
1763 /* fall through */
1764 }
1765 }
1766 case GST_ASF_DEMUX_STATE_HEADER:{
1767 ret = gst_asf_demux_chain_headers (demux);
1768 if (demux->state != GST_ASF_DEMUX_STATE_DATA)
1769 break;
1770 /* otherwise fall through */
1771 }
1772 case GST_ASF_DEMUX_STATE_DATA:
1773 {
1774 guint64 data_size;
1776 data_size = demux->packet_size;
1778 while (gst_adapter_available (demux->adapter) >= data_size) {
1779 GstBuffer *buf;
1781 /* we don't know the length of the stream
1782 * check for a chained asf everytime */
1783 if (demux->num_packets == 0) {
1784 gint result = gst_asf_demux_check_header (demux);
1786 if (result == GST_ASF_DEMUX_CHECK_HEADER_YES) {
1787 GST_INFO_OBJECT (demux, "Chained asf starting");
1788 /* cleanup and get ready for a chained asf */
1789 gst_asf_demux_reset (demux, TRUE);
1790 break;
1791 }
1792 } else if (G_UNLIKELY (demux->num_packets != 0 && demux->packet >= 0
1793 && demux->packet >= demux->num_packets)) {
1794 /* do not overshoot data section when streaming */
1795 break;
1796 }
1798 buf = gst_adapter_take_buffer (demux->adapter, data_size);
1800 /* FIXME: maybe we should just skip broken packets and error out only
1801 * after a few broken packets in a row? */
1802 if (G_UNLIKELY (!gst_asf_demux_parse_packet (demux, buf))) {
1803 GST_WARNING_OBJECT (demux, "Parse error");
1804 }
1806 gst_buffer_unref (buf);
1808 ret = gst_asf_demux_push_complete_payloads (demux, FALSE);
1810 if (demux->packet >= 0)
1811 ++demux->packet;
1812 }
1813 if (G_UNLIKELY (demux->num_packets != 0 && demux->packet >= 0
1814 && demux->packet >= demux->num_packets)) {
1815 demux->state = GST_ASF_DEMUX_STATE_INDEX;
1816 }
1817 break;
1818 }
1819 default:
1820 g_assert_not_reached ();
1821 }
1823 done:
1824 if (ret != GST_FLOW_OK)
1825 GST_DEBUG_OBJECT (demux, "flow: %s", gst_flow_get_name (ret));
1827 return ret;
1829 eos:
1830 {
1831 GST_DEBUG_OBJECT (demux, "Handled last packet, setting EOS");
1832 ret = GST_FLOW_UNEXPECTED;
1833 goto done;
1834 }
1835 }
1837 static inline gboolean
1838 gst_asf_demux_skip_bytes (guint num_bytes, guint8 ** p_data, guint64 * p_size)
1839 {
1840 if (*p_size < num_bytes)
1841 return FALSE;
1843 *p_data += num_bytes;
1844 *p_size -= num_bytes;
1845 return TRUE;
1846 }
1848 static inline guint8
1849 gst_asf_demux_get_uint8 (guint8 ** p_data, guint64 * p_size)
1850 {
1851 guint8 ret;
1853 g_assert (*p_size >= 1);
1854 ret = GST_READ_UINT8 (*p_data);
1855 *p_data += sizeof (guint8);
1856 *p_size -= sizeof (guint8);
1857 return ret;
1858 }
1860 static inline guint16
1861 gst_asf_demux_get_uint16 (guint8 ** p_data, guint64 * p_size)
1862 {
1863 guint16 ret;
1865 g_assert (*p_size >= 2);
1866 ret = GST_READ_UINT16_LE (*p_data);
1867 *p_data += sizeof (guint16);
1868 *p_size -= sizeof (guint16);
1869 return ret;
1870 }
1872 static inline guint32
1873 gst_asf_demux_get_uint32 (guint8 ** p_data, guint64 * p_size)
1874 {
1875 guint32 ret;
1877 g_assert (*p_size >= 4);
1878 ret = GST_READ_UINT32_LE (*p_data);
1879 *p_data += sizeof (guint32);
1880 *p_size -= sizeof (guint32);
1881 return ret;
1882 }
1884 static inline guint64
1885 gst_asf_demux_get_uint64 (guint8 ** p_data, guint64 * p_size)
1886 {
1887 guint64 ret;
1889 g_assert (*p_size >= 8);
1890 ret = GST_READ_UINT64_LE (*p_data);
1891 *p_data += sizeof (guint64);
1892 *p_size -= sizeof (guint64);
1893 return ret;
1894 }
1896 static inline guint32
1897 gst_asf_demux_get_var_length (guint8 type, guint8 ** p_data, guint64 * p_size)
1898 {
1899 switch (type) {
1900 case 0:
1901 return 0;
1903 case 1:
1904 g_assert (*p_size >= 1);
1905 return gst_asf_demux_get_uint8 (p_data, p_size);
1907 case 2:
1908 g_assert (*p_size >= 2);
1909 return gst_asf_demux_get_uint16 (p_data, p_size);
1911 case 3:
1912 g_assert (*p_size >= 4);
1913 return gst_asf_demux_get_uint32 (p_data, p_size);
1915 default:
1916 g_assert_not_reached ();
1917 break;
1918 }
1919 return 0;
1920 }
1922 static gboolean
1923 gst_asf_demux_get_buffer (GstBuffer ** p_buf, guint num_bytes_to_read,
1924 guint8 ** p_data, guint64 * p_size)
1925 {
1926 *p_buf = NULL;
1928 if (*p_size < num_bytes_to_read)
1929 return FALSE;
1931 *p_buf = gst_buffer_new_and_alloc (num_bytes_to_read);
1932 memcpy (GST_BUFFER_DATA (*p_buf), *p_data, num_bytes_to_read);
1933 *p_data += num_bytes_to_read;
1934 *p_size -= num_bytes_to_read;
1935 return TRUE;
1936 }
1938 static gboolean
1939 gst_asf_demux_get_bytes (guint8 ** p_buf, guint num_bytes_to_read,
1940 guint8 ** p_data, guint64 * p_size)
1941 {
1942 *p_buf = NULL;
1944 if (*p_size < num_bytes_to_read)
1945 return FALSE;
1947 *p_buf = g_memdup (*p_data, num_bytes_to_read);
1948 *p_data += num_bytes_to_read;
1949 *p_size -= num_bytes_to_read;
1950 return TRUE;
1951 }
1953 static gboolean
1954 gst_asf_demux_get_string (gchar ** p_str, guint16 * p_strlen,
1955 guint8 ** p_data, guint64 * p_size)
1956 {
1957 guint16 s_length;
1958 guint8 *s;
1960 *p_str = NULL;
1962 if (*p_size < 2)
1963 return FALSE;
1965 s_length = gst_asf_demux_get_uint16 (p_data, p_size);
1967 if (p_strlen)
1968 *p_strlen = s_length;
1970 if (s_length == 0) {
1971 GST_WARNING ("zero-length string");
1972 *p_str = g_strdup ("");
1973 return TRUE;
1974 }
1976 if (!gst_asf_demux_get_bytes (&s, s_length, p_data, p_size))
1977 return FALSE;
1979 g_assert (s != NULL);
1981 /* just because They don't exist doesn't
1982 * mean They are not out to get you ... */
1983 if (s[s_length - 1] != '\0') {
1984 s = g_realloc (s, s_length + 1);
1985 s[s_length] = '\0';
1986 }
1988 *p_str = (gchar *) s;
1989 return TRUE;
1990 }
1993 static void
1994 gst_asf_demux_get_guid (ASFGuid * guid, guint8 ** p_data, guint64 * p_size)
1995 {
1996 g_assert (*p_size >= 4 * sizeof (guint32));
1998 guid->v1 = gst_asf_demux_get_uint32 (p_data, p_size);
1999 guid->v2 = gst_asf_demux_get_uint32 (p_data, p_size);
2000 guid->v3 = gst_asf_demux_get_uint32 (p_data, p_size);
2001 guid->v4 = gst_asf_demux_get_uint32 (p_data, p_size);
2002 }
2004 static gboolean
2005 gst_asf_demux_get_stream_audio (asf_stream_audio * audio, guint8 ** p_data,
2006 guint64 * p_size)
2007 {
2008 if (*p_size < (2 + 2 + 4 + 4 + 2 + 2 + 2))
2009 return FALSE;
2011 /* WAVEFORMATEX Structure */
2012 audio->codec_tag = gst_asf_demux_get_uint16 (p_data, p_size);
2013 audio->channels = gst_asf_demux_get_uint16 (p_data, p_size);
2014 audio->sample_rate = gst_asf_demux_get_uint32 (p_data, p_size);
2015 audio->byte_rate = gst_asf_demux_get_uint32 (p_data, p_size);
2016 audio->block_align = gst_asf_demux_get_uint16 (p_data, p_size);
2017 audio->word_size = gst_asf_demux_get_uint16 (p_data, p_size);
2018 /* Codec specific data size */
2019 audio->size = gst_asf_demux_get_uint16 (p_data, p_size);
2020 return TRUE;
2021 }
2023 static gboolean
2024 gst_asf_demux_get_stream_video (asf_stream_video * video, guint8 ** p_data,
2025 guint64 * p_size)
2026 {
2027 if (*p_size < (4 + 4 + 1 + 2))
2028 return FALSE;
2030 video->width = gst_asf_demux_get_uint32 (p_data, p_size);
2031 video->height = gst_asf_demux_get_uint32 (p_data, p_size);
2032 video->unknown = gst_asf_demux_get_uint8 (p_data, p_size);
2033 video->size = gst_asf_demux_get_uint16 (p_data, p_size);
2034 return TRUE;
2035 }
2037 static gboolean
2038 gst_asf_demux_get_stream_video_format (asf_stream_video_format * fmt,
2039 guint8 ** p_data, guint64 * p_size)
2040 {
2041 if (*p_size < (4 + 4 + 4 + 2 + 2 + 4 + 4 + 4 + 4 + 4 + 4))
2042 return FALSE;
2044 fmt->size = gst_asf_demux_get_uint32 (p_data, p_size);
2045 fmt->width = gst_asf_demux_get_uint32 (p_data, p_size);
2046 fmt->height = gst_asf_demux_get_uint32 (p_data, p_size);
2047 fmt->planes = gst_asf_demux_get_uint16 (p_data, p_size);
2048 fmt->depth = gst_asf_demux_get_uint16 (p_data, p_size);
2049 fmt->tag = gst_asf_demux_get_uint32 (p_data, p_size);
2050 fmt->image_size = gst_asf_demux_get_uint32 (p_data, p_size);
2051 fmt->xpels_meter = gst_asf_demux_get_uint32 (p_data, p_size);
2052 fmt->ypels_meter = gst_asf_demux_get_uint32 (p_data, p_size);
2053 fmt->num_colors = gst_asf_demux_get_uint32 (p_data, p_size);
2054 fmt->imp_colors = gst_asf_demux_get_uint32 (p_data, p_size);
2055 return TRUE;
2056 }
2058 AsfStream *
2059 gst_asf_demux_get_stream (GstASFDemux * demux, guint16 id)
2060 {
2061 guint i;
2063 for (i = 0; i < demux->num_streams; i++) {
2064 if (demux->stream[i].id == id)
2065 return &demux->stream[i];
2066 }
2068 GST_WARNING ("Segment found for undefined stream: (%d)", id);
2069 return NULL;
2070 }
2072 static void
2073 gst_asf_demux_setup_pad (GstASFDemux * demux, GstPad * src_pad,
2074 GstCaps * caps, guint16 id, gboolean is_video, GstTagList * tags)
2075 {
2076 AsfStream *stream;
2078 gst_pad_use_fixed_caps (src_pad);
2079 gst_pad_set_caps (src_pad, caps);
2081 gst_pad_set_event_function (src_pad,
2082 GST_DEBUG_FUNCPTR (gst_asf_demux_handle_src_event));
2083 gst_pad_set_query_type_function (src_pad,
2084 GST_DEBUG_FUNCPTR (gst_asf_demux_get_src_query_types));
2085 gst_pad_set_query_function (src_pad,
2086 GST_DEBUG_FUNCPTR (gst_asf_demux_handle_src_query));
2088 stream = &demux->stream[demux->num_streams];
2089 stream->caps = caps;
2090 stream->pad = src_pad;
2091 stream->id = id;
2092 stream->fps_known = !is_video; /* bit hacky for audio */
2093 stream->is_video = is_video;
2094 stream->pending_tags = tags;
2095 stream->discont = TRUE;
2096 if (is_video) {
2097 GstStructure *st;
2098 gint par_x, par_y;
2099 st = gst_caps_get_structure (caps, 0);
2100 if (gst_structure_get_fraction (st, "pixel-aspect-ratio", &par_x, &par_y) &&
2101 par_x > 0 && par_y > 0) {
2102 GST_DEBUG ("PAR %d/%d", par_x, par_y);
2103 stream->par_x = par_x;
2104 stream->par_y = par_y;
2105 }
2106 }
2108 stream->payloads = g_array_new (FALSE, FALSE, sizeof (AsfPayload));
2110 GST_INFO ("Created pad %s for stream %u with caps %" GST_PTR_FORMAT,
2111 GST_PAD_NAME (src_pad), demux->num_streams, caps);
2113 ++demux->num_streams;
2115 stream->active = FALSE;
2116 }
2118 static void
2119 gst_asf_demux_add_audio_stream (GstASFDemux * demux,
2120 asf_stream_audio * audio, guint16 id, guint8 ** p_data, guint64 * p_size)
2121 {
2122 GstTagList *tags = NULL;
2123 GstBuffer *extradata = NULL;
2124 GstPad *src_pad;
2125 GstCaps *caps;
2126 guint16 size_left = 0;
2127 gchar *codec_name = NULL;
2128 gchar *name = NULL;
2130 size_left = audio->size;
2132 /* Create the audio pad */
2133 name = g_strdup_printf ("audio_%02d", demux->num_audio_streams);
2135 src_pad = gst_pad_new_from_static_template (&audio_src_template, name);
2136 g_free (name);
2138 /* Swallow up any left over data and set up the
2139 * standard properties from the header info */
2140 if (size_left) {
2141 GST_INFO_OBJECT (demux, "Audio header contains %d bytes of "
2142 "codec specific data", size_left);
2144 g_assert (size_left <= *p_size);
2145 gst_asf_demux_get_buffer (&extradata, size_left, p_data, p_size);
2146 }
2148 /* asf_stream_audio is the same as gst_riff_strf_auds, but with an
2149 * additional two bytes indicating extradata. */
2150 caps = gst_riff_create_audio_caps (audio->codec_tag, NULL,
2151 (gst_riff_strf_auds *) audio, extradata, NULL, &codec_name);
2153 if (caps == NULL) {
2154 caps = gst_caps_new_simple ("audio/x-asf-unknown", "codec_id",
2155 G_TYPE_INT, (gint) audio->codec_tag, NULL);
2156 }
2158 /* Informing about that audio format we just added */
2159 if (codec_name) {
2160 tags = gst_tag_list_new ();
2161 gst_tag_list_add (tags, GST_TAG_MERGE_APPEND, GST_TAG_AUDIO_CODEC,
2162 codec_name, NULL);
2163 g_free (codec_name);
2164 }
2166 if (extradata)
2167 gst_buffer_unref (extradata);
2169 GST_INFO ("Adding audio stream #%u, id %u codec %u (0x%04x), tags=%"
2170 GST_PTR_FORMAT, demux->num_audio_streams, id, audio->codec_tag,
2171 audio->codec_tag, tags);
2173 ++demux->num_audio_streams;
2175 gst_asf_demux_setup_pad (demux, src_pad, caps, id, FALSE, tags);
2176 }
2178 static void
2179 gst_asf_demux_add_video_stream (GstASFDemux * demux,
2180 asf_stream_video_format * video, guint16 id,
2181 guint8 ** p_data, guint64 * p_size)
2182 {
2183 GstTagList *tags = NULL;
2184 GstBuffer *extradata = NULL;
2185 GstPad *src_pad;
2186 GstCaps *caps;
2187 gchar *name = NULL;
2188 gchar *codec_name = NULL;
2189 gint size_left = video->size - 40;
2191 /* Create the video pad */
2192 name = g_strdup_printf ("video_%02d", demux->num_video_streams);
2193 src_pad = gst_pad_new_from_static_template (&video_src_template, name);
2194 g_free (name);
2196 /* Now try some gstreamer formatted MIME types (from gst_avi_demux_strf_vids) */
2197 if (size_left) {
2198 GST_LOG ("Video header has %d bytes of codec specific data", size_left);
2199 g_assert (size_left <= *p_size);
2200 gst_asf_demux_get_buffer (&extradata, size_left, p_data, p_size);
2201 }
2203 GST_DEBUG ("video codec %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (video->tag));
2205 /* yes, asf_stream_video_format and gst_riff_strf_vids are the same */
2206 caps = gst_riff_create_video_caps (video->tag, NULL,
2207 (gst_riff_strf_vids *) video, extradata, NULL, &codec_name);
2209 if (caps == NULL) {
2210 caps = gst_caps_new_simple ("video/x-asf-unknown", "fourcc",
2211 GST_TYPE_FOURCC, video->tag, NULL);
2212 } else {
2213 GstStructure *s;
2214 gint ax, ay;
2216 s = gst_asf_demux_get_metadata_for_stream (demux, id);
2217 if (gst_structure_get_int (s, "AspectRatioX", &ax) &&
2218 gst_structure_get_int (s, "AspectRatioY", &ay) && (ax > 0 && ay > 0)) {
2219 gst_caps_set_simple (caps, "pixel-aspect-ratio", GST_TYPE_FRACTION,
2220 ax, ay, NULL);
2222 } else {
2223 guint ax, ay;
2224 /* retry with the global metadata */
2225 GST_DEBUG ("Retrying with global metadata %" GST_PTR_FORMAT,
2226 demux->global_metadata);
2227 s = demux->global_metadata;
2228 if (gst_structure_get_uint (s, "AspectRatioX", &ax) &&
2229 gst_structure_get_uint (s, "AspectRatioY", &ay)) {
2230 GST_DEBUG ("ax:%d, ay:%d", ax, ay);
2231 if (ax > 0 && ay > 0)
2232 gst_caps_set_simple (caps, "pixel-aspect-ratio", GST_TYPE_FRACTION,
2233 ax, ay, NULL);
2234 }
2235 }
2236 s = gst_caps_get_structure (caps, 0);
2237 gst_structure_remove_field (s, "framerate");
2238 }
2240 /* add fourcc format to caps, some proprietary decoders seem to need it */
2241 gst_caps_set_simple (caps, "format", GST_TYPE_FOURCC, video->tag, NULL);
2243 if (codec_name) {
2244 tags = gst_tag_list_new ();
2245 gst_tag_list_add (tags, GST_TAG_MERGE_APPEND, GST_TAG_VIDEO_CODEC,
2246 codec_name, NULL);
2247 g_free (codec_name);
2248 }
2250 if (extradata)
2251 gst_buffer_unref (extradata);
2253 GST_INFO ("Adding video stream #%u, id %u, codec %"
2254 GST_FOURCC_FORMAT " (0x%08x)", demux->num_video_streams, id,
2255 GST_FOURCC_ARGS (video->tag), video->tag);
2257 ++demux->num_video_streams;
2259 gst_asf_demux_setup_pad (demux, src_pad, caps, id, TRUE, tags);
2260 }
2262 static void
2263 gst_asf_demux_activate_stream (GstASFDemux * demux, AsfStream * stream)
2264 {
2265 if (!stream->active) {
2266 GST_INFO_OBJECT (demux, "Activating stream %2u, pad %s, caps %"
2267 GST_PTR_FORMAT, stream->id, GST_PAD_NAME (stream->pad), stream->caps);
2268 gst_pad_set_active (stream->pad, TRUE);
2269 gst_element_add_pad (GST_ELEMENT_CAST (demux), stream->pad);
2270 stream->active = TRUE;
2271 }
2272 }
2274 static AsfStream *
2275 gst_asf_demux_parse_stream_object (GstASFDemux * demux, guint8 * data,
2276 guint64 size)
2277 {
2278 AsfCorrectionType correction_type;
2279 AsfStreamType stream_type;
2280 GstClockTime time_offset;
2281 gboolean is_encrypted G_GNUC_UNUSED;
2282 guint16 stream_id;
2283 guint16 flags;
2284 ASFGuid guid;
2285 guint stream_specific_size;
2286 guint type_specific_size G_GNUC_UNUSED;
2287 guint unknown G_GNUC_UNUSED;
2289 /* Get the rest of the header's header */
2290 if (size < (16 + 16 + 8 + 4 + 4 + 2 + 4))
2291 goto not_enough_data;
2293 gst_asf_demux_get_guid (&guid, &data, &size);
2294 stream_type = gst_asf_demux_identify_guid (asf_stream_guids, &guid);
2296 gst_asf_demux_get_guid (&guid, &data, &size);
2297 correction_type = gst_asf_demux_identify_guid (asf_correction_guids, &guid);
2299 time_offset = gst_asf_demux_get_uint64 (&data, &size) * 100;
2301 type_specific_size = gst_asf_demux_get_uint32 (&data, &size);
2302 stream_specific_size = gst_asf_demux_get_uint32 (&data, &size);
2304 flags = gst_asf_demux_get_uint16 (&data, &size);
2305 stream_id = flags & 0x7f;
2306 is_encrypted = ! !((flags & 0x8000) << 15);
2307 unknown = gst_asf_demux_get_uint32 (&data, &size);
2309 GST_DEBUG_OBJECT (demux, "Found stream %u, time_offset=%" GST_TIME_FORMAT,
2310 stream_id, GST_TIME_ARGS (time_offset));
2312 switch (stream_type) {
2313 case ASF_STREAM_AUDIO:{
2314 asf_stream_audio audio_object;
2316 if (!gst_asf_demux_get_stream_audio (&audio_object, &data, &size))
2317 goto not_enough_data;
2319 GST_INFO ("Object is an audio stream with %u bytes of additional data",
2320 audio_object.size);
2322 gst_asf_demux_add_audio_stream (demux, &audio_object, stream_id,
2323 &data, &size);
2325 switch (correction_type) {
2326 case ASF_CORRECTION_ON:{
2327 guint span, packet_size, chunk_size, data_size, silence_data;
2329 GST_INFO ("Using error correction");
2331 if (size < (1 + 2 + 2 + 2 + 1))
2332 goto not_enough_data;
2334 span = gst_asf_demux_get_uint8 (&data, &size);
2335 packet_size = gst_asf_demux_get_uint16 (&data, &size);
2336 chunk_size = gst_asf_demux_get_uint16 (&data, &size);
2337 data_size = gst_asf_demux_get_uint16 (&data, &size);
2338 silence_data = gst_asf_demux_get_uint8 (&data, &size);
2340 /* FIXME: shouldn't this be per-stream? */
2341 demux->span = span;
2343 GST_DEBUG_OBJECT (demux, "Descrambling ps:%u cs:%u ds:%u s:%u sd:%u",
2344 packet_size, chunk_size, data_size, span, silence_data);
2346 if (demux->span > 1) {
2347 if (chunk_size == 0 || ((packet_size / chunk_size) <= 1)) {
2348 /* Disable descrambling */
2349 demux->span = 0;
2350 } else {
2351 /* FIXME: this else branch was added for
2352 * weird_al_yankovic - the saga begins.asf */
2353 demux->ds_packet_size = packet_size;
2354 demux->ds_chunk_size = chunk_size;
2355 }
2356 } else {
2357 /* Descambling is enabled */
2358 demux->ds_packet_size = packet_size;
2359 demux->ds_chunk_size = chunk_size;
2360 }
2361 #if 0
2362 /* Now skip the rest of the silence data */
2363 if (data_size > 1)
2364 gst_bytestream_flush (demux->bs, data_size - 1);
2365 #else
2366 /* FIXME: CHECKME. And why -1? */
2367 if (data_size > 1) {
2368 if (!gst_asf_demux_skip_bytes (data_size - 1, &data, &size)) {
2369 goto not_enough_data;
2370 }
2371 }
2372 #endif
2373 break;
2374 }
2375 case ASF_CORRECTION_OFF:{
2376 GST_INFO ("Error correction off");
2377 if (!gst_asf_demux_skip_bytes (stream_specific_size, &data, &size))
2378 goto not_enough_data;
2379 break;
2380 }
2381 default:
2382 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
2383 ("Audio stream using unknown error correction"));
2384 return NULL;
2385 }
2387 break;
2388 }
2390 case ASF_STREAM_VIDEO:{
2391 asf_stream_video_format video_format_object;
2392 asf_stream_video video_object;
2393 guint16 vsize;
2395 if (!gst_asf_demux_get_stream_video (&video_object, &data, &size))
2396 goto not_enough_data;
2398 vsize = video_object.size - 40; /* Byte order gets offset by single byte */
2400 GST_INFO ("object is a video stream with %u bytes of "
2401 "additional data", vsize);
2403 if (!gst_asf_demux_get_stream_video_format (&video_format_object,
2404 &data, &size)) {
2405 goto not_enough_data;
2406 }
2408 gst_asf_demux_add_video_stream (demux, &video_format_object, stream_id,
2409 &data, &size);
2411 break;
2412 }
2414 default:
2415 GST_WARNING_OBJECT (demux, "Unknown stream type for stream %u",
2416 stream_id);
2417 break;
2418 }
2420 return gst_asf_demux_get_stream (demux, stream_id);
2422 not_enough_data:
2423 {
2424 GST_WARNING_OBJECT (demux, "Unexpected end of data parsing stream object");
2425 /* we'll error out later if we found no streams */
2426 return NULL;
2427 }
2428 }
2430 static const gchar *
2431 gst_asf_demux_get_gst_tag_from_tag_name (const gchar * name_utf8)
2432 {
2433 const struct
2434 {
2435 const gchar *asf_name;
2436 const gchar *gst_name;
2437 } tags[] = {
2438 {
2439 "WM/Genre", GST_TAG_GENRE}, {
2440 "WM/AlbumTitle", GST_TAG_ALBUM}, {
2441 "WM/AlbumArtist", GST_TAG_ARTIST}, {
2442 "WM/Picture", GST_TAG_IMAGE}, {
2443 "WM/Track", GST_TAG_TRACK_NUMBER}, {
2444 "WM/TrackNumber", GST_TAG_TRACK_NUMBER}, {
2445 "WM/Year", GST_TAG_DATE}
2446 /* { "WM/Composer", GST_TAG_COMPOSER } */
2447 };
2448 gsize out;
2449 guint i;
2451 if (name_utf8 == NULL) {
2452 GST_WARNING ("Failed to convert name to UTF8, skipping");
2453 return NULL;
2454 }
2456 out = strlen (name_utf8);
2458 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
2459 if (strncmp (tags[i].asf_name, name_utf8, out) == 0) {
2460 GST_LOG ("map tagname '%s' -> '%s'", name_utf8, tags[i].gst_name);
2461 return tags[i].gst_name;
2462 }
2463 }
2465 return NULL;
2466 }
2468 /* gst_asf_demux_add_global_tags() takes ownership of taglist! */
2469 static void
2470 gst_asf_demux_add_global_tags (GstASFDemux * demux, GstTagList * taglist)
2471 {
2472 GstTagList *t;
2474 GST_DEBUG_OBJECT (demux, "adding global tags: %" GST_PTR_FORMAT, taglist);
2476 if (taglist == NULL)
2477 return;
2479 if (gst_tag_list_is_empty (taglist)) {
2480 gst_tag_list_free (taglist);
2481 return;
2482 }
2484 t = gst_tag_list_merge (demux->taglist, taglist, GST_TAG_MERGE_APPEND);
2485 if (demux->taglist)
2486 gst_tag_list_free (demux->taglist);
2487 gst_tag_list_free (taglist);
2488 demux->taglist = t;
2489 GST_LOG_OBJECT (demux, "global tags now: %" GST_PTR_FORMAT, demux->taglist);
2490 }
2492 #define ASF_DEMUX_DATA_TYPE_UTF16LE_STRING 0
2493 #define ASF_DEMUX_DATA_TYPE_BYTE_ARRAY 1
2494 #define ASF_DEMUX_DATA_TYPE_DWORD 3
2496 static void
2497 asf_demux_parse_picture_tag (GstTagList * tags, const guint8 * tag_data,
2498 guint tag_data_len)
2499 {
2500 GstByteReader r;
2501 const guint8 *img_data = NULL;
2502 guint32 img_data_len = 0;
2503 guint8 pic_type = 0;
2505 gst_byte_reader_init (&r, tag_data, tag_data_len);
2507 /* skip mime type string (we don't trust it and do our own typefinding),
2508 * and also skip the description string, since we don't use it */
2509 if (!gst_byte_reader_get_uint8 (&r, &pic_type) ||
2510 !gst_byte_reader_get_uint32_le (&r, &img_data_len) ||
2511 !gst_byte_reader_skip_string_utf16 (&r) ||
2512 !gst_byte_reader_skip_string_utf16 (&r) ||
2513 !gst_byte_reader_get_data (&r, img_data_len, &img_data)) {
2514 goto not_enough_data;
2515 }
2518 if (!gst_tag_list_add_id3_image (tags, img_data, img_data_len, pic_type))
2519 GST_DEBUG ("failed to add image extracted from WM/Picture tag to taglist");
2521 return;
2523 not_enough_data:
2524 {
2525 GST_DEBUG ("Failed to read WM/Picture tag: not enough data");
2526 GST_MEMDUMP ("WM/Picture data", tag_data, tag_data_len);
2527 return;
2528 }
2529 }
2531 /* Extended Content Description Object */
2532 static GstFlowReturn
2533 gst_asf_demux_process_ext_content_desc (GstASFDemux * demux, guint8 * data,
2534 guint64 size)
2535 {
2536 /* Other known (and unused) 'text/unicode' metadata available :
2537 *
2538 * WM/Lyrics =
2539 * WM/MediaPrimaryClassID = {D1607DBC-E323-4BE2-86A1-48A42A28441E}
2540 * WMFSDKVersion = 9.00.00.2980
2541 * WMFSDKNeeded = 0.0.0.0000
2542 * WM/UniqueFileIdentifier = AMGa_id=R 15334;AMGp_id=P 5149;AMGt_id=T 2324984
2543 * WM/Publisher = 4AD
2544 * WM/Provider = AMG
2545 * WM/ProviderRating = 8
2546 * WM/ProviderStyle = Rock (similar to WM/Genre)
2547 * WM/GenreID (similar to WM/Genre)
2548 * WM/TrackNumber (same as WM/Track but as a string)
2549 *
2550 * Other known (and unused) 'non-text' metadata available :
2551 *
2552 * WM/EncodingTime
2553 * WM/MCDI
2554 * IsVBR
2555 *
2556 * We might want to read WM/TrackNumber and use atoi() if we don't have
2557 * WM/Track
2558 */
2560 GstTagList *taglist;
2561 guint16 blockcount, i;
2563 GST_INFO_OBJECT (demux, "object is an extended content description");
2565 taglist = gst_tag_list_new ();
2567 /* Content Descriptor Count */
2568 if (size < 2)
2569 goto not_enough_data;
2571 blockcount = gst_asf_demux_get_uint16 (&data, &size);
2573 for (i = 1; i <= blockcount; ++i) {
2574 const gchar *gst_tag_name;
2575 guint16 datatype;
2576 guint16 value_len;
2577 guint16 name_len;
2578 GValue tag_value = { 0, };
2579 gsize in, out;
2580 gchar *name;
2581 gchar *name_utf8 = NULL;
2582 gchar *value;
2584 /* Descriptor */
2585 if (!gst_asf_demux_get_string (&name, &name_len, &data, &size))
2586 goto not_enough_data;
2588 if (size < 2) {
2589 g_free (name);
2590 goto not_enough_data;
2591 }
2592 /* Descriptor Value Data Type */
2593 datatype = gst_asf_demux_get_uint16 (&data, &size);
2595 /* Descriptor Value (not really a string, but same thing reading-wise) */
2596 if (!gst_asf_demux_get_string (&value, &value_len, &data, &size)) {
2597 g_free (name);
2598 goto not_enough_data;
2599 }
2601 name_utf8 =
2602 g_convert (name, name_len, "UTF-8", "UTF-16LE", &in, &out, NULL);
2604 if (name_utf8 != NULL) {
2605 GST_DEBUG ("Found tag/metadata %s", name_utf8);
2607 gst_tag_name = gst_asf_demux_get_gst_tag_from_tag_name (name_utf8);
2608 GST_DEBUG ("gst_tag_name %s", GST_STR_NULL (gst_tag_name));
2610 switch (datatype) {
2611 case ASF_DEMUX_DATA_TYPE_UTF16LE_STRING:{
2612 gchar *value_utf8;
2614 value_utf8 = g_convert (value, value_len, "UTF-8", "UTF-16LE",
2615 &in, &out, NULL);
2617 /* get rid of tags with empty value */
2618 if (value_utf8 != NULL && *value_utf8 != '\0') {
2619 GST_DEBUG ("string value %s", value_utf8);
2621 value_utf8[out] = '\0';
2623 if (gst_tag_name != NULL) {
2624 if (strcmp (gst_tag_name, GST_TAG_DATE) == 0) {
2625 guint year = atoi (value_utf8);
2627 if (year > 0) {
2628 GDate *date = g_date_new_dmy (1, 1, year);
2630 g_value_init (&tag_value, GST_TYPE_DATE);
2631 gst_value_set_date (&tag_value, date);
2632 g_date_free (date);
2633 }
2634 } else if (strcmp (gst_tag_name, GST_TAG_GENRE) == 0) {
2635 guint id3v1_genre_id;
2636 const gchar *genre_str;
2638 if (sscanf (value_utf8, "(%u)", &id3v1_genre_id) == 1 &&
2639 ((genre_str = gst_tag_id3_genre_get (id3v1_genre_id)))) {
2640 GST_DEBUG ("Genre: %s -> %s", value_utf8, genre_str);
2641 g_free (value_utf8);
2642 value_utf8 = g_strdup (genre_str);
2643 }
2644 } else {
2645 GType tag_type;
2647 /* convert tag from string to other type if required */
2648 tag_type = gst_tag_get_type (gst_tag_name);
2649 g_value_init (&tag_value, tag_type);
2650 if (!gst_value_deserialize (&tag_value, value_utf8)) {
2651 GValue from_val = { 0, };
2653 g_value_init (&from_val, G_TYPE_STRING);
2654 g_value_set_string (&from_val, value_utf8);
2655 if (!g_value_transform (&from_val, &tag_value)) {
2656 GST_WARNING_OBJECT (demux,
2657 "Could not transform string tag to " "%s tag type %s",
2658 gst_tag_name, g_type_name (tag_type));
2659 g_value_unset (&tag_value);
2660 }
2661 g_value_unset (&from_val);
2662 }
2663 }
2664 } else {
2665 /* metadata ! */
2666 GST_DEBUG ("Setting metadata");
2667 g_value_init (&tag_value, G_TYPE_STRING);
2668 g_value_set_string (&tag_value, value_utf8);
2669 }
2670 } else if (value_utf8 == NULL) {
2671 GST_WARNING ("Failed to convert string value to UTF8, skipping");
2672 } else {
2673 GST_DEBUG ("Skipping empty string value for %s",
2674 GST_STR_NULL (gst_tag_name));
2675 }
2676 g_free (value_utf8);
2677 break;
2678 }
2679 case ASF_DEMUX_DATA_TYPE_BYTE_ARRAY:{
2680 if (gst_tag_name) {
2681 if (!g_str_equal (gst_tag_name, GST_TAG_IMAGE)) {
2682 GST_FIXME ("Unhandled byte array tag %s",
2683 GST_STR_NULL (gst_tag_name));
2684 break;
2685 } else {
2686 asf_demux_parse_picture_tag (taglist, (guint8 *) value,
2687 value_len);
2688 }
2689 }
2690 break;
2691 }
2692 case ASF_DEMUX_DATA_TYPE_DWORD:{
2693 guint uint_val = GST_READ_UINT32_LE (value);
2695 /* this is the track number */
2696 g_value_init (&tag_value, G_TYPE_UINT);
2698 /* WM/Track counts from 0 */
2699 if (!strcmp (name_utf8, "WM/Track"))
2700 ++uint_val;
2702 g_value_set_uint (&tag_value, uint_val);
2703 break;
2704 }
2705 default:{
2706 GST_DEBUG ("Skipping tag %s of type %d", gst_tag_name, datatype);
2707 break;
2708 }
2709 }
2711 if (G_IS_VALUE (&tag_value)) {
2712 if (gst_tag_name) {
2713 GstTagMergeMode merge_mode = GST_TAG_MERGE_APPEND;
2715 /* WM/TrackNumber is more reliable than WM/Track, since the latter
2716 * is supposed to have a 0 base but is often wrongly written to start
2717 * from 1 as well, so prefer WM/TrackNumber when we have it: either
2718 * replace the value added earlier from WM/Track or put it first in
2719 * the list, so that it will get picked up by _get_uint() */
2720 if (strcmp (name_utf8, "WM/TrackNumber") == 0)
2721 merge_mode = GST_TAG_MERGE_REPLACE;
2723 gst_tag_list_add_values (taglist, merge_mode, gst_tag_name,
2724 &tag_value, NULL);
2725 } else {
2726 GST_DEBUG ("Setting global metadata %s", name_utf8);
2727 gst_structure_set_value (demux->global_metadata, name_utf8,
2728 &tag_value);
2729 }
2731 g_value_unset (&tag_value);
2732 }
2733 }
2735 g_free (name);
2736 g_free (value);
2737 g_free (name_utf8);
2738 }
2740 gst_asf_demux_add_global_tags (demux, taglist);
2742 return GST_FLOW_OK;
2744 /* Errors */
2745 not_enough_data:
2746 {
2747 GST_WARNING ("Unexpected end of data parsing ext content desc object");
2748 gst_tag_list_free (taglist);
2749 return GST_FLOW_OK; /* not really fatal */
2750 }
2751 }
2753 static GstStructure *
2754 gst_asf_demux_get_metadata_for_stream (GstASFDemux * demux, guint stream_num)
2755 {
2756 gchar sname[32];
2757 guint i;
2759 g_snprintf (sname, sizeof (sname), "stream-%u", stream_num);
2761 for (i = 0; i < gst_caps_get_size (demux->metadata); ++i) {
2762 GstStructure *s;
2764 s = gst_caps_get_structure (demux->metadata, i);
2765 if (gst_structure_has_name (s, sname))
2766 return s;
2767 }
2769 gst_caps_append_structure (demux->metadata, gst_structure_empty_new (sname));
2771 /* try lookup again; demux->metadata took ownership of the structure, so we
2772 * can't really make any assumptions about what happened to it, so we can't
2773 * just return it directly after appending it */
2774 return gst_asf_demux_get_metadata_for_stream (demux, stream_num);
2775 }
2777 static GstFlowReturn
2778 gst_asf_demux_process_metadata (GstASFDemux * demux, guint8 * data,
2779 guint64 size)
2780 {
2781 guint16 blockcount, i;
2783 GST_INFO_OBJECT (demux, "object is a metadata object");
2785 /* Content Descriptor Count */
2786 if (size < 2)
2787 goto not_enough_data;
2789 blockcount = gst_asf_demux_get_uint16 (&data, &size);
2791 for (i = 0; i < blockcount; ++i) {
2792 GstStructure *s;
2793 guint16 stream_num, name_len, data_type, lang_idx G_GNUC_UNUSED;
2794 guint32 data_len, ival;
2795 gchar *name_utf8;
2797 if (size < (2 + 2 + 2 + 2 + 4))
2798 goto not_enough_data;
2800 lang_idx = gst_asf_demux_get_uint16 (&data, &size);
2801 stream_num = gst_asf_demux_get_uint16 (&data, &size);
2802 name_len = gst_asf_demux_get_uint16 (&data, &size);
2803 data_type = gst_asf_demux_get_uint16 (&data, &size);
2804 data_len = gst_asf_demux_get_uint32 (&data, &size);
2806 if (size < name_len + data_len)
2807 goto not_enough_data;
2809 /* convert name to UTF-8 */
2810 name_utf8 = g_convert ((gchar *) data, name_len, "UTF-8", "UTF-16LE",
2811 NULL, NULL, NULL);
2812 gst_asf_demux_skip_bytes (name_len, &data, &size);
2814 if (name_utf8 == NULL) {
2815 GST_WARNING ("Failed to convert value name to UTF8, skipping");
2816 gst_asf_demux_skip_bytes (data_len, &data, &size);
2817 continue;
2818 }
2820 if (data_type != ASF_DEMUX_DATA_TYPE_DWORD) {
2821 gst_asf_demux_skip_bytes (data_len, &data, &size);
2822 g_free (name_utf8);
2823 continue;
2824 }
2826 /* read DWORD */
2827 if (size < 4) {
2828 g_free (name_utf8);
2829 goto not_enough_data;
2830 }
2832 ival = gst_asf_demux_get_uint32 (&data, &size);
2834 /* skip anything else there may be, just in case */
2835 gst_asf_demux_skip_bytes (data_len - 4, &data, &size);
2837 s = gst_asf_demux_get_metadata_for_stream (demux, stream_num);
2838 gst_structure_set (s, name_utf8, G_TYPE_INT, ival, NULL);
2839 g_free (name_utf8);
2840 }
2842 GST_INFO_OBJECT (demux, "metadata = %" GST_PTR_FORMAT, demux->metadata);
2843 return GST_FLOW_OK;
2845 /* Errors */
2846 not_enough_data:
2847 {
2848 GST_WARNING ("Unexpected end of data parsing metadata object");
2849 return GST_FLOW_OK; /* not really fatal */
2850 }
2851 }
2853 static GstFlowReturn
2854 gst_asf_demux_process_header (GstASFDemux * demux, guint8 * data, guint64 size)
2855 {
2856 GstFlowReturn ret = GST_FLOW_OK;
2857 guint32 i, num_objects;
2858 guint8 unknown G_GNUC_UNUSED;
2860 /* Get the rest of the header's header */
2861 if (size < (4 + 1 + 1))
2862 goto not_enough_data;
2864 num_objects = gst_asf_demux_get_uint32 (&data, &size);
2865 unknown = gst_asf_demux_get_uint8 (&data, &size);
2866 unknown = gst_asf_demux_get_uint8 (&data, &size);
2868 GST_INFO_OBJECT (demux, "object is a header with %u parts", num_objects);
2870 /* Loop through the header's objects, processing those */
2871 for (i = 0; i < num_objects; ++i) {
2872 GST_INFO_OBJECT (demux, "reading header part %u", i);
2873 ret = gst_asf_demux_process_object (demux, &data, &size);
2874 if (ret != GST_FLOW_OK) {
2875 GST_WARNING ("process_object returned %s", gst_asf_get_flow_name (ret));
2876 break;
2877 }
2878 }
2880 return ret;
2882 not_enough_data:
2883 {
2884 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
2885 ("short read parsing HEADER object"));
2886 return GST_FLOW_ERROR;
2887 }
2888 }
2890 static GstFlowReturn
2891 gst_asf_demux_process_file (GstASFDemux * demux, guint8 * data, guint64 size)
2892 {
2893 guint64 creation_time G_GNUC_UNUSED;
2894 guint64 file_size G_GNUC_UNUSED;
2895 guint64 send_time G_GNUC_UNUSED;
2896 guint64 packets_count, play_time, preroll;
2897 guint32 flags, min_pktsize, max_pktsize, min_bitrate G_GNUC_UNUSED;
2899 if (size < (16 + 8 + 8 + 8 + 8 + 8 + 8 + 4 + 4 + 4 + 4))
2900 goto not_enough_data;
2902 gst_asf_demux_skip_bytes (16, &data, &size); /* skip GUID */
2903 file_size = gst_asf_demux_get_uint64 (&data, &size);
2904 creation_time = gst_asf_demux_get_uint64 (&data, &size);
2905 packets_count = gst_asf_demux_get_uint64 (&data, &size);
2906 play_time = gst_asf_demux_get_uint64 (&data, &size);
2907 send_time = gst_asf_demux_get_uint64 (&data, &size);
2908 preroll = gst_asf_demux_get_uint64 (&data, &size);
2909 flags = gst_asf_demux_get_uint32 (&data, &size);
2910 min_pktsize = gst_asf_demux_get_uint32 (&data, &size);
2911 max_pktsize = gst_asf_demux_get_uint32 (&data, &size);
2912 min_bitrate = gst_asf_demux_get_uint32 (&data, &size);
2914 demux->broadcast = ! !(flags & 0x01);
2915 demux->seekable = ! !(flags & 0x02);
2917 GST_DEBUG_OBJECT (demux, "min_pktsize = %u", min_pktsize);
2918 GST_DEBUG_OBJECT (demux, "flags::broadcast = %d", demux->broadcast);
2919 GST_DEBUG_OBJECT (demux, "flags::seekable = %d", demux->seekable);
2921 if (demux->broadcast) {
2922 /* these fields are invalid if the broadcast flag is set */
2923 play_time = 0;
2924 file_size = 0;
2925 }
2927 if (min_pktsize != max_pktsize)
2928 goto non_fixed_packet_size;
2930 demux->packet_size = max_pktsize;
2932 /* FIXME: do we need send_time as well? what is it? */
2933 if ((play_time * 100) >= (preroll * GST_MSECOND))
2934 demux->play_time = (play_time * 100) - (preroll * GST_MSECOND);
2935 else
2936 demux->play_time = 0;
2938 demux->preroll = preroll * GST_MSECOND;
2940 /* initial latency */
2941 demux->latency = demux->preroll;
2943 if (demux->play_time == 0)
2944 demux->seekable = FALSE;
2946 GST_DEBUG_OBJECT (demux, "play_time %" GST_TIME_FORMAT,
2947 GST_TIME_ARGS (demux->play_time));
2948 GST_DEBUG_OBJECT (demux, "preroll %" GST_TIME_FORMAT,
2949 GST_TIME_ARGS (demux->preroll));
2951 if (demux->play_time > 0) {
2952 gst_segment_set_duration (&demux->segment, GST_FORMAT_TIME,
2953 demux->play_time);
2954 }
2956 GST_INFO ("object is a file with %" G_GUINT64_FORMAT " data packets",
2957 packets_count);
2958 GST_INFO ("preroll = %" G_GUINT64_FORMAT, demux->preroll);
2960 return GST_FLOW_OK;
2962 /* ERRORS */
2963 non_fixed_packet_size:
2964 {
2965 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
2966 ("packet size must be fixed"));
2967 return GST_FLOW_ERROR;
2968 }
2969 not_enough_data:
2970 {
2971 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
2972 ("short read parsing FILE object"));
2973 return GST_FLOW_ERROR;
2974 }
2975 }
2977 /* Content Description Object */
2978 static GstFlowReturn
2979 gst_asf_demux_process_comment (GstASFDemux * demux, guint8 * data, guint64 size)
2980 {
2981 struct
2982 {
2983 const gchar *gst_tag;
2984 guint16 val_length;
2985 gchar *val_utf8;
2986 } tags[5] = {
2987 {
2988 GST_TAG_TITLE, 0, NULL}, {
2989 GST_TAG_ARTIST, 0, NULL}, {
2990 GST_TAG_COPYRIGHT, 0, NULL}, {
2991 GST_TAG_DESCRIPTION, 0, NULL}, {
2992 GST_TAG_COMMENT, 0, NULL}
2993 };
2994 GstTagList *taglist;
2995 GValue value = { 0 };
2996 gsize in, out;
2997 gint i = -1;
2999 GST_INFO_OBJECT (demux, "object is a comment");
3001 if (size < (2 + 2 + 2 + 2 + 2))
3002 goto not_enough_data;
3004 tags[0].val_length = gst_asf_demux_get_uint16 (&data, &size);
3005 tags[1].val_length = gst_asf_demux_get_uint16 (&data, &size);
3006 tags[2].val_length = gst_asf_demux_get_uint16 (&data, &size);
3007 tags[3].val_length = gst_asf_demux_get_uint16 (&data, &size);
3008 tags[4].val_length = gst_asf_demux_get_uint16 (&data, &size);
3010 GST_DEBUG_OBJECT (demux, "Comment lengths: title=%d author=%d copyright=%d "
3011 "description=%d rating=%d", tags[0].val_length, tags[1].val_length,
3012 tags[2].val_length, tags[3].val_length, tags[4].val_length);
3014 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
3015 if (size < tags[i].val_length)
3016 goto not_enough_data;
3018 /* might be just '/0', '/0'... */
3019 if (tags[i].val_length > 2 && tags[i].val_length % 2 == 0) {
3020 /* convert to UTF-8 */
3021 tags[i].val_utf8 = g_convert ((gchar *) data, tags[i].val_length,
3022 "UTF-8", "UTF-16LE", &in, &out, NULL);
3023 }
3024 gst_asf_demux_skip_bytes (tags[i].val_length, &data, &size);
3025 }
3027 /* parse metadata into taglist */
3028 taglist = gst_tag_list_new ();
3029 g_value_init (&value, G_TYPE_STRING);
3030 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
3031 if (tags[i].val_utf8 && strlen (tags[i].val_utf8) > 0 && tags[i].gst_tag) {
3032 g_value_set_string (&value, tags[i].val_utf8);
3033 gst_tag_list_add_values (taglist, GST_TAG_MERGE_APPEND,
3034 tags[i].gst_tag, &value, NULL);
3035 }
3036 }
3037 g_value_unset (&value);
3039 gst_asf_demux_add_global_tags (demux, taglist);
3041 for (i = 0; i < G_N_ELEMENTS (tags); ++i)
3042 g_free (tags[i].val_utf8);
3044 return GST_FLOW_OK;
3046 not_enough_data:
3047 {
3048 GST_WARNING_OBJECT (demux, "unexpectedly short of data while processing "
3049 "comment tag section %d, skipping comment object", i);
3050 for (i = 0; i < G_N_ELEMENTS (tags); i++)
3051 g_free (tags[i].val_utf8);
3052 return GST_FLOW_OK; /* not really fatal */
3053 }
3054 }
3056 static GstFlowReturn
3057 gst_asf_demux_process_bitrate_props_object (GstASFDemux * demux, guint8 * data,
3058 guint64 size)
3059 {
3060 guint16 num_streams, i;
3061 AsfStream *stream;
3063 if (size < 2)
3064 goto not_enough_data;
3066 num_streams = gst_asf_demux_get_uint16 (&data, &size);
3068 GST_INFO ("object is a bitrate properties object with %u streams",
3069 num_streams);
3071 if (size < (num_streams * (2 + 4)))
3072 goto not_enough_data;
3074 for (i = 0; i < num_streams; ++i) {
3075 guint32 bitrate;
3076 guint16 stream_id;
3078 stream_id = gst_asf_demux_get_uint16 (&data, &size);
3079 bitrate = gst_asf_demux_get_uint32 (&data, &size);
3081 if (stream_id < GST_ASF_DEMUX_NUM_STREAM_IDS) {
3082 GST_DEBUG_OBJECT (demux, "bitrate of stream %u = %u", stream_id, bitrate);
3083 stream = gst_asf_demux_get_stream (demux, stream_id);
3084 if (stream) {
3085 if (stream->pending_tags == NULL)
3086 stream->pending_tags = gst_tag_list_new ();
3087 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
3088 GST_TAG_BITRATE, bitrate, NULL);
3089 } else {
3090 GST_WARNING_OBJECT (demux, "Stream id %u wasn't found", stream_id);
3091 }
3092 } else {
3093 GST_WARNING ("stream id %u is too large", stream_id);
3094 }
3095 }
3097 return GST_FLOW_OK;
3099 not_enough_data:
3100 {
3101 GST_WARNING_OBJECT (demux, "short read parsing bitrate props object!");
3102 return GST_FLOW_OK; /* not really fatal */
3103 }
3104 }
3106 static GstFlowReturn
3107 gst_asf_demux_process_header_ext (GstASFDemux * demux, guint8 * data,
3108 guint64 size)
3109 {
3110 GstFlowReturn ret = GST_FLOW_OK;
3111 guint64 hdr_size;
3113 /* Get the rest of the header's header */
3114 if (size < (16 + 2 + 4))
3115 goto not_enough_data;
3117 /* skip GUID and two other bytes */
3118 gst_asf_demux_skip_bytes (16 + 2, &data, &size);
3119 hdr_size = gst_asf_demux_get_uint32 (&data, &size);
3121 GST_INFO ("extended header object with a size of %u bytes", (guint) size);
3123 /* FIXME: does data_size include the rest of the header that we have read? */
3124 if (hdr_size > size)
3125 goto not_enough_data;
3127 while (hdr_size > 0) {
3128 ret = gst_asf_demux_process_object (demux, &data, &hdr_size);
3129 if (ret != GST_FLOW_OK)
3130 break;
3131 }
3133 return ret;
3135 not_enough_data:
3136 {
3137 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3138 ("short read parsing extended header object"));
3139 return GST_FLOW_ERROR;
3140 }
3141 }
3143 static GstFlowReturn
3144 gst_asf_demux_process_language_list (GstASFDemux * demux, guint8 * data,
3145 guint64 size)
3146 {
3147 guint i;
3149 if (size < 2)
3150 goto not_enough_data;
3152 if (demux->languages) {
3153 GST_WARNING ("More than one LANGUAGE_LIST object in stream");
3154 g_strfreev (demux->languages);
3155 demux->languages = NULL;
3156 demux->num_languages = 0;
3157 }
3159 demux->num_languages = gst_asf_demux_get_uint16 (&data, &size);
3160 GST_LOG ("%u languages:", demux->num_languages);
3162 demux->languages = g_new0 (gchar *, demux->num_languages + 1);
3163 for (i = 0; i < demux->num_languages; ++i) {
3164 guint8 len, *lang_data = NULL;
3166 if (size < 1)
3167 goto not_enough_data;
3168 len = gst_asf_demux_get_uint8 (&data, &size);
3169 if (gst_asf_demux_get_bytes (&lang_data, len, &data, &size)) {
3170 gchar *utf8;
3172 utf8 = g_convert ((gchar *) lang_data, len, "UTF-8", "UTF-16LE", NULL,
3173 NULL, NULL);
3175 /* truncate "en-us" etc. to just "en" */
3176 if (utf8 && strlen (utf8) >= 5 && (utf8[2] == '-' || utf8[2] == '_')) {
3177 utf8[2] = '\0';
3178 }
3179 GST_DEBUG ("[%u] %s", i, GST_STR_NULL (utf8));
3180 demux->languages[i] = utf8;
3181 g_free (lang_data);
3182 } else {
3183 goto not_enough_data;
3184 }
3185 }
3187 return GST_FLOW_OK;
3189 not_enough_data:
3190 {
3191 GST_WARNING_OBJECT (demux, "short read parsing language list object!");
3192 g_free (demux->languages);
3193 demux->languages = NULL;
3194 return GST_FLOW_OK; /* not fatal */
3195 }
3196 }
3198 static GstFlowReturn
3199 gst_asf_demux_process_simple_index (GstASFDemux * demux, guint8 * data,
3200 guint64 size)
3201 {
3202 GstClockTime interval;
3203 guint32 count, i;
3205 if (size < (16 + 8 + 4 + 4))
3206 goto not_enough_data;
3208 /* skip file id */
3209 gst_asf_demux_skip_bytes (16, &data, &size);
3210 interval = gst_asf_demux_get_uint64 (&data, &size) * (GstClockTime) 100;
3211 gst_asf_demux_skip_bytes (4, &data, &size);
3212 count = gst_asf_demux_get_uint32 (&data, &size);
3213 if (count > 0) {
3214 demux->sidx_interval = interval;
3215 demux->sidx_num_entries = count;
3216 g_free (demux->sidx_entries);
3217 demux->sidx_entries = g_new0 (AsfSimpleIndexEntry, count);
3219 for (i = 0; i < count; ++i) {
3220 if (G_UNLIKELY (size <= 6))
3221 break;
3222 demux->sidx_entries[i].packet = gst_asf_demux_get_uint32 (&data, &size);
3223 demux->sidx_entries[i].count = gst_asf_demux_get_uint16 (&data, &size);
3224 GST_LOG_OBJECT (demux, "%" GST_TIME_FORMAT " = packet %4u count : %2d",
3225 GST_TIME_ARGS (i * interval), demux->sidx_entries[i].packet,
3226 demux->sidx_entries[i].count);
3227 }
3228 } else {
3229 GST_DEBUG_OBJECT (demux, "simple index object with 0 entries");
3230 }
3232 return GST_FLOW_OK;
3234 not_enough_data:
3235 {
3236 GST_WARNING_OBJECT (demux, "short read parsing simple index object!");
3237 return GST_FLOW_OK; /* not fatal */
3238 }
3239 }
3241 static GstFlowReturn
3242 gst_asf_demux_process_advanced_mutual_exclusion (GstASFDemux * demux,
3243 guint8 * data, guint64 size)
3244 {
3245 ASFGuid guid;
3246 guint16 num, i;
3247 guint8 *mes;
3249 if (size < 16 + 2 + (2 * 2))
3250 goto not_enough_data;
3252 gst_asf_demux_get_guid (&guid, &data, &size);
3253 num = gst_asf_demux_get_uint16 (&data, &size);
3255 if (num < 2) {
3256 GST_WARNING_OBJECT (demux, "nonsensical mutually exclusive streams count");
3257 return GST_FLOW_OK;
3258 }
3260 if (size < (num * sizeof (guint16)))
3261 goto not_enough_data;
3263 /* read mutually exclusive stream numbers */
3264 mes = g_new (guint8, num + 1);
3265 for (i = 0; i < num; ++i) {
3266 mes[i] = gst_asf_demux_get_uint16 (&data, &size) & 0x7f;
3267 GST_LOG_OBJECT (demux, "mutually exclusive: stream #%d", mes[i]);
3268 }
3270 /* add terminator so we can easily get the count or know when to stop */
3271 mes[i] = (guint8) - 1;
3273 demux->mut_ex_streams = g_slist_append (demux->mut_ex_streams, mes);
3275 return GST_FLOW_OK;
3277 /* Errors */
3278 not_enough_data:
3279 {
3280 GST_WARNING_OBJECT (demux, "short read parsing advanced mutual exclusion");
3281 return GST_FLOW_OK; /* not absolutely fatal */
3282 }
3283 }
3285 static GstFlowReturn
3286 gst_asf_demux_process_ext_stream_props (GstASFDemux * demux, guint8 * data,
3287 guint64 size)
3288 {
3289 AsfStreamExtProps esp;
3290 AsfStream *stream = NULL;
3291 AsfObject stream_obj;
3292 guint16 stream_name_count;
3293 guint16 num_payload_ext;
3294 guint64 len;
3295 guint8 *stream_obj_data = NULL;
3296 guint8 *data_start;
3297 guint obj_size;
3298 guint i, stream_num;
3300 data_start = data;
3301 obj_size = (guint) size;
3303 if (size < 64)
3304 goto not_enough_data;
3306 esp.valid = TRUE;
3307 esp.start_time = gst_asf_demux_get_uint64 (&data, &size) * GST_MSECOND;
3308 esp.end_time = gst_asf_demux_get_uint64 (&data, &size) * GST_MSECOND;
3309 esp.data_bitrate = gst_asf_demux_get_uint32 (&data, &size);
3310 esp.buffer_size = gst_asf_demux_get_uint32 (&data, &size);
3311 esp.intial_buf_fullness = gst_asf_demux_get_uint32 (&data, &size);
3312 esp.data_bitrate2 = gst_asf_demux_get_uint32 (&data, &size);
3313 esp.buffer_size2 = gst_asf_demux_get_uint32 (&data, &size);
3314 esp.intial_buf_fullness2 = gst_asf_demux_get_uint32 (&data, &size);
3315 esp.max_obj_size = gst_asf_demux_get_uint32 (&data, &size);
3316 esp.flags = gst_asf_demux_get_uint32 (&data, &size);
3317 stream_num = gst_asf_demux_get_uint16 (&data, &size);
3318 esp.lang_idx = gst_asf_demux_get_uint16 (&data, &size);
3319 esp.avg_time_per_frame = gst_asf_demux_get_uint64 (&data, &size);
3320 stream_name_count = gst_asf_demux_get_uint16 (&data, &size);
3321 num_payload_ext = gst_asf_demux_get_uint16 (&data, &size);
3323 GST_INFO ("start_time = %" GST_TIME_FORMAT,
3324 GST_TIME_ARGS (esp.start_time));
3325 GST_INFO ("end_time = %" GST_TIME_FORMAT,
3326 GST_TIME_ARGS (esp.end_time));
3327 GST_INFO ("flags = %08x", esp.flags);
3328 GST_INFO ("average time per frame = %" GST_TIME_FORMAT,
3329 GST_TIME_ARGS (esp.avg_time_per_frame * 100));
3330 GST_INFO ("stream number = %u", stream_num);
3331 GST_INFO ("stream language ID idx = %u (%s)", esp.lang_idx,
3332 (esp.lang_idx < demux->num_languages) ?
3333 GST_STR_NULL (demux->languages[esp.lang_idx]) : "??");
3334 GST_INFO ("stream name count = %u", stream_name_count);
3336 /* read stream names */
3337 for (i = 0; i < stream_name_count; ++i) {
3338 guint16 stream_lang_idx G_GNUC_UNUSED;
3339 gchar *stream_name = NULL;
3341 if (size < 2)
3342 goto not_enough_data;
3343 stream_lang_idx = gst_asf_demux_get_uint16 (&data, &size);
3344 if (!gst_asf_demux_get_string (&stream_name, NULL, &data, &size))
3345 goto not_enough_data;
3346 GST_INFO ("stream name %d: %s", i, GST_STR_NULL (stream_name));
3347 g_free (stream_name); /* TODO: store names in struct */
3348 }
3350 /* read payload extension systems stuff */
3351 GST_LOG ("payload extension systems count = %u", num_payload_ext);
3353 if (num_payload_ext > 0)
3354 esp.payload_extensions = g_new0 (AsfPayloadExtension, num_payload_ext + 1);
3355 else
3356 esp.payload_extensions = NULL;
3358 for (i = 0; i < num_payload_ext; ++i) {
3359 AsfPayloadExtension ext;
3360 ASFGuid ext_guid;
3361 guint32 sys_info_len;
3363 if (size < 16 + 2 + 4)
3364 goto not_enough_data;
3366 gst_asf_demux_get_guid (&ext_guid, &data, &size);
3367 ext.id = gst_asf_demux_identify_guid (asf_payload_ext_guids, &ext_guid);
3368 ext.len = gst_asf_demux_get_uint16 (&data, &size);
3370 sys_info_len = gst_asf_demux_get_uint32 (&data, &size);
3371 GST_LOG ("payload systems info len = %u", sys_info_len);
3372 if (!gst_asf_demux_skip_bytes (sys_info_len, &data, &size))
3373 goto not_enough_data;
3375 esp.payload_extensions[i] = ext;
3376 }
3378 GST_LOG ("bytes read: %u/%u", (guint) (data - data_start), obj_size);
3380 /* there might be an optional STREAM_INFO object here now; if not, we
3381 * should have parsed the corresponding stream info object already (since
3382 * we are parsing the extended stream properties objects delayed) */
3383 if (size == 0) {
3384 stream = gst_asf_demux_get_stream (demux, stream_num);
3385 goto done;
3386 }
3388 /* get size of the stream object */
3389 if (!asf_demux_peek_object (demux, data, size, &stream_obj, TRUE))
3390 goto not_enough_data;
3392 if (stream_obj.id != ASF_OBJ_STREAM)
3393 goto expected_stream_object;
3395 if (stream_obj.size < ASF_OBJECT_HEADER_SIZE ||
3396 stream_obj.size > (10 * 1024 * 1024))
3397 goto not_enough_data;
3399 gst_asf_demux_skip_bytes (ASF_OBJECT_HEADER_SIZE, &data, &size);
3401 /* process this stream object later after all the other 'normal' ones
3402 * have been processed (since the others are more important/non-hidden) */
3403 len = stream_obj.size - ASF_OBJECT_HEADER_SIZE;
3404 if (!gst_asf_demux_get_bytes (&stream_obj_data, len, &data, &size))
3405 goto not_enough_data;
3407 /* parse stream object */
3408 stream = gst_asf_demux_parse_stream_object (demux, stream_obj_data, len);
3409 g_free (stream_obj_data);
3411 done:
3413 if (stream) {
3414 stream->ext_props = esp;
3416 /* try to set the framerate */
3417 if (stream->is_video && stream->caps) {
3418 GValue framerate = { 0 };
3419 GstStructure *s;
3420 gint num, denom;
3422 g_value_init (&framerate, GST_TYPE_FRACTION);
3424 num = GST_SECOND / 100;
3425 denom = esp.avg_time_per_frame;
3426 if (denom == 0) {
3427 /* avoid division by 0, assume 25/1 framerate */
3428 denom = GST_SECOND / 2500;
3429 }
3431 gst_value_set_fraction (&framerate, num, denom);
3433 stream->caps = gst_caps_make_writable (stream->caps);
3434 s = gst_caps_get_structure (stream->caps, 0);
3435 gst_structure_set_value (s, "framerate", &framerate);
3436 g_value_unset (&framerate);
3437 GST_DEBUG_OBJECT (demux, "setting framerate of %d/%d = %f",
3438 num, denom, ((gdouble) num) / denom);
3439 }
3441 /* add language info now if we have it */
3442 if (stream->ext_props.lang_idx < demux->num_languages) {
3443 if (stream->pending_tags == NULL)
3444 stream->pending_tags = gst_tag_list_new ();
3445 GST_LOG_OBJECT (demux, "stream %u has language '%s'", stream->id,
3446 demux->languages[stream->ext_props.lang_idx]);
3447 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_APPEND,
3448 GST_TAG_LANGUAGE_CODE, demux->languages[stream->ext_props.lang_idx],
3449 NULL);
3450 }
3451 } else {
3452 GST_WARNING_OBJECT (demux, "Ext. stream properties for unknown stream");
3453 }
3455 return GST_FLOW_OK;
3457 /* Errors */
3458 not_enough_data:
3459 {
3460 GST_WARNING_OBJECT (demux, "short read parsing ext stream props object!");
3461 return GST_FLOW_OK; /* not absolutely fatal */
3462 }
3463 expected_stream_object:
3464 {
3465 GST_WARNING_OBJECT (demux, "error parsing extended stream properties "
3466 "object: expected embedded stream object, but got %s object instead!",
3467 gst_asf_get_guid_nick (asf_object_guids, stream_obj.id));
3468 return GST_FLOW_OK; /* not absolutely fatal */
3469 }
3470 }
3472 static const gchar *
3473 gst_asf_demux_push_obj (GstASFDemux * demux, guint32 obj_id)
3474 {
3475 const gchar *nick;
3477 nick = gst_asf_get_guid_nick (asf_object_guids, obj_id);
3478 if (g_str_has_prefix (nick, "ASF_OBJ_"))
3479 nick += strlen ("ASF_OBJ_");
3481 if (demux->objpath == NULL) {
3482 demux->objpath = g_strdup (nick);
3483 } else {
3484 gchar *newpath;
3486 newpath = g_strdup_printf ("%s/%s", demux->objpath, nick);
3487 g_free (demux->objpath);
3488 demux->objpath = newpath;
3489 }
3491 return (const gchar *) demux->objpath;
3492 }
3494 static void
3495 gst_asf_demux_pop_obj (GstASFDemux * demux)
3496 {
3497 gchar *s;
3499 if ((s = g_strrstr (demux->objpath, "/"))) {
3500 *s = '\0';
3501 } else {
3502 g_free (demux->objpath);
3503 demux->objpath = NULL;
3504 }
3505 }
3507 static void
3508 gst_asf_demux_process_queued_extended_stream_objects (GstASFDemux * demux)
3509 {
3510 GSList *l;
3511 guint i;
3513 /* Parse the queued extended stream property objects and add the info
3514 * to the existing streams or add the new embedded streams, but without
3515 * activating them yet */
3516 GST_LOG_OBJECT (demux, "%u queued extended stream properties objects",
3517 g_slist_length (demux->ext_stream_props));
3519 for (l = demux->ext_stream_props, i = 0; l != NULL; l = l->next, ++i) {
3520 GstBuffer *buf = GST_BUFFER (l->data);
3522 GST_LOG_OBJECT (demux, "parsing ext. stream properties object #%u", i);
3523 gst_asf_demux_process_ext_stream_props (demux, GST_BUFFER_DATA (buf),
3524 GST_BUFFER_SIZE (buf));
3525 gst_buffer_unref (buf);
3526 }
3527 g_slist_free (demux->ext_stream_props);
3528 demux->ext_stream_props = NULL;
3529 }
3531 #if 0
3532 static void
3533 gst_asf_demux_activate_ext_props_streams (GstASFDemux * demux)
3534 {
3535 guint i, j;
3537 for (i = 0; i < demux->num_streams; ++i) {
3538 AsfStream *stream;
3539 gboolean is_hidden;
3540 GSList *x;
3542 stream = &demux->stream[i];
3544 GST_LOG_OBJECT (demux, "checking stream %2u", stream->id);
3546 if (stream->active) {
3547 GST_LOG_OBJECT (demux, "stream %2u is already activated", stream->id);
3548 continue;
3549 }
3551 is_hidden = FALSE;
3552 for (x = demux->mut_ex_streams; x != NULL; x = x->next) {
3553 guint8 *mes;
3555 /* check for each mutual exclusion whether it affects this stream */
3556 for (mes = (guint8 *) x->data; mes != NULL && *mes != 0xff; ++mes) {
3557 if (*mes == stream->id) {
3558 /* if yes, check if we've already added streams that are mutually
3559 * exclusive with the stream we're about to add */
3560 for (mes = (guint8 *) x->data; mes != NULL && *mes != 0xff; ++mes) {
3561 for (j = 0; j < demux->num_streams; ++j) {
3562 /* if the broadcast flag is set, assume the hidden streams aren't
3563 * actually streamed and hide them (or playbin won't work right),
3564 * otherwise assume their data is available */
3565 if (demux->stream[j].id == *mes && demux->broadcast) {
3566 is_hidden = TRUE;
3567 GST_LOG_OBJECT (demux, "broadcast stream ID %d to be added is "
3568 "mutually exclusive with already existing stream ID %d, "
3569 "hiding stream", stream->id, demux->stream[j].id);
3570 goto next;
3571 }
3572 }
3573 }
3574 break;
3575 }
3576 }
3577 }
3579 next:
3581 /* FIXME: we should do stream activation based on preroll data in
3582 * streaming mode too */
3583 if (demux->streaming && !is_hidden)
3584 gst_asf_demux_activate_stream (demux, stream);
3585 }
3586 }
3587 #endif
3589 static GstFlowReturn
3590 gst_asf_demux_process_object (GstASFDemux * demux, guint8 ** p_data,
3591 guint64 * p_size)
3592 {
3593 GstFlowReturn ret = GST_FLOW_OK;
3594 AsfObject obj;
3595 guint64 obj_data_size;
3597 if (*p_size < ASF_OBJECT_HEADER_SIZE)
3598 return ASF_FLOW_NEED_MORE_DATA;
3600 asf_demux_peek_object (demux, *p_data, ASF_OBJECT_HEADER_SIZE, &obj, TRUE);
3601 gst_asf_demux_skip_bytes (ASF_OBJECT_HEADER_SIZE, p_data, p_size);
3603 obj_data_size = obj.size - ASF_OBJECT_HEADER_SIZE;
3605 if (*p_size < obj_data_size)
3606 return ASF_FLOW_NEED_MORE_DATA;
3608 gst_asf_demux_push_obj (demux, obj.id);
3610 GST_INFO ("%s: size %" G_GUINT64_FORMAT, demux->objpath, obj.size);
3612 switch (obj.id) {
3613 case ASF_OBJ_STREAM:
3614 gst_asf_demux_parse_stream_object (demux, *p_data, obj_data_size);
3615 ret = GST_FLOW_OK;
3616 break;
3617 case ASF_OBJ_FILE:
3618 ret = gst_asf_demux_process_file (demux, *p_data, obj_data_size);
3619 break;
3620 case ASF_OBJ_HEADER:
3621 ret = gst_asf_demux_process_header (demux, *p_data, obj_data_size);
3622 break;
3623 case ASF_OBJ_COMMENT:
3624 ret = gst_asf_demux_process_comment (demux, *p_data, obj_data_size);
3625 break;
3626 case ASF_OBJ_HEAD1:
3627 ret = gst_asf_demux_process_header_ext (demux, *p_data, obj_data_size);
3628 break;
3629 case ASF_OBJ_BITRATE_PROPS:
3630 ret =
3631 gst_asf_demux_process_bitrate_props_object (demux, *p_data,
3632 obj_data_size);
3633 break;
3634 case ASF_OBJ_EXT_CONTENT_DESC:
3635 ret =
3636 gst_asf_demux_process_ext_content_desc (demux, *p_data,
3637 obj_data_size);
3638 break;
3639 case ASF_OBJ_METADATA_OBJECT:
3640 ret = gst_asf_demux_process_metadata (demux, *p_data, obj_data_size);
3641 break;
3642 case ASF_OBJ_EXTENDED_STREAM_PROPS:{
3643 GstBuffer *buf;
3645 /* process these later, we might not have parsed the corresponding
3646 * stream object yet */
3647 GST_LOG ("%s: queued for later parsing", demux->objpath);
3648 buf = gst_buffer_new_and_alloc (obj_data_size);
3649 memcpy (GST_BUFFER_DATA (buf), *p_data, obj_data_size);
3650 demux->ext_stream_props = g_slist_append (demux->ext_stream_props, buf);
3651 ret = GST_FLOW_OK;
3652 break;
3653 }
3654 case ASF_OBJ_LANGUAGE_LIST:
3655 ret = gst_asf_demux_process_language_list (demux, *p_data, obj_data_size);
3656 break;
3657 case ASF_OBJ_ADVANCED_MUTUAL_EXCLUSION:
3658 ret = gst_asf_demux_process_advanced_mutual_exclusion (demux, *p_data,
3659 obj_data_size);
3660 break;
3661 case ASF_OBJ_SIMPLE_INDEX:
3662 ret = gst_asf_demux_process_simple_index (demux, *p_data, obj_data_size);
3663 break;
3664 case ASF_OBJ_CONTENT_ENCRYPTION:
3665 case ASF_OBJ_EXT_CONTENT_ENCRYPTION:
3666 case ASF_OBJ_DIGITAL_SIGNATURE_OBJECT:
3667 case ASF_OBJ_UNKNOWN_ENCRYPTION_OBJECT:
3668 goto error_encrypted;
3669 case ASF_OBJ_CONCEAL_NONE:
3670 case ASF_OBJ_HEAD2:
3671 case ASF_OBJ_UNDEFINED:
3672 case ASF_OBJ_CODEC_COMMENT:
3673 case ASF_OBJ_INDEX:
3674 case ASF_OBJ_PADDING:
3675 case ASF_OBJ_BITRATE_MUTEX:
3676 case ASF_OBJ_COMPATIBILITY:
3677 case ASF_OBJ_INDEX_PLACEHOLDER:
3678 case ASF_OBJ_INDEX_PARAMETERS:
3679 case ASF_OBJ_STREAM_PRIORITIZATION:
3680 case ASF_OBJ_SCRIPT_COMMAND:
3681 default:
3682 /* Unknown/unhandled object, skip it and hope for the best */
3683 GST_INFO ("%s: skipping object", demux->objpath);
3684 ret = GST_FLOW_OK;
3685 break;
3686 }
3688 /* this can't fail, we checked the number of bytes available before */
3689 gst_asf_demux_skip_bytes (obj_data_size, p_data, p_size);
3691 GST_LOG ("%s: ret = %s", demux->objpath, gst_asf_get_flow_name (ret));
3693 gst_asf_demux_pop_obj (demux);
3695 return ret;
3697 /* ERRORS */
3698 error_encrypted:
3699 {
3700 GST_ELEMENT_ERROR (demux, STREAM, DECRYPT, (NULL), (NULL));
3701 return GST_FLOW_ERROR;
3702 }
3703 }
3705 static void
3706 gst_asf_demux_descramble_buffer (GstASFDemux * demux, AsfStream * stream,
3707 GstBuffer ** p_buffer)
3708 {
3709 GstBuffer *descrambled_buffer;
3710 GstBuffer *scrambled_buffer;
3711 GstBuffer *sub_buffer;
3712 guint offset;
3713 guint off;
3714 guint row;
3715 guint col;
3716 guint idx;
3718 /* descrambled_buffer is initialised in the first iteration */
3719 descrambled_buffer = NULL;
3720 scrambled_buffer = *p_buffer;
3722 if (GST_BUFFER_SIZE (scrambled_buffer) < demux->ds_packet_size * demux->span)
3723 return;
3725 for (offset = 0; offset < GST_BUFFER_SIZE (scrambled_buffer);
3726 offset += demux->ds_chunk_size) {
3727 off = offset / demux->ds_chunk_size;
3728 row = off / demux->span;
3729 col = off % demux->span;
3730 idx = row + col * demux->ds_packet_size / demux->ds_chunk_size;
3731 GST_DEBUG ("idx=%u, row=%u, col=%u, off=%u, ds_chunk_size=%u", idx, row,
3732 col, off, demux->ds_chunk_size);
3733 GST_DEBUG ("scrambled buffer size=%u, span=%u, packet_size=%u",
3734 GST_BUFFER_SIZE (scrambled_buffer), demux->span, demux->ds_packet_size);
3735 GST_DEBUG ("GST_BUFFER_SIZE (scrambled_buffer) = %u",
3736 GST_BUFFER_SIZE (scrambled_buffer));
3737 sub_buffer =
3738 gst_buffer_create_sub (scrambled_buffer, idx * demux->ds_chunk_size,
3739 demux->ds_chunk_size);
3740 if (!offset) {
3741 descrambled_buffer = sub_buffer;
3742 } else {
3743 descrambled_buffer = gst_buffer_join (descrambled_buffer, sub_buffer);
3744 }
3745 }
3747 gst_buffer_copy_metadata (descrambled_buffer, scrambled_buffer,
3748 GST_BUFFER_COPY_TIMESTAMPS);
3750 /* FIXME/CHECK: do we need to transfer buffer flags here too? */
3752 gst_buffer_unref (scrambled_buffer);
3753 *p_buffer = descrambled_buffer;
3754 }
3756 static gboolean
3757 gst_asf_demux_element_send_event (GstElement * element, GstEvent * event)
3758 {
3759 GstASFDemux *demux = GST_ASF_DEMUX (element);
3760 gint i;
3762 GST_DEBUG ("handling element event of type %s", GST_EVENT_TYPE_NAME (event));
3764 for (i = 0; i < demux->num_streams; ++i) {
3765 gst_event_ref (event);
3766 if (gst_asf_demux_handle_src_event (demux->stream[i].pad, event)) {
3767 gst_event_unref (event);
3768 return TRUE;
3769 }
3770 }
3772 gst_event_unref (event);
3773 return FALSE;
3774 }
3776 /* takes ownership of the passed event */
3777 static gboolean
3778 gst_asf_demux_send_event_unlocked (GstASFDemux * demux, GstEvent * event)
3779 {
3780 gboolean ret = TRUE;
3781 gint i;
3783 GST_DEBUG_OBJECT (demux, "sending %s event to all source pads",
3784 GST_EVENT_TYPE_NAME (event));
3786 for (i = 0; i < demux->num_streams; ++i) {
3787 gst_event_ref (event);
3788 ret &= gst_pad_push_event (demux->stream[i].pad, event);
3789 }
3790 gst_event_unref (event);
3791 return ret;
3792 }
3794 static const GstQueryType *
3795 gst_asf_demux_get_src_query_types (GstPad * pad)
3796 {
3797 static const GstQueryType types[] = {
3798 GST_QUERY_POSITION,
3799 GST_QUERY_DURATION,
3800 GST_QUERY_SEEKING,
3801 0
3802 };
3804 return types;
3805 }
3807 static gboolean
3808 gst_asf_demux_handle_src_query (GstPad * pad, GstQuery * query)
3809 {
3810 GstASFDemux *demux;
3811 gboolean res = FALSE;
3813 demux = GST_ASF_DEMUX (gst_pad_get_parent (pad));
3815 GST_DEBUG ("handling %s query",
3816 gst_query_type_get_name (GST_QUERY_TYPE (query)));
3818 switch (GST_QUERY_TYPE (query)) {
3819 case GST_QUERY_DURATION:
3820 {
3821 GstFormat format;
3823 gst_query_parse_duration (query, &format, NULL);
3825 if (format != GST_FORMAT_TIME) {
3826 GST_LOG ("only support duration queries in TIME format");
3827 break;
3828 }
3830 GST_OBJECT_LOCK (demux);
3832 if (demux->segment.duration != GST_CLOCK_TIME_NONE) {
3833 GST_LOG ("returning duration: %" GST_TIME_FORMAT,
3834 GST_TIME_ARGS (demux->segment.duration));
3836 gst_query_set_duration (query, GST_FORMAT_TIME,
3837 demux->segment.duration);
3839 res = TRUE;
3840 } else {
3841 GST_LOG ("duration not known yet");
3842 }
3844 GST_OBJECT_UNLOCK (demux);
3845 break;
3846 }
3848 case GST_QUERY_POSITION:{
3849 GstFormat format;
3851 gst_query_parse_position (query, &format, NULL);
3853 if (format != GST_FORMAT_TIME) {
3854 GST_LOG ("only support position queries in TIME format");
3855 break;
3856 }
3858 GST_OBJECT_LOCK (demux);
3860 if (demux->segment.last_stop != GST_CLOCK_TIME_NONE) {
3861 GST_LOG ("returning position: %" GST_TIME_FORMAT,
3862 GST_TIME_ARGS (demux->segment.last_stop));
3864 gst_query_set_position (query, GST_FORMAT_TIME,
3865 demux->segment.last_stop);
3867 res = TRUE;
3868 } else {
3869 GST_LOG ("position not known yet");
3870 }
3872 GST_OBJECT_UNLOCK (demux);
3873 break;
3874 }
3876 case GST_QUERY_SEEKING:{
3877 GstFormat format;
3879 gst_query_parse_seeking (query, &format, NULL, NULL, NULL);
3880 if (format == GST_FORMAT_TIME) {
3881 gint64 duration;
3883 GST_OBJECT_LOCK (demux);
3884 duration = demux->segment.duration;
3885 GST_OBJECT_UNLOCK (demux);
3887 if (!demux->streaming || !demux->seekable) {
3888 gst_query_set_seeking (query, GST_FORMAT_TIME, demux->seekable, 0,
3889 duration);
3890 res = TRUE;
3891 } else {
3892 GstFormat fmt;
3893 gboolean seekable;
3895 /* try downstream first in TIME */
3896 res = gst_pad_query_default (pad, query);
3898 gst_query_parse_seeking (query, &fmt, &seekable, NULL, NULL);
3899 GST_LOG_OBJECT (demux, "upstream %s seekable %d",
3900 GST_STR_NULL (gst_format_get_name (fmt)), seekable);
3901 /* if no luck, maybe in BYTES */
3902 if (!seekable || fmt != GST_FORMAT_TIME) {
3903 GstQuery *q;
3905 q = gst_query_new_seeking (GST_FORMAT_BYTES);
3906 if ((res = gst_pad_peer_query (demux->sinkpad, q))) {
3907 gst_query_parse_seeking (q, &fmt, &seekable, NULL, NULL);
3908 GST_LOG_OBJECT (demux, "upstream %s seekable %d",
3909 GST_STR_NULL (gst_format_get_name (fmt)), seekable);
3910 if (fmt != GST_FORMAT_BYTES)
3911 seekable = FALSE;
3912 }
3913 gst_query_unref (q);
3914 gst_query_set_seeking (query, GST_FORMAT_TIME, seekable, 0,
3915 duration);
3916 res = TRUE;
3917 }
3918 }
3919 } else
3920 GST_LOG_OBJECT (demux, "only support seeking in TIME format");
3921 break;
3922 }
3924 case GST_QUERY_LATENCY:
3925 {
3926 gboolean live;
3927 GstClockTime min, max;
3929 /* preroll delay does not matter in non-live pipeline,
3930 * but we might end up in a live (rtsp) one ... */
3932 /* first forward */
3933 res = gst_pad_query_default (pad, query);
3934 if (!res)
3935 break;
3937 gst_query_parse_latency (query, &live, &min, &max);
3939 GST_DEBUG_OBJECT (demux, "Peer latency: live %d, min %"
3940 GST_TIME_FORMAT " max %" GST_TIME_FORMAT, live,
3941 GST_TIME_ARGS (min), GST_TIME_ARGS (max));
3943 GST_OBJECT_LOCK (demux);
3944 if (min != -1)
3945 min += demux->latency;
3946 if (max != -1)
3947 max += demux->latency;
3948 GST_OBJECT_UNLOCK (demux);
3950 gst_query_set_latency (query, live, min, max);
3951 break;
3952 }
3953 default:
3954 res = gst_pad_query_default (pad, query);
3955 break;
3956 }
3958 gst_object_unref (demux);
3959 return res;
3960 }
3962 static GstStateChangeReturn
3963 gst_asf_demux_change_state (GstElement * element, GstStateChange transition)
3964 {
3965 GstASFDemux *demux = GST_ASF_DEMUX (element);
3966 GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
3968 switch (transition) {
3969 case GST_STATE_CHANGE_NULL_TO_READY:{
3970 gst_segment_init (&demux->segment, GST_FORMAT_TIME);
3971 demux->need_newsegment = TRUE;
3972 demux->segment_running = FALSE;
3973 demux->accurate = FALSE;
3974 demux->adapter = gst_adapter_new ();
3975 demux->metadata = gst_caps_new_empty ();
3976 demux->global_metadata = gst_structure_empty_new ("metadata");
3977 demux->data_size = 0;
3978 demux->data_offset = 0;
3979 demux->index_offset = 0;
3980 demux->base_offset = 0;
3981 break;
3982 }
3983 default:
3984 break;
3985 }
3987 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
3988 if (ret == GST_STATE_CHANGE_FAILURE)
3989 return ret;
3991 switch (transition) {
3992 case GST_STATE_CHANGE_PAUSED_TO_READY:
3993 case GST_STATE_CHANGE_READY_TO_NULL:
3994 gst_asf_demux_reset (demux, FALSE);
3995 break;
3996 default:
3997 break;
3998 }
4000 return ret;
4001 }