1 /* GStreamer ASF/WMV/WMA demuxer
2 * Copyright (C) 1999 Erik Walthinsen <omega@cse.ogi.edu>
3 * Copyright (C) 2006-2007 Tim-Philipp Müller <tim centricular net>
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
14 *
15 * You should have received a copy of the GNU Library General Public
16 * License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 * Boston, MA 02111-1307, USA.
19 */
21 /* TODO:
22 *
23 * - _loop():
24 * stop if at end of segment if != end of file, ie. demux->segment.stop
25 *
26 * - fix packet parsing:
27 * there's something wrong with timestamps for packets with keyframes,
28 * and durations too.
29 */
31 #ifdef HAVE_CONFIG_H
32 #include "config.h"
33 #endif
35 #include <gst/gstutils.h>
36 #include <gst/riff/riff-media.h>
37 #include <gst/gst-i18n-plugin.h>
38 #include <stdlib.h>
39 #include <string.h>
41 #include "gstasfdemux.h"
42 #include "asfheaders.h"
43 #include "asfpacket.h"
45 static GstStaticPadTemplate gst_asf_demux_sink_template =
46 GST_STATIC_PAD_TEMPLATE ("sink",
47 GST_PAD_SINK,
48 GST_PAD_ALWAYS,
49 GST_STATIC_CAPS ("video/x-ms-asf")
50 );
52 static GstStaticPadTemplate audio_src_template =
53 GST_STATIC_PAD_TEMPLATE ("audio_%02d",
54 GST_PAD_SRC,
55 GST_PAD_SOMETIMES,
56 GST_STATIC_CAPS_ANY);
58 static GstStaticPadTemplate video_src_template =
59 GST_STATIC_PAD_TEMPLATE ("video_%02d",
60 GST_PAD_SRC,
61 GST_PAD_SOMETIMES,
62 GST_STATIC_CAPS_ANY);
64 /* size of an ASF object header, ie. GUID (16 bytes) + object size (8 bytes) */
65 #define ASF_OBJECT_HEADER_SIZE (16+8)
67 /* FIXME: get rid of this */
68 /* abuse this GstFlowReturn enum for internal usage */
69 #define ASF_FLOW_NEED_MORE_DATA 99
71 #define gst_asf_get_flow_name(flow) \
72 (flow == ASF_FLOW_NEED_MORE_DATA) ? \
73 "need-more-data" : gst_flow_get_name (flow)
75 GST_DEBUG_CATEGORY (asfdemux_dbg);
77 static GstStateChangeReturn gst_asf_demux_change_state (GstElement * element,
78 GstStateChange transition);
79 static gboolean gst_asf_demux_element_send_event (GstElement * element,
80 GstEvent * event);
81 static gboolean gst_asf_demux_send_event_unlocked (GstASFDemux * demux,
82 GstEvent * event);
83 static gboolean gst_asf_demux_handle_src_query (GstPad * pad, GstQuery * query);
84 static const GstQueryType *gst_asf_demux_get_src_query_types (GstPad * pad);
85 static GstFlowReturn gst_asf_demux_chain (GstPad * pad, GstBuffer * buf);
86 static gboolean gst_asf_demux_sink_event (GstPad * pad, GstEvent * event);
87 static GstFlowReturn gst_asf_demux_process_object (GstASFDemux * demux,
88 guint8 ** p_data, guint64 * p_size);
89 static gboolean gst_asf_demux_activate (GstPad * sinkpad);
90 static gboolean gst_asf_demux_activate_push (GstPad * sinkpad, gboolean active);
91 static gboolean gst_asf_demux_activate_pull (GstPad * sinkpad, gboolean active);
92 static void gst_asf_demux_loop (GstASFDemux * demux);
93 static void
94 gst_asf_demux_process_queued_extended_stream_objects (GstASFDemux * demux);
95 static gboolean gst_asf_demux_pull_headers (GstASFDemux * demux);
96 static void gst_asf_demux_pull_indices (GstASFDemux * demux);
97 static void gst_asf_demux_reset_stream_state_after_discont (GstASFDemux * asf);
98 static gboolean
99 gst_asf_demux_parse_data_object_start (GstASFDemux * demux, guint8 * data);
100 static void gst_asf_demux_descramble_buffer (GstASFDemux * demux,
101 AsfStream * stream, GstBuffer ** p_buffer);
102 static void gst_asf_demux_activate_stream (GstASFDemux * demux,
103 AsfStream * stream);
104 static GstStructure *gst_asf_demux_get_metadata_for_stream (GstASFDemux * d,
105 guint stream_num);
107 GST_BOILERPLATE (GstASFDemux, gst_asf_demux, GstElement, GST_TYPE_ELEMENT);
109 static void
110 gst_asf_demux_base_init (gpointer g_class)
111 {
112 GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
113 static GstElementDetails gst_asf_demux_details = {
114 "ASF Demuxer",
115 "Codec/Demuxer",
116 "Demultiplexes ASF Streams",
117 "Owen Fraser-Green <owen@discobabe.net>"
118 };
120 gst_element_class_add_pad_template (element_class,
121 gst_static_pad_template_get (&audio_src_template));
122 gst_element_class_add_pad_template (element_class,
123 gst_static_pad_template_get (&video_src_template));
124 gst_element_class_add_pad_template (element_class,
125 gst_static_pad_template_get (&gst_asf_demux_sink_template));
127 gst_element_class_set_details (element_class, &gst_asf_demux_details);
128 }
130 static void
131 gst_asf_demux_class_init (GstASFDemuxClass * klass)
132 {
133 GstElementClass *gstelement_class;
135 gstelement_class = (GstElementClass *) klass;
137 gstelement_class->change_state =
138 GST_DEBUG_FUNCPTR (gst_asf_demux_change_state);
139 gstelement_class->send_event =
140 GST_DEBUG_FUNCPTR (gst_asf_demux_element_send_event);
141 }
143 static void
144 gst_asf_demux_free_stream (GstASFDemux * demux, AsfStream * stream)
145 {
146 gst_buffer_replace (&stream->cache, NULL);
147 gst_buffer_replace (&stream->payload, NULL);
148 gst_caps_replace (&stream->caps, NULL);
149 if (stream->pending_tags) {
150 gst_tag_list_free (stream->pending_tags);
151 stream->pending_tags = NULL;
152 }
153 if (stream->pad) {
154 if (stream->active)
155 gst_element_remove_pad (GST_ELEMENT_CAST (demux), stream->pad);
156 else
157 gst_object_unref (stream->pad);
158 stream->pad = NULL;
159 }
160 if (stream->payloads) {
161 g_array_free (stream->payloads, TRUE);
162 stream->payloads = NULL;
163 }
164 if (stream->ext_props.valid) {
165 g_free (stream->ext_props.payload_extensions);
166 stream->ext_props.payload_extensions = NULL;
167 }
168 }
170 static void
171 gst_asf_demux_reset (GstASFDemux * demux)
172 {
173 GST_LOG_OBJECT (demux, "resetting");
175 gst_segment_init (&demux->segment, GST_FORMAT_UNDEFINED);
176 demux->segment_running = FALSE;
177 if (demux->adapter) {
178 gst_adapter_clear (demux->adapter);
179 g_object_unref (demux->adapter);
180 demux->adapter = NULL;
181 }
182 if (demux->taglist) {
183 gst_tag_list_free (demux->taglist);
184 demux->taglist = NULL;
185 }
186 if (demux->metadata) {
187 gst_caps_unref (demux->metadata);
188 demux->metadata = NULL;
189 }
190 demux->state = GST_ASF_DEMUX_STATE_HEADER;
191 g_free (demux->objpath);
192 demux->objpath = NULL;
193 g_strfreev (demux->languages);
194 demux->languages = NULL;
195 demux->num_languages = 0;
196 g_slist_foreach (demux->ext_stream_props, (GFunc) gst_mini_object_unref,
197 NULL);
198 g_slist_free (demux->ext_stream_props);
199 demux->ext_stream_props = NULL;
200 while (demux->num_streams > 0) {
201 gst_asf_demux_free_stream (demux, &demux->stream[demux->num_streams - 1]);
202 --demux->num_streams;
203 }
204 memset (demux->stream, 0, sizeof (demux->stream));
205 demux->num_audio_streams = 0;
206 demux->num_video_streams = 0;
207 demux->num_streams = 0;
208 demux->activated_streams = FALSE;
209 demux->first_ts = GST_CLOCK_TIME_NONE;
210 demux->state = GST_ASF_DEMUX_STATE_HEADER;
211 demux->seekable = FALSE;
212 demux->broadcast = FALSE;
213 demux->sidx_interval = 0;
214 demux->sidx_num_entries = 0;
215 g_free (demux->sidx_entries);
216 demux->sidx_entries = NULL;
217 }
219 static void
220 gst_asf_demux_init (GstASFDemux * demux, GstASFDemuxClass * klass)
221 {
222 demux->sinkpad =
223 gst_pad_new_from_static_template (&gst_asf_demux_sink_template, "sink");
224 gst_pad_set_chain_function (demux->sinkpad,
225 GST_DEBUG_FUNCPTR (gst_asf_demux_chain));
226 gst_pad_set_event_function (demux->sinkpad,
227 GST_DEBUG_FUNCPTR (gst_asf_demux_sink_event));
228 gst_pad_set_activate_function (demux->sinkpad,
229 GST_DEBUG_FUNCPTR (gst_asf_demux_activate));
230 gst_pad_set_activatepull_function (demux->sinkpad,
231 GST_DEBUG_FUNCPTR (gst_asf_demux_activate_pull));
232 gst_pad_set_activatepush_function (demux->sinkpad,
233 GST_DEBUG_FUNCPTR (gst_asf_demux_activate_push));
234 gst_element_add_pad (GST_ELEMENT (demux), demux->sinkpad);
236 /* set initial state */
237 gst_asf_demux_reset (demux);
238 }
240 static gboolean
241 gst_asf_demux_activate (GstPad * sinkpad)
242 {
243 if (gst_pad_check_pull_range (sinkpad)) {
244 return gst_pad_activate_pull (sinkpad, TRUE);
245 } else {
246 return gst_pad_activate_push (sinkpad, TRUE);
247 }
248 }
250 static gboolean
251 gst_asf_demux_activate_push (GstPad * sinkpad, gboolean active)
252 {
253 GstASFDemux *demux;
255 demux = GST_ASF_DEMUX (GST_OBJECT_PARENT (sinkpad));
257 demux->state = GST_ASF_DEMUX_STATE_HEADER;
258 demux->streaming = TRUE;
260 return TRUE;
261 }
263 static gboolean
264 gst_asf_demux_activate_pull (GstPad * pad, gboolean active)
265 {
266 GstASFDemux *demux;
268 demux = GST_ASF_DEMUX (GST_OBJECT_PARENT (pad));
270 if (active) {
271 demux->state = GST_ASF_DEMUX_STATE_HEADER;
272 demux->streaming = FALSE;
274 return gst_pad_start_task (pad, (GstTaskFunction) gst_asf_demux_loop,
275 demux);
276 } else {
277 return gst_pad_stop_task (pad);
278 }
279 }
282 static gboolean
283 gst_asf_demux_sink_event (GstPad * pad, GstEvent * event)
284 {
285 GstASFDemux *demux;
286 gboolean ret = TRUE;
288 demux = GST_ASF_DEMUX (gst_pad_get_parent (pad));
290 GST_LOG_OBJECT (demux, "handling %s event", GST_EVENT_TYPE_NAME (event));
291 switch (GST_EVENT_TYPE (event)) {
292 case GST_EVENT_NEWSEGMENT:{
293 GstFormat newsegment_format;
294 gint64 newsegment_start;
296 gst_event_parse_new_segment (event, NULL, NULL, &newsegment_format,
297 &newsegment_start, NULL, NULL);
299 if (newsegment_format == GST_FORMAT_BYTES) {
300 if (demux->packet_size && newsegment_start > demux->data_offset)
301 demux->packet = (newsegment_start - demux->data_offset) /
302 demux->packet_size;
303 else
304 demux->packet = 0;
305 } else if (newsegment_format == GST_FORMAT_TIME) {
306 /* do not know packet position, not really a problem */
307 demux->packet = -1;
308 } else {
309 GST_WARNING_OBJECT (demux, "unsupported newsegment format , ignoring");
310 gst_event_unref (event);
311 break;
312 }
314 /* in either case, clear some state and generate newsegment later on */
315 GST_OBJECT_LOCK (demux);
316 demux->first_ts = GST_CLOCK_TIME_NONE;
317 demux->need_newsegment = TRUE;
318 gst_asf_demux_reset_stream_state_after_discont (demux);
319 GST_OBJECT_UNLOCK (demux);
321 gst_event_unref (event);
322 break;
323 }
324 case GST_EVENT_EOS:{
325 if (demux->state == GST_ASF_DEMUX_STATE_HEADER) {
326 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
327 (_("This stream contains no data.")),
328 ("got eos and didn't receive a complete header object"));
329 break;
330 }
331 GST_OBJECT_LOCK (demux);
332 gst_adapter_clear (demux->adapter);
333 GST_OBJECT_UNLOCK (demux);
334 gst_asf_demux_send_event_unlocked (demux, event);
335 break;
336 }
338 case GST_EVENT_FLUSH_STOP:
339 GST_OBJECT_LOCK (demux);
340 gst_asf_demux_reset_stream_state_after_discont (demux);
341 GST_OBJECT_UNLOCK (demux);
342 gst_asf_demux_send_event_unlocked (demux, event);
343 break;
345 default:
346 ret = gst_pad_event_default (pad, event);
347 break;
348 }
350 gst_object_unref (demux);
351 return ret;
352 }
354 static gboolean
355 gst_asf_demux_seek_index_lookup (GstASFDemux * demux, guint * packet,
356 GstClockTime seek_time, GstClockTime * p_idx_time)
357 {
358 GstClockTime idx_time;
359 guint idx;
361 if (demux->sidx_num_entries == 0 || demux->sidx_interval == 0)
362 return FALSE;
364 idx = (guint) (seek_time / demux->sidx_interval);
366 /* FIXME: seek beyond end of file should result in immediate EOS from
367 * streaming thread instead of a failed seek */
368 if (idx >= demux->sidx_num_entries)
369 return FALSE;
371 *packet = demux->sidx_entries[idx];
373 /* so we get closer to the actual time of the packet ... actually, let's not
374 * do this, since we throw away superfluous payloads before the seek position
375 * anyway; this way, our key unit seek 'snap resolution' is a bit better
376 * (ie. same as index resolution) */
377 /*
378 while (idx > 0 && demux->sidx_entries[idx-1] == demux->sidx_entries[idx])
379 --idx;
380 */
382 idx_time = demux->sidx_interval * idx;
384 GST_DEBUG_OBJECT (demux, "%" GST_TIME_FORMAT " => packet %u at %"
385 GST_TIME_FORMAT, GST_TIME_ARGS (seek_time), *packet,
386 GST_TIME_ARGS (idx_time));
388 if (p_idx_time)
389 *p_idx_time = idx_time;
391 return TRUE;
392 }
394 static void
395 gst_asf_demux_reset_stream_state_after_discont (GstASFDemux * demux)
396 {
397 guint n;
399 demux->pts = 0; //why?
400 gst_adapter_clear (demux->adapter);
402 for (n = 0; n < demux->num_streams; n++) {
403 gst_buffer_replace (&demux->stream[n].payload, NULL);
404 gst_buffer_replace (&demux->stream[n].cache, NULL);
405 demux->stream[n].frag_offset = 0;
406 demux->stream[n].last_pts = GST_CLOCK_TIME_NONE;
407 demux->stream[n].last_buffer_timestamp = GST_CLOCK_TIME_NONE;
408 demux->stream[n].sequence = 0;
409 demux->stream[n].discont = TRUE;
410 demux->stream[n].last_flow = GST_FLOW_OK;
412 while (demux->stream[n].payloads->len > 0) {
413 AsfPayload *payload;
414 guint last;
416 last = demux->stream[n].payloads->len - 1;
417 payload = &g_array_index (demux->stream[n].payloads, AsfPayload, last);
418 gst_buffer_replace (&payload->buf, NULL);
419 g_array_remove_index (demux->stream[n].payloads, last);
420 }
421 }
422 }
424 /* do a seek in push based mode */
425 static gboolean
426 gst_asf_demux_handle_seek_push (GstASFDemux * demux, GstEvent * event)
427 {
428 gdouble rate;
429 GstFormat format;
430 GstSeekFlags flags;
431 GstSeekType cur_type, stop_type;
432 gint64 cur, stop;
433 guint packet;
434 gboolean res;
436 gst_event_parse_seek (event, &rate, &format, &flags, &cur_type, &cur,
437 &stop_type, &stop);
439 stop_type = GST_SEEK_TYPE_NONE;
440 stop = -1;
442 GST_DEBUG_OBJECT (demux, "seeking to %" GST_TIME_FORMAT, GST_TIME_ARGS (cur));
444 /* determine packet, by index or by estimation */
445 if (!gst_asf_demux_seek_index_lookup (demux, &packet, cur, NULL)) {
446 packet = (guint) gst_util_uint64_scale (demux->num_packets,
447 cur, demux->play_time);
448 }
450 if (packet > demux->num_packets) {
451 GST_DEBUG_OBJECT (demux, "could not determine packet to seek to, "
452 "seek aborted.");
453 return FALSE;
454 }
456 GST_DEBUG_OBJECT (demux, "seeking to packet %d", packet);
458 cur = demux->data_offset + (packet * demux->packet_size);
460 GST_DEBUG_OBJECT (demux, "Pushing BYTE seek rate %g, "
461 "start %" G_GINT64_FORMAT ", stop %" G_GINT64_FORMAT, rate, cur, stop);
462 /* BYTE seek event */
463 event = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags, cur_type, cur,
464 stop_type, stop);
465 res = gst_pad_push_event (demux->sinkpad, event);
467 return res;
468 }
470 static gboolean
471 gst_asf_demux_handle_seek_event (GstASFDemux * demux, GstEvent * event)
472 {
473 GstClockTime idx_time;
474 GstSegment segment;
475 GstSeekFlags flags;
476 GstSeekType cur_type, stop_type;
477 GstFormat format;
478 gboolean only_need_update;
479 gboolean keyunit_sync;
480 gboolean accurate;
481 gboolean flush;
482 gdouble rate;
483 gint64 cur, stop;
484 gint64 seek_time;
485 guint packet;
487 if (demux->seekable == FALSE || demux->packet_size == 0 ||
488 demux->num_packets == 0 || demux->play_time == 0) {
489 GST_LOG_OBJECT (demux, "stream is not seekable");
490 return FALSE;
491 }
493 if (!demux->activated_streams) {
494 GST_LOG_OBJECT (demux, "streams not yet activated, ignoring seek");
495 return FALSE;
496 }
498 gst_event_parse_seek (event, &rate, &format, &flags, &cur_type, &cur,
499 &stop_type, &stop);
501 if (format != GST_FORMAT_TIME) {
502 GST_LOG_OBJECT (demux, "seeking is only supported in TIME format");
503 return FALSE;
504 }
506 if (rate <= 0.0) {
507 GST_LOG_OBJECT (demux, "backward playback is not supported yet");
508 return FALSE;
509 }
511 flush = ((flags & GST_SEEK_FLAG_FLUSH) == GST_SEEK_FLAG_FLUSH);
512 accurate = ((flags & GST_SEEK_FLAG_ACCURATE) == GST_SEEK_FLAG_ACCURATE);
513 keyunit_sync = ((flags & GST_SEEK_FLAG_KEY_UNIT) == GST_SEEK_FLAG_KEY_UNIT);
515 if (demux->streaming) {
516 /* support it safely needs more segment handling, e.g. closing etc */
517 if (!flush) {
518 GST_LOG_OBJECT (demux, "streaming; non-flushing seek not supported");
519 return FALSE;
520 }
521 /* we can (re)construct the start later on, but not the end */
522 if (stop_type != GST_SEEK_TYPE_NONE) {
523 GST_LOG_OBJECT (demux, "streaming; end type must be NONE");
524 return FALSE;
525 }
526 gst_event_ref (event);
527 /* upstream might handle TIME seek, e.g. mms or rtsp,
528 * or not, e.g. http, then we give it a hand */
529 if (!gst_pad_push_event (demux->sinkpad, event))
530 return gst_asf_demux_handle_seek_push (demux, event);
531 else
532 return TRUE;
533 }
535 /* unlock the streaming thread */
536 if (flush) {
537 gst_pad_push_event (demux->sinkpad, gst_event_new_flush_start ());
538 gst_asf_demux_send_event_unlocked (demux, gst_event_new_flush_start ());
539 } else {
540 gst_pad_pause_task (demux->sinkpad);
541 }
543 /* grab the stream lock so that streaming cannot continue, for
544 * non flushing seeks when the element is in PAUSED this could block
545 * forever */
546 GST_PAD_STREAM_LOCK (demux->sinkpad);
548 /* we now can stop flushing, since we have the stream lock now */
549 gst_pad_push_event (demux->sinkpad, gst_event_new_flush_stop ());
551 if (flush)
552 gst_asf_demux_send_event_unlocked (demux, gst_event_new_flush_stop ());
554 /* operating on copy of segment until we know the seek worked */
555 segment = demux->segment;
557 if (demux->segment_running && !flush) {
558 GstEvent *newseg;
560 /* create the segment event to close the current segment */
561 newseg = gst_event_new_new_segment (TRUE, segment.rate,
562 GST_FORMAT_TIME, segment.start, segment.last_stop, segment.time);
564 gst_asf_demux_send_event_unlocked (demux, newseg);
565 }
567 gst_segment_set_seek (&segment, rate, format, flags, cur_type,
568 cur, stop_type, stop, &only_need_update);
570 GST_DEBUG_OBJECT (demux, "seeking to time %" GST_TIME_FORMAT ", segment: "
571 "%" GST_SEGMENT_FORMAT, GST_TIME_ARGS (segment.start), &segment);
573 seek_time = segment.start;
575 /* FIXME: should check the KEY_UNIT flag; need to adjust last_stop to
576 * real start of data and segment_start to indexed time for key unit seek*/
577 if (!gst_asf_demux_seek_index_lookup (demux, &packet, seek_time, &idx_time)) {
578 /* First try to query our source to see if it can convert for us. This is
579 the case when our source is an mms stream, notice that in this case
580 gstmms will do a time based seek to get the byte offset, this is not a
581 problem as the seek to this offset needs to happen anway. */
582 gint64 offset;
583 GstFormat dest_format = GST_FORMAT_BYTES;
585 if (gst_pad_query_peer_convert (demux->sinkpad, GST_FORMAT_TIME, seek_time,
586 &dest_format, &offset) && dest_format == GST_FORMAT_BYTES) {
587 packet = (offset - demux->data_offset) / demux->packet_size;
588 GST_LOG_OBJECT (demux, "convert %" GST_TIME_FORMAT
589 " to bytes query result: %lld, data_ofset: %llu, packet_size: %u,"
590 " resulting packet: %u\n", GST_TIME_ARGS (seek_time), offset,
591 demux->data_offset, demux->packet_size, packet);
592 } else {
593 /* Hackety hack, this sucks. We just seek to an earlier position
594 * and let the sinks throw away the stuff before the segment start */
595 if (flush && (accurate || keyunit_sync)) {
596 seek_time -= 5 * GST_SECOND;
597 if (seek_time < 0)
598 seek_time = 0;
599 }
601 packet = (guint) gst_util_uint64_scale (demux->num_packets,
602 seek_time, demux->play_time);
604 if (packet > demux->num_packets)
605 packet = demux->num_packets;
606 }
607 } else {
608 if (keyunit_sync) {
609 GST_DEBUG_OBJECT (demux, "key unit seek, adjust seek_time = %"
610 GST_TIME_FORMAT " to index_time = %" GST_TIME_FORMAT,
611 GST_TIME_ARGS (seek_time), GST_TIME_ARGS (idx_time));
612 segment.start = idx_time;
613 segment.last_stop = idx_time;
614 segment.time = idx_time;
615 }
616 }
618 GST_DEBUG_OBJECT (demux, "seeking to packet %u", packet);
620 GST_OBJECT_LOCK (demux);
621 demux->segment = segment;
622 demux->packet = packet;
623 demux->need_newsegment = TRUE;
624 gst_asf_demux_reset_stream_state_after_discont (demux);
625 GST_OBJECT_UNLOCK (demux);
627 /* restart our task since it might have been stopped when we did the flush */
628 gst_pad_start_task (demux->sinkpad, (GstTaskFunction) gst_asf_demux_loop,
629 demux);
631 /* streaming can continue now */
632 GST_PAD_STREAM_UNLOCK (demux->sinkpad);
634 return TRUE;
635 }
637 static gboolean
638 gst_asf_demux_handle_src_event (GstPad * pad, GstEvent * event)
639 {
640 GstASFDemux *demux;
641 gboolean ret;
643 demux = GST_ASF_DEMUX (gst_pad_get_parent (pad));
645 switch (GST_EVENT_TYPE (event)) {
646 case GST_EVENT_SEEK:
647 GST_LOG_OBJECT (pad, "seek event");
648 ret = gst_asf_demux_handle_seek_event (demux, event);
649 gst_event_unref (event);
650 break;
651 case GST_EVENT_QOS:
652 case GST_EVENT_NAVIGATION:
653 /* just drop these two silently */
654 gst_event_unref (event);
655 ret = FALSE;
656 break;
657 default:
658 GST_LOG_OBJECT (pad, "%s event", GST_EVENT_TYPE_NAME (event));
659 ret = gst_pad_event_default (pad, event);
660 break;
661 }
663 gst_object_unref (demux);
664 return ret;
665 }
667 static inline guint32
668 gst_asf_demux_identify_guid (const ASFGuidHash * guids, ASFGuid * guid)
669 {
670 guint32 ret;
672 ret = gst_asf_identify_guid (guids, guid);
674 GST_LOG ("%s 0x%08x-0x%08x-0x%08x-0x%08x",
675 gst_asf_get_guid_nick (guids, ret),
676 guid->v1, guid->v2, guid->v3, guid->v4);
678 return ret;
679 }
681 typedef struct
682 {
683 AsfObjectID id;
684 guint64 size;
685 } AsfObject;
687 static gboolean
688 asf_demux_peek_object (GstASFDemux * demux, const guint8 * data,
689 guint data_len, AsfObject * object)
690 {
691 ASFGuid guid;
693 if (data_len < ASF_OBJECT_HEADER_SIZE)
694 return FALSE;
696 guid.v1 = GST_READ_UINT32_LE (data + 0);
697 guid.v2 = GST_READ_UINT32_LE (data + 4);
698 guid.v3 = GST_READ_UINT32_LE (data + 8);
699 guid.v4 = GST_READ_UINT32_LE (data + 12);
701 object->size = GST_READ_UINT64_LE (data + 16);
703 /* FIXME: make asf_demux_identify_object_guid() */
704 object->id = gst_asf_demux_identify_guid (asf_object_guids, &guid);
705 if (object->id == ASF_OBJ_UNDEFINED) {
706 GST_WARNING_OBJECT (demux, "Unknown object %08x-%08x-%08x-%08x",
707 guid.v1, guid.v2, guid.v3, guid.v4);
708 }
710 return TRUE;
711 }
713 static GstFlowReturn
714 gst_asf_demux_chain_headers (GstASFDemux * demux)
715 {
716 GstFlowReturn flow;
717 AsfObject obj;
718 guint8 *header_data, *data = NULL;
719 guint64 header_size;
721 data = (guint8 *) gst_adapter_peek (demux->adapter, ASF_OBJECT_HEADER_SIZE);
722 if (data == NULL)
723 goto need_more_data;
725 asf_demux_peek_object (demux, data, ASF_OBJECT_HEADER_SIZE, &obj);
726 if (obj.id != ASF_OBJ_HEADER)
727 goto wrong_type;
729 GST_LOG_OBJECT (demux, "header size = %u", (guint) obj.size);
731 /* + 50 for non-packet data at beginning of ASF_OBJ_DATA */
732 if (gst_adapter_available (demux->adapter) < obj.size + 50)
733 goto need_more_data;
735 data = gst_adapter_take (demux->adapter, obj.size + 50);
737 header_data = data;
738 header_size = obj.size;
739 flow = gst_asf_demux_process_object (demux, &header_data, &header_size);
740 if (flow != GST_FLOW_OK)
741 goto parse_failed;
743 /* calculate where the packet data starts */
744 demux->data_offset = obj.size + 50;
746 /* now parse the beginning of the ASF_OBJ_DATA object */
747 if (!gst_asf_demux_parse_data_object_start (demux, data + obj.size))
748 goto wrong_type;
750 if (demux->num_streams == 0)
751 goto no_streams;
753 g_free (data);
754 return GST_FLOW_OK;
756 /* NON-FATAL */
757 need_more_data:
758 {
759 GST_LOG_OBJECT (demux, "not enough data in adapter yet");
760 return GST_FLOW_OK;
761 }
763 /* ERRORS */
764 wrong_type:
765 {
766 GST_ELEMENT_ERROR (demux, STREAM, WRONG_TYPE, (NULL),
767 ("This doesn't seem to be an ASF file"));
768 g_free (data);
769 return GST_FLOW_ERROR;
770 }
771 no_streams:
772 parse_failed:
773 {
774 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
775 ("header parsing failed, or no streams found, flow = %s",
776 gst_flow_get_name (flow)));
777 g_free (data);
778 return GST_FLOW_ERROR;
779 }
780 }
782 static GstFlowReturn
783 gst_asf_demux_aggregate_flow_return (GstASFDemux * demux)
784 {
785 int i;
786 GST_DEBUG_OBJECT (demux, "Aggregating");
788 for (i = 0; i < demux->num_streams; i++) {
789 if (demux->stream[i].active) {
790 GstFlowReturn flowret = demux->stream[i].last_flow;
791 GST_DEBUG_OBJECT (demux, "Aggregating: flow %i return %s", i,
792 gst_flow_get_name (flowret));
793 if (flowret != GST_FLOW_NOT_LINKED)
794 return flowret;
795 }
796 }
798 /* If we got here, then all our active streams are not linked */
799 return GST_FLOW_NOT_LINKED;
800 }
802 static gboolean
803 gst_asf_demux_pull_data (GstASFDemux * demux, guint64 offset, guint size,
804 GstBuffer ** p_buf, GstFlowReturn * p_flow)
805 {
806 GstFlowReturn flow;
808 GST_LOG_OBJECT (demux, "pulling buffer at %" G_GUINT64_FORMAT "+%u",
809 offset, size);
811 flow = gst_pad_pull_range (demux->sinkpad, offset, size, p_buf);
813 if (p_flow)
814 *p_flow = flow;
816 if (flow != GST_FLOW_OK) {
817 GST_DEBUG_OBJECT (demux, "flow %s pulling buffer at %" G_GUINT64_FORMAT
818 "+%u", gst_flow_get_name (flow), offset, size);
819 *p_buf = NULL;
820 return FALSE;
821 }
823 g_assert (*p_buf != NULL);
825 if (GST_BUFFER_SIZE (*p_buf) < size) {
826 GST_DEBUG_OBJECT (demux, "short read pulling buffer at %" G_GUINT64_FORMAT
827 "+%u (got only %u bytes)", offset, size, GST_BUFFER_SIZE (*p_buf));
828 gst_buffer_unref (*p_buf);
829 if (p_flow)
830 *p_flow = GST_FLOW_UNEXPECTED;
831 *p_buf = NULL;
832 return FALSE;
833 }
835 return TRUE;
836 }
838 static void
839 gst_asf_demux_pull_indices (GstASFDemux * demux)
840 {
841 GstBuffer *buf = NULL;
842 guint64 offset;
843 guint num_read = 0;
845 offset = demux->index_offset;
847 if (offset == 0) {
848 GST_DEBUG_OBJECT (demux, "can't read indices, don't know index offset");
849 return;
850 }
852 while (gst_asf_demux_pull_data (demux, offset, 16 + 8, &buf, NULL)) {
853 GstFlowReturn flow;
854 AsfObject obj;
856 asf_demux_peek_object (demux, GST_BUFFER_DATA (buf), 16 + 8, &obj);
857 gst_buffer_replace (&buf, NULL);
859 /* check for sanity */
860 if (obj.size > (5 * 1024 * 1024)) {
861 GST_DEBUG_OBJECT (demux, "implausible index object size, bailing out");
862 break;
863 }
865 if (!gst_asf_demux_pull_data (demux, offset, obj.size, &buf, NULL))
866 break;
868 GST_LOG_OBJECT (demux, "index object at offset 0x%" G_GINT64_MODIFIER "X"
869 ", size %u", offset, (guint) obj.size);
871 offset += obj.size; /* increase before _process_object changes it */
873 flow = gst_asf_demux_process_object (demux, &buf->data, &obj.size);
874 gst_buffer_replace (&buf, NULL);
876 if (flow != GST_FLOW_OK)
877 break;
879 ++num_read;
880 }
881 GST_DEBUG_OBJECT (demux, "read %u index objects", num_read);
882 }
884 static gboolean
885 gst_asf_demux_parse_data_object_start (GstASFDemux * demux, guint8 * data)
886 {
887 AsfObject obj;
889 asf_demux_peek_object (demux, data, 50, &obj);
890 if (obj.id != ASF_OBJ_DATA) {
891 GST_WARNING_OBJECT (demux, "headers not followed by a DATA object");
892 return FALSE;
893 }
895 demux->state = GST_ASF_DEMUX_STATE_DATA;
897 if (!demux->broadcast && obj.size > 50) {
898 demux->data_size = obj.size - 50;
899 /* CHECKME: for at least one file this is off by +158 bytes?! */
900 demux->index_offset = demux->data_offset + demux->data_size;
901 } else {
902 demux->data_size = 0;
903 demux->index_offset = 0;
904 }
906 demux->packet = 0;
908 if (!demux->broadcast) {
909 /* skip object header (24 bytes) and file GUID (16 bytes) */
910 demux->num_packets = GST_READ_UINT64_LE (data + (16 + 8) + 16);
911 } else {
912 demux->num_packets = 0;
913 }
915 if (demux->num_packets == 0)
916 demux->seekable = FALSE;
918 /* fallback in the unlikely case that headers are inconsistent, can't hurt */
919 if (demux->data_size == 0 && demux->num_packets > 0) {
920 demux->data_size = demux->num_packets * demux->packet_size;
921 demux->index_offset = demux->data_offset + demux->data_size;
922 }
924 /* process pending stream objects and create pads for those */
925 gst_asf_demux_process_queued_extended_stream_objects (demux);
927 GST_INFO_OBJECT (demux, "Stream has %" G_GUINT64_FORMAT " packets, "
928 "data_offset=%" G_GINT64_FORMAT ", data_size=%" G_GINT64_FORMAT
929 ", index_offset=%" G_GUINT64_FORMAT, demux->num_packets,
930 demux->data_offset, demux->data_size, demux->index_offset);
932 return TRUE;
933 }
935 static gboolean
936 gst_asf_demux_pull_headers (GstASFDemux * demux)
937 {
938 GstFlowReturn flow;
939 AsfObject obj;
940 GstBuffer *buf = NULL;
941 guint64 size;
943 GST_LOG_OBJECT (demux, "reading headers");
945 /* pull HEADER object header, so we know its size */
946 if (!gst_asf_demux_pull_data (demux, 0, 16 + 8, &buf, NULL))
947 goto read_failed;
949 asf_demux_peek_object (demux, GST_BUFFER_DATA (buf), 16 + 8, &obj);
950 gst_buffer_replace (&buf, NULL);
952 if (obj.id != ASF_OBJ_HEADER)
953 goto wrong_type;
955 GST_LOG_OBJECT (demux, "header size = %u", (guint) obj.size);
957 /* pull HEADER object */
958 if (!gst_asf_demux_pull_data (demux, 0, obj.size, &buf, NULL))
959 goto read_failed;
961 size = obj.size; /* don't want obj.size changed */
962 flow = gst_asf_demux_process_object (demux, &buf->data, &size);
963 gst_buffer_replace (&buf, NULL);
965 if (flow != GST_FLOW_OK) {
966 GST_WARNING_OBJECT (demux, "process_object: %s", gst_flow_get_name (flow));
967 goto parse_failed;
968 }
970 /* calculate where the packet data starts */
971 demux->data_offset = obj.size + 50;
973 /* now pull beginning of DATA object before packet data */
974 if (!gst_asf_demux_pull_data (demux, obj.size, 50, &buf, NULL))
975 goto read_failed;
977 if (!gst_asf_demux_parse_data_object_start (demux, GST_BUFFER_DATA (buf)))
978 goto wrong_type;
980 if (demux->num_streams == 0)
981 goto no_streams;
983 gst_buffer_replace (&buf, NULL);
984 return TRUE;
986 /* ERRORS */
987 wrong_type:
988 {
989 gst_buffer_replace (&buf, NULL);
990 GST_ELEMENT_ERROR (demux, STREAM, WRONG_TYPE, (NULL),
991 ("This doesn't seem to be an ASF file"));
992 return FALSE;
993 }
994 no_streams:
995 read_failed:
996 parse_failed:
997 {
998 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL), (NULL));
999 return FALSE;
1000 }
1001 }
1003 static gboolean
1004 all_streams_prerolled (GstASFDemux * demux)
1005 {
1006 GstClockTime preroll_time;
1007 guint i, num_no_data = 0;
1009 preroll_time = demux->preroll;
1011 /* returns TRUE as long as there isn't a stream which (a) has data queued
1012 * and (b) the timestamp of last piece of data queued is < demux->preroll
1013 * AND there is at least one other stream with data queued */
1014 for (i = 0; i < demux->num_streams; ++i) {
1015 AsfPayload *last_payload;
1016 AsfStream *stream;
1017 guint last_idx;
1019 stream = &demux->stream[i];
1020 if (stream->payloads->len == 0) {
1021 ++num_no_data;
1022 GST_LOG_OBJECT (stream->pad, "no data queued");
1023 continue;
1024 }
1026 last_idx = stream->payloads->len - 1;
1027 last_payload = &g_array_index (stream->payloads, AsfPayload, last_idx);
1029 GST_LOG_OBJECT (stream->pad, "checking if %" GST_TIME_FORMAT " > %"
1030 GST_TIME_FORMAT, GST_TIME_ARGS (last_payload->ts),
1031 GST_TIME_ARGS (preroll_time));
1032 if (last_payload->ts <= preroll_time) {
1033 GST_LOG_OBJECT (stream->pad, "not beyond preroll point yet");
1034 return FALSE;
1035 }
1036 }
1038 if (num_no_data == demux->num_streams)
1039 return FALSE;
1041 return TRUE;
1042 }
1044 #if 0
1045 static gboolean
1046 gst_asf_demux_have_mutually_exclusive_active_stream (GstASFDemux * demux,
1047 AsfStream * stream)
1048 {
1049 GSList *l;
1051 for (l = demux->mut_ex_streams; l != NULL; l = l->next) {
1052 guint8 *mes;
1054 /* check for each mutual exclusion group whether it affects this stream */
1055 for (mes = (guint8 *) l->data; mes != NULL && *mes != 0xff; ++mes) {
1056 if (*mes == stream->id) {
1057 /* we are in this group; let's check if we've already activated streams
1058 * that are in the same group (and hence mutually exclusive to this
1059 * one) */
1060 for (mes = (guint8 *) l->data; mes != NULL && *mes != 0xff; ++mes) {
1061 guint i;
1063 for (i = 0; i < demux->num_streams; ++i) {
1064 if (demux->stream[i].id == *mes && demux->stream[i].active) {
1065 GST_LOG_OBJECT (demux, "stream with ID %d is mutually exclusive "
1066 "to already active stream with ID %d", stream->id,
1067 demux->stream[i].id);
1068 return TRUE;
1069 }
1070 }
1071 }
1072 /* we can only be in this group once, let's break out and move on to
1073 * the next mutual exclusion group */
1074 break;
1075 }
1076 }
1077 }
1079 return FALSE;
1080 }
1081 #endif
1083 static gboolean
1084 gst_asf_demux_check_activate_streams (GstASFDemux * demux, gboolean force)
1085 {
1086 guint i;
1088 if (demux->activated_streams)
1089 return TRUE;
1091 if (!all_streams_prerolled (demux) && !force) {
1092 GST_DEBUG_OBJECT (demux, "not all streams with data beyond preroll yet");
1093 return FALSE;
1094 }
1096 for (i = 0; i < demux->num_streams; ++i) {
1097 AsfStream *stream = &demux->stream[i];
1099 if (stream->payloads->len > 0) {
1100 /* we don't check mutual exclusion stuff here; either we have data for
1101 * a stream, then we active it, or we don't, then we'll ignore it */
1102 GST_LOG_OBJECT (stream->pad, "is prerolled - activate!");
1103 gst_asf_demux_activate_stream (demux, stream);
1104 } else {
1105 GST_LOG_OBJECT (stream->pad, "no data, ignoring stream");
1106 }
1107 }
1109 demux->activated_streams = TRUE;
1110 GST_LOG_OBJECT (demux, "signalling no more pads");
1111 gst_element_no_more_pads (GST_ELEMENT (demux));
1112 return TRUE;
1113 }
1115 /* returns the stream that has a complete payload with the lowest timestamp
1116 * queued, or NULL (we push things by timestamp because during the internal
1117 * prerolling we might accumulate more data then the external queues can take,
1118 * so we'd lock up if we pushed all accumulated data for stream N in one go) */
1119 static AsfStream *
1120 gst_asf_demux_find_stream_with_complete_payload (GstASFDemux * demux)
1121 {
1122 AsfPayload *best_payload = NULL;
1123 AsfStream *best_stream = NULL;
1124 guint i;
1126 for (i = 0; i < demux->num_streams; ++i) {
1127 AsfStream *stream;
1129 stream = &demux->stream[i];
1131 /* Don't push any data until we have at least one payload that falls within
1132 * the current segment. This way we can remove out-of-segment payloads that
1133 * don't need to be decoded after a seek, sending only data from the
1134 * keyframe directly before our segment start */
1135 if (stream->payloads->len > 0) {
1136 AsfPayload *payload;
1137 guint last_idx;
1139 last_idx = stream->payloads->len - 1;
1140 payload = &g_array_index (stream->payloads, AsfPayload, last_idx);
1141 if (GST_CLOCK_TIME_IS_VALID (payload->ts) &&
1142 payload->ts < demux->segment.start) {
1143 GST_DEBUG_OBJECT (stream->pad, "Last queued payload has timestamp %"
1144 GST_TIME_FORMAT " which is before our segment start %"
1145 GST_TIME_FORMAT ", not pushing yet", GST_TIME_ARGS (payload->ts),
1146 GST_TIME_ARGS (demux->segment.start));
1147 continue;
1148 }
1149 }
1151 /* Now see if there's a complete payload queued for this stream */
1152 if (stream->payloads->len > 0) {
1153 AsfPayload *payload;
1155 payload = &g_array_index (stream->payloads, AsfPayload, 0);
1156 if (!gst_asf_payload_is_complete (payload))
1157 continue;
1159 /* ... and whether its timestamp is lower than the current best */
1160 if (best_stream == NULL || best_payload->ts > payload->ts) {
1161 best_stream = stream;
1162 best_payload = payload;
1163 }
1164 }
1165 }
1167 return best_stream;
1168 }
1170 static GstFlowReturn
1171 gst_asf_demux_push_complete_payloads (GstASFDemux * demux, gboolean force)
1172 {
1173 AsfStream *stream;
1175 if (G_UNLIKELY (!demux->activated_streams)) {
1176 if (!gst_asf_demux_check_activate_streams (demux, force))
1177 return GST_FLOW_OK;
1178 /* streams are now activated */
1179 }
1181 /* do we need to send a newsegment event */
1182 if (demux->need_newsegment) {
1184 /* wait until we had a chance to "lock on" some payload's timestamp */
1185 if (!GST_CLOCK_TIME_IS_VALID (demux->first_ts))
1186 return GST_FLOW_OK;
1188 if (demux->segment.stop == GST_CLOCK_TIME_NONE &&
1189 demux->segment.duration > 0) {
1190 demux->segment.stop = demux->segment.duration;
1191 }
1193 GST_DEBUG_OBJECT (demux, "sending new-segment event %" GST_SEGMENT_FORMAT,
1194 &demux->segment);
1196 /* note: we fix up all timestamps to start from 0, so this should be ok */
1197 gst_asf_demux_send_event_unlocked (demux,
1198 gst_event_new_new_segment (FALSE, demux->segment.rate,
1199 GST_FORMAT_TIME, demux->segment.start, demux->segment.stop,
1200 demux->segment.start));
1202 demux->need_newsegment = FALSE;
1203 demux->segment_running = TRUE;
1204 }
1206 while ((stream = gst_asf_demux_find_stream_with_complete_payload (demux))) {
1207 AsfPayload *payload;
1209 payload = &g_array_index (stream->payloads, AsfPayload, 0);
1211 /* Do we have tags pending for this stream? */
1212 if (stream->pending_tags) {
1213 GST_LOG_OBJECT (stream->pad, "%" GST_PTR_FORMAT, stream->pending_tags);
1214 gst_element_found_tags_for_pad (GST_ELEMENT (demux), stream->pad,
1215 stream->pending_tags);
1216 stream->pending_tags = NULL;
1217 }
1219 /* We have the whole packet now so we should push the packet to
1220 * the src pad now. First though we should check if we need to do
1221 * descrambling */
1222 if (demux->span > 1) {
1223 gst_asf_demux_descramble_buffer (demux, stream, &payload->buf);
1224 }
1226 payload->buf = gst_buffer_make_metadata_writable (payload->buf);
1228 if (!payload->keyframe) {
1229 GST_BUFFER_FLAG_SET (payload->buf, GST_BUFFER_FLAG_DELTA_UNIT);
1230 }
1232 if (stream->discont) {
1233 GST_BUFFER_FLAG_SET (payload->buf, GST_BUFFER_FLAG_DISCONT);
1234 stream->discont = FALSE;
1235 }
1237 gst_buffer_set_caps (payload->buf, stream->caps);
1239 GST_BUFFER_TIMESTAMP (payload->buf) = payload->ts;
1240 GST_BUFFER_DURATION (payload->buf) = payload->duration;
1242 /* FIXME: we should really set durations on buffers if we can */
1244 GST_LOG_OBJECT (stream->pad, "pushing buffer, ts=%" GST_TIME_FORMAT
1245 ", dur=%" GST_TIME_FORMAT " size=%u",
1246 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (payload->buf)),
1247 GST_TIME_ARGS (GST_BUFFER_DURATION (payload->buf)),
1248 GST_BUFFER_SIZE (payload->buf));
1250 stream->last_flow = gst_pad_push (stream->pad, payload->buf);
1251 payload->buf = NULL;
1252 g_array_remove_index (stream->payloads, 0);
1253 }
1255 return gst_asf_demux_aggregate_flow_return (demux);
1256 }
1258 static void
1259 gst_asf_demux_loop (GstASFDemux * demux)
1260 {
1261 GstFlowReturn flow = GST_FLOW_OK;
1262 GstBuffer *buf = NULL;
1263 guint64 off;
1265 if (demux->state == GST_ASF_DEMUX_STATE_HEADER) {
1266 if (!gst_asf_demux_pull_headers (demux)) {
1267 flow = GST_FLOW_ERROR;
1268 goto pause;
1269 }
1271 gst_asf_demux_pull_indices (demux);
1272 }
1274 g_assert (demux->state == GST_ASF_DEMUX_STATE_DATA);
1276 if (demux->num_packets != 0 && demux->packet >= demux->num_packets)
1277 goto eos;
1279 GST_LOG_OBJECT (demux, "packet %u/%u", (guint) demux->packet + 1,
1280 (guint) demux->num_packets);
1282 off = demux->data_offset + (demux->packet * demux->packet_size);
1284 if (!gst_asf_demux_pull_data (demux, off, demux->packet_size, &buf, &flow)) {
1285 GST_DEBUG_OBJECT (demux, "got flow %s", gst_flow_get_name (flow));
1286 if (flow == GST_FLOW_UNEXPECTED)
1287 goto eos;
1288 else if (!GST_FLOW_IS_FATAL (flow)) {
1289 GST_DEBUG_OBJECT (demux, "Not fatal");
1290 goto pause;
1291 } else
1292 goto read_failed;
1293 }
1295 /* FIXME: maybe we should just skip broken packets and error out only
1296 * after a few broken packets in a row? */
1297 if (!gst_asf_demux_parse_packet (demux, buf))
1298 goto parse_error;
1300 gst_buffer_unref (buf);
1302 flow = gst_asf_demux_push_complete_payloads (demux, FALSE);
1304 ++demux->packet;
1306 if (demux->num_packets > 0 && demux->packet >= demux->num_packets) {
1307 GST_LOG_OBJECT (demux, "reached EOS");
1308 goto eos;
1309 }
1311 if (flow != GST_FLOW_OK) {
1312 GST_DEBUG_OBJECT (demux, "pushing complete payloads failed");
1313 goto pause;
1314 }
1316 /* check if we're at the end of the configured segment */
1317 /* FIXME: check if segment end reached etc. */
1319 return;
1321 eos:
1322 {
1323 /* if we haven't activated our streams yet, this might be because we have
1324 * less data queued than required for preroll; force stream activation and
1325 * send any pending payloads before sending EOS */
1326 if (!demux->activated_streams)
1327 flow = gst_asf_demux_push_complete_payloads (demux, TRUE);
1329 if (GST_FLOW_IS_FATAL (flow) || flow == GST_FLOW_NOT_LINKED) {
1330 GST_DEBUG_OBJECT (demux, "pushing complete payloads failed");
1331 goto pause;
1332 }
1334 if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
1335 gint64 stop;
1337 /* for segment playback we need to post when (in stream time)
1338 * we stopped, this is either stop (when set) or the duration. */
1339 if ((stop = demux->segment.stop) == -1)
1340 stop = demux->segment.duration;
1342 GST_INFO_OBJECT (demux, "Posting segment-done, at end of segment");
1343 gst_element_post_message (GST_ELEMENT_CAST (demux),
1344 gst_message_new_segment_done (GST_OBJECT (demux), GST_FORMAT_TIME,
1345 stop));
1346 } else {
1347 /* normal playback, send EOS to all linked pads */
1348 GST_INFO_OBJECT (demux, "Sending EOS, at end of stream");
1349 gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
1350 }
1351 /* ... and fall through to pause */
1352 GST_DEBUG_OBJECT (demux, "EOSing");
1353 }
1354 pause:
1355 {
1356 GST_DEBUG_OBJECT (demux, "pausing task");
1357 demux->segment_running = FALSE;
1358 gst_pad_pause_task (demux->sinkpad);
1360 /* For the error cases (not EOS) */
1361 if (GST_FLOW_IS_FATAL (flow) || flow == GST_FLOW_NOT_LINKED) {
1362 /* Post an error. Hopefully something else already has, but if not... */
1363 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
1364 (_("Internal data stream error.")),
1365 ("streaming stopped, reason %s", gst_flow_get_name (flow)));
1366 }
1367 return;
1368 }
1370 /* ERRORS */
1371 read_failed:
1372 {
1373 GST_DEBUG_OBJECT (demux, "Read failed, doh");
1374 gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
1375 flow = GST_FLOW_UNEXPECTED;
1376 goto pause;
1377 }
1378 parse_error:
1379 {
1380 gst_buffer_unref (buf);
1381 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
1382 ("Error parsing ASF packet %u", (guint) demux->packet));
1383 gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
1384 flow = GST_FLOW_ERROR;
1385 goto pause;
1386 }
1387 }
1389 static GstFlowReturn
1390 gst_asf_demux_chain (GstPad * pad, GstBuffer * buf)
1391 {
1392 GstFlowReturn ret = GST_FLOW_OK;
1393 GstASFDemux *demux;
1395 demux = GST_ASF_DEMUX (GST_PAD_PARENT (pad));
1397 GST_LOG_OBJECT (demux, "buffer: size=%u, offset=%" G_GINT64_FORMAT,
1398 GST_BUFFER_SIZE (buf), GST_BUFFER_OFFSET (buf));
1400 if (GST_BUFFER_IS_DISCONT (buf))
1401 gst_asf_demux_reset_stream_state_after_discont (demux);
1403 gst_adapter_push (demux->adapter, buf);
1405 switch (demux->state) {
1406 case GST_ASF_DEMUX_STATE_HEADER:{
1407 ret = gst_asf_demux_chain_headers (demux);
1408 if (demux->state != GST_ASF_DEMUX_STATE_DATA)
1409 break;
1410 /* otherwise fall through */
1411 }
1412 case GST_ASF_DEMUX_STATE_DATA:
1413 {
1414 guint64 data_size;
1416 data_size = demux->packet_size;
1418 while (gst_adapter_available (demux->adapter) >= data_size) {
1419 GstBuffer *buf;
1421 /* do not overshoot data section when streaming */
1422 if (demux->num_packets != 0 && demux->packet >= 0
1423 && demux->packet >= demux->num_packets)
1424 goto eos;
1426 buf = gst_adapter_take_buffer (demux->adapter, data_size);
1428 /* FIXME: maybe we should just skip broken packets and error out only
1429 * after a few broken packets in a row? */
1430 if (!gst_asf_demux_parse_packet (demux, buf)) {
1431 GST_WARNING_OBJECT (demux, "Parse error");
1432 }
1434 gst_buffer_unref (buf);
1436 ret = gst_asf_demux_push_complete_payloads (demux, FALSE);
1438 if (demux->packet >= 0)
1439 ++demux->packet;
1440 }
1441 break;
1442 }
1443 default:
1444 g_assert_not_reached ();
1445 }
1447 done:
1448 if (ret != GST_FLOW_OK)
1449 GST_DEBUG_OBJECT (demux, "flow: %s", gst_flow_get_name (ret));
1451 return ret;
1453 eos:
1454 {
1455 GST_DEBUG_OBJECT (demux, "Handled last packet, setting EOS");
1456 ret = GST_FLOW_UNEXPECTED;
1457 goto done;
1458 }
1459 }
1461 static inline gboolean
1462 gst_asf_demux_skip_bytes (guint num_bytes, guint8 ** p_data, guint64 * p_size)
1463 {
1464 if (*p_size < num_bytes)
1465 return FALSE;
1467 *p_data += num_bytes;
1468 *p_size -= num_bytes;
1469 return TRUE;
1470 }
1472 static inline guint8
1473 gst_asf_demux_get_uint8 (guint8 ** p_data, guint64 * p_size)
1474 {
1475 guint8 ret;
1477 g_assert (*p_size >= 1);
1478 ret = GST_READ_UINT8 (*p_data);
1479 *p_data += sizeof (guint8);
1480 *p_size -= sizeof (guint8);
1481 return ret;
1482 }
1484 static inline guint16
1485 gst_asf_demux_get_uint16 (guint8 ** p_data, guint64 * p_size)
1486 {
1487 guint16 ret;
1489 g_assert (*p_size >= 2);
1490 ret = GST_READ_UINT16_LE (*p_data);
1491 *p_data += sizeof (guint16);
1492 *p_size -= sizeof (guint16);
1493 return ret;
1494 }
1496 static inline guint32
1497 gst_asf_demux_get_uint32 (guint8 ** p_data, guint64 * p_size)
1498 {
1499 guint32 ret;
1501 g_assert (*p_size >= 4);
1502 ret = GST_READ_UINT32_LE (*p_data);
1503 *p_data += sizeof (guint32);
1504 *p_size -= sizeof (guint32);
1505 return ret;
1506 }
1508 static inline guint64
1509 gst_asf_demux_get_uint64 (guint8 ** p_data, guint64 * p_size)
1510 {
1511 guint64 ret;
1513 g_assert (*p_size >= 8);
1514 ret = GST_READ_UINT64_LE (*p_data);
1515 *p_data += sizeof (guint64);
1516 *p_size -= sizeof (guint64);
1517 return ret;
1518 }
1520 static inline guint32
1521 gst_asf_demux_get_var_length (guint8 type, guint8 ** p_data, guint64 * p_size)
1522 {
1523 switch (type) {
1524 case 0:
1525 return 0;
1527 case 1:
1528 g_assert (*p_size >= 1);
1529 return gst_asf_demux_get_uint8 (p_data, p_size);
1531 case 2:
1532 g_assert (*p_size >= 2);
1533 return gst_asf_demux_get_uint16 (p_data, p_size);
1535 case 3:
1536 g_assert (*p_size >= 4);
1537 return gst_asf_demux_get_uint32 (p_data, p_size);
1539 default:
1540 break;
1541 }
1543 g_assert_not_reached ();
1544 }
1546 static gboolean
1547 gst_asf_demux_get_buffer (GstBuffer ** p_buf, guint num_bytes_to_read,
1548 guint8 ** p_data, guint64 * p_size)
1549 {
1550 *p_buf = NULL;
1552 if (*p_size < num_bytes_to_read)
1553 return FALSE;
1555 *p_buf = gst_buffer_new_and_alloc (num_bytes_to_read);
1556 memcpy (GST_BUFFER_DATA (*p_buf), *p_data, num_bytes_to_read);
1557 *p_data += num_bytes_to_read;
1558 *p_size -= num_bytes_to_read;
1559 return TRUE;
1560 }
1562 static gboolean
1563 gst_asf_demux_get_bytes (guint8 ** p_buf, guint num_bytes_to_read,
1564 guint8 ** p_data, guint64 * p_size)
1565 {
1566 *p_buf = NULL;
1568 if (*p_size < num_bytes_to_read)
1569 return FALSE;
1571 *p_buf = g_memdup (*p_data, num_bytes_to_read);
1572 *p_data += num_bytes_to_read;
1573 *p_size -= num_bytes_to_read;
1574 return TRUE;
1575 }
1577 static gboolean
1578 gst_asf_demux_get_string (gchar ** p_str, guint16 * p_strlen,
1579 guint8 ** p_data, guint64 * p_size)
1580 {
1581 guint16 s_length;
1582 guint8 *s;
1584 *p_str = NULL;
1586 if (*p_size < 2)
1587 return FALSE;
1589 s_length = gst_asf_demux_get_uint16 (p_data, p_size);
1591 if (p_strlen)
1592 *p_strlen = s_length;
1594 if (s_length == 0) {
1595 GST_WARNING ("zero-length string");
1596 *p_str = g_strdup ("");
1597 return TRUE;
1598 }
1600 if (!gst_asf_demux_get_bytes (&s, s_length, p_data, p_size))
1601 return FALSE;
1603 g_assert (s != NULL);
1605 /* just because They don't exist doesn't
1606 * mean They are not out to get you ... */
1607 if (s[s_length - 1] != '\0') {
1608 s = g_realloc (s, s_length + 1);
1609 s[s_length] = '\0';
1610 }
1612 *p_str = (gchar *) s;
1613 return TRUE;
1614 }
1617 static void
1618 gst_asf_demux_get_guid (ASFGuid * guid, guint8 ** p_data, guint64 * p_size)
1619 {
1620 g_assert (*p_size >= 4 * sizeof (guint32));
1622 guid->v1 = gst_asf_demux_get_uint32 (p_data, p_size);
1623 guid->v2 = gst_asf_demux_get_uint32 (p_data, p_size);
1624 guid->v3 = gst_asf_demux_get_uint32 (p_data, p_size);
1625 guid->v4 = gst_asf_demux_get_uint32 (p_data, p_size);
1626 }
1628 static gboolean
1629 gst_asf_demux_get_stream_audio (asf_stream_audio * audio, guint8 ** p_data,
1630 guint64 * p_size)
1631 {
1632 if (*p_size < (2 + 2 + 4 + 4 + 2 + 2 + 2))
1633 return FALSE;
1635 /* WAVEFORMATEX Structure */
1636 audio->codec_tag = gst_asf_demux_get_uint16 (p_data, p_size);
1637 audio->channels = gst_asf_demux_get_uint16 (p_data, p_size);
1638 audio->sample_rate = gst_asf_demux_get_uint32 (p_data, p_size);
1639 audio->byte_rate = gst_asf_demux_get_uint32 (p_data, p_size);
1640 audio->block_align = gst_asf_demux_get_uint16 (p_data, p_size);
1641 audio->word_size = gst_asf_demux_get_uint16 (p_data, p_size);
1642 /* Codec specific data size */
1643 audio->size = gst_asf_demux_get_uint16 (p_data, p_size);
1644 return TRUE;
1645 }
1647 static gboolean
1648 gst_asf_demux_get_stream_video (asf_stream_video * video, guint8 ** p_data,
1649 guint64 * p_size)
1650 {
1651 if (*p_size < (4 + 4 + 1 + 2))
1652 return FALSE;
1654 video->width = gst_asf_demux_get_uint32 (p_data, p_size);
1655 video->height = gst_asf_demux_get_uint32 (p_data, p_size);
1656 video->unknown = gst_asf_demux_get_uint8 (p_data, p_size);
1657 video->size = gst_asf_demux_get_uint16 (p_data, p_size);
1658 return TRUE;
1659 }
1661 static gboolean
1662 gst_asf_demux_get_stream_video_format (asf_stream_video_format * fmt,
1663 guint8 ** p_data, guint64 * p_size)
1664 {
1665 if (*p_size < (4 + 4 + 4 + 2 + 2 + 4 + 4 + 4 + 4 + 4 + 4))
1666 return FALSE;
1668 fmt->size = gst_asf_demux_get_uint32 (p_data, p_size);
1669 fmt->width = gst_asf_demux_get_uint32 (p_data, p_size);
1670 fmt->height = gst_asf_demux_get_uint32 (p_data, p_size);
1671 fmt->planes = gst_asf_demux_get_uint16 (p_data, p_size);
1672 fmt->depth = gst_asf_demux_get_uint16 (p_data, p_size);
1673 fmt->tag = gst_asf_demux_get_uint32 (p_data, p_size);
1674 fmt->image_size = gst_asf_demux_get_uint32 (p_data, p_size);
1675 fmt->xpels_meter = gst_asf_demux_get_uint32 (p_data, p_size);
1676 fmt->ypels_meter = gst_asf_demux_get_uint32 (p_data, p_size);
1677 fmt->num_colors = gst_asf_demux_get_uint32 (p_data, p_size);
1678 fmt->imp_colors = gst_asf_demux_get_uint32 (p_data, p_size);
1679 return TRUE;
1680 }
1682 AsfStream *
1683 gst_asf_demux_get_stream (GstASFDemux * demux, guint16 id)
1684 {
1685 guint i;
1687 for (i = 0; i < demux->num_streams; i++) {
1688 if (demux->stream[i].id == id)
1689 return &demux->stream[i];
1690 }
1692 GST_WARNING ("Segment found for undefined stream: (%d)", id);
1693 return NULL;
1694 }
1696 static void
1697 gst_asf_demux_setup_pad (GstASFDemux * demux, GstPad * src_pad,
1698 GstCaps * caps, guint16 id, gboolean is_video, GstTagList * tags)
1699 {
1700 AsfStream *stream;
1702 gst_pad_use_fixed_caps (src_pad);
1703 gst_pad_set_caps (src_pad, caps);
1705 gst_pad_set_event_function (src_pad,
1706 GST_DEBUG_FUNCPTR (gst_asf_demux_handle_src_event));
1707 gst_pad_set_query_type_function (src_pad,
1708 GST_DEBUG_FUNCPTR (gst_asf_demux_get_src_query_types));
1709 gst_pad_set_query_function (src_pad,
1710 GST_DEBUG_FUNCPTR (gst_asf_demux_handle_src_query));
1712 stream = &demux->stream[demux->num_streams];
1713 stream->caps = caps;
1714 stream->pad = src_pad;
1715 stream->id = id;
1716 stream->frag_offset = 0;
1717 stream->sequence = 0;
1718 stream->delay = 0;
1719 stream->first_pts = GST_CLOCK_TIME_NONE;
1720 stream->last_pts = GST_CLOCK_TIME_NONE;
1721 stream->last_buffer_timestamp = GST_CLOCK_TIME_NONE;
1722 stream->fps_known = !is_video; /* bit hacky for audio */
1723 stream->is_video = is_video;
1724 stream->pending_tags = tags;
1725 stream->discont = TRUE;
1727 stream->payloads = g_array_new (FALSE, FALSE, sizeof (AsfPayload));
1729 GST_INFO ("Created pad %s for stream %u with caps %" GST_PTR_FORMAT,
1730 GST_PAD_NAME (src_pad), demux->num_streams, caps);
1732 ++demux->num_streams;
1734 stream->active = FALSE;
1735 }
1737 static void
1738 gst_asf_demux_add_audio_stream (GstASFDemux * demux,
1739 asf_stream_audio * audio, guint16 id, guint8 ** p_data, guint64 * p_size)
1740 {
1741 GstTagList *tags = NULL;
1742 GstBuffer *extradata = NULL;
1743 GstPad *src_pad;
1744 GstCaps *caps;
1745 guint16 size_left = 0;
1746 gchar *codec_name = NULL;
1747 gchar *name = NULL;
1749 size_left = audio->size;
1751 /* Create the audio pad */
1752 name = g_strdup_printf ("audio_%02d", demux->num_audio_streams);
1754 src_pad = gst_pad_new_from_static_template (&audio_src_template, name);
1755 g_free (name);
1757 /* Swallow up any left over data and set up the
1758 * standard properties from the header info */
1759 if (size_left) {
1760 GST_INFO_OBJECT (demux, "Audio header contains %d bytes of "
1761 "codec specific data", size_left);
1763 g_assert (size_left <= *p_size);
1764 gst_asf_demux_get_buffer (&extradata, size_left, p_data, p_size);
1765 }
1767 /* asf_stream_audio is the same as gst_riff_strf_auds, but with an
1768 * additional two bytes indicating extradata. */
1769 caps = gst_riff_create_audio_caps (audio->codec_tag, NULL,
1770 (gst_riff_strf_auds *) audio, extradata, NULL, &codec_name);
1772 if (caps == NULL) {
1773 caps = gst_caps_new_simple ("audio/x-asf-unknown", "codec_id",
1774 G_TYPE_INT, (gint) audio->codec_tag, NULL);
1775 }
1777 /* Informing about that audio format we just added */
1778 if (codec_name) {
1779 tags = gst_tag_list_new ();
1780 gst_tag_list_add (tags, GST_TAG_MERGE_APPEND, GST_TAG_AUDIO_CODEC,
1781 codec_name, NULL);
1782 g_free (codec_name);
1783 }
1785 if (extradata)
1786 gst_buffer_unref (extradata);
1788 GST_INFO ("Adding audio stream #%u, id %u codec %u (0x%04x), tags=%"
1789 GST_PTR_FORMAT, demux->num_audio_streams, id, audio->codec_tag,
1790 audio->codec_tag, tags);
1792 ++demux->num_audio_streams;
1794 gst_asf_demux_setup_pad (demux, src_pad, caps, id, FALSE, tags);
1795 }
1797 static void
1798 gst_asf_demux_add_video_stream (GstASFDemux * demux,
1799 asf_stream_video_format * video, guint16 id,
1800 guint8 ** p_data, guint64 * p_size)
1801 {
1802 GstTagList *tags = NULL;
1803 GstBuffer *extradata = NULL;
1804 GstPad *src_pad;
1805 GstCaps *caps;
1806 gchar *name = NULL;
1807 gchar *codec_name = NULL;
1808 gint size_left = video->size - 40;
1810 /* Create the video pad */
1811 name = g_strdup_printf ("video_%02d", demux->num_video_streams);
1812 src_pad = gst_pad_new_from_static_template (&video_src_template, name);
1813 g_free (name);
1815 /* Now try some gstreamer formatted MIME types (from gst_avi_demux_strf_vids) */
1816 if (size_left) {
1817 GST_LOG ("Video header has %d bytes of codec specific data", size_left);
1818 g_assert (size_left <= *p_size);
1819 gst_asf_demux_get_buffer (&extradata, size_left, p_data, p_size);
1820 }
1822 GST_DEBUG ("video codec %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (video->tag));
1824 /* yes, asf_stream_video_format and gst_riff_strf_vids are the same */
1825 caps = gst_riff_create_video_caps (video->tag, NULL,
1826 (gst_riff_strf_vids *) video, extradata, NULL, &codec_name);
1828 if (caps == NULL) {
1829 caps = gst_caps_new_simple ("video/x-asf-unknown", "fourcc",
1830 GST_TYPE_FOURCC, video->tag, NULL);
1831 } else {
1832 GstStructure *s;
1833 gint ax, ay;
1835 s = gst_asf_demux_get_metadata_for_stream (demux, id);
1836 if (gst_structure_get_int (s, "AspectRatioX", &ax) &&
1837 gst_structure_get_int (s, "AspectRatioY", &ay)) {
1838 /* only copy sane values */
1839 if (ax > 0 && ay > 0) {
1840 gst_caps_set_simple (caps, "pixel-aspect-ratio", GST_TYPE_FRACTION,
1841 ax, ay, NULL);
1842 }
1843 }
1844 /* remove the framerate we will guess and add it later */
1845 s = gst_caps_get_structure (caps, 0);
1846 gst_structure_remove_field (s, "framerate");
1847 }
1849 /* add fourcc format to caps, some proprietary decoders seem to need it */
1850 gst_caps_set_simple (caps, "format", GST_TYPE_FOURCC, video->tag, NULL);
1852 if (codec_name) {
1853 tags = gst_tag_list_new ();
1854 gst_tag_list_add (tags, GST_TAG_MERGE_APPEND, GST_TAG_VIDEO_CODEC,
1855 codec_name, NULL);
1856 g_free (codec_name);
1857 }
1859 if (extradata)
1860 gst_buffer_unref (extradata);
1862 GST_INFO ("Adding video stream #%u, id %u, codec %"
1863 GST_FOURCC_FORMAT " (0x%08x)", demux->num_video_streams, id,
1864 GST_FOURCC_ARGS (video->tag), video->tag);
1866 ++demux->num_video_streams;
1868 gst_asf_demux_setup_pad (demux, src_pad, caps, id, TRUE, tags);
1869 }
1871 static void
1872 gst_asf_demux_activate_stream (GstASFDemux * demux, AsfStream * stream)
1873 {
1874 if (!stream->active) {
1875 GST_INFO_OBJECT (demux, "Activating stream %2u, pad %s, caps %"
1876 GST_PTR_FORMAT, stream->id, GST_PAD_NAME (stream->pad), stream->caps);
1877 gst_pad_set_active (stream->pad, TRUE);
1878 gst_element_add_pad (GST_ELEMENT_CAST (demux), stream->pad);
1879 stream->active = TRUE;
1880 }
1881 }
1883 static AsfStream *
1884 gst_asf_demux_parse_stream_object (GstASFDemux * demux, guint8 * data,
1885 guint64 size)
1886 {
1887 AsfCorrectionType correction_type;
1888 AsfStreamType stream_type;
1889 GstClockTime time_offset;
1890 gboolean is_encrypted;
1891 guint16 stream_id;
1892 guint16 flags;
1893 ASFGuid guid;
1894 guint stream_specific_size;
1895 guint type_specific_size;
1896 guint unknown;
1898 /* Get the rest of the header's header */
1899 if (size < (16 + 16 + 8 + 4 + 4 + 2 + 4))
1900 goto not_enough_data;
1902 gst_asf_demux_get_guid (&guid, &data, &size);
1903 stream_type = gst_asf_demux_identify_guid (asf_stream_guids, &guid);
1905 gst_asf_demux_get_guid (&guid, &data, &size);
1906 correction_type = gst_asf_demux_identify_guid (asf_correction_guids, &guid);
1908 time_offset = gst_asf_demux_get_uint64 (&data, &size) * 100;
1910 type_specific_size = gst_asf_demux_get_uint32 (&data, &size);
1911 stream_specific_size = gst_asf_demux_get_uint32 (&data, &size);
1913 flags = gst_asf_demux_get_uint16 (&data, &size);
1914 stream_id = flags & 0x7f;
1915 is_encrypted = !!((flags & 0x8000) << 15);
1916 unknown = gst_asf_demux_get_uint32 (&data, &size);
1918 GST_DEBUG_OBJECT (demux, "Found stream %u, time_offset=%" GST_TIME_FORMAT,
1919 stream_id, GST_TIME_ARGS (time_offset));
1921 switch (stream_type) {
1922 case ASF_STREAM_AUDIO:{
1923 asf_stream_audio audio_object;
1925 if (!gst_asf_demux_get_stream_audio (&audio_object, &data, &size))
1926 goto not_enough_data;
1928 GST_INFO ("Object is an audio stream with %u bytes of additional data",
1929 audio_object.size);
1931 gst_asf_demux_add_audio_stream (demux, &audio_object, stream_id,
1932 &data, &size);
1934 switch (correction_type) {
1935 case ASF_CORRECTION_ON:{
1936 guint span, packet_size, chunk_size, data_size, silence_data;
1938 GST_INFO ("Using error correction");
1940 if (size < (1 + 2 + 2 + 2 + 1))
1941 goto not_enough_data;
1943 span = gst_asf_demux_get_uint8 (&data, &size);
1944 packet_size = gst_asf_demux_get_uint16 (&data, &size);
1945 chunk_size = gst_asf_demux_get_uint16 (&data, &size);
1946 data_size = gst_asf_demux_get_uint16 (&data, &size);
1947 silence_data = gst_asf_demux_get_uint8 (&data, &size);
1949 /* FIXME: shouldn't this be per-stream? */
1950 demux->span = span;
1952 GST_DEBUG_OBJECT (demux, "Descrambling ps:%u cs:%u ds:%u s:%u sd:%u",
1953 packet_size, chunk_size, data_size, span, silence_data);
1955 if (demux->span > 1) {
1956 if (chunk_size == 0 || ((packet_size / chunk_size) <= 1)) {
1957 /* Disable descrambling */
1958 demux->span = 0;
1959 } else {
1960 /* FIXME: this else branch was added for
1961 * weird_al_yankovic - the saga begins.asf */
1962 demux->ds_packet_size = packet_size;
1963 demux->ds_chunk_size = chunk_size;
1964 }
1965 } else {
1966 /* Descambling is enabled */
1967 demux->ds_packet_size = packet_size;
1968 demux->ds_chunk_size = chunk_size;
1969 }
1970 #if 0
1971 /* Now skip the rest of the silence data */
1972 if (data_size > 1)
1973 gst_bytestream_flush (demux->bs, data_size - 1);
1974 #else
1975 /* FIXME: CHECKME. And why -1? */
1976 if (data_size > 1) {
1977 if (!gst_asf_demux_skip_bytes (data_size - 1, &data, &size)) {
1978 goto not_enough_data;
1979 }
1980 }
1981 #endif
1982 break;
1983 }
1984 case ASF_CORRECTION_OFF:{
1985 GST_INFO ("Error correction off");
1986 if (!gst_asf_demux_skip_bytes (stream_specific_size, &data, &size))
1987 goto not_enough_data;
1988 break;
1989 }
1990 default:
1991 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
1992 ("Audio stream using unknown error correction"));
1993 return NULL;
1994 }
1996 break;
1997 }
1999 case ASF_STREAM_VIDEO:{
2000 asf_stream_video_format video_format_object;
2001 asf_stream_video video_object;
2002 guint16 vsize;
2004 if (!gst_asf_demux_get_stream_video (&video_object, &data, &size))
2005 goto not_enough_data;
2007 vsize = video_object.size - 40; /* Byte order gets offset by single byte */
2009 GST_INFO ("object is a video stream with %u bytes of "
2010 "additional data", vsize);
2012 if (!gst_asf_demux_get_stream_video_format (&video_format_object,
2013 &data, &size)) {
2014 goto not_enough_data;
2015 }
2017 gst_asf_demux_add_video_stream (demux, &video_format_object, stream_id,
2018 &data, &size);
2020 break;
2021 }
2023 default:
2024 GST_WARNING_OBJECT (demux, "Unknown stream type for stream %u",
2025 stream_id);
2026 break;
2027 }
2029 return gst_asf_demux_get_stream (demux, stream_id);
2031 not_enough_data:
2032 {
2033 GST_WARNING_OBJECT (demux, "Unexpected end of data parsing stream object");
2034 /* we'll error out later if we found no streams */
2035 return NULL;
2036 }
2037 }
2039 static const gchar *
2040 gst_asf_demux_get_gst_tag_from_tag_name (const gchar * name_utf16le,
2041 gsize name_len)
2042 {
2043 const struct
2044 {
2045 const gchar *asf_name;
2046 const gchar *gst_name;
2047 } tags[] = {
2048 {
2049 "WM/Genre", GST_TAG_GENRE}, {
2050 "WM/AlbumTitle", GST_TAG_ALBUM}, {
2051 "WM/AlbumArtist", GST_TAG_ARTIST}, {
2052 "WM/Track", GST_TAG_TRACK_NUMBER}, {
2053 "WM/Year", GST_TAG_DATE}
2054 /* { "WM/Composer", GST_TAG_COMPOSER } */
2055 };
2056 gchar *name_utf8;
2057 gsize in, out;
2058 guint i;
2060 /* convert name to UTF-8 */
2061 name_utf8 = g_convert (name_utf16le, name_len, "UTF-8", "UTF-16LE", &in,
2062 &out, NULL);
2064 if (name_utf8 == NULL) {
2065 GST_WARNING ("Failed to convert name to UTF8, skipping");
2066 return NULL;
2067 }
2069 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
2070 if (strncmp (tags[i].asf_name, name_utf8, out) == 0) {
2071 GST_LOG ("map tagname '%s' -> '%s'", name_utf8, tags[i].gst_name);
2072 g_free (name_utf8);
2073 return tags[i].gst_name;
2074 }
2075 }
2077 GST_LOG ("unhandled tagname '%s'", name_utf8);
2078 g_free (name_utf8);
2079 return NULL;
2080 }
2082 /* gst_asf_demux_commit_taglist() takes ownership of taglist! */
2083 static void
2084 gst_asf_demux_commit_taglist (GstASFDemux * demux, GstTagList * taglist)
2085 {
2086 GST_DEBUG ("Committing tags: %" GST_PTR_FORMAT, taglist);
2088 gst_element_found_tags (GST_ELEMENT (demux), gst_tag_list_copy (taglist));
2090 /* save internally */
2091 if (!demux->taglist)
2092 demux->taglist = taglist;
2093 else {
2094 GstTagList *t;
2096 t = gst_tag_list_merge (demux->taglist, taglist, GST_TAG_MERGE_APPEND);
2097 gst_tag_list_free (demux->taglist);
2098 gst_tag_list_free (taglist);
2099 demux->taglist = t;
2100 }
2101 }
2103 #define ASF_DEMUX_DATA_TYPE_UTF16LE_STRING 0
2104 #define ASF_DEMUX_DATA_TYPE_DWORD 3
2106 /* Extended Content Description Object */
2107 static GstFlowReturn
2108 gst_asf_demux_process_ext_content_desc (GstASFDemux * demux, guint8 * data,
2109 guint64 size)
2110 {
2111 /* Other known (and unused) 'text/unicode' metadata available :
2112 *
2113 * WM/Lyrics =
2114 * WM/MediaPrimaryClassID = {D1607DBC-E323-4BE2-86A1-48A42A28441E}
2115 * WMFSDKVersion = 9.00.00.2980
2116 * WMFSDKNeeded = 0.0.0.0000
2117 * WM/UniqueFileIdentifier = AMGa_id=R 15334;AMGp_id=P 5149;AMGt_id=T 2324984
2118 * WM/Publisher = 4AD
2119 * WM/Provider = AMG
2120 * WM/ProviderRating = 8
2121 * WM/ProviderStyle = Rock (similar to WM/Genre)
2122 * WM/GenreID (similar to WM/Genre)
2123 * WM/TrackNumber (same as WM/Track but as a string)
2124 *
2125 * Other known (and unused) 'non-text' metadata available :
2126 *
2127 * WM/EncodingTime
2128 * WM/MCDI
2129 * IsVBR
2130 *
2131 * We might want to read WM/TrackNumber and use atoi() if we don't have
2132 * WM/Track
2133 */
2135 GstTagList *taglist;
2136 guint16 blockcount, i;
2138 GST_INFO_OBJECT (demux, "object is an extended content description");
2140 taglist = gst_tag_list_new ();
2142 /* Content Descriptor Count */
2143 if (size < 2)
2144 goto not_enough_data;
2146 blockcount = gst_asf_demux_get_uint16 (&data, &size);
2148 for (i = 1; i <= blockcount; ++i) {
2149 const gchar *gst_tag_name;
2150 guint16 datatype;
2151 guint16 value_len;
2152 guint16 name_len;
2153 GValue tag_value = { 0, };
2154 gsize in, out;
2155 gchar *name;
2156 gchar *value;
2158 /* Descriptor */
2159 if (!gst_asf_demux_get_string (&name, &name_len, &data, &size))
2160 goto not_enough_data;
2162 if (size < 2) {
2163 g_free (name);
2164 goto not_enough_data;
2165 }
2166 /* Descriptor Value Data Type */
2167 datatype = gst_asf_demux_get_uint16 (&data, &size);
2169 /* Descriptor Value (not really a string, but same thing reading-wise) */
2170 if (!gst_asf_demux_get_string (&value, &value_len, &data, &size)) {
2171 g_free (name);
2172 goto not_enough_data;
2173 }
2175 gst_tag_name = gst_asf_demux_get_gst_tag_from_tag_name (name, name_len);
2176 if (gst_tag_name != NULL) {
2177 switch (datatype) {
2178 case ASF_DEMUX_DATA_TYPE_UTF16LE_STRING:{
2179 gchar *value_utf8;
2181 value_utf8 = g_convert (value, value_len, "UTF-8", "UTF-16LE",
2182 &in, &out, NULL);
2184 /* get rid of tags with empty value */
2185 if (value_utf8 != NULL && *value_utf8 != '\0') {
2186 value_utf8[out] = '\0';
2188 if (strcmp (gst_tag_name, GST_TAG_DATE) == 0) {
2189 guint year = atoi (value_utf8);
2191 if (year > 0) {
2192 GDate *date = g_date_new_dmy (1, 1, year);
2194 g_value_init (&tag_value, GST_TYPE_DATE);
2195 gst_value_set_date (&tag_value, date);
2196 g_date_free (date);
2197 }
2198 } else {
2199 GType tag_type;
2201 /* convert tag from string to other type if required */
2202 tag_type = gst_tag_get_type (gst_tag_name);
2203 g_value_init (&tag_value, tag_type);
2204 if (!gst_value_deserialize (&tag_value, value_utf8)) {
2205 GValue from_val = { 0, };
2207 g_value_init (&from_val, G_TYPE_STRING);
2208 g_value_set_string (&from_val, value_utf8);
2209 if (!g_value_transform (&from_val, &tag_value)) {
2210 GST_WARNING_OBJECT (demux,
2211 "Could not transform string tag to " "%s tag type %s",
2212 gst_tag_name, g_type_name (tag_type));
2213 g_value_unset (&tag_value);
2214 }
2215 g_value_unset (&from_val);
2216 }
2217 }
2218 } else if (value_utf8 == NULL) {
2219 GST_WARNING ("Failed to convert string value to UTF8, skipping");
2220 } else {
2221 GST_DEBUG ("Skipping empty string value for %s", gst_tag_name);
2222 }
2223 g_free (value_utf8);
2224 break;
2225 }
2226 case ASF_DEMUX_DATA_TYPE_DWORD:{
2227 /* this is the track number */
2228 g_value_init (&tag_value, G_TYPE_UINT);
2229 g_value_set_uint (&tag_value, (guint) GST_READ_UINT32_LE (value));
2230 break;
2231 }
2232 default:{
2233 GST_DEBUG ("Skipping tag %s of type %d", gst_tag_name, datatype);
2234 break;
2235 }
2236 }
2238 if (G_IS_VALUE (&tag_value)) {
2239 gst_tag_list_add_values (taglist, GST_TAG_MERGE_APPEND,
2240 gst_tag_name, &tag_value, NULL);
2242 g_value_unset (&tag_value);
2243 }
2244 }
2246 g_free (name);
2247 g_free (value);
2248 }
2250 if (gst_structure_n_fields (GST_STRUCTURE (taglist)) > 0) {
2251 gst_asf_demux_commit_taglist (demux, taglist);
2252 } else {
2253 gst_tag_list_free (taglist);
2254 }
2256 return GST_FLOW_OK;
2258 /* Errors */
2259 not_enough_data:
2260 {
2261 GST_WARNING ("Unexpected end of data parsing ext content desc object");
2262 gst_tag_list_free (taglist);
2263 return GST_FLOW_OK; /* not really fatal */
2264 }
2265 }
2267 static GstStructure *
2268 gst_asf_demux_get_metadata_for_stream (GstASFDemux * demux, guint stream_num)
2269 {
2270 gchar sname[32];
2271 guint i;
2273 g_snprintf (sname, sizeof (sname), "stream-%u", stream_num);
2275 for (i = 0; i < gst_caps_get_size (demux->metadata); ++i) {
2276 GstStructure *s;
2278 s = gst_caps_get_structure (demux->metadata, i);
2279 if (gst_structure_has_name (s, sname))
2280 return s;
2281 }
2283 gst_caps_append_structure (demux->metadata, gst_structure_empty_new (sname));
2285 /* try lookup again; demux->metadata took ownership of the structure, so we
2286 * can't really make any assumptions about what happened to it, so we can't
2287 * just return it directly after appending it */
2288 return gst_asf_demux_get_metadata_for_stream (demux, stream_num);
2289 }
2291 static GstFlowReturn
2292 gst_asf_demux_process_metadata (GstASFDemux * demux, guint8 * data,
2293 guint64 size)
2294 {
2295 guint16 blockcount, i;
2297 GST_INFO_OBJECT (demux, "object is a metadata object");
2299 /* Content Descriptor Count */
2300 if (size < 2)
2301 goto not_enough_data;
2303 blockcount = gst_asf_demux_get_uint16 (&data, &size);
2305 for (i = 0; i < blockcount; ++i) {
2306 GstStructure *s;
2307 guint16 lang_idx, stream_num, name_len, data_type;
2308 guint32 data_len, ival;
2309 gchar *name_utf8;
2311 if (size < (2 + 2 + 2 + 2 + 4))
2312 goto not_enough_data;
2314 lang_idx = gst_asf_demux_get_uint16 (&data, &size);
2315 stream_num = gst_asf_demux_get_uint16 (&data, &size);
2316 name_len = gst_asf_demux_get_uint16 (&data, &size);
2317 data_type = gst_asf_demux_get_uint16 (&data, &size);
2318 data_len = gst_asf_demux_get_uint32 (&data, &size);
2320 if (size < name_len + data_len)
2321 goto not_enough_data;
2323 /* convert name to UTF-8 */
2324 name_utf8 = g_convert ((gchar *) data, name_len, "UTF-8", "UTF-16LE",
2325 NULL, NULL, NULL);
2326 gst_asf_demux_skip_bytes (name_len, &data, &size);
2328 if (name_utf8 == NULL) {
2329 GST_WARNING ("Failed to convert value name to UTF8, skipping");
2330 gst_asf_demux_skip_bytes (data_len, &data, &size);
2331 continue;
2332 }
2334 if (data_type != ASF_DEMUX_DATA_TYPE_DWORD) {
2335 gst_asf_demux_skip_bytes (data_len, &data, &size);
2336 g_free (name_utf8);
2337 continue;
2338 }
2340 /* read DWORD */
2341 if (size < 4) {
2342 g_free (name_utf8);
2343 goto not_enough_data;
2344 }
2346 ival = gst_asf_demux_get_uint32 (&data, &size);
2348 /* skip anything else there may be, just in case */
2349 gst_asf_demux_skip_bytes (data_len - 4, &data, &size);
2351 s = gst_asf_demux_get_metadata_for_stream (demux, stream_num);
2352 gst_structure_set (s, name_utf8, G_TYPE_INT, ival, NULL);
2353 g_free (name_utf8);
2354 }
2356 GST_INFO_OBJECT (demux, "metadata = %" GST_PTR_FORMAT, demux->metadata);
2357 return GST_FLOW_OK;
2359 /* Errors */
2360 not_enough_data:
2361 {
2362 GST_WARNING ("Unexpected end of data parsing metadata object");
2363 return GST_FLOW_OK; /* not really fatal */
2364 }
2365 }
2367 static GstFlowReturn
2368 gst_asf_demux_process_header (GstASFDemux * demux, guint8 * data, guint64 size)
2369 {
2370 GstFlowReturn ret = GST_FLOW_OK;
2371 guint32 i, num_objects;
2372 guint8 unknown;
2374 /* Get the rest of the header's header */
2375 if (size < (4 + 1 + 1))
2376 goto not_enough_data;
2378 num_objects = gst_asf_demux_get_uint32 (&data, &size);
2379 unknown = gst_asf_demux_get_uint8 (&data, &size);
2380 unknown = gst_asf_demux_get_uint8 (&data, &size);
2382 GST_INFO_OBJECT (demux, "object is a header with %u parts", num_objects);
2384 /* Loop through the header's objects, processing those */
2385 for (i = 0; i < num_objects; ++i) {
2386 GST_INFO_OBJECT (demux, "reading header part %u", i);
2387 ret = gst_asf_demux_process_object (demux, &data, &size);
2388 if (ret != GST_FLOW_OK) {
2389 GST_WARNING ("process_object returned %s", gst_asf_get_flow_name (ret));
2390 break;
2391 }
2392 }
2394 return ret;
2396 not_enough_data:
2397 {
2398 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
2399 ("short read parsing HEADER object"));
2400 return GST_FLOW_ERROR;
2401 }
2402 }
2404 static GstFlowReturn
2405 gst_asf_demux_process_file (GstASFDemux * demux, guint8 * data, guint64 size)
2406 {
2407 guint64 file_size, creation_time, packets_count;
2408 guint64 play_time, send_time, preroll;
2409 guint32 flags, min_pktsize, max_pktsize, min_bitrate;
2411 if (size < (16 + 8 + 8 + 8 + 8 + 8 + 8 + 4 + 4 + 4 + 4))
2412 goto not_enough_data;
2414 gst_asf_demux_skip_bytes (16, &data, &size); /* skip GUID */
2415 file_size = gst_asf_demux_get_uint64 (&data, &size);
2416 creation_time = gst_asf_demux_get_uint64 (&data, &size);
2417 packets_count = gst_asf_demux_get_uint64 (&data, &size);
2418 play_time = gst_asf_demux_get_uint64 (&data, &size);
2419 send_time = gst_asf_demux_get_uint64 (&data, &size);
2420 preroll = gst_asf_demux_get_uint64 (&data, &size);
2421 flags = gst_asf_demux_get_uint32 (&data, &size);
2422 min_pktsize = gst_asf_demux_get_uint32 (&data, &size);
2423 max_pktsize = gst_asf_demux_get_uint32 (&data, &size);
2424 min_bitrate = gst_asf_demux_get_uint32 (&data, &size);
2426 demux->broadcast = !!(flags & 0x01);
2427 demux->seekable = !!(flags & 0x02);
2429 GST_DEBUG_OBJECT (demux, "min_pktsize = %u", min_pktsize);
2430 GST_DEBUG_OBJECT (demux, "flags::broadcast = %d", demux->broadcast);
2431 GST_DEBUG_OBJECT (demux, "flags::seekable = %d", demux->seekable);
2433 if (demux->broadcast) {
2434 /* these fields are invalid if the broadcast flag is set */
2435 play_time = 0;
2436 file_size = 0;
2437 }
2439 if (min_pktsize != max_pktsize)
2440 goto non_fixed_packet_size;
2442 demux->packet_size = max_pktsize;
2444 /* FIXME: do we need send_time as well? what is it? */
2445 if ((play_time * 100) >= (preroll * GST_MSECOND))
2446 demux->play_time = (play_time * 100) - (preroll * GST_MSECOND);
2447 else
2448 demux->play_time = 0;
2450 demux->preroll = preroll * GST_MSECOND;
2452 /* initial latency */
2453 demux->latency = demux->preroll;
2455 if (demux->play_time == 0)
2456 demux->seekable = FALSE;
2458 GST_DEBUG_OBJECT (demux, "play_time %" GST_TIME_FORMAT,
2459 GST_TIME_ARGS (demux->play_time));
2460 GST_DEBUG_OBJECT (demux, "preroll %" GST_TIME_FORMAT,
2461 GST_TIME_ARGS (demux->preroll));
2463 if (demux->play_time > 0) {
2464 gst_segment_set_duration (&demux->segment, GST_FORMAT_TIME,
2465 demux->play_time);
2466 }
2468 GST_INFO ("object is a file with %" G_GUINT64_FORMAT " data packets",
2469 packets_count);
2470 GST_INFO ("preroll = %" G_GUINT64_FORMAT, demux->preroll);
2472 return GST_FLOW_OK;
2474 /* ERRORS */
2475 non_fixed_packet_size:
2476 {
2477 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
2478 ("packet size must be fixed"));
2479 return GST_FLOW_ERROR;
2480 }
2481 not_enough_data:
2482 {
2483 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
2484 ("short read parsing FILE object"));
2485 return GST_FLOW_ERROR;
2486 }
2487 }
2489 /* Content Description Object */
2490 static GstFlowReturn
2491 gst_asf_demux_process_comment (GstASFDemux * demux, guint8 * data, guint64 size)
2492 {
2493 struct
2494 {
2495 const gchar *gst_tag;
2496 guint16 val_length;
2497 gchar *val_utf8;
2498 } tags[5] = {
2499 {
2500 GST_TAG_TITLE, 0, NULL}, {
2501 GST_TAG_ARTIST, 0, NULL}, {
2502 GST_TAG_COPYRIGHT, 0, NULL}, {
2503 GST_TAG_DESCRIPTION, 0, NULL}, {
2504 GST_TAG_COMMENT, 0, NULL}
2505 };
2506 GstTagList *taglist;
2507 GValue value = { 0 };
2508 gsize in, out;
2509 gint i = -1;
2511 GST_INFO_OBJECT (demux, "object is a comment");
2513 if (size < (2 + 2 + 2 + 2 + 2))
2514 goto not_enough_data;
2516 tags[0].val_length = gst_asf_demux_get_uint16 (&data, &size);
2517 tags[1].val_length = gst_asf_demux_get_uint16 (&data, &size);
2518 tags[2].val_length = gst_asf_demux_get_uint16 (&data, &size);
2519 tags[3].val_length = gst_asf_demux_get_uint16 (&data, &size);
2520 tags[4].val_length = gst_asf_demux_get_uint16 (&data, &size);
2522 GST_DEBUG_OBJECT (demux, "Comment lengths: title=%d author=%d copyright=%d "
2523 "description=%d rating=%d", tags[0].val_length, tags[1].val_length,
2524 tags[2].val_length, tags[3].val_length, tags[4].val_length);
2526 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
2527 if (size < tags[i].val_length)
2528 goto not_enough_data;
2530 /* might be just '/0', '/0'... */
2531 if (tags[i].val_length > 2 && tags[i].val_length % 2 == 0) {
2532 /* convert to UTF-8 */
2533 tags[i].val_utf8 = g_convert ((gchar *) data, tags[i].val_length,
2534 "UTF-8", "UTF-16LE", &in, &out, NULL);
2535 }
2536 gst_asf_demux_skip_bytes (tags[i].val_length, &data, &size);
2537 }
2539 /* parse metadata into taglist */
2540 taglist = gst_tag_list_new ();
2541 g_value_init (&value, G_TYPE_STRING);
2542 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
2543 if (tags[i].val_utf8 && strlen (tags[i].val_utf8) > 0 && tags[i].gst_tag) {
2544 g_value_set_string (&value, tags[i].val_utf8);
2545 gst_tag_list_add_values (taglist, GST_TAG_MERGE_APPEND,
2546 tags[i].gst_tag, &value, NULL);
2547 }
2548 }
2549 g_value_unset (&value);
2551 if (gst_structure_n_fields (GST_STRUCTURE (taglist)) > 0) {
2552 gst_asf_demux_commit_taglist (demux, taglist);
2553 } else {
2554 gst_tag_list_free (taglist);
2555 }
2557 for (i = 0; i < G_N_ELEMENTS (tags); ++i)
2558 g_free (tags[i].val_utf8);
2560 return GST_FLOW_OK;
2562 not_enough_data:
2563 {
2564 GST_WARNING_OBJECT (demux, "unexpectedly short of data while processing "
2565 "comment tag section %d, skipping comment object", i);
2566 for (i = 0; i < G_N_ELEMENTS (tags); i++)
2567 g_free (tags[i].val_utf8);
2568 return GST_FLOW_OK; /* not really fatal */
2569 }
2570 }
2572 static GstFlowReturn
2573 gst_asf_demux_process_bitrate_props_object (GstASFDemux * demux, guint8 * data,
2574 guint64 size)
2575 {
2576 guint16 num_streams, i;
2578 if (size < 2)
2579 goto not_enough_data;
2581 num_streams = gst_asf_demux_get_uint16 (&data, &size);
2583 GST_INFO ("object is a bitrate properties object with %u streams",
2584 num_streams);
2586 if (size < (num_streams * (2 + 4)))
2587 goto not_enough_data;
2589 for (i = 0; i < num_streams; ++i) {
2590 guint32 bitrate;
2591 guint16 stream_id;
2593 stream_id = gst_asf_demux_get_uint16 (&data, &size);
2594 bitrate = gst_asf_demux_get_uint32 (&data, &size);
2596 if (stream_id < GST_ASF_DEMUX_NUM_STREAM_IDS) {
2597 demux->bitrate[stream_id] = bitrate;
2598 GST_DEBUG ("bitrate[%u] = %u", stream_id, bitrate);
2599 } else {
2600 GST_WARNING ("stream id %u is too large", stream_id);
2601 }
2602 }
2604 return GST_FLOW_OK;
2606 not_enough_data:
2607 {
2608 GST_WARNING_OBJECT (demux, "short read parsing bitrate props object!");
2609 return GST_FLOW_OK; /* not really fatal */
2610 }
2611 }
2613 static GstFlowReturn
2614 gst_asf_demux_process_header_ext (GstASFDemux * demux, guint8 * data,
2615 guint64 size)
2616 {
2617 GstFlowReturn ret = GST_FLOW_OK;
2618 guint64 hdr_size;
2620 /* Get the rest of the header's header */
2621 if (size < (16 + 2 + 4))
2622 goto not_enough_data;
2624 /* skip GUID and two other bytes */
2625 gst_asf_demux_skip_bytes (16 + 2, &data, &size);
2626 hdr_size = gst_asf_demux_get_uint32 (&data, &size);
2628 GST_INFO ("extended header object with a size of %u bytes", (guint) size);
2630 /* FIXME: does data_size include the rest of the header that we have read? */
2631 if (hdr_size > size)
2632 goto not_enough_data;
2634 while (hdr_size > 0) {
2635 ret = gst_asf_demux_process_object (demux, &data, &hdr_size);
2636 if (ret != GST_FLOW_OK)
2637 break;
2638 }
2640 return ret;
2642 not_enough_data:
2643 {
2644 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
2645 ("short read parsing extended header object"));
2646 return GST_FLOW_ERROR;
2647 }
2648 }
2650 static GstFlowReturn
2651 gst_asf_demux_process_language_list (GstASFDemux * demux, guint8 * data,
2652 guint64 size)
2653 {
2654 guint i;
2656 if (size < 2)
2657 goto not_enough_data;
2659 if (demux->languages) {
2660 GST_WARNING ("More than one LANGUAGE_LIST object in stream");
2661 g_strfreev (demux->languages);
2662 demux->languages = NULL;
2663 demux->num_languages = 0;
2664 }
2666 demux->num_languages = gst_asf_demux_get_uint16 (&data, &size);
2667 GST_LOG ("%u languages:", demux->num_languages);
2669 demux->languages = g_new0 (gchar *, demux->num_languages + 1);
2670 for (i = 0; i < demux->num_languages; ++i) {
2671 guint8 len, *lang_data = NULL;
2673 if (size < 1)
2674 goto not_enough_data;
2675 len = gst_asf_demux_get_uint8 (&data, &size);
2676 if (gst_asf_demux_get_bytes (&lang_data, len, &data, &size)) {
2677 gchar *utf8;
2679 utf8 = g_convert ((gchar *) lang_data, len, "UTF-8", "UTF-16LE", NULL,
2680 NULL, NULL);
2682 /* truncate "en-us" etc. to just "en" */
2683 if (utf8 && strlen (utf8) >= 5 && (utf8[2] == '-' || utf8[2] == '_')) {
2684 utf8[2] = '\0';
2685 }
2686 GST_DEBUG ("[%u] %s", i, GST_STR_NULL (utf8));
2687 demux->languages[i] = utf8;
2688 g_free (lang_data);
2689 } else {
2690 goto not_enough_data;
2691 }
2692 }
2694 return GST_FLOW_OK;
2696 not_enough_data:
2697 {
2698 GST_WARNING_OBJECT (demux, "short read parsing language list object!");
2699 g_free (demux->languages);
2700 demux->languages = NULL;
2701 return GST_FLOW_OK; /* not fatal */
2702 }
2703 }
2705 static GstFlowReturn
2706 gst_asf_demux_process_simple_index (GstASFDemux * demux, guint8 * data,
2707 guint64 size)
2708 {
2709 GstClockTime interval;
2710 guint32 x, count, i;
2712 if (size < (16 + 8 + 4 + 4))
2713 goto not_enough_data;
2715 /* skip file id */
2716 gst_asf_demux_skip_bytes (16, &data, &size);
2717 interval = gst_asf_demux_get_uint64 (&data, &size) * (GstClockTime) 100;
2718 x = gst_asf_demux_get_uint32 (&data, &size);
2719 count = gst_asf_demux_get_uint32 (&data, &size);
2720 if (count > 0) {
2721 demux->sidx_interval = interval;
2722 demux->sidx_num_entries = count;
2723 g_free (demux->sidx_entries);
2724 demux->sidx_entries = g_new0 (guint32, count);
2726 for (i = 0; i < count && size > (4 + 2); ++i) {
2727 demux->sidx_entries[i] = gst_asf_demux_get_uint32 (&data, &size);
2728 x = (guint32) gst_asf_demux_get_uint16 (&data, &size);
2729 GST_LOG_OBJECT (demux, "%" GST_TIME_FORMAT " = packet %4u",
2730 GST_TIME_ARGS (i * interval), demux->sidx_entries[i]);
2731 }
2732 } else {
2733 GST_DEBUG_OBJECT (demux, "simple index object with 0 entries");
2734 }
2736 return GST_FLOW_OK;
2738 not_enough_data:
2739 {
2740 GST_WARNING_OBJECT (demux, "short read parsing simple index object!");
2741 return GST_FLOW_OK; /* not fatal */
2742 }
2743 }
2745 static GstFlowReturn
2746 gst_asf_demux_process_advanced_mutual_exclusion (GstASFDemux * demux,
2747 guint8 * data, guint64 size)
2748 {
2749 ASFGuid guid;
2750 guint16 num, i;
2751 guint8 *mes;
2753 if (size < 16 + 2 + (2 * 2))
2754 goto not_enough_data;
2756 gst_asf_demux_get_guid (&guid, &data, &size);
2757 num = gst_asf_demux_get_uint16 (&data, &size);
2759 if (num < 2) {
2760 GST_WARNING_OBJECT (demux, "nonsensical mutually exclusive streams count");
2761 return GST_FLOW_OK;
2762 }
2764 if (size < (num * sizeof (guint16)))
2765 goto not_enough_data;
2767 /* read mutually exclusive stream numbers */
2768 mes = g_new (guint8, num + 1);
2769 for (i = 0; i < num; ++i) {
2770 mes[i] = gst_asf_demux_get_uint16 (&data, &size) & 0x7f;
2771 GST_LOG_OBJECT (demux, "mutually exclusive: stream #%d", mes[i]);
2772 }
2774 /* add terminator so we can easily get the count or know when to stop */
2775 mes[i] = (guint8) - 1;
2777 demux->mut_ex_streams = g_slist_append (demux->mut_ex_streams, mes);
2779 return GST_FLOW_OK;
2781 /* Errors */
2782 not_enough_data:
2783 {
2784 GST_WARNING_OBJECT (demux, "short read parsing advanced mutual exclusion");
2785 return GST_FLOW_OK; /* not absolutely fatal */
2786 }
2787 }
2789 static GstFlowReturn
2790 gst_asf_demux_process_ext_stream_props (GstASFDemux * demux, guint8 * data,
2791 guint64 size)
2792 {
2793 AsfStreamExtProps esp;
2794 AsfStream *stream = NULL;
2795 AsfObject stream_obj;
2796 guint16 stream_name_count;
2797 guint16 num_payload_ext;
2798 guint64 len;
2799 guint8 *stream_obj_data = NULL;
2800 guint8 *data_start;
2801 guint obj_size;
2802 guint i, stream_num;
2804 data_start = data;
2805 obj_size = (guint) size;
2807 if (size < 64)
2808 goto not_enough_data;
2810 esp.valid = TRUE;
2811 esp.start_time = gst_asf_demux_get_uint64 (&data, &size) * GST_MSECOND;
2812 esp.end_time = gst_asf_demux_get_uint64 (&data, &size) * GST_MSECOND;
2813 esp.data_bitrate = gst_asf_demux_get_uint32 (&data, &size);
2814 esp.buffer_size = gst_asf_demux_get_uint32 (&data, &size);
2815 esp.intial_buf_fullness = gst_asf_demux_get_uint32 (&data, &size);
2816 esp.data_bitrate2 = gst_asf_demux_get_uint32 (&data, &size);
2817 esp.buffer_size2 = gst_asf_demux_get_uint32 (&data, &size);
2818 esp.intial_buf_fullness2 = gst_asf_demux_get_uint32 (&data, &size);
2819 esp.max_obj_size = gst_asf_demux_get_uint32 (&data, &size);
2820 esp.flags = gst_asf_demux_get_uint32 (&data, &size);
2821 stream_num = gst_asf_demux_get_uint16 (&data, &size);
2822 esp.lang_idx = gst_asf_demux_get_uint16 (&data, &size);
2823 esp.avg_time_per_frame = gst_asf_demux_get_uint64 (&data, &size);
2824 stream_name_count = gst_asf_demux_get_uint16 (&data, &size);
2825 num_payload_ext = gst_asf_demux_get_uint16 (&data, &size);
2827 GST_INFO ("start_time = %" GST_TIME_FORMAT,
2828 GST_TIME_ARGS (esp.start_time));
2829 GST_INFO ("end_time = %" GST_TIME_FORMAT,
2830 GST_TIME_ARGS (esp.end_time));
2831 GST_INFO ("flags = %08x", esp.flags);
2832 GST_INFO ("average time per frame = %" GST_TIME_FORMAT,
2833 GST_TIME_ARGS (esp.avg_time_per_frame * 100));
2834 GST_INFO ("stream number = %u", stream_num);
2835 GST_INFO ("stream language ID idx = %u (%s)", esp.lang_idx,
2836 (esp.lang_idx < demux->num_languages) ?
2837 GST_STR_NULL (demux->languages[esp.lang_idx]) : "??");
2838 GST_INFO ("stream name count = %u", stream_name_count);
2840 /* read stream names */
2841 for (i = 0; i < stream_name_count; ++i) {
2842 guint16 stream_lang_idx;
2843 gchar *stream_name = NULL;
2845 if (size < 2)
2846 goto not_enough_data;
2847 stream_lang_idx = gst_asf_demux_get_uint16 (&data, &size);
2848 if (!gst_asf_demux_get_string (&stream_name, NULL, &data, &size))
2849 goto not_enough_data;
2850 GST_INFO ("stream name %d: %s", i, GST_STR_NULL (stream_name));
2851 g_free (stream_name); /* TODO: store names in struct */
2852 }
2854 /* read payload extension systems stuff */
2855 GST_LOG ("payload extension systems count = %u", num_payload_ext);
2857 if (num_payload_ext > 0)
2858 esp.payload_extensions = g_new0 (AsfPayloadExtension, num_payload_ext + 1);
2859 else
2860 esp.payload_extensions = NULL;
2862 for (i = 0; i < num_payload_ext; ++i) {
2863 AsfPayloadExtension ext;
2864 ASFGuid ext_guid;
2865 guint32 sys_info_len;
2867 if (size < 16 + 2 + 4)
2868 goto not_enough_data;
2870 gst_asf_demux_get_guid (&ext_guid, &data, &size);
2871 ext.id = gst_asf_demux_identify_guid (asf_payload_ext_guids, &ext_guid);
2872 ext.len = gst_asf_demux_get_uint16 (&data, &size);
2874 sys_info_len = gst_asf_demux_get_uint32 (&data, &size);
2875 GST_LOG ("payload systems info len = %u", sys_info_len);
2876 if (!gst_asf_demux_skip_bytes (sys_info_len, &data, &size))
2877 goto not_enough_data;
2879 esp.payload_extensions[i] = ext;
2880 }
2882 GST_LOG ("bytes read: %u/%u", (guint) (data - data_start), obj_size);
2884 /* there might be an optional STREAM_INFO object here now; if not, we
2885 * should have parsed the corresponding stream info object already (since
2886 * we are parsing the extended stream properties objects delayed) */
2887 if (size == 0) {
2888 stream = gst_asf_demux_get_stream (demux, stream_num);
2889 goto done;
2890 }
2892 /* get size of the stream object */
2893 if (!asf_demux_peek_object (demux, data, size, &stream_obj))
2894 goto not_enough_data;
2896 if (stream_obj.id != ASF_OBJ_STREAM)
2897 goto expected_stream_object;
2899 if (stream_obj.size < ASF_OBJECT_HEADER_SIZE ||
2900 stream_obj.size > (10 * 1024 * 1024))
2901 goto not_enough_data;
2903 gst_asf_demux_skip_bytes (ASF_OBJECT_HEADER_SIZE, &data, &size);
2905 /* process this stream object later after all the other 'normal' ones
2906 * have been processed (since the others are more important/non-hidden) */
2907 len = stream_obj.size - ASF_OBJECT_HEADER_SIZE;
2908 if (!gst_asf_demux_get_bytes (&stream_obj_data, len, &data, &size))
2909 goto not_enough_data;
2911 /* parse stream object */
2912 stream = gst_asf_demux_parse_stream_object (demux, stream_obj_data, len);
2913 g_free (stream_obj_data);
2915 done:
2917 if (stream) {
2918 stream->ext_props = esp;
2920 /* try to set the framerate */
2921 if (stream->is_video && stream->caps) {
2922 GValue framerate = { 0 };
2923 GstStructure *s;
2924 gint num, denom;
2926 g_value_init (&framerate, GST_TYPE_FRACTION);
2928 num = GST_SECOND / 100;
2929 denom = esp.avg_time_per_frame;
2930 if (denom == 0) {
2931 /* avoid division by 0, assume 25/1 framerate */
2932 denom = GST_SECOND / 2500;
2933 }
2935 gst_value_set_fraction (&framerate, num, denom);
2937 stream->caps = gst_caps_make_writable (stream->caps);
2938 s = gst_caps_get_structure (stream->caps, 0);
2939 gst_structure_set_value (s, "framerate", &framerate);
2940 g_value_unset (&framerate);
2941 GST_DEBUG_OBJECT (demux, "setting framerate of %d/%d = %f",
2942 num, denom, ((gdouble) num) / denom);
2943 }
2945 /* add language info now if we have it */
2946 if (stream->ext_props.lang_idx < demux->num_languages) {
2947 if (stream->pending_tags == NULL)
2948 stream->pending_tags = gst_tag_list_new ();
2949 GST_LOG_OBJECT (demux, "stream %u has language '%s'", stream->id,
2950 demux->languages[stream->ext_props.lang_idx]);
2951 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_APPEND,
2952 GST_TAG_LANGUAGE_CODE, demux->languages[stream->ext_props.lang_idx],
2953 NULL);
2954 }
2955 } else {
2956 GST_WARNING_OBJECT (demux, "Ext. stream properties for unknown stream");
2957 }
2959 return GST_FLOW_OK;
2961 /* Errors */
2962 not_enough_data:
2963 {
2964 GST_WARNING_OBJECT (demux, "short read parsing ext stream props object!");
2965 return GST_FLOW_OK; /* not absolutely fatal */
2966 }
2967 expected_stream_object:
2968 {
2969 GST_WARNING_OBJECT (demux, "error parsing extended stream properties "
2970 "object: expected embedded stream object, but got %s object instead!",
2971 gst_asf_get_guid_nick (asf_object_guids, stream_obj.id));
2972 return GST_FLOW_OK; /* not absolutely fatal */
2973 }
2974 }
2976 static const gchar *
2977 gst_asf_demux_push_obj (GstASFDemux * demux, guint32 obj_id)
2978 {
2979 const gchar *nick;
2981 nick = gst_asf_get_guid_nick (asf_object_guids, obj_id);
2982 if (g_str_has_prefix (nick, "ASF_OBJ_"))
2983 nick += strlen ("ASF_OBJ_");
2985 if (demux->objpath == NULL) {
2986 demux->objpath = g_strdup (nick);
2987 } else {
2988 gchar *newpath;
2990 newpath = g_strdup_printf ("%s/%s", demux->objpath, nick);
2991 g_free (demux->objpath);
2992 demux->objpath = newpath;
2993 }
2995 return (const gchar *) demux->objpath;
2996 }
2998 static void
2999 gst_asf_demux_pop_obj (GstASFDemux * demux)
3000 {
3001 gchar *s;
3003 if ((s = g_strrstr (demux->objpath, "/"))) {
3004 *s = '\0';
3005 } else {
3006 g_free (demux->objpath);
3007 demux->objpath = NULL;
3008 }
3009 }
3011 static void
3012 gst_asf_demux_process_queued_extended_stream_objects (GstASFDemux * demux)
3013 {
3014 GSList *l;
3015 guint i;
3017 /* Parse the queued extended stream property objects and add the info
3018 * to the existing streams or add the new embedded streams, but without
3019 * activating them yet */
3020 GST_LOG_OBJECT (demux, "%u queued extended stream properties objects",
3021 g_slist_length (demux->ext_stream_props));
3023 for (l = demux->ext_stream_props, i = 0; l != NULL; l = l->next, ++i) {
3024 GstBuffer *buf = GST_BUFFER (l->data);
3026 GST_LOG_OBJECT (demux, "parsing ext. stream properties object #%u", i);
3027 gst_asf_demux_process_ext_stream_props (demux, GST_BUFFER_DATA (buf),
3028 GST_BUFFER_SIZE (buf));
3029 gst_buffer_unref (buf);
3030 }
3031 g_slist_free (demux->ext_stream_props);
3032 demux->ext_stream_props = NULL;
3033 }
3035 #if 0
3036 static void
3037 gst_asf_demux_activate_ext_props_streams (GstASFDemux * demux)
3038 {
3039 guint i, j;
3041 for (i = 0; i < demux->num_streams; ++i) {
3042 AsfStream *stream;
3043 gboolean is_hidden;
3044 GSList *x;
3046 stream = &demux->stream[i];
3048 GST_LOG_OBJECT (demux, "checking stream %2u", stream->id);
3050 if (stream->active) {
3051 GST_LOG_OBJECT (demux, "stream %2u is already activated", stream->id);
3052 continue;
3053 }
3055 is_hidden = FALSE;
3056 for (x = demux->mut_ex_streams; x != NULL; x = x->next) {
3057 guint8 *mes;
3059 /* check for each mutual exclusion whether it affects this stream */
3060 for (mes = (guint8 *) x->data; mes != NULL && *mes != 0xff; ++mes) {
3061 if (*mes == stream->id) {
3062 /* if yes, check if we've already added streams that are mutually
3063 * exclusive with the stream we're about to add */
3064 for (mes = (guint8 *) x->data; mes != NULL && *mes != 0xff; ++mes) {
3065 for (j = 0; j < demux->num_streams; ++j) {
3066 /* if the broadcast flag is set, assume the hidden streams aren't
3067 * actually streamed and hide them (or playbin won't work right),
3068 * otherwise assume their data is available */
3069 if (demux->stream[j].id == *mes && demux->broadcast) {
3070 is_hidden = TRUE;
3071 GST_LOG_OBJECT (demux, "broadcast stream ID %d to be added is "
3072 "mutually exclusive with already existing stream ID %d, "
3073 "hiding stream", stream->id, demux->stream[j].id);
3074 goto next;
3075 }
3076 }
3077 }
3078 break;
3079 }
3080 }
3081 }
3083 next:
3085 /* FIXME: we should do stream activation based on preroll data in
3086 * streaming mode too */
3087 if (demux->streaming && !is_hidden)
3088 gst_asf_demux_activate_stream (demux, stream);
3089 }
3090 }
3091 #endif
3093 static GstFlowReturn
3094 gst_asf_demux_process_object (GstASFDemux * demux, guint8 ** p_data,
3095 guint64 * p_size)
3096 {
3097 GstFlowReturn ret = GST_FLOW_OK;
3098 AsfObject obj;
3099 guint64 obj_data_size;
3101 if (*p_size < ASF_OBJECT_HEADER_SIZE)
3102 return ASF_FLOW_NEED_MORE_DATA;
3104 asf_demux_peek_object (demux, *p_data, ASF_OBJECT_HEADER_SIZE, &obj);
3105 gst_asf_demux_skip_bytes (ASF_OBJECT_HEADER_SIZE, p_data, p_size);
3107 obj_data_size = obj.size - ASF_OBJECT_HEADER_SIZE;
3109 if (*p_size < obj_data_size)
3110 return ASF_FLOW_NEED_MORE_DATA;
3112 gst_asf_demux_push_obj (demux, obj.id);
3114 GST_INFO ("%s: size %" G_GUINT64_FORMAT, demux->objpath, obj.size);
3116 switch (obj.id) {
3117 case ASF_OBJ_STREAM:{
3118 AsfStream *stream;
3120 stream =
3121 gst_asf_demux_parse_stream_object (demux, *p_data, obj_data_size);
3123 ret = GST_FLOW_OK;
3124 break;
3125 }
3126 case ASF_OBJ_FILE:
3127 ret = gst_asf_demux_process_file (demux, *p_data, obj_data_size);
3128 break;
3129 case ASF_OBJ_HEADER:
3130 ret = gst_asf_demux_process_header (demux, *p_data, obj_data_size);
3131 break;
3132 case ASF_OBJ_COMMENT:
3133 ret = gst_asf_demux_process_comment (demux, *p_data, obj_data_size);
3134 break;
3135 case ASF_OBJ_HEAD1:
3136 ret = gst_asf_demux_process_header_ext (demux, *p_data, obj_data_size);
3137 break;
3138 case ASF_OBJ_BITRATE_PROPS:
3139 ret =
3140 gst_asf_demux_process_bitrate_props_object (demux, *p_data,
3141 obj_data_size);
3142 break;
3143 case ASF_OBJ_EXT_CONTENT_DESC:
3144 ret =
3145 gst_asf_demux_process_ext_content_desc (demux, *p_data,
3146 obj_data_size);
3147 break;
3148 case ASF_OBJ_METADATA_OBJECT:
3149 ret = gst_asf_demux_process_metadata (demux, *p_data, obj_data_size);
3150 break;
3151 case ASF_OBJ_EXTENDED_STREAM_PROPS:{
3152 GstBuffer *buf;
3154 /* process these later, we might not have parsed the corresponding
3155 * stream object yet */
3156 GST_LOG ("%s: queued for later parsing", demux->objpath);
3157 buf = gst_buffer_new_and_alloc (obj_data_size);
3158 memcpy (GST_BUFFER_DATA (buf), *p_data, obj_data_size);
3159 demux->ext_stream_props = g_slist_append (demux->ext_stream_props, buf);
3160 ret = GST_FLOW_OK;
3161 break;
3162 }
3163 case ASF_OBJ_LANGUAGE_LIST:
3164 ret = gst_asf_demux_process_language_list (demux, *p_data, obj_data_size);
3165 break;
3166 case ASF_OBJ_ADVANCED_MUTUAL_EXCLUSION:
3167 ret = gst_asf_demux_process_advanced_mutual_exclusion (demux, *p_data,
3168 obj_data_size);
3169 break;
3170 case ASF_OBJ_SIMPLE_INDEX:
3171 ret = gst_asf_demux_process_simple_index (demux, *p_data, obj_data_size);
3172 break;
3173 case ASF_OBJ_CONTENT_ENCRYPTION:
3174 case ASF_OBJ_EXT_CONTENT_ENCRYPTION:
3175 case ASF_OBJ_DIGITAL_SIGNATURE_OBJECT:
3176 goto error_encrypted;
3177 case ASF_OBJ_CONCEAL_NONE:
3178 case ASF_OBJ_HEAD2:
3179 case ASF_OBJ_UNDEFINED:
3180 case ASF_OBJ_CODEC_COMMENT:
3181 case ASF_OBJ_INDEX:
3182 case ASF_OBJ_PADDING:
3183 case ASF_OBJ_BITRATE_MUTEX:
3184 case ASF_OBJ_COMPATIBILITY:
3185 case ASF_OBJ_INDEX_PLACEHOLDER:
3186 case ASF_OBJ_INDEX_PARAMETERS:
3187 case ASF_OBJ_STREAM_PRIORITIZATION:
3188 case ASF_OBJ_SCRIPT_COMMAND:
3189 default:
3190 /* Unknown/unhandled object, skip it and hope for the best */
3191 GST_INFO ("%s: skipping object", demux->objpath);
3192 ret = GST_FLOW_OK;
3193 break;
3194 }
3196 /* this can't fail, we checked the number of bytes available before */
3197 gst_asf_demux_skip_bytes (obj_data_size, p_data, p_size);
3199 GST_LOG ("%s: ret = %s", demux->objpath, gst_asf_get_flow_name (ret));
3201 gst_asf_demux_pop_obj (demux);
3203 return ret;
3205 /* ERRORS */
3206 error_encrypted:
3207 {
3208 GST_ELEMENT_ERROR (demux, STREAM, DECRYPT, (NULL), (NULL));
3209 return GST_FLOW_ERROR;
3210 }
3211 }
3213 static void
3214 gst_asf_demux_descramble_buffer (GstASFDemux * demux, AsfStream * stream,
3215 GstBuffer ** p_buffer)
3216 {
3217 GstBuffer *descrambled_buffer;
3218 GstBuffer *scrambled_buffer;
3219 GstBuffer *sub_buffer;
3220 guint offset;
3221 guint off;
3222 guint row;
3223 guint col;
3224 guint idx;
3226 /* descrambled_buffer is initialised in the first iteration */
3227 descrambled_buffer = NULL;
3228 scrambled_buffer = *p_buffer;
3230 if (GST_BUFFER_SIZE (scrambled_buffer) < demux->ds_packet_size * demux->span)
3231 return;
3233 for (offset = 0; offset < GST_BUFFER_SIZE (scrambled_buffer);
3234 offset += demux->ds_chunk_size) {
3235 off = offset / demux->ds_chunk_size;
3236 row = off / demux->span;
3237 col = off % demux->span;
3238 idx = row + col * demux->ds_packet_size / demux->ds_chunk_size;
3239 GST_DEBUG ("idx=%u, row=%u, col=%u, off=%u, ds_chunk_size=%u", idx, row,
3240 col, off, demux->ds_chunk_size);
3241 GST_DEBUG ("scrambled buffer size=%u, span=%u, packet_size=%u",
3242 GST_BUFFER_SIZE (scrambled_buffer), demux->span, demux->ds_packet_size);
3243 GST_DEBUG ("GST_BUFFER_SIZE (scrambled_buffer) = %u",
3244 GST_BUFFER_SIZE (scrambled_buffer));
3245 sub_buffer =
3246 gst_buffer_create_sub (scrambled_buffer, idx * demux->ds_chunk_size,
3247 demux->ds_chunk_size);
3248 if (!offset) {
3249 descrambled_buffer = sub_buffer;
3250 } else {
3251 descrambled_buffer = gst_buffer_join (descrambled_buffer, sub_buffer);
3252 }
3253 }
3255 gst_buffer_copy_metadata (descrambled_buffer, scrambled_buffer,
3256 GST_BUFFER_COPY_TIMESTAMPS);
3258 /* FIXME/CHECK: do we need to transfer buffer flags here too? */
3260 gst_buffer_unref (scrambled_buffer);
3261 *p_buffer = descrambled_buffer;
3262 }
3264 static gboolean
3265 gst_asf_demux_element_send_event (GstElement * element, GstEvent * event)
3266 {
3267 GstASFDemux *demux = GST_ASF_DEMUX (element);
3268 gint i;
3270 GST_DEBUG ("handling element event of type %s", GST_EVENT_TYPE_NAME (event));
3272 for (i = 0; i < demux->num_streams; ++i) {
3273 gst_event_ref (event);
3274 if (gst_asf_demux_handle_src_event (demux->stream[i].pad, event)) {
3275 gst_event_unref (event);
3276 return TRUE;
3277 }
3278 }
3280 gst_event_unref (event);
3281 return FALSE;
3282 }
3284 /* takes ownership of the passed event */
3285 static gboolean
3286 gst_asf_demux_send_event_unlocked (GstASFDemux * demux, GstEvent * event)
3287 {
3288 gboolean ret = TRUE;
3289 gint i;
3291 GST_DEBUG_OBJECT (demux, "sending %s event to all source pads",
3292 GST_EVENT_TYPE_NAME (event));
3294 for (i = 0; i < demux->num_streams; ++i) {
3295 gst_event_ref (event);
3296 ret &= gst_pad_push_event (demux->stream[i].pad, event);
3297 }
3298 gst_event_unref (event);
3299 return ret;
3300 }
3302 static const GstQueryType *
3303 gst_asf_demux_get_src_query_types (GstPad * pad)
3304 {
3305 static const GstQueryType types[] = {
3306 GST_QUERY_POSITION,
3307 GST_QUERY_DURATION,
3308 GST_QUERY_SEEKING,
3309 0
3310 };
3312 return types;
3313 }
3315 static gboolean
3316 gst_asf_demux_handle_src_query (GstPad * pad, GstQuery * query)
3317 {
3318 GstASFDemux *demux;
3319 gboolean res = FALSE;
3321 demux = GST_ASF_DEMUX (gst_pad_get_parent (pad));
3323 GST_DEBUG ("handling %s query",
3324 gst_query_type_get_name (GST_QUERY_TYPE (query)));
3326 switch (GST_QUERY_TYPE (query)) {
3327 case GST_QUERY_DURATION:
3328 {
3329 GstFormat format;
3331 gst_query_parse_duration (query, &format, NULL);
3333 if (format != GST_FORMAT_TIME) {
3334 GST_LOG ("only support duration queries in TIME format");
3335 break;
3336 }
3338 GST_OBJECT_LOCK (demux);
3340 if (demux->segment.duration != GST_CLOCK_TIME_NONE) {
3341 GST_LOG ("returning duration: %" GST_TIME_FORMAT,
3342 GST_TIME_ARGS (demux->segment.duration));
3344 gst_query_set_duration (query, GST_FORMAT_TIME,
3345 demux->segment.duration);
3347 res = TRUE;
3348 } else {
3349 GST_LOG ("duration not known yet");
3350 }
3352 GST_OBJECT_UNLOCK (demux);
3353 break;
3354 }
3356 case GST_QUERY_POSITION:{
3357 GstFormat format;
3359 gst_query_parse_position (query, &format, NULL);
3361 if (format != GST_FORMAT_TIME) {
3362 GST_LOG ("only support position queries in TIME format");
3363 break;
3364 }
3366 GST_OBJECT_LOCK (demux);
3368 if (demux->segment.last_stop != GST_CLOCK_TIME_NONE) {
3369 GST_LOG ("returning position: %" GST_TIME_FORMAT,
3370 GST_TIME_ARGS (demux->segment.last_stop));
3372 gst_query_set_position (query, GST_FORMAT_TIME,
3373 demux->segment.last_stop);
3375 res = TRUE;
3376 } else {
3377 GST_LOG ("position not known yet");
3378 }
3380 GST_OBJECT_UNLOCK (demux);
3381 break;
3382 }
3384 case GST_QUERY_SEEKING:{
3385 GstFormat format;
3387 gst_query_parse_seeking (query, &format, NULL, NULL, NULL);
3388 if (format == GST_FORMAT_TIME) {
3389 gint64 duration;
3391 GST_OBJECT_LOCK (demux);
3392 duration = demux->segment.duration;
3393 GST_OBJECT_UNLOCK (demux);
3395 if (!demux->streaming || !demux->seekable) {
3396 gst_query_set_seeking (query, GST_FORMAT_TIME, demux->seekable, 0,
3397 duration);
3398 res = TRUE;
3399 } else {
3400 GstFormat fmt;
3401 gboolean seekable;
3403 /* try downstream first in TIME */
3404 res = gst_pad_query_default (pad, query);
3406 gst_query_parse_seeking (query, &fmt, &seekable, NULL, NULL);
3407 GST_LOG_OBJECT (demux, "upstream %s seekable %d",
3408 GST_STR_NULL (gst_format_get_name (fmt)), seekable);
3409 /* if no luck, maybe in BYTES */
3410 if (!seekable || fmt != GST_FORMAT_TIME) {
3411 GstQuery *q;
3413 q = gst_query_new_seeking (GST_FORMAT_BYTES);
3414 if ((res = gst_pad_peer_query (demux->sinkpad, q))) {
3415 gst_query_parse_seeking (q, &fmt, &seekable, NULL, NULL);
3416 GST_LOG_OBJECT (demux, "upstream %s seekable %d",
3417 GST_STR_NULL (gst_format_get_name (fmt)), seekable);
3418 if (fmt != GST_FORMAT_BYTES)
3419 seekable = FALSE;
3420 }
3421 gst_query_unref (q);
3422 gst_query_set_seeking (query, GST_FORMAT_TIME, seekable, 0,
3423 duration);
3424 res = TRUE;
3425 }
3426 }
3427 } else
3428 GST_LOG_OBJECT (demux, "only support seeking in TIME format");
3429 break;
3430 }
3432 default:
3433 res = gst_pad_query_default (pad, query);
3434 break;
3435 }
3437 gst_object_unref (demux);
3438 return res;
3439 }
3441 static GstStateChangeReturn
3442 gst_asf_demux_change_state (GstElement * element, GstStateChange transition)
3443 {
3444 GstASFDemux *demux = GST_ASF_DEMUX (element);
3445 GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
3447 switch (transition) {
3448 case GST_STATE_CHANGE_NULL_TO_READY:{
3449 gst_segment_init (&demux->segment, GST_FORMAT_TIME);
3450 demux->need_newsegment = TRUE;
3451 demux->segment_running = FALSE;
3452 demux->adapter = gst_adapter_new ();
3453 demux->metadata = gst_caps_new_empty ();
3454 demux->data_size = 0;
3455 demux->data_offset = 0;
3456 demux->index_offset = 0;
3457 break;
3458 }
3459 default:
3460 break;
3461 }
3463 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
3464 if (ret == GST_STATE_CHANGE_FAILURE)
3465 return ret;
3467 switch (transition) {
3468 case GST_STATE_CHANGE_PAUSED_TO_READY:
3469 case GST_STATE_CHANGE_READY_TO_NULL:
3470 gst_asf_demux_reset (demux);
3471 break;
3472 default:
3473 break;
3474 }
3476 return ret;
3477 }