1 /* GStreamer ASF/WMV/WMA demuxer
2 * Copyright (C) 1999 Erik Walthinsen <omega@cse.ogi.edu>
3 * Copyright (C) 2006-2009 Tim-Philipp Müller <tim centricular net>
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
14 *
15 * You should have received a copy of the GNU Library General Public
16 * License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 * Boston, MA 02111-1307, USA.
19 */
21 /* TODO:
22 *
23 * - _loop():
24 * stop if at end of segment if != end of file, ie. demux->segment.stop
25 *
26 * - fix packet parsing:
27 * there's something wrong with timestamps for packets with keyframes,
28 * and durations too.
29 */
31 #ifdef HAVE_CONFIG_H
32 #include "config.h"
33 #endif
35 /* FIXME 0.11: suppress warnings for deprecated API such as GStaticRecMutex
36 * with newer GLib versions (>= 2.31.0) */
37 #define GLIB_DISABLE_DEPRECATION_WARNINGS
39 #include <gst/gstutils.h>
40 #include <gst/base/gstbytereader.h>
41 #include <gst/riff/riff-media.h>
42 #include <gst/tag/tag.h>
43 #include <gst/gst-i18n-plugin.h>
44 #include <stdio.h>
45 #include <stdlib.h>
46 #include <string.h>
48 #include "gstasfdemux.h"
49 #include "asfheaders.h"
50 #include "asfpacket.h"
52 static GstStaticPadTemplate gst_asf_demux_sink_template =
53 GST_STATIC_PAD_TEMPLATE ("sink",
54 GST_PAD_SINK,
55 GST_PAD_ALWAYS,
56 GST_STATIC_CAPS ("video/x-ms-asf")
57 );
59 static GstStaticPadTemplate audio_src_template =
60 GST_STATIC_PAD_TEMPLATE ("audio_%02d",
61 GST_PAD_SRC,
62 GST_PAD_SOMETIMES,
63 GST_STATIC_CAPS_ANY);
65 static GstStaticPadTemplate video_src_template =
66 GST_STATIC_PAD_TEMPLATE ("video_%02d",
67 GST_PAD_SRC,
68 GST_PAD_SOMETIMES,
69 GST_STATIC_CAPS_ANY);
71 /* size of an ASF object header, ie. GUID (16 bytes) + object size (8 bytes) */
72 #define ASF_OBJECT_HEADER_SIZE (16+8)
74 /* FIXME: get rid of this */
75 /* abuse this GstFlowReturn enum for internal usage */
76 #define ASF_FLOW_NEED_MORE_DATA 99
78 #define gst_asf_get_flow_name(flow) \
79 (flow == ASF_FLOW_NEED_MORE_DATA) ? \
80 "need-more-data" : gst_flow_get_name (flow)
82 GST_DEBUG_CATEGORY (asfdemux_dbg);
84 static GstStateChangeReturn gst_asf_demux_change_state (GstElement * element,
85 GstStateChange transition);
86 static gboolean gst_asf_demux_element_send_event (GstElement * element,
87 GstEvent * event);
88 static gboolean gst_asf_demux_send_event_unlocked (GstASFDemux * demux,
89 GstEvent * event);
90 static gboolean gst_asf_demux_handle_src_query (GstPad * pad, GstQuery * query);
91 static const GstQueryType *gst_asf_demux_get_src_query_types (GstPad * pad);
92 static GstFlowReturn gst_asf_demux_chain (GstPad * pad, GstBuffer * buf);
93 static gboolean gst_asf_demux_sink_event (GstPad * pad, GstEvent * event);
94 static GstFlowReturn gst_asf_demux_process_object (GstASFDemux * demux,
95 guint8 ** p_data, guint64 * p_size);
96 static gboolean gst_asf_demux_activate (GstPad * sinkpad);
97 static gboolean gst_asf_demux_activate_push (GstPad * sinkpad, gboolean active);
98 static gboolean gst_asf_demux_activate_pull (GstPad * sinkpad, gboolean active);
99 static void gst_asf_demux_loop (GstASFDemux * demux);
100 static void
101 gst_asf_demux_process_queued_extended_stream_objects (GstASFDemux * demux);
102 static gboolean gst_asf_demux_pull_headers (GstASFDemux * demux);
103 static void gst_asf_demux_pull_indices (GstASFDemux * demux);
104 static void gst_asf_demux_reset_stream_state_after_discont (GstASFDemux * asf);
105 static gboolean
106 gst_asf_demux_parse_data_object_start (GstASFDemux * demux, guint8 * data);
107 static void gst_asf_demux_descramble_buffer (GstASFDemux * demux,
108 AsfStream * stream, GstBuffer ** p_buffer);
109 static void gst_asf_demux_activate_stream (GstASFDemux * demux,
110 AsfStream * stream);
111 static GstStructure *gst_asf_demux_get_metadata_for_stream (GstASFDemux * d,
112 guint stream_num);
113 static GstFlowReturn gst_asf_demux_push_complete_payloads (GstASFDemux * demux,
114 gboolean force);
116 GST_BOILERPLATE (GstASFDemux, gst_asf_demux, GstElement, GST_TYPE_ELEMENT);
118 static void
119 gst_asf_demux_base_init (gpointer g_class)
120 {
121 GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
123 gst_element_class_add_static_pad_template (element_class,
124 &audio_src_template);
125 gst_element_class_add_static_pad_template (element_class,
126 &video_src_template);
127 gst_element_class_add_static_pad_template (element_class,
128 &gst_asf_demux_sink_template);
130 gst_element_class_set_details_simple (element_class, "ASF Demuxer",
131 "Codec/Demuxer",
132 "Demultiplexes ASF Streams", "Owen Fraser-Green <owen@discobabe.net>");
133 }
135 static void
136 gst_asf_demux_class_init (GstASFDemuxClass * klass)
137 {
138 GstElementClass *gstelement_class;
140 gstelement_class = (GstElementClass *) klass;
142 gstelement_class->change_state =
143 GST_DEBUG_FUNCPTR (gst_asf_demux_change_state);
144 gstelement_class->send_event =
145 GST_DEBUG_FUNCPTR (gst_asf_demux_element_send_event);
146 }
148 static void
149 gst_asf_demux_free_stream (GstASFDemux * demux, AsfStream * stream)
150 {
151 gst_caps_replace (&stream->caps, NULL);
152 if (stream->pending_tags) {
153 gst_tag_list_free (stream->pending_tags);
154 stream->pending_tags = NULL;
155 }
156 if (stream->pad) {
157 if (stream->active)
158 gst_element_remove_pad (GST_ELEMENT_CAST (demux), stream->pad);
159 else
160 gst_object_unref (stream->pad);
161 stream->pad = NULL;
162 }
164 while (stream->payloads->len > 0) {
165 AsfPayload *payload;
166 guint last;
168 last = stream->payloads->len - 1;
169 payload = &g_array_index (stream->payloads, AsfPayload, last);
170 gst_buffer_replace (&payload->buf, NULL);
171 g_array_remove_index (stream->payloads, last);
172 }
173 if (stream->payloads) {
174 int i;
175 for (i = 0; i < stream->payloads->len; i++) {
176 AsfPayload *payload;
177 payload = &g_array_index (stream->payloads, AsfPayload, i);
178 gst_buffer_replace (&payload->buf, NULL);
179 }
180 g_array_free (stream->payloads, TRUE);
181 stream->payloads = NULL;
182 }
183 if (stream->ext_props.valid) {
184 g_free (stream->ext_props.payload_extensions);
185 stream->ext_props.payload_extensions = NULL;
186 }
187 }
189 static void
190 gst_asf_demux_reset (GstASFDemux * demux, gboolean chain_reset)
191 {
192 GST_LOG_OBJECT (demux, "resetting");
194 gst_segment_init (&demux->segment, GST_FORMAT_UNDEFINED);
195 demux->segment_running = FALSE;
196 if (demux->adapter && !chain_reset) {
197 gst_adapter_clear (demux->adapter);
198 g_object_unref (demux->adapter);
199 demux->adapter = NULL;
200 }
201 if (demux->taglist) {
202 gst_tag_list_free (demux->taglist);
203 demux->taglist = NULL;
204 }
205 if (demux->metadata) {
206 gst_caps_unref (demux->metadata);
207 demux->metadata = NULL;
208 }
209 if (demux->global_metadata) {
210 gst_structure_free (demux->global_metadata);
211 demux->global_metadata = NULL;
212 }
214 demux->state = GST_ASF_DEMUX_STATE_HEADER;
215 g_free (demux->objpath);
216 demux->objpath = NULL;
217 g_strfreev (demux->languages);
218 demux->languages = NULL;
219 demux->num_languages = 0;
220 g_slist_foreach (demux->ext_stream_props, (GFunc) gst_mini_object_unref,
221 NULL);
222 g_slist_free (demux->ext_stream_props);
223 demux->ext_stream_props = NULL;
225 while (demux->old_num_streams > 0) {
226 gst_asf_demux_free_stream (demux,
227 &demux->old_stream[demux->old_num_streams - 1]);
228 --demux->old_num_streams;
229 }
230 memset (demux->old_stream, 0, sizeof (demux->old_stream));
231 demux->old_num_streams = 0;
233 /* when resetting for a new chained asf, we don't want to remove the pads
234 * before adding the new ones */
235 if (chain_reset) {
236 memcpy (demux->old_stream, demux->stream, sizeof (demux->stream));
237 demux->old_num_streams = demux->num_streams;
238 demux->num_streams = 0;
239 }
241 while (demux->num_streams > 0) {
242 gst_asf_demux_free_stream (demux, &demux->stream[demux->num_streams - 1]);
243 --demux->num_streams;
244 }
245 memset (demux->stream, 0, sizeof (demux->stream));
246 if (!chain_reset) {
247 /* do not remove those for not adding pads with same name */
248 demux->num_audio_streams = 0;
249 demux->num_video_streams = 0;
250 }
251 demux->num_streams = 0;
252 demux->activated_streams = FALSE;
253 demux->first_ts = GST_CLOCK_TIME_NONE;
254 demux->segment_ts = GST_CLOCK_TIME_NONE;
255 demux->in_gap = 0;
256 if (!chain_reset)
257 gst_segment_init (&demux->in_segment, GST_FORMAT_UNDEFINED);
258 demux->state = GST_ASF_DEMUX_STATE_HEADER;
259 demux->seekable = FALSE;
260 demux->broadcast = FALSE;
261 demux->sidx_interval = 0;
262 demux->sidx_num_entries = 0;
263 g_free (demux->sidx_entries);
264 demux->sidx_entries = NULL;
266 demux->speed_packets = 1;
268 if (chain_reset) {
269 GST_LOG_OBJECT (demux, "Restarting");
270 gst_segment_init (&demux->segment, GST_FORMAT_TIME);
271 demux->need_newsegment = TRUE;
272 demux->segment_running = FALSE;
273 demux->accurate = FALSE;
274 demux->metadata = gst_caps_new_empty ();
275 demux->global_metadata = gst_structure_empty_new ("metadata");
276 demux->data_size = 0;
277 demux->data_offset = 0;
278 demux->index_offset = 0;
279 } else {
280 demux->base_offset = 0;
281 }
282 }
284 static void
285 gst_asf_demux_init (GstASFDemux * demux, GstASFDemuxClass * klass)
286 {
287 demux->sinkpad =
288 gst_pad_new_from_static_template (&gst_asf_demux_sink_template, "sink");
289 gst_pad_set_chain_function (demux->sinkpad,
290 GST_DEBUG_FUNCPTR (gst_asf_demux_chain));
291 gst_pad_set_event_function (demux->sinkpad,
292 GST_DEBUG_FUNCPTR (gst_asf_demux_sink_event));
293 gst_pad_set_activate_function (demux->sinkpad,
294 GST_DEBUG_FUNCPTR (gst_asf_demux_activate));
295 gst_pad_set_activatepull_function (demux->sinkpad,
296 GST_DEBUG_FUNCPTR (gst_asf_demux_activate_pull));
297 gst_pad_set_activatepush_function (demux->sinkpad,
298 GST_DEBUG_FUNCPTR (gst_asf_demux_activate_push));
299 gst_element_add_pad (GST_ELEMENT (demux), demux->sinkpad);
301 /* set initial state */
302 gst_asf_demux_reset (demux, FALSE);
303 }
305 static gboolean
306 gst_asf_demux_activate (GstPad * sinkpad)
307 {
308 if (gst_pad_check_pull_range (sinkpad)) {
309 return gst_pad_activate_pull (sinkpad, TRUE);
310 } else {
311 return gst_pad_activate_push (sinkpad, TRUE);
312 }
313 }
315 static gboolean
316 gst_asf_demux_activate_push (GstPad * sinkpad, gboolean active)
317 {
318 GstASFDemux *demux;
320 demux = GST_ASF_DEMUX (GST_OBJECT_PARENT (sinkpad));
322 demux->state = GST_ASF_DEMUX_STATE_HEADER;
323 demux->streaming = TRUE;
325 return TRUE;
326 }
328 static gboolean
329 gst_asf_demux_activate_pull (GstPad * pad, gboolean active)
330 {
331 GstASFDemux *demux;
333 demux = GST_ASF_DEMUX (GST_OBJECT_PARENT (pad));
335 if (active) {
336 demux->state = GST_ASF_DEMUX_STATE_HEADER;
337 demux->streaming = FALSE;
339 return gst_pad_start_task (pad, (GstTaskFunction) gst_asf_demux_loop,
340 demux);
341 } else {
342 return gst_pad_stop_task (pad);
343 }
344 }
347 static gboolean
348 gst_asf_demux_sink_event (GstPad * pad, GstEvent * event)
349 {
350 GstASFDemux *demux;
351 gboolean ret = TRUE;
353 demux = GST_ASF_DEMUX (gst_pad_get_parent (pad));
355 GST_LOG_OBJECT (demux, "handling %s event", GST_EVENT_TYPE_NAME (event));
356 switch (GST_EVENT_TYPE (event)) {
357 case GST_EVENT_NEWSEGMENT:{
358 GstFormat newsegment_format;
359 gint64 newsegment_start, stop, time;
360 gdouble rate, arate;
361 gboolean update;
363 gst_event_parse_new_segment_full (event, &update, &rate, &arate,
364 &newsegment_format, &newsegment_start, &stop, &time);
366 if (newsegment_format == GST_FORMAT_BYTES) {
367 if (demux->packet_size && newsegment_start > demux->data_offset)
368 demux->packet = (newsegment_start - demux->data_offset) /
369 demux->packet_size;
370 else
371 demux->packet = 0;
372 } else if (newsegment_format == GST_FORMAT_TIME) {
373 /* do not know packet position, not really a problem */
374 demux->packet = -1;
375 } else {
376 GST_WARNING_OBJECT (demux, "unsupported newsegment format, ignoring");
377 gst_event_unref (event);
378 break;
379 }
381 /* record upstream segment for interpolation */
382 if (newsegment_format != demux->in_segment.format)
383 gst_segment_init (&demux->in_segment, GST_FORMAT_UNDEFINED);
384 gst_segment_set_newsegment_full (&demux->in_segment, update, rate, arate,
385 newsegment_format, newsegment_start, stop, time);
387 /* in either case, clear some state and generate newsegment later on */
388 GST_OBJECT_LOCK (demux);
389 demux->segment_ts = GST_CLOCK_TIME_NONE;
390 demux->in_gap = GST_CLOCK_TIME_NONE;
391 demux->need_newsegment = TRUE;
392 gst_asf_demux_reset_stream_state_after_discont (demux);
393 GST_OBJECT_UNLOCK (demux);
395 gst_event_unref (event);
396 break;
397 }
398 case GST_EVENT_EOS:{
399 GstFlowReturn flow;
401 if (demux->state == GST_ASF_DEMUX_STATE_HEADER) {
402 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
403 (_("This stream contains no data.")),
404 ("got eos and didn't receive a complete header object"));
405 break;
406 }
407 flow = gst_asf_demux_push_complete_payloads (demux, TRUE);
408 if (flow < GST_FLOW_UNEXPECTED || flow == GST_FLOW_NOT_LINKED) {
409 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
410 (_("Internal data stream error.")),
411 ("streaming stopped, reason %s", gst_flow_get_name (flow)));
412 break;
413 }
415 GST_OBJECT_LOCK (demux);
416 gst_adapter_clear (demux->adapter);
417 GST_OBJECT_UNLOCK (demux);
418 gst_asf_demux_send_event_unlocked (demux, event);
419 break;
420 }
422 case GST_EVENT_FLUSH_STOP:
423 GST_OBJECT_LOCK (demux);
424 gst_asf_demux_reset_stream_state_after_discont (demux);
425 GST_OBJECT_UNLOCK (demux);
426 gst_asf_demux_send_event_unlocked (demux, event);
427 /* upon activation, latency is no longer introduced, e.g. after seek */
428 if (demux->activated_streams)
429 demux->latency = 0;
430 break;
432 default:
433 ret = gst_pad_event_default (pad, event);
434 break;
435 }
437 gst_object_unref (demux);
438 return ret;
439 }
441 static gboolean
442 gst_asf_demux_seek_index_lookup (GstASFDemux * demux, guint * packet,
443 GstClockTime seek_time, GstClockTime * p_idx_time, guint * speed)
444 {
445 GstClockTime idx_time;
446 guint idx;
448 if (G_UNLIKELY (demux->sidx_num_entries == 0 || demux->sidx_interval == 0))
449 return FALSE;
451 idx = (guint) ((seek_time + demux->preroll) / demux->sidx_interval);
453 /* FIXME: seek beyond end of file should result in immediate EOS from
454 * streaming thread instead of a failed seek */
455 if (G_UNLIKELY (idx >= demux->sidx_num_entries))
456 return FALSE;
458 *packet = demux->sidx_entries[idx].packet;
459 if (speed)
460 *speed = demux->sidx_entries[idx].count;
462 /* so we get closer to the actual time of the packet ... actually, let's not
463 * do this, since we throw away superfluous payloads before the seek position
464 * anyway; this way, our key unit seek 'snap resolution' is a bit better
465 * (ie. same as index resolution) */
466 /*
467 while (idx > 0 && demux->sidx_entries[idx-1] == demux->sidx_entries[idx])
468 --idx;
469 */
471 idx_time = demux->sidx_interval * idx;
472 if (G_LIKELY (idx_time >= demux->preroll))
473 idx_time -= demux->preroll;
475 GST_DEBUG_OBJECT (demux, "%" GST_TIME_FORMAT " => packet %u at %"
476 GST_TIME_FORMAT, GST_TIME_ARGS (seek_time), *packet,
477 GST_TIME_ARGS (idx_time));
479 if (G_LIKELY (p_idx_time))
480 *p_idx_time = idx_time;
482 return TRUE;
483 }
485 static void
486 gst_asf_demux_reset_stream_state_after_discont (GstASFDemux * demux)
487 {
488 guint n;
490 gst_adapter_clear (demux->adapter);
492 GST_DEBUG_OBJECT (demux, "reset stream state");
494 for (n = 0; n < demux->num_streams; n++) {
495 demux->stream[n].discont = TRUE;
496 demux->stream[n].last_flow = GST_FLOW_OK;
498 while (demux->stream[n].payloads->len > 0) {
499 AsfPayload *payload;
500 guint last;
502 last = demux->stream[n].payloads->len - 1;
503 payload = &g_array_index (demux->stream[n].payloads, AsfPayload, last);
504 gst_buffer_replace (&payload->buf, NULL);
505 g_array_remove_index (demux->stream[n].payloads, last);
506 }
507 }
508 }
510 static void
511 gst_asf_demux_mark_discont (GstASFDemux * demux)
512 {
513 guint n;
515 GST_DEBUG_OBJECT (demux, "Mark stream discont");
517 for (n = 0; n < demux->num_streams; n++)
518 demux->stream[n].discont = TRUE;
519 }
521 /* do a seek in push based mode */
522 static gboolean
523 gst_asf_demux_handle_seek_push (GstASFDemux * demux, GstEvent * event)
524 {
525 gdouble rate;
526 GstFormat format;
527 GstSeekFlags flags;
528 GstSeekType cur_type, stop_type;
529 gint64 cur, stop;
530 guint packet;
531 gboolean res;
533 gst_event_parse_seek (event, &rate, &format, &flags, &cur_type, &cur,
534 &stop_type, &stop);
536 stop_type = GST_SEEK_TYPE_NONE;
537 stop = -1;
539 GST_DEBUG_OBJECT (demux, "seeking to %" GST_TIME_FORMAT, GST_TIME_ARGS (cur));
541 /* determine packet, by index or by estimation */
542 if (!gst_asf_demux_seek_index_lookup (demux, &packet, cur, NULL, NULL)) {
543 packet = (guint) gst_util_uint64_scale (demux->num_packets,
544 cur, demux->play_time);
545 }
547 if (packet > demux->num_packets) {
548 GST_DEBUG_OBJECT (demux, "could not determine packet to seek to, "
549 "seek aborted.");
550 return FALSE;
551 }
553 GST_DEBUG_OBJECT (demux, "seeking to packet %d", packet);
555 cur = demux->data_offset + (packet * demux->packet_size);
557 GST_DEBUG_OBJECT (demux, "Pushing BYTE seek rate %g, "
558 "start %" G_GINT64_FORMAT ", stop %" G_GINT64_FORMAT, rate, cur, stop);
559 /* BYTE seek event */
560 event = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags, cur_type, cur,
561 stop_type, stop);
562 res = gst_pad_push_event (demux->sinkpad, event);
564 return res;
565 }
567 static gboolean
568 gst_asf_demux_handle_seek_event (GstASFDemux * demux, GstEvent * event)
569 {
570 GstClockTime idx_time;
571 GstSegment segment;
572 GstSeekFlags flags;
573 GstSeekType cur_type, stop_type;
574 GstFormat format;
575 gboolean only_need_update;
576 gboolean keyunit_sync;
577 gboolean flush;
578 gdouble rate;
579 gint64 cur, stop;
580 gint64 seek_time;
581 guint packet, speed_count = 1;
583 if (G_UNLIKELY (demux->seekable == FALSE || demux->packet_size == 0 ||
584 demux->num_packets == 0 || demux->play_time == 0)) {
585 GST_LOG_OBJECT (demux, "stream is not seekable");
586 return FALSE;
587 }
589 if (G_UNLIKELY (!demux->activated_streams)) {
590 GST_LOG_OBJECT (demux, "streams not yet activated, ignoring seek");
591 return FALSE;
592 }
594 gst_event_parse_seek (event, &rate, &format, &flags, &cur_type, &cur,
595 &stop_type, &stop);
597 if (G_UNLIKELY (format != GST_FORMAT_TIME)) {
598 GST_LOG_OBJECT (demux, "seeking is only supported in TIME format");
599 return FALSE;
600 }
602 if (G_UNLIKELY (rate <= 0.0)) {
603 GST_LOG_OBJECT (demux, "backward playback is not supported yet");
604 return FALSE;
605 }
607 flush = ((flags & GST_SEEK_FLAG_FLUSH) == GST_SEEK_FLAG_FLUSH);
608 demux->accurate =
609 ((flags & GST_SEEK_FLAG_ACCURATE) == GST_SEEK_FLAG_ACCURATE);
610 keyunit_sync = ((flags & GST_SEEK_FLAG_KEY_UNIT) == GST_SEEK_FLAG_KEY_UNIT);
612 if (G_UNLIKELY (demux->streaming)) {
613 /* support it safely needs more segment handling, e.g. closing etc */
614 if (!flush) {
615 GST_LOG_OBJECT (demux, "streaming; non-flushing seek not supported");
616 return FALSE;
617 }
618 /* we can (re)construct the start later on, but not the end */
619 if (stop_type != GST_SEEK_TYPE_NONE) {
620 GST_LOG_OBJECT (demux, "streaming; end type must be NONE");
621 return FALSE;
622 }
623 gst_event_ref (event);
624 /* upstream might handle TIME seek, e.g. mms or rtsp,
625 * or not, e.g. http, then we give it a hand */
626 if (!gst_pad_push_event (demux->sinkpad, event))
627 return gst_asf_demux_handle_seek_push (demux, event);
628 else
629 return TRUE;
630 }
632 /* unlock the streaming thread */
633 if (G_LIKELY (flush)) {
634 gst_pad_push_event (demux->sinkpad, gst_event_new_flush_start ());
635 gst_asf_demux_send_event_unlocked (demux, gst_event_new_flush_start ());
636 } else {
637 gst_pad_pause_task (demux->sinkpad);
638 }
640 /* grab the stream lock so that streaming cannot continue, for
641 * non flushing seeks when the element is in PAUSED this could block
642 * forever */
643 GST_PAD_STREAM_LOCK (demux->sinkpad);
645 /* we now can stop flushing, since we have the stream lock now */
646 gst_pad_push_event (demux->sinkpad, gst_event_new_flush_stop ());
648 if (G_LIKELY (flush))
649 gst_asf_demux_send_event_unlocked (demux, gst_event_new_flush_stop ());
651 /* operating on copy of segment until we know the seek worked */
652 segment = demux->segment;
654 if (G_UNLIKELY (demux->segment_running && !flush)) {
655 GstEvent *newseg;
657 /* create the segment event to close the current segment */
658 newseg = gst_event_new_new_segment (TRUE, segment.rate,
659 GST_FORMAT_TIME, segment.start, segment.last_stop, segment.time);
661 gst_asf_demux_send_event_unlocked (demux, newseg);
662 }
664 gst_segment_set_seek (&segment, rate, format, flags, cur_type,
665 cur, stop_type, stop, &only_need_update);
667 GST_DEBUG_OBJECT (demux, "seeking to time %" GST_TIME_FORMAT ", segment: "
668 "%" GST_SEGMENT_FORMAT, GST_TIME_ARGS (segment.start), &segment);
670 seek_time = segment.start;
672 /* FIXME: should check the KEY_UNIT flag; need to adjust last_stop to
673 * real start of data and segment_start to indexed time for key unit seek*/
674 if (G_UNLIKELY (!gst_asf_demux_seek_index_lookup (demux, &packet, seek_time,
675 &idx_time, &speed_count))) {
676 /* First try to query our source to see if it can convert for us. This is
677 the case when our source is an mms stream, notice that in this case
678 gstmms will do a time based seek to get the byte offset, this is not a
679 problem as the seek to this offset needs to happen anway. */
680 gint64 offset;
681 GstFormat dest_format = GST_FORMAT_BYTES;
683 if (gst_pad_query_peer_convert (demux->sinkpad, GST_FORMAT_TIME, seek_time,
684 &dest_format, &offset) && dest_format == GST_FORMAT_BYTES) {
685 packet = (offset - demux->data_offset) / demux->packet_size;
686 GST_LOG_OBJECT (demux, "convert %" GST_TIME_FORMAT
687 " to bytes query result: %" G_GINT64_FORMAT ", data_ofset: %"
688 G_GINT64_FORMAT ", packet_size: %u," " resulting packet: %u\n",
689 GST_TIME_ARGS (seek_time), offset, demux->data_offset,
690 demux->packet_size, packet);
691 } else {
692 /* FIXME: For streams containing video, seek to an earlier position in
693 * the hope of hitting a keyframe and let the sinks throw away the stuff
694 * before the segment start. For audio-only this is unnecessary as every
695 * frame is 'key'. */
696 if (flush && (demux->accurate || keyunit_sync)
697 && demux->num_video_streams > 0) {
698 seek_time -= 5 * GST_SECOND;
699 if (seek_time < 0)
700 seek_time = 0;
701 }
703 packet = (guint) gst_util_uint64_scale (demux->num_packets,
704 seek_time, demux->play_time);
706 if (packet > demux->num_packets)
707 packet = demux->num_packets;
708 }
709 } else {
710 if (G_LIKELY (keyunit_sync)) {
711 GST_DEBUG_OBJECT (demux, "key unit seek, adjust seek_time = %"
712 GST_TIME_FORMAT " to index_time = %" GST_TIME_FORMAT,
713 GST_TIME_ARGS (seek_time), GST_TIME_ARGS (idx_time));
714 segment.start = idx_time;
715 segment.last_stop = idx_time;
716 segment.time = idx_time;
717 }
718 }
720 GST_DEBUG_OBJECT (demux, "seeking to packet %u (%d)", packet, speed_count);
722 GST_OBJECT_LOCK (demux);
723 demux->segment = segment;
724 demux->packet = packet;
725 demux->need_newsegment = TRUE;
726 demux->speed_packets = speed_count;
727 gst_asf_demux_reset_stream_state_after_discont (demux);
728 GST_OBJECT_UNLOCK (demux);
730 /* restart our task since it might have been stopped when we did the flush */
731 gst_pad_start_task (demux->sinkpad, (GstTaskFunction) gst_asf_demux_loop,
732 demux);
734 /* streaming can continue now */
735 GST_PAD_STREAM_UNLOCK (demux->sinkpad);
737 return TRUE;
738 }
740 static gboolean
741 gst_asf_demux_handle_src_event (GstPad * pad, GstEvent * event)
742 {
743 GstASFDemux *demux;
744 gboolean ret;
746 demux = GST_ASF_DEMUX (gst_pad_get_parent (pad));
748 switch (GST_EVENT_TYPE (event)) {
749 case GST_EVENT_SEEK:
750 GST_LOG_OBJECT (pad, "seek event");
751 ret = gst_asf_demux_handle_seek_event (demux, event);
752 gst_event_unref (event);
753 break;
754 case GST_EVENT_QOS:
755 case GST_EVENT_NAVIGATION:
756 /* just drop these two silently */
757 gst_event_unref (event);
758 ret = FALSE;
759 break;
760 default:
761 GST_LOG_OBJECT (pad, "%s event", GST_EVENT_TYPE_NAME (event));
762 ret = gst_pad_event_default (pad, event);
763 break;
764 }
766 gst_object_unref (demux);
767 return ret;
768 }
770 static inline guint32
771 gst_asf_demux_identify_guid (const ASFGuidHash * guids, ASFGuid * guid)
772 {
773 guint32 ret;
775 ret = gst_asf_identify_guid (guids, guid);
777 GST_LOG ("%s 0x%08x-0x%08x-0x%08x-0x%08x",
778 gst_asf_get_guid_nick (guids, ret),
779 guid->v1, guid->v2, guid->v3, guid->v4);
781 return ret;
782 }
784 typedef struct
785 {
786 AsfObjectID id;
787 guint64 size;
788 } AsfObject;
791 /* expect is true when the user is expeting an object,
792 * when false, it will give no warnings if the object
793 * is not identified
794 */
795 static gboolean
796 asf_demux_peek_object (GstASFDemux * demux, const guint8 * data,
797 guint data_len, AsfObject * object, gboolean expect)
798 {
799 ASFGuid guid;
801 if (data_len < ASF_OBJECT_HEADER_SIZE)
802 return FALSE;
804 guid.v1 = GST_READ_UINT32_LE (data + 0);
805 guid.v2 = GST_READ_UINT32_LE (data + 4);
806 guid.v3 = GST_READ_UINT32_LE (data + 8);
807 guid.v4 = GST_READ_UINT32_LE (data + 12);
809 object->size = GST_READ_UINT64_LE (data + 16);
811 /* FIXME: make asf_demux_identify_object_guid() */
812 object->id = gst_asf_demux_identify_guid (asf_object_guids, &guid);
813 if (object->id == ASF_OBJ_UNDEFINED && expect) {
814 GST_WARNING_OBJECT (demux, "Unknown object %08x-%08x-%08x-%08x",
815 guid.v1, guid.v2, guid.v3, guid.v4);
816 }
818 return TRUE;
819 }
821 static void
822 gst_asf_demux_release_old_pads (GstASFDemux * demux)
823 {
824 GST_DEBUG_OBJECT (demux, "Releasing old pads");
826 while (demux->old_num_streams > 0) {
827 gst_pad_push_event (demux->old_stream[demux->old_num_streams - 1].pad,
828 gst_event_new_eos ());
829 gst_asf_demux_free_stream (demux,
830 &demux->old_stream[demux->old_num_streams - 1]);
831 --demux->old_num_streams;
832 }
833 memset (demux->old_stream, 0, sizeof (demux->old_stream));
834 demux->old_num_streams = 0;
835 }
837 static GstFlowReturn
838 gst_asf_demux_chain_headers (GstASFDemux * demux)
839 {
840 GstFlowReturn flow;
841 AsfObject obj;
842 guint8 *header_data, *data = NULL;
843 const guint8 *cdata = NULL;
844 guint64 header_size;
846 cdata = (guint8 *) gst_adapter_peek (demux->adapter, ASF_OBJECT_HEADER_SIZE);
847 if (cdata == NULL)
848 goto need_more_data;
850 asf_demux_peek_object (demux, cdata, ASF_OBJECT_HEADER_SIZE, &obj, TRUE);
851 if (obj.id != ASF_OBJ_HEADER)
852 goto wrong_type;
854 GST_LOG_OBJECT (demux, "header size = %u", (guint) obj.size);
856 /* + 50 for non-packet data at beginning of ASF_OBJ_DATA */
857 if (gst_adapter_available (demux->adapter) < obj.size + 50)
858 goto need_more_data;
860 data = gst_adapter_take (demux->adapter, obj.size + 50);
862 header_data = data;
863 header_size = obj.size;
864 flow = gst_asf_demux_process_object (demux, &header_data, &header_size);
865 if (flow != GST_FLOW_OK)
866 goto parse_failed;
868 /* calculate where the packet data starts */
869 demux->data_offset = obj.size + 50;
871 /* now parse the beginning of the ASF_OBJ_DATA object */
872 if (!gst_asf_demux_parse_data_object_start (demux, data + obj.size))
873 goto wrong_type;
875 if (demux->num_streams == 0)
876 goto no_streams;
878 g_free (data);
879 return GST_FLOW_OK;
881 /* NON-FATAL */
882 need_more_data:
883 {
884 GST_LOG_OBJECT (demux, "not enough data in adapter yet");
885 return GST_FLOW_OK;
886 }
888 /* ERRORS */
889 wrong_type:
890 {
891 GST_ELEMENT_ERROR (demux, STREAM, WRONG_TYPE, (NULL),
892 ("This doesn't seem to be an ASF file"));
893 g_free (data);
894 return GST_FLOW_ERROR;
895 }
896 no_streams:
897 parse_failed:
898 {
899 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
900 ("header parsing failed, or no streams found, flow = %s",
901 gst_flow_get_name (flow)));
902 g_free (data);
903 return GST_FLOW_ERROR;
904 }
905 }
907 static GstFlowReturn
908 gst_asf_demux_aggregate_flow_return (GstASFDemux * demux, AsfStream * stream,
909 GstFlowReturn flow)
910 {
911 int i;
913 GST_DEBUG_OBJECT (demux, "Aggregating");
915 /* Store the value */
916 stream->last_flow = flow;
918 /* any other error that is not not-linked can be returned right away */
919 if (flow != GST_FLOW_NOT_LINKED)
920 goto done;
922 for (i = 0; i < demux->num_streams; i++) {
923 if (demux->stream[i].active) {
924 flow = demux->stream[i].last_flow;
925 GST_DEBUG_OBJECT (demux, "Aggregating: flow %i return %s", i,
926 gst_flow_get_name (flow));
927 if (flow != GST_FLOW_NOT_LINKED)
928 goto done;
929 }
930 }
932 /* If we got here, then all our active streams are not linked */
933 done:
934 return flow;
935 }
937 static gboolean
938 gst_asf_demux_pull_data (GstASFDemux * demux, guint64 offset, guint size,
939 GstBuffer ** p_buf, GstFlowReturn * p_flow)
940 {
941 GstFlowReturn flow;
943 GST_LOG_OBJECT (demux, "pulling buffer at %" G_GUINT64_FORMAT "+%u",
944 offset, size);
946 flow = gst_pad_pull_range (demux->sinkpad, offset, size, p_buf);
948 if (G_LIKELY (p_flow))
949 *p_flow = flow;
951 if (G_UNLIKELY (flow != GST_FLOW_OK)) {
952 GST_DEBUG_OBJECT (demux, "flow %s pulling buffer at %" G_GUINT64_FORMAT
953 "+%u", gst_flow_get_name (flow), offset, size);
954 *p_buf = NULL;
955 return FALSE;
956 }
958 g_assert (*p_buf != NULL);
960 if (G_UNLIKELY (GST_BUFFER_SIZE (*p_buf) < size)) {
961 GST_DEBUG_OBJECT (demux, "short read pulling buffer at %" G_GUINT64_FORMAT
962 "+%u (got only %u bytes)", offset, size, GST_BUFFER_SIZE (*p_buf));
963 gst_buffer_unref (*p_buf);
964 if (G_LIKELY (p_flow))
965 *p_flow = GST_FLOW_UNEXPECTED;
966 *p_buf = NULL;
967 return FALSE;
968 }
970 return TRUE;
971 }
973 static void
974 gst_asf_demux_pull_indices (GstASFDemux * demux)
975 {
976 GstBuffer *buf = NULL;
977 guint64 offset;
978 guint num_read = 0;
980 offset = demux->index_offset;
982 if (G_UNLIKELY (offset == 0)) {
983 GST_DEBUG_OBJECT (demux, "can't read indices, don't know index offset");
984 return;
985 }
987 while (gst_asf_demux_pull_data (demux, offset, 16 + 8, &buf, NULL)) {
988 GstFlowReturn flow;
989 AsfObject obj;
991 asf_demux_peek_object (demux, GST_BUFFER_DATA (buf), 16 + 8, &obj, TRUE);
992 gst_buffer_replace (&buf, NULL);
994 /* check for sanity */
995 if (G_UNLIKELY (obj.size > (5 * 1024 * 1024))) {
996 GST_DEBUG_OBJECT (demux, "implausible index object size, bailing out");
997 break;
998 }
1000 if (G_UNLIKELY (!gst_asf_demux_pull_data (demux, offset, obj.size, &buf,
1001 NULL)))
1002 break;
1004 GST_LOG_OBJECT (demux, "index object at offset 0x%" G_GINT64_MODIFIER "X"
1005 ", size %u", offset, (guint) obj.size);
1007 offset += obj.size; /* increase before _process_object changes it */
1009 flow = gst_asf_demux_process_object (demux, &buf->data, &obj.size);
1010 gst_buffer_replace (&buf, NULL);
1012 if (G_UNLIKELY (flow != GST_FLOW_OK))
1013 break;
1015 ++num_read;
1016 }
1017 GST_DEBUG_OBJECT (demux, "read %u index objects", num_read);
1018 }
1020 static gboolean
1021 gst_asf_demux_parse_data_object_start (GstASFDemux * demux, guint8 * data)
1022 {
1023 AsfObject obj;
1025 asf_demux_peek_object (demux, data, 50, &obj, TRUE);
1026 if (obj.id != ASF_OBJ_DATA) {
1027 GST_WARNING_OBJECT (demux, "headers not followed by a DATA object");
1028 return FALSE;
1029 }
1031 demux->state = GST_ASF_DEMUX_STATE_DATA;
1033 if (!demux->broadcast && obj.size > 50) {
1034 demux->data_size = obj.size - 50;
1035 /* CHECKME: for at least one file this is off by +158 bytes?! */
1036 demux->index_offset = demux->data_offset + demux->data_size;
1037 } else {
1038 demux->data_size = 0;
1039 demux->index_offset = 0;
1040 }
1042 demux->packet = 0;
1044 if (!demux->broadcast) {
1045 /* skip object header (24 bytes) and file GUID (16 bytes) */
1046 demux->num_packets = GST_READ_UINT64_LE (data + (16 + 8) + 16);
1047 } else {
1048 demux->num_packets = 0;
1049 }
1051 if (demux->num_packets == 0)
1052 demux->seekable = FALSE;
1054 /* fallback in the unlikely case that headers are inconsistent, can't hurt */
1055 if (demux->data_size == 0 && demux->num_packets > 0) {
1056 demux->data_size = demux->num_packets * demux->packet_size;
1057 demux->index_offset = demux->data_offset + demux->data_size;
1058 }
1060 /* process pending stream objects and create pads for those */
1061 gst_asf_demux_process_queued_extended_stream_objects (demux);
1063 GST_INFO_OBJECT (demux, "Stream has %" G_GUINT64_FORMAT " packets, "
1064 "data_offset=%" G_GINT64_FORMAT ", data_size=%" G_GINT64_FORMAT
1065 ", index_offset=%" G_GUINT64_FORMAT, demux->num_packets,
1066 demux->data_offset, demux->data_size, demux->index_offset);
1068 return TRUE;
1069 }
1071 static gboolean
1072 gst_asf_demux_pull_headers (GstASFDemux * demux)
1073 {
1074 GstFlowReturn flow;
1075 AsfObject obj;
1076 GstBuffer *buf = NULL;
1077 guint64 size;
1079 GST_LOG_OBJECT (demux, "reading headers");
1081 /* pull HEADER object header, so we know its size */
1082 if (!gst_asf_demux_pull_data (demux, demux->base_offset, 16 + 8, &buf, NULL))
1083 goto read_failed;
1085 asf_demux_peek_object (demux, GST_BUFFER_DATA (buf), 16 + 8, &obj, TRUE);
1086 gst_buffer_replace (&buf, NULL);
1088 if (obj.id != ASF_OBJ_HEADER)
1089 goto wrong_type;
1091 GST_LOG_OBJECT (demux, "header size = %u", (guint) obj.size);
1093 /* pull HEADER object */
1094 if (!gst_asf_demux_pull_data (demux, demux->base_offset, obj.size, &buf,
1095 NULL))
1096 goto read_failed;
1098 size = obj.size; /* don't want obj.size changed */
1099 flow = gst_asf_demux_process_object (demux, &buf->data, &size);
1100 gst_buffer_replace (&buf, NULL);
1102 if (flow != GST_FLOW_OK) {
1103 GST_WARNING_OBJECT (demux, "process_object: %s", gst_flow_get_name (flow));
1104 goto parse_failed;
1105 }
1107 /* calculate where the packet data starts */
1108 demux->data_offset = demux->base_offset + obj.size + 50;
1110 /* now pull beginning of DATA object before packet data */
1111 if (!gst_asf_demux_pull_data (demux, demux->base_offset + obj.size, 50, &buf,
1112 NULL))
1113 goto read_failed;
1115 if (!gst_asf_demux_parse_data_object_start (demux, GST_BUFFER_DATA (buf)))
1116 goto wrong_type;
1118 if (demux->num_streams == 0)
1119 goto no_streams;
1121 gst_buffer_replace (&buf, NULL);
1122 return TRUE;
1124 /* ERRORS */
1125 wrong_type:
1126 {
1127 gst_buffer_replace (&buf, NULL);
1128 GST_ELEMENT_ERROR (demux, STREAM, WRONG_TYPE, (NULL),
1129 ("This doesn't seem to be an ASF file"));
1130 return FALSE;
1131 }
1132 no_streams:
1133 read_failed:
1134 parse_failed:
1135 {
1136 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL), (NULL));
1137 return FALSE;
1138 }
1139 }
1141 static gboolean
1142 all_streams_prerolled (GstASFDemux * demux)
1143 {
1144 GstClockTime preroll_time;
1145 guint i, num_no_data = 0;
1147 /* Allow at least 500ms of preroll_time */
1148 preroll_time = MAX (demux->preroll, 500 * GST_MSECOND);
1150 /* returns TRUE as long as there isn't a stream which (a) has data queued
1151 * and (b) the timestamp of last piece of data queued is < demux->preroll
1152 * AND there is at least one other stream with data queued */
1153 for (i = 0; i < demux->num_streams; ++i) {
1154 AsfPayload *last_payload;
1155 AsfStream *stream;
1156 guint last_idx;
1158 stream = &demux->stream[i];
1159 if (G_UNLIKELY (stream->payloads->len == 0)) {
1160 ++num_no_data;
1161 GST_LOG_OBJECT (stream->pad, "no data queued");
1162 continue;
1163 }
1165 last_idx = stream->payloads->len - 1;
1166 last_payload = &g_array_index (stream->payloads, AsfPayload, last_idx);
1168 GST_LOG_OBJECT (stream->pad, "checking if %" GST_TIME_FORMAT " > %"
1169 GST_TIME_FORMAT, GST_TIME_ARGS (last_payload->ts),
1170 GST_TIME_ARGS (preroll_time));
1171 if (G_UNLIKELY (last_payload->ts <= preroll_time)) {
1172 GST_LOG_OBJECT (stream->pad, "not beyond preroll point yet");
1173 return FALSE;
1174 }
1175 }
1177 if (G_UNLIKELY (num_no_data == demux->num_streams))
1178 return FALSE;
1180 return TRUE;
1181 }
1183 #if 0
1184 static gboolean
1185 gst_asf_demux_have_mutually_exclusive_active_stream (GstASFDemux * demux,
1186 AsfStream * stream)
1187 {
1188 GSList *l;
1190 for (l = demux->mut_ex_streams; l != NULL; l = l->next) {
1191 guint8 *mes;
1193 /* check for each mutual exclusion group whether it affects this stream */
1194 for (mes = (guint8 *) l->data; mes != NULL && *mes != 0xff; ++mes) {
1195 if (*mes == stream->id) {
1196 /* we are in this group; let's check if we've already activated streams
1197 * that are in the same group (and hence mutually exclusive to this
1198 * one) */
1199 for (mes = (guint8 *) l->data; mes != NULL && *mes != 0xff; ++mes) {
1200 guint i;
1202 for (i = 0; i < demux->num_streams; ++i) {
1203 if (demux->stream[i].id == *mes && demux->stream[i].active) {
1204 GST_LOG_OBJECT (demux, "stream with ID %d is mutually exclusive "
1205 "to already active stream with ID %d", stream->id,
1206 demux->stream[i].id);
1207 return TRUE;
1208 }
1209 }
1210 }
1211 /* we can only be in this group once, let's break out and move on to
1212 * the next mutual exclusion group */
1213 break;
1214 }
1215 }
1216 }
1218 return FALSE;
1219 }
1220 #endif
1222 static gboolean
1223 gst_asf_demux_check_activate_streams (GstASFDemux * demux, gboolean force)
1224 {
1225 guint i;
1227 if (demux->activated_streams)
1228 return TRUE;
1230 if (!all_streams_prerolled (demux) && !force) {
1231 GST_DEBUG_OBJECT (demux, "not all streams with data beyond preroll yet");
1232 return FALSE;
1233 }
1235 for (i = 0; i < demux->num_streams; ++i) {
1236 AsfStream *stream = &demux->stream[i];
1238 if (stream->payloads->len > 0) {
1239 /* we don't check mutual exclusion stuff here; either we have data for
1240 * a stream, then we active it, or we don't, then we'll ignore it */
1241 GST_LOG_OBJECT (stream->pad, "is prerolled - activate!");
1242 gst_asf_demux_activate_stream (demux, stream);
1243 } else {
1244 GST_LOG_OBJECT (stream->pad, "no data, ignoring stream");
1245 }
1246 }
1248 gst_asf_demux_release_old_pads (demux);
1250 demux->activated_streams = TRUE;
1251 GST_LOG_OBJECT (demux, "signalling no more pads");
1252 gst_element_no_more_pads (GST_ELEMENT (demux));
1253 return TRUE;
1254 }
1256 /* returns the stream that has a complete payload with the lowest timestamp
1257 * queued, or NULL (we push things by timestamp because during the internal
1258 * prerolling we might accumulate more data then the external queues can take,
1259 * so we'd lock up if we pushed all accumulated data for stream N in one go) */
1260 static AsfStream *
1261 gst_asf_demux_find_stream_with_complete_payload (GstASFDemux * demux)
1262 {
1263 AsfPayload *best_payload = NULL;
1264 AsfStream *best_stream = NULL;
1265 guint i;
1267 for (i = 0; i < demux->num_streams; ++i) {
1268 AsfStream *stream;
1270 stream = &demux->stream[i];
1272 /* Don't push any data until we have at least one payload that falls within
1273 * the current segment. This way we can remove out-of-segment payloads that
1274 * don't need to be decoded after a seek, sending only data from the
1275 * keyframe directly before our segment start */
1276 if (stream->payloads->len > 0) {
1277 AsfPayload *payload;
1278 guint last_idx;
1280 last_idx = stream->payloads->len - 1;
1281 payload = &g_array_index (stream->payloads, AsfPayload, last_idx);
1282 if (G_UNLIKELY (GST_CLOCK_TIME_IS_VALID (payload->ts) &&
1283 (payload->ts < demux->segment.start))) {
1284 if (G_UNLIKELY ((!demux->accurate) && payload->keyframe)) {
1285 GST_DEBUG_OBJECT (stream->pad,
1286 "Found keyframe, updating segment start to %" GST_TIME_FORMAT,
1287 GST_TIME_ARGS (payload->ts));
1288 demux->segment.start = payload->ts;
1289 demux->segment.time = payload->ts;
1290 } else {
1291 GST_DEBUG_OBJECT (stream->pad, "Last queued payload has timestamp %"
1292 GST_TIME_FORMAT " which is before our segment start %"
1293 GST_TIME_FORMAT ", not pushing yet", GST_TIME_ARGS (payload->ts),
1294 GST_TIME_ARGS (demux->segment.start));
1295 continue;
1296 }
1297 }
1299 /* Now see if there's a complete payload queued for this stream */
1301 payload = &g_array_index (stream->payloads, AsfPayload, 0);
1302 if (!gst_asf_payload_is_complete (payload))
1303 continue;
1305 /* ... and whether its timestamp is lower than the current best */
1306 if (best_stream == NULL || best_payload->ts > payload->ts) {
1307 best_stream = stream;
1308 best_payload = payload;
1309 }
1310 }
1311 }
1313 return best_stream;
1314 }
1316 static GstFlowReturn
1317 gst_asf_demux_push_complete_payloads (GstASFDemux * demux, gboolean force)
1318 {
1319 AsfStream *stream;
1320 GstFlowReturn ret = GST_FLOW_OK;
1322 if (G_UNLIKELY (!demux->activated_streams)) {
1323 if (!gst_asf_demux_check_activate_streams (demux, force))
1324 return GST_FLOW_OK;
1325 /* streams are now activated */
1326 }
1328 /* wait until we had a chance to "lock on" some payload's timestamp */
1329 if (G_UNLIKELY (demux->need_newsegment
1330 && !GST_CLOCK_TIME_IS_VALID (demux->segment_ts)))
1331 return GST_FLOW_OK;
1333 while ((stream = gst_asf_demux_find_stream_with_complete_payload (demux))) {
1334 AsfPayload *payload;
1336 payload = &g_array_index (stream->payloads, AsfPayload, 0);
1338 /* do we need to send a newsegment event */
1339 if ((G_UNLIKELY (demux->need_newsegment))) {
1341 /* safe default if insufficient upstream info */
1342 if (!GST_CLOCK_TIME_IS_VALID (demux->in_gap))
1343 demux->in_gap = 0;
1345 if (demux->segment.stop == GST_CLOCK_TIME_NONE &&
1346 demux->segment.duration > 0) {
1347 /* slight HACK; prevent clipping of last bit */
1348 demux->segment.stop = demux->segment.duration + demux->in_gap;
1349 }
1351 /* FIXME : only if ACCURATE ! */
1352 if (G_LIKELY (!demux->accurate
1353 && (GST_CLOCK_TIME_IS_VALID (payload->ts)))) {
1354 GST_DEBUG ("Adjusting newsegment start to %" GST_TIME_FORMAT,
1355 GST_TIME_ARGS (payload->ts));
1356 demux->segment.start = payload->ts;
1357 demux->segment.time = payload->ts;
1358 }
1360 GST_DEBUG_OBJECT (demux, "sending new-segment event %" GST_SEGMENT_FORMAT,
1361 &demux->segment);
1363 /* note: we fix up all timestamps to start from 0, so this should be ok */
1364 gst_asf_demux_send_event_unlocked (demux,
1365 gst_event_new_new_segment (FALSE, demux->segment.rate,
1366 GST_FORMAT_TIME, demux->segment.start, demux->segment.stop,
1367 demux->segment.start));
1369 /* now post any global tags we may have found */
1370 if (demux->taglist == NULL)
1371 demux->taglist = gst_tag_list_new ();
1373 gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
1374 GST_TAG_CONTAINER_FORMAT, "ASF", NULL);
1376 GST_DEBUG_OBJECT (demux, "global tags: %" GST_PTR_FORMAT, demux->taglist);
1377 gst_element_found_tags (GST_ELEMENT (demux), demux->taglist);
1378 demux->taglist = NULL;
1380 demux->need_newsegment = FALSE;
1381 demux->segment_running = TRUE;
1382 }
1384 /* Do we have tags pending for this stream? */
1385 if (G_UNLIKELY (stream->pending_tags)) {
1386 GST_LOG_OBJECT (stream->pad, "%" GST_PTR_FORMAT, stream->pending_tags);
1387 gst_element_found_tags_for_pad (GST_ELEMENT (demux), stream->pad,
1388 stream->pending_tags);
1389 stream->pending_tags = NULL;
1390 }
1392 /* We have the whole packet now so we should push the packet to
1393 * the src pad now. First though we should check if we need to do
1394 * descrambling */
1395 if (G_UNLIKELY (demux->span > 1)) {
1396 gst_asf_demux_descramble_buffer (demux, stream, &payload->buf);
1397 }
1399 payload->buf = gst_buffer_make_metadata_writable (payload->buf);
1401 if (G_LIKELY (!payload->keyframe)) {
1402 GST_BUFFER_FLAG_SET (payload->buf, GST_BUFFER_FLAG_DELTA_UNIT);
1403 }
1405 if (G_UNLIKELY (stream->discont)) {
1406 GST_DEBUG_OBJECT (stream->pad, "marking DISCONT on stream");
1407 GST_BUFFER_FLAG_SET (payload->buf, GST_BUFFER_FLAG_DISCONT);
1408 stream->discont = FALSE;
1409 }
1411 if (G_UNLIKELY (stream->is_video && payload->par_x && payload->par_y &&
1412 (payload->par_x != stream->par_x) &&
1413 (payload->par_y != stream->par_y))) {
1414 GST_DEBUG ("Updating PAR (%d/%d => %d/%d)",
1415 stream->par_x, stream->par_y, payload->par_x, payload->par_y);
1416 stream->par_x = payload->par_x;
1417 stream->par_y = payload->par_y;
1418 gst_caps_set_simple (stream->caps, "pixel-aspect-ratio",
1419 GST_TYPE_FRACTION, stream->par_x, stream->par_y, NULL);
1420 gst_pad_set_caps (stream->pad, stream->caps);
1421 }
1423 if (G_UNLIKELY (stream->interlaced != payload->interlaced)) {
1424 GST_DEBUG ("Updating interlaced status (%d => %d)", stream->interlaced,
1425 payload->interlaced);
1426 stream->interlaced = payload->interlaced;
1427 gst_caps_set_simple (stream->caps, "interlaced", G_TYPE_BOOLEAN,
1428 stream->interlaced, NULL);
1429 }
1431 gst_buffer_set_caps (payload->buf, stream->caps);
1433 /* (sort of) interpolate timestamps using upstream "frame of reference",
1434 * typically useful for live src, but might (unavoidably) mess with
1435 * position reporting if a live src is playing not so live content
1436 * (e.g. rtspsrc taking some time to fall back to tcp) */
1437 GST_BUFFER_TIMESTAMP (payload->buf) = payload->ts + demux->in_gap;
1438 if (payload->duration == GST_CLOCK_TIME_NONE
1439 && stream->ext_props.avg_time_per_frame != 0)
1440 GST_BUFFER_DURATION (payload->buf) =
1441 stream->ext_props.avg_time_per_frame * 100;
1442 else
1443 GST_BUFFER_DURATION (payload->buf) = payload->duration;
1445 /* FIXME: we should really set durations on buffers if we can */
1447 GST_LOG_OBJECT (stream->pad, "pushing buffer, ts=%" GST_TIME_FORMAT
1448 ", dur=%" GST_TIME_FORMAT " size=%u",
1449 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (payload->buf)),
1450 GST_TIME_ARGS (GST_BUFFER_DURATION (payload->buf)),
1451 GST_BUFFER_SIZE (payload->buf));
1453 ret = gst_pad_push (stream->pad, payload->buf);
1454 ret = gst_asf_demux_aggregate_flow_return (demux, stream, ret);
1455 payload->buf = NULL;
1456 g_array_remove_index (stream->payloads, 0);
1458 /* Break out as soon as we have an issue */
1459 if (G_UNLIKELY (ret != GST_FLOW_OK))
1460 break;
1461 }
1463 return ret;
1464 }
1466 static gboolean
1467 gst_asf_demux_check_buffer_is_header (GstASFDemux * demux, GstBuffer * buf)
1468 {
1469 AsfObject obj;
1470 g_assert (buf != NULL);
1472 GST_LOG_OBJECT (demux, "Checking if buffer is a header");
1474 /* we return false on buffer too small */
1475 if (GST_BUFFER_SIZE (buf) < ASF_OBJECT_HEADER_SIZE)
1476 return FALSE;
1478 /* check if it is a header */
1479 asf_demux_peek_object (demux, GST_BUFFER_DATA (buf),
1480 ASF_OBJECT_HEADER_SIZE, &obj, TRUE);
1481 if (obj.id == ASF_OBJ_HEADER) {
1482 return TRUE;
1483 }
1484 return FALSE;
1485 }
1487 static gboolean
1488 gst_asf_demux_check_chained_asf (GstASFDemux * demux)
1489 {
1490 guint64 off = demux->data_offset + (demux->packet * demux->packet_size);
1491 GstFlowReturn ret = GST_FLOW_OK;
1492 GstBuffer *buf = NULL;
1493 gboolean header = FALSE;
1495 /* TODO maybe we should skip index objects after the data and look
1496 * further for a new header */
1497 if (gst_asf_demux_pull_data (demux, off, ASF_OBJECT_HEADER_SIZE, &buf, &ret)) {
1498 g_assert (buf != NULL);
1499 /* check if it is a header */
1500 if (gst_asf_demux_check_buffer_is_header (demux, buf)) {
1501 GST_DEBUG_OBJECT (demux, "new base offset: %" G_GUINT64_FORMAT, off);
1502 demux->base_offset = off;
1503 header = TRUE;
1504 }
1506 gst_buffer_unref (buf);
1507 }
1509 return header;
1510 }
1512 static void
1513 gst_asf_demux_loop (GstASFDemux * demux)
1514 {
1515 GstFlowReturn flow = GST_FLOW_OK;
1516 GstBuffer *buf = NULL;
1517 guint64 off;
1518 gboolean sent_eos = FALSE;
1520 if (G_UNLIKELY (demux->state == GST_ASF_DEMUX_STATE_HEADER)) {
1521 if (!gst_asf_demux_pull_headers (demux)) {
1522 flow = GST_FLOW_ERROR;
1523 goto pause;
1524 }
1526 gst_asf_demux_pull_indices (demux);
1527 }
1529 g_assert (demux->state == GST_ASF_DEMUX_STATE_DATA);
1531 if (G_UNLIKELY (demux->num_packets != 0
1532 && demux->packet >= demux->num_packets))
1533 goto eos;
1535 GST_LOG_OBJECT (demux, "packet %u/%u", (guint) demux->packet + 1,
1536 (guint) demux->num_packets);
1538 off = demux->data_offset + (demux->packet * demux->packet_size);
1540 if (G_UNLIKELY (!gst_asf_demux_pull_data (demux, off,
1541 demux->packet_size * demux->speed_packets, &buf, &flow))) {
1542 GST_DEBUG_OBJECT (demux, "got flow %s", gst_flow_get_name (flow));
1543 if (flow == GST_FLOW_UNEXPECTED)
1544 goto eos;
1545 else if (flow == GST_FLOW_WRONG_STATE) {
1546 GST_DEBUG_OBJECT (demux, "Not fatal");
1547 goto pause;
1548 } else
1549 goto read_failed;
1550 }
1552 if (G_LIKELY (demux->speed_packets == 1)) {
1553 /* FIXME: maybe we should just skip broken packets and error out only
1554 * after a few broken packets in a row? */
1555 if (G_UNLIKELY (!gst_asf_demux_parse_packet (demux, buf))) {
1556 /* when we don't know when the data object ends, we should check
1557 * for a chained asf */
1558 if (demux->num_packets == 0) {
1559 if (gst_asf_demux_check_buffer_is_header (demux, buf)) {
1560 GST_INFO_OBJECT (demux, "Chained asf found");
1561 demux->base_offset = off;
1562 gst_asf_demux_reset (demux, TRUE);
1563 gst_buffer_unref (buf);
1564 return;
1565 }
1566 }
1567 goto parse_error;
1568 }
1570 flow = gst_asf_demux_push_complete_payloads (demux, FALSE);
1572 ++demux->packet;
1574 } else {
1575 guint n;
1576 for (n = 0; n < demux->speed_packets; n++) {
1577 GstBuffer *sub;
1579 sub =
1580 gst_buffer_create_sub (buf, n * demux->packet_size,
1581 demux->packet_size);
1582 /* FIXME: maybe we should just skip broken packets and error out only
1583 * after a few broken packets in a row? */
1584 if (G_UNLIKELY (!gst_asf_demux_parse_packet (demux, sub))) {
1585 /* when we don't know when the data object ends, we should check
1586 * for a chained asf */
1587 if (demux->num_packets == 0) {
1588 if (gst_asf_demux_check_buffer_is_header (demux, sub)) {
1589 GST_INFO_OBJECT (demux, "Chained asf found");
1590 demux->base_offset = off + n * demux->packet_size;
1591 gst_asf_demux_reset (demux, TRUE);
1592 gst_buffer_unref (sub);
1593 gst_buffer_unref (buf);
1594 return;
1595 }
1596 }
1597 goto parse_error;
1598 }
1600 gst_buffer_unref (sub);
1602 flow = gst_asf_demux_push_complete_payloads (demux, FALSE);
1604 ++demux->packet;
1606 }
1608 /* reset speed pull */
1609 demux->speed_packets = 1;
1610 }
1612 gst_buffer_unref (buf);
1614 if (G_UNLIKELY (demux->num_packets > 0
1615 && demux->packet >= demux->num_packets)) {
1616 GST_LOG_OBJECT (demux, "reached EOS");
1617 goto eos;
1618 }
1620 if (G_UNLIKELY (flow != GST_FLOW_OK)) {
1621 GST_DEBUG_OBJECT (demux, "pushing complete payloads failed");
1622 goto pause;
1623 }
1625 /* check if we're at the end of the configured segment */
1626 /* FIXME: check if segment end reached etc. */
1628 return;
1630 eos:
1631 {
1632 /* if we haven't activated our streams yet, this might be because we have
1633 * less data queued than required for preroll; force stream activation and
1634 * send any pending payloads before sending EOS */
1635 if (!demux->activated_streams)
1636 gst_asf_demux_push_complete_payloads (demux, TRUE);
1638 /* we want to push an eos or post a segment-done in any case */
1639 if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
1640 gint64 stop;
1642 /* for segment playback we need to post when (in stream time)
1643 * we stopped, this is either stop (when set) or the duration. */
1644 if ((stop = demux->segment.stop) == -1)
1645 stop = demux->segment.duration;
1647 GST_INFO_OBJECT (demux, "Posting segment-done, at end of segment");
1648 gst_element_post_message (GST_ELEMENT_CAST (demux),
1649 gst_message_new_segment_done (GST_OBJECT (demux), GST_FORMAT_TIME,
1650 stop));
1651 } else if (flow != GST_FLOW_UNEXPECTED) {
1652 /* check if we have a chained asf, in case, we don't eos yet */
1653 if (gst_asf_demux_check_chained_asf (demux)) {
1654 GST_INFO_OBJECT (demux, "Chained ASF starting");
1655 gst_asf_demux_reset (demux, TRUE);
1656 return;
1657 }
1658 }
1659 /* normal playback, send EOS to all linked pads */
1660 GST_INFO_OBJECT (demux, "Sending EOS, at end of stream");
1661 gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
1662 sent_eos = TRUE;
1663 /* ... and fall through to pause */
1664 }
1665 pause:
1666 {
1667 GST_DEBUG_OBJECT (demux, "pausing task, flow return: %s",
1668 gst_flow_get_name (flow));
1669 demux->segment_running = FALSE;
1670 gst_pad_pause_task (demux->sinkpad);
1672 /* For the error cases (not EOS) */
1673 if (!sent_eos) {
1674 if (flow == GST_FLOW_UNEXPECTED)
1675 gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
1676 else if (flow < GST_FLOW_UNEXPECTED || flow == GST_FLOW_NOT_LINKED) {
1677 /* Post an error. Hopefully something else already has, but if not... */
1678 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
1679 (_("Internal data stream error.")),
1680 ("streaming stopped, reason %s", gst_flow_get_name (flow)));
1681 }
1682 }
1683 return;
1684 }
1686 /* ERRORS */
1687 read_failed:
1688 {
1689 GST_DEBUG_OBJECT (demux, "Read failed, doh");
1690 gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
1691 flow = GST_FLOW_UNEXPECTED;
1692 goto pause;
1693 }
1694 parse_error:
1695 {
1696 gst_buffer_unref (buf);
1697 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
1698 ("Error parsing ASF packet %u", (guint) demux->packet));
1699 gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
1700 flow = GST_FLOW_ERROR;
1701 goto pause;
1702 }
1703 }
1705 #define GST_ASF_DEMUX_CHECK_HEADER_YES 0
1706 #define GST_ASF_DEMUX_CHECK_HEADER_NO 1
1707 #define GST_ASF_DEMUX_CHECK_HEADER_NEED_DATA 2
1709 static gint
1710 gst_asf_demux_check_header (GstASFDemux * demux)
1711 {
1712 AsfObject obj;
1713 guint8 *cdata = (guint8 *) gst_adapter_peek (demux->adapter,
1714 ASF_OBJECT_HEADER_SIZE);
1715 if (cdata == NULL) /* need more data */
1716 return GST_ASF_DEMUX_CHECK_HEADER_NEED_DATA;
1718 asf_demux_peek_object (demux, cdata, ASF_OBJECT_HEADER_SIZE, &obj, FALSE);
1719 if (obj.id != ASF_OBJ_HEADER) {
1720 return GST_ASF_DEMUX_CHECK_HEADER_NO;
1721 } else {
1722 return GST_ASF_DEMUX_CHECK_HEADER_YES;
1723 }
1724 }
1726 static GstFlowReturn
1727 gst_asf_demux_chain (GstPad * pad, GstBuffer * buf)
1728 {
1729 GstFlowReturn ret = GST_FLOW_OK;
1730 GstASFDemux *demux;
1732 demux = GST_ASF_DEMUX (GST_PAD_PARENT (pad));
1734 GST_LOG_OBJECT (demux, "buffer: size=%u, offset=%" G_GINT64_FORMAT ", time=%"
1735 GST_TIME_FORMAT, GST_BUFFER_SIZE (buf), GST_BUFFER_OFFSET (buf),
1736 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)));
1738 if (G_UNLIKELY (GST_BUFFER_IS_DISCONT (buf))) {
1739 GST_DEBUG_OBJECT (demux, "received DISCONT");
1740 gst_asf_demux_mark_discont (demux);
1741 }
1743 if (G_UNLIKELY ((!GST_CLOCK_TIME_IS_VALID (demux->in_gap) &&
1744 GST_BUFFER_TIMESTAMP_IS_VALID (buf)))) {
1745 demux->in_gap = GST_BUFFER_TIMESTAMP (buf) - demux->in_segment.start;
1746 GST_DEBUG_OBJECT (demux, "upstream segment start %" GST_TIME_FORMAT
1747 ", interpolation gap: %" GST_TIME_FORMAT,
1748 GST_TIME_ARGS (demux->in_segment.start), GST_TIME_ARGS (demux->in_gap));
1749 }
1751 gst_adapter_push (demux->adapter, buf);
1753 switch (demux->state) {
1754 case GST_ASF_DEMUX_STATE_INDEX:{
1755 gint result = gst_asf_demux_check_header (demux);
1756 if (result == GST_ASF_DEMUX_CHECK_HEADER_NEED_DATA) /* need more data */
1757 break;
1759 if (result == GST_ASF_DEMUX_CHECK_HEADER_NO) {
1760 /* we don't care about this, probably an index */
1761 /* TODO maybe would be smarter to skip all the indices
1762 * until we got a new header or EOS to decide */
1763 GST_LOG_OBJECT (demux, "Received index object, its EOS");
1764 goto eos;
1765 } else {
1766 GST_INFO_OBJECT (demux, "Chained asf starting");
1767 /* cleanup and get ready for a chained asf */
1768 gst_asf_demux_reset (demux, TRUE);
1769 /* fall through */
1770 }
1771 }
1772 case GST_ASF_DEMUX_STATE_HEADER:{
1773 ret = gst_asf_demux_chain_headers (demux);
1774 if (demux->state != GST_ASF_DEMUX_STATE_DATA)
1775 break;
1776 /* otherwise fall through */
1777 }
1778 case GST_ASF_DEMUX_STATE_DATA:
1779 {
1780 guint64 data_size;
1782 data_size = demux->packet_size;
1784 while (gst_adapter_available (demux->adapter) >= data_size) {
1785 GstBuffer *buf;
1787 /* we don't know the length of the stream
1788 * check for a chained asf everytime */
1789 if (demux->num_packets == 0) {
1790 gint result = gst_asf_demux_check_header (demux);
1792 if (result == GST_ASF_DEMUX_CHECK_HEADER_YES) {
1793 GST_INFO_OBJECT (demux, "Chained asf starting");
1794 /* cleanup and get ready for a chained asf */
1795 gst_asf_demux_reset (demux, TRUE);
1796 break;
1797 }
1798 } else if (G_UNLIKELY (demux->num_packets != 0 && demux->packet >= 0
1799 && demux->packet >= demux->num_packets)) {
1800 /* do not overshoot data section when streaming */
1801 break;
1802 }
1804 buf = gst_adapter_take_buffer (demux->adapter, data_size);
1806 /* FIXME: maybe we should just skip broken packets and error out only
1807 * after a few broken packets in a row? */
1808 if (G_UNLIKELY (!gst_asf_demux_parse_packet (demux, buf))) {
1809 GST_WARNING_OBJECT (demux, "Parse error");
1810 }
1812 gst_buffer_unref (buf);
1814 ret = gst_asf_demux_push_complete_payloads (demux, FALSE);
1816 if (demux->packet >= 0)
1817 ++demux->packet;
1818 }
1819 if (G_UNLIKELY (demux->num_packets != 0 && demux->packet >= 0
1820 && demux->packet >= demux->num_packets)) {
1821 demux->state = GST_ASF_DEMUX_STATE_INDEX;
1822 }
1823 break;
1824 }
1825 default:
1826 g_assert_not_reached ();
1827 }
1829 done:
1830 if (ret != GST_FLOW_OK)
1831 GST_DEBUG_OBJECT (demux, "flow: %s", gst_flow_get_name (ret));
1833 return ret;
1835 eos:
1836 {
1837 GST_DEBUG_OBJECT (demux, "Handled last packet, setting EOS");
1838 ret = GST_FLOW_UNEXPECTED;
1839 goto done;
1840 }
1841 }
1843 static inline gboolean
1844 gst_asf_demux_skip_bytes (guint num_bytes, guint8 ** p_data, guint64 * p_size)
1845 {
1846 if (*p_size < num_bytes)
1847 return FALSE;
1849 *p_data += num_bytes;
1850 *p_size -= num_bytes;
1851 return TRUE;
1852 }
1854 static inline guint8
1855 gst_asf_demux_get_uint8 (guint8 ** p_data, guint64 * p_size)
1856 {
1857 guint8 ret;
1859 g_assert (*p_size >= 1);
1860 ret = GST_READ_UINT8 (*p_data);
1861 *p_data += sizeof (guint8);
1862 *p_size -= sizeof (guint8);
1863 return ret;
1864 }
1866 static inline guint16
1867 gst_asf_demux_get_uint16 (guint8 ** p_data, guint64 * p_size)
1868 {
1869 guint16 ret;
1871 g_assert (*p_size >= 2);
1872 ret = GST_READ_UINT16_LE (*p_data);
1873 *p_data += sizeof (guint16);
1874 *p_size -= sizeof (guint16);
1875 return ret;
1876 }
1878 static inline guint32
1879 gst_asf_demux_get_uint32 (guint8 ** p_data, guint64 * p_size)
1880 {
1881 guint32 ret;
1883 g_assert (*p_size >= 4);
1884 ret = GST_READ_UINT32_LE (*p_data);
1885 *p_data += sizeof (guint32);
1886 *p_size -= sizeof (guint32);
1887 return ret;
1888 }
1890 static inline guint64
1891 gst_asf_demux_get_uint64 (guint8 ** p_data, guint64 * p_size)
1892 {
1893 guint64 ret;
1895 g_assert (*p_size >= 8);
1896 ret = GST_READ_UINT64_LE (*p_data);
1897 *p_data += sizeof (guint64);
1898 *p_size -= sizeof (guint64);
1899 return ret;
1900 }
1902 static inline guint32
1903 gst_asf_demux_get_var_length (guint8 type, guint8 ** p_data, guint64 * p_size)
1904 {
1905 switch (type) {
1906 case 0:
1907 return 0;
1909 case 1:
1910 g_assert (*p_size >= 1);
1911 return gst_asf_demux_get_uint8 (p_data, p_size);
1913 case 2:
1914 g_assert (*p_size >= 2);
1915 return gst_asf_demux_get_uint16 (p_data, p_size);
1917 case 3:
1918 g_assert (*p_size >= 4);
1919 return gst_asf_demux_get_uint32 (p_data, p_size);
1921 default:
1922 g_assert_not_reached ();
1923 break;
1924 }
1925 return 0;
1926 }
1928 static gboolean
1929 gst_asf_demux_get_buffer (GstBuffer ** p_buf, guint num_bytes_to_read,
1930 guint8 ** p_data, guint64 * p_size)
1931 {
1932 *p_buf = NULL;
1934 if (*p_size < num_bytes_to_read)
1935 return FALSE;
1937 *p_buf = gst_buffer_new_and_alloc (num_bytes_to_read);
1938 memcpy (GST_BUFFER_DATA (*p_buf), *p_data, num_bytes_to_read);
1939 *p_data += num_bytes_to_read;
1940 *p_size -= num_bytes_to_read;
1941 return TRUE;
1942 }
1944 static gboolean
1945 gst_asf_demux_get_bytes (guint8 ** p_buf, guint num_bytes_to_read,
1946 guint8 ** p_data, guint64 * p_size)
1947 {
1948 *p_buf = NULL;
1950 if (*p_size < num_bytes_to_read)
1951 return FALSE;
1953 *p_buf = g_memdup (*p_data, num_bytes_to_read);
1954 *p_data += num_bytes_to_read;
1955 *p_size -= num_bytes_to_read;
1956 return TRUE;
1957 }
1959 static gboolean
1960 gst_asf_demux_get_string (gchar ** p_str, guint16 * p_strlen,
1961 guint8 ** p_data, guint64 * p_size)
1962 {
1963 guint16 s_length;
1964 guint8 *s;
1966 *p_str = NULL;
1968 if (*p_size < 2)
1969 return FALSE;
1971 s_length = gst_asf_demux_get_uint16 (p_data, p_size);
1973 if (p_strlen)
1974 *p_strlen = s_length;
1976 if (s_length == 0) {
1977 GST_WARNING ("zero-length string");
1978 *p_str = g_strdup ("");
1979 return TRUE;
1980 }
1982 if (!gst_asf_demux_get_bytes (&s, s_length, p_data, p_size))
1983 return FALSE;
1985 g_assert (s != NULL);
1987 /* just because They don't exist doesn't
1988 * mean They are not out to get you ... */
1989 if (s[s_length - 1] != '\0') {
1990 s = g_realloc (s, s_length + 1);
1991 s[s_length] = '\0';
1992 }
1994 *p_str = (gchar *) s;
1995 return TRUE;
1996 }
1999 static void
2000 gst_asf_demux_get_guid (ASFGuid * guid, guint8 ** p_data, guint64 * p_size)
2001 {
2002 g_assert (*p_size >= 4 * sizeof (guint32));
2004 guid->v1 = gst_asf_demux_get_uint32 (p_data, p_size);
2005 guid->v2 = gst_asf_demux_get_uint32 (p_data, p_size);
2006 guid->v3 = gst_asf_demux_get_uint32 (p_data, p_size);
2007 guid->v4 = gst_asf_demux_get_uint32 (p_data, p_size);
2008 }
2010 static gboolean
2011 gst_asf_demux_get_stream_audio (asf_stream_audio * audio, guint8 ** p_data,
2012 guint64 * p_size)
2013 {
2014 if (*p_size < (2 + 2 + 4 + 4 + 2 + 2 + 2))
2015 return FALSE;
2017 /* WAVEFORMATEX Structure */
2018 audio->codec_tag = gst_asf_demux_get_uint16 (p_data, p_size);
2019 audio->channels = gst_asf_demux_get_uint16 (p_data, p_size);
2020 audio->sample_rate = gst_asf_demux_get_uint32 (p_data, p_size);
2021 audio->byte_rate = gst_asf_demux_get_uint32 (p_data, p_size);
2022 audio->block_align = gst_asf_demux_get_uint16 (p_data, p_size);
2023 audio->word_size = gst_asf_demux_get_uint16 (p_data, p_size);
2024 /* Codec specific data size */
2025 audio->size = gst_asf_demux_get_uint16 (p_data, p_size);
2026 return TRUE;
2027 }
2029 static gboolean
2030 gst_asf_demux_get_stream_video (asf_stream_video * video, guint8 ** p_data,
2031 guint64 * p_size)
2032 {
2033 if (*p_size < (4 + 4 + 1 + 2))
2034 return FALSE;
2036 video->width = gst_asf_demux_get_uint32 (p_data, p_size);
2037 video->height = gst_asf_demux_get_uint32 (p_data, p_size);
2038 video->unknown = gst_asf_demux_get_uint8 (p_data, p_size);
2039 video->size = gst_asf_demux_get_uint16 (p_data, p_size);
2040 return TRUE;
2041 }
2043 static gboolean
2044 gst_asf_demux_get_stream_video_format (asf_stream_video_format * fmt,
2045 guint8 ** p_data, guint64 * p_size)
2046 {
2047 if (*p_size < (4 + 4 + 4 + 2 + 2 + 4 + 4 + 4 + 4 + 4 + 4))
2048 return FALSE;
2050 fmt->size = gst_asf_demux_get_uint32 (p_data, p_size);
2051 fmt->width = gst_asf_demux_get_uint32 (p_data, p_size);
2052 fmt->height = gst_asf_demux_get_uint32 (p_data, p_size);
2053 fmt->planes = gst_asf_demux_get_uint16 (p_data, p_size);
2054 fmt->depth = gst_asf_demux_get_uint16 (p_data, p_size);
2055 fmt->tag = gst_asf_demux_get_uint32 (p_data, p_size);
2056 fmt->image_size = gst_asf_demux_get_uint32 (p_data, p_size);
2057 fmt->xpels_meter = gst_asf_demux_get_uint32 (p_data, p_size);
2058 fmt->ypels_meter = gst_asf_demux_get_uint32 (p_data, p_size);
2059 fmt->num_colors = gst_asf_demux_get_uint32 (p_data, p_size);
2060 fmt->imp_colors = gst_asf_demux_get_uint32 (p_data, p_size);
2061 return TRUE;
2062 }
2064 AsfStream *
2065 gst_asf_demux_get_stream (GstASFDemux * demux, guint16 id)
2066 {
2067 guint i;
2069 for (i = 0; i < demux->num_streams; i++) {
2070 if (demux->stream[i].id == id)
2071 return &demux->stream[i];
2072 }
2074 GST_WARNING ("Segment found for undefined stream: (%d)", id);
2075 return NULL;
2076 }
2078 static void
2079 gst_asf_demux_setup_pad (GstASFDemux * demux, GstPad * src_pad,
2080 GstCaps * caps, guint16 id, gboolean is_video, GstTagList * tags)
2081 {
2082 AsfStream *stream;
2084 gst_pad_use_fixed_caps (src_pad);
2085 gst_pad_set_caps (src_pad, caps);
2087 gst_pad_set_event_function (src_pad,
2088 GST_DEBUG_FUNCPTR (gst_asf_demux_handle_src_event));
2089 gst_pad_set_query_type_function (src_pad,
2090 GST_DEBUG_FUNCPTR (gst_asf_demux_get_src_query_types));
2091 gst_pad_set_query_function (src_pad,
2092 GST_DEBUG_FUNCPTR (gst_asf_demux_handle_src_query));
2094 stream = &demux->stream[demux->num_streams];
2095 stream->caps = caps;
2096 stream->pad = src_pad;
2097 stream->id = id;
2098 stream->fps_known = !is_video; /* bit hacky for audio */
2099 stream->is_video = is_video;
2100 stream->pending_tags = tags;
2101 stream->discont = TRUE;
2102 if (is_video) {
2103 GstStructure *st;
2104 gint par_x, par_y;
2105 st = gst_caps_get_structure (caps, 0);
2106 if (gst_structure_get_fraction (st, "pixel-aspect-ratio", &par_x, &par_y) &&
2107 par_x > 0 && par_y > 0) {
2108 GST_DEBUG ("PAR %d/%d", par_x, par_y);
2109 stream->par_x = par_x;
2110 stream->par_y = par_y;
2111 }
2112 }
2114 stream->payloads = g_array_new (FALSE, FALSE, sizeof (AsfPayload));
2116 GST_INFO ("Created pad %s for stream %u with caps %" GST_PTR_FORMAT,
2117 GST_PAD_NAME (src_pad), demux->num_streams, caps);
2119 ++demux->num_streams;
2121 stream->active = FALSE;
2122 }
2124 static void
2125 gst_asf_demux_add_audio_stream (GstASFDemux * demux,
2126 asf_stream_audio * audio, guint16 id, guint8 ** p_data, guint64 * p_size)
2127 {
2128 GstTagList *tags = NULL;
2129 GstBuffer *extradata = NULL;
2130 GstPad *src_pad;
2131 GstCaps *caps;
2132 guint16 size_left = 0;
2133 gchar *codec_name = NULL;
2134 gchar *name = NULL;
2136 size_left = audio->size;
2138 /* Create the audio pad */
2139 name = g_strdup_printf ("audio_%02d", demux->num_audio_streams);
2141 src_pad = gst_pad_new_from_static_template (&audio_src_template, name);
2142 g_free (name);
2144 /* Swallow up any left over data and set up the
2145 * standard properties from the header info */
2146 if (size_left) {
2147 GST_INFO_OBJECT (demux, "Audio header contains %d bytes of "
2148 "codec specific data", size_left);
2150 g_assert (size_left <= *p_size);
2151 gst_asf_demux_get_buffer (&extradata, size_left, p_data, p_size);
2152 }
2154 /* asf_stream_audio is the same as gst_riff_strf_auds, but with an
2155 * additional two bytes indicating extradata. */
2156 caps = gst_riff_create_audio_caps (audio->codec_tag, NULL,
2157 (gst_riff_strf_auds *) audio, extradata, NULL, &codec_name);
2159 if (caps == NULL) {
2160 caps = gst_caps_new_simple ("audio/x-asf-unknown", "codec_id",
2161 G_TYPE_INT, (gint) audio->codec_tag, NULL);
2162 }
2164 /* Informing about that audio format we just added */
2165 if (codec_name) {
2166 tags = gst_tag_list_new ();
2167 gst_tag_list_add (tags, GST_TAG_MERGE_APPEND, GST_TAG_AUDIO_CODEC,
2168 codec_name, NULL);
2169 g_free (codec_name);
2170 }
2172 if (extradata)
2173 gst_buffer_unref (extradata);
2175 GST_INFO ("Adding audio stream #%u, id %u codec %u (0x%04x), tags=%"
2176 GST_PTR_FORMAT, demux->num_audio_streams, id, audio->codec_tag,
2177 audio->codec_tag, tags);
2179 ++demux->num_audio_streams;
2181 gst_asf_demux_setup_pad (demux, src_pad, caps, id, FALSE, tags);
2182 }
2184 static void
2185 gst_asf_demux_add_video_stream (GstASFDemux * demux,
2186 asf_stream_video_format * video, guint16 id,
2187 guint8 ** p_data, guint64 * p_size)
2188 {
2189 GstTagList *tags = NULL;
2190 GstBuffer *extradata = NULL;
2191 GstPad *src_pad;
2192 GstCaps *caps;
2193 gchar *name = NULL;
2194 gchar *codec_name = NULL;
2195 gint size_left = video->size - 40;
2197 /* Create the video pad */
2198 name = g_strdup_printf ("video_%02d", demux->num_video_streams);
2199 src_pad = gst_pad_new_from_static_template (&video_src_template, name);
2200 g_free (name);
2202 /* Now try some gstreamer formatted MIME types (from gst_avi_demux_strf_vids) */
2203 if (size_left) {
2204 GST_LOG ("Video header has %d bytes of codec specific data", size_left);
2205 g_assert (size_left <= *p_size);
2206 gst_asf_demux_get_buffer (&extradata, size_left, p_data, p_size);
2207 }
2209 GST_DEBUG ("video codec %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (video->tag));
2211 /* yes, asf_stream_video_format and gst_riff_strf_vids are the same */
2212 caps = gst_riff_create_video_caps (video->tag, NULL,
2213 (gst_riff_strf_vids *) video, extradata, NULL, &codec_name);
2215 if (caps == NULL) {
2216 caps = gst_caps_new_simple ("video/x-asf-unknown", "fourcc",
2217 GST_TYPE_FOURCC, video->tag, NULL);
2218 } else {
2219 GstStructure *s;
2220 gint ax, ay;
2222 s = gst_asf_demux_get_metadata_for_stream (demux, id);
2223 if (gst_structure_get_int (s, "AspectRatioX", &ax) &&
2224 gst_structure_get_int (s, "AspectRatioY", &ay) && (ax > 0 && ay > 0)) {
2225 gst_caps_set_simple (caps, "pixel-aspect-ratio", GST_TYPE_FRACTION,
2226 ax, ay, NULL);
2228 } else {
2229 guint ax, ay;
2230 /* retry with the global metadata */
2231 GST_DEBUG ("Retrying with global metadata %" GST_PTR_FORMAT,
2232 demux->global_metadata);
2233 s = demux->global_metadata;
2234 if (gst_structure_get_uint (s, "AspectRatioX", &ax) &&
2235 gst_structure_get_uint (s, "AspectRatioY", &ay)) {
2236 GST_DEBUG ("ax:%d, ay:%d", ax, ay);
2237 if (ax > 0 && ay > 0)
2238 gst_caps_set_simple (caps, "pixel-aspect-ratio", GST_TYPE_FRACTION,
2239 ax, ay, NULL);
2240 }
2241 }
2242 s = gst_caps_get_structure (caps, 0);
2243 gst_structure_remove_field (s, "framerate");
2244 }
2246 /* add fourcc format to caps, some proprietary decoders seem to need it */
2247 gst_caps_set_simple (caps, "format", GST_TYPE_FOURCC, video->tag, NULL);
2249 if (codec_name) {
2250 tags = gst_tag_list_new ();
2251 gst_tag_list_add (tags, GST_TAG_MERGE_APPEND, GST_TAG_VIDEO_CODEC,
2252 codec_name, NULL);
2253 g_free (codec_name);
2254 }
2256 if (extradata)
2257 gst_buffer_unref (extradata);
2259 GST_INFO ("Adding video stream #%u, id %u, codec %"
2260 GST_FOURCC_FORMAT " (0x%08x)", demux->num_video_streams, id,
2261 GST_FOURCC_ARGS (video->tag), video->tag);
2263 ++demux->num_video_streams;
2265 gst_asf_demux_setup_pad (demux, src_pad, caps, id, TRUE, tags);
2266 }
2268 static void
2269 gst_asf_demux_activate_stream (GstASFDemux * demux, AsfStream * stream)
2270 {
2271 if (!stream->active) {
2272 GST_INFO_OBJECT (demux, "Activating stream %2u, pad %s, caps %"
2273 GST_PTR_FORMAT, stream->id, GST_PAD_NAME (stream->pad), stream->caps);
2274 gst_pad_set_active (stream->pad, TRUE);
2275 gst_element_add_pad (GST_ELEMENT_CAST (demux), stream->pad);
2276 stream->active = TRUE;
2277 }
2278 }
2280 static AsfStream *
2281 gst_asf_demux_parse_stream_object (GstASFDemux * demux, guint8 * data,
2282 guint64 size)
2283 {
2284 AsfCorrectionType correction_type;
2285 AsfStreamType stream_type;
2286 GstClockTime time_offset;
2287 gboolean is_encrypted G_GNUC_UNUSED;
2288 guint16 stream_id;
2289 guint16 flags;
2290 ASFGuid guid;
2291 guint stream_specific_size;
2292 guint type_specific_size G_GNUC_UNUSED;
2293 guint unknown G_GNUC_UNUSED;
2295 /* Get the rest of the header's header */
2296 if (size < (16 + 16 + 8 + 4 + 4 + 2 + 4))
2297 goto not_enough_data;
2299 gst_asf_demux_get_guid (&guid, &data, &size);
2300 stream_type = gst_asf_demux_identify_guid (asf_stream_guids, &guid);
2302 gst_asf_demux_get_guid (&guid, &data, &size);
2303 correction_type = gst_asf_demux_identify_guid (asf_correction_guids, &guid);
2305 time_offset = gst_asf_demux_get_uint64 (&data, &size) * 100;
2307 type_specific_size = gst_asf_demux_get_uint32 (&data, &size);
2308 stream_specific_size = gst_asf_demux_get_uint32 (&data, &size);
2310 flags = gst_asf_demux_get_uint16 (&data, &size);
2311 stream_id = flags & 0x7f;
2312 is_encrypted = ! !((flags & 0x8000) << 15);
2313 unknown = gst_asf_demux_get_uint32 (&data, &size);
2315 GST_DEBUG_OBJECT (demux, "Found stream %u, time_offset=%" GST_TIME_FORMAT,
2316 stream_id, GST_TIME_ARGS (time_offset));
2318 switch (stream_type) {
2319 case ASF_STREAM_AUDIO:{
2320 asf_stream_audio audio_object;
2322 if (!gst_asf_demux_get_stream_audio (&audio_object, &data, &size))
2323 goto not_enough_data;
2325 GST_INFO ("Object is an audio stream with %u bytes of additional data",
2326 audio_object.size);
2328 gst_asf_demux_add_audio_stream (demux, &audio_object, stream_id,
2329 &data, &size);
2331 switch (correction_type) {
2332 case ASF_CORRECTION_ON:{
2333 guint span, packet_size, chunk_size, data_size, silence_data;
2335 GST_INFO ("Using error correction");
2337 if (size < (1 + 2 + 2 + 2 + 1))
2338 goto not_enough_data;
2340 span = gst_asf_demux_get_uint8 (&data, &size);
2341 packet_size = gst_asf_demux_get_uint16 (&data, &size);
2342 chunk_size = gst_asf_demux_get_uint16 (&data, &size);
2343 data_size = gst_asf_demux_get_uint16 (&data, &size);
2344 silence_data = gst_asf_demux_get_uint8 (&data, &size);
2346 /* FIXME: shouldn't this be per-stream? */
2347 demux->span = span;
2349 GST_DEBUG_OBJECT (demux, "Descrambling ps:%u cs:%u ds:%u s:%u sd:%u",
2350 packet_size, chunk_size, data_size, span, silence_data);
2352 if (demux->span > 1) {
2353 if (chunk_size == 0 || ((packet_size / chunk_size) <= 1)) {
2354 /* Disable descrambling */
2355 demux->span = 0;
2356 } else {
2357 /* FIXME: this else branch was added for
2358 * weird_al_yankovic - the saga begins.asf */
2359 demux->ds_packet_size = packet_size;
2360 demux->ds_chunk_size = chunk_size;
2361 }
2362 } else {
2363 /* Descambling is enabled */
2364 demux->ds_packet_size = packet_size;
2365 demux->ds_chunk_size = chunk_size;
2366 }
2367 #if 0
2368 /* Now skip the rest of the silence data */
2369 if (data_size > 1)
2370 gst_bytestream_flush (demux->bs, data_size - 1);
2371 #else
2372 /* FIXME: CHECKME. And why -1? */
2373 if (data_size > 1) {
2374 if (!gst_asf_demux_skip_bytes (data_size - 1, &data, &size)) {
2375 goto not_enough_data;
2376 }
2377 }
2378 #endif
2379 break;
2380 }
2381 case ASF_CORRECTION_OFF:{
2382 GST_INFO ("Error correction off");
2383 if (!gst_asf_demux_skip_bytes (stream_specific_size, &data, &size))
2384 goto not_enough_data;
2385 break;
2386 }
2387 default:
2388 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
2389 ("Audio stream using unknown error correction"));
2390 return NULL;
2391 }
2393 break;
2394 }
2396 case ASF_STREAM_VIDEO:{
2397 asf_stream_video_format video_format_object;
2398 asf_stream_video video_object;
2399 guint16 vsize;
2401 if (!gst_asf_demux_get_stream_video (&video_object, &data, &size))
2402 goto not_enough_data;
2404 vsize = video_object.size - 40; /* Byte order gets offset by single byte */
2406 GST_INFO ("object is a video stream with %u bytes of "
2407 "additional data", vsize);
2409 if (!gst_asf_demux_get_stream_video_format (&video_format_object,
2410 &data, &size)) {
2411 goto not_enough_data;
2412 }
2414 gst_asf_demux_add_video_stream (demux, &video_format_object, stream_id,
2415 &data, &size);
2417 break;
2418 }
2420 default:
2421 GST_WARNING_OBJECT (demux, "Unknown stream type for stream %u",
2422 stream_id);
2423 break;
2424 }
2426 return gst_asf_demux_get_stream (demux, stream_id);
2428 not_enough_data:
2429 {
2430 GST_WARNING_OBJECT (demux, "Unexpected end of data parsing stream object");
2431 /* we'll error out later if we found no streams */
2432 return NULL;
2433 }
2434 }
2436 static const gchar *
2437 gst_asf_demux_get_gst_tag_from_tag_name (const gchar * name_utf8)
2438 {
2439 const struct
2440 {
2441 const gchar *asf_name;
2442 const gchar *gst_name;
2443 } tags[] = {
2444 {
2445 "WM/Genre", GST_TAG_GENRE}, {
2446 "WM/AlbumTitle", GST_TAG_ALBUM}, {
2447 "WM/AlbumArtist", GST_TAG_ARTIST}, {
2448 "WM/Picture", GST_TAG_IMAGE}, {
2449 "WM/Track", GST_TAG_TRACK_NUMBER}, {
2450 "WM/TrackNumber", GST_TAG_TRACK_NUMBER}, {
2451 "WM/Year", GST_TAG_DATE}
2452 /* { "WM/Composer", GST_TAG_COMPOSER } */
2453 };
2454 gsize out;
2455 guint i;
2457 if (name_utf8 == NULL) {
2458 GST_WARNING ("Failed to convert name to UTF8, skipping");
2459 return NULL;
2460 }
2462 out = strlen (name_utf8);
2464 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
2465 if (strncmp (tags[i].asf_name, name_utf8, out) == 0) {
2466 GST_LOG ("map tagname '%s' -> '%s'", name_utf8, tags[i].gst_name);
2467 return tags[i].gst_name;
2468 }
2469 }
2471 return NULL;
2472 }
2474 /* gst_asf_demux_add_global_tags() takes ownership of taglist! */
2475 static void
2476 gst_asf_demux_add_global_tags (GstASFDemux * demux, GstTagList * taglist)
2477 {
2478 GstTagList *t;
2480 GST_DEBUG_OBJECT (demux, "adding global tags: %" GST_PTR_FORMAT, taglist);
2482 if (taglist == NULL)
2483 return;
2485 if (gst_tag_list_is_empty (taglist)) {
2486 gst_tag_list_free (taglist);
2487 return;
2488 }
2490 t = gst_tag_list_merge (demux->taglist, taglist, GST_TAG_MERGE_APPEND);
2491 if (demux->taglist)
2492 gst_tag_list_free (demux->taglist);
2493 gst_tag_list_free (taglist);
2494 demux->taglist = t;
2495 GST_LOG_OBJECT (demux, "global tags now: %" GST_PTR_FORMAT, demux->taglist);
2496 }
2498 #define ASF_DEMUX_DATA_TYPE_UTF16LE_STRING 0
2499 #define ASF_DEMUX_DATA_TYPE_BYTE_ARRAY 1
2500 #define ASF_DEMUX_DATA_TYPE_DWORD 3
2502 static void
2503 asf_demux_parse_picture_tag (GstTagList * tags, const guint8 * tag_data,
2504 guint tag_data_len)
2505 {
2506 GstByteReader r;
2507 const guint8 *img_data = NULL;
2508 guint32 img_data_len = 0;
2509 guint8 pic_type = 0;
2511 gst_byte_reader_init (&r, tag_data, tag_data_len);
2513 /* skip mime type string (we don't trust it and do our own typefinding),
2514 * and also skip the description string, since we don't use it */
2515 if (!gst_byte_reader_get_uint8 (&r, &pic_type) ||
2516 !gst_byte_reader_get_uint32_le (&r, &img_data_len) ||
2517 !gst_byte_reader_skip_string_utf16 (&r) ||
2518 !gst_byte_reader_skip_string_utf16 (&r) ||
2519 !gst_byte_reader_get_data (&r, img_data_len, &img_data)) {
2520 goto not_enough_data;
2521 }
2524 if (!gst_tag_list_add_id3_image (tags, img_data, img_data_len, pic_type))
2525 GST_DEBUG ("failed to add image extracted from WM/Picture tag to taglist");
2527 return;
2529 not_enough_data:
2530 {
2531 GST_DEBUG ("Failed to read WM/Picture tag: not enough data");
2532 GST_MEMDUMP ("WM/Picture data", tag_data, tag_data_len);
2533 return;
2534 }
2535 }
2537 /* Extended Content Description Object */
2538 static GstFlowReturn
2539 gst_asf_demux_process_ext_content_desc (GstASFDemux * demux, guint8 * data,
2540 guint64 size)
2541 {
2542 /* Other known (and unused) 'text/unicode' metadata available :
2543 *
2544 * WM/Lyrics =
2545 * WM/MediaPrimaryClassID = {D1607DBC-E323-4BE2-86A1-48A42A28441E}
2546 * WMFSDKVersion = 9.00.00.2980
2547 * WMFSDKNeeded = 0.0.0.0000
2548 * WM/UniqueFileIdentifier = AMGa_id=R 15334;AMGp_id=P 5149;AMGt_id=T 2324984
2549 * WM/Publisher = 4AD
2550 * WM/Provider = AMG
2551 * WM/ProviderRating = 8
2552 * WM/ProviderStyle = Rock (similar to WM/Genre)
2553 * WM/GenreID (similar to WM/Genre)
2554 * WM/TrackNumber (same as WM/Track but as a string)
2555 *
2556 * Other known (and unused) 'non-text' metadata available :
2557 *
2558 * WM/EncodingTime
2559 * WM/MCDI
2560 * IsVBR
2561 *
2562 * We might want to read WM/TrackNumber and use atoi() if we don't have
2563 * WM/Track
2564 */
2566 GstTagList *taglist;
2567 guint16 blockcount, i;
2569 GST_INFO_OBJECT (demux, "object is an extended content description");
2571 taglist = gst_tag_list_new ();
2573 /* Content Descriptor Count */
2574 if (size < 2)
2575 goto not_enough_data;
2577 blockcount = gst_asf_demux_get_uint16 (&data, &size);
2579 for (i = 1; i <= blockcount; ++i) {
2580 const gchar *gst_tag_name;
2581 guint16 datatype;
2582 guint16 value_len;
2583 guint16 name_len;
2584 GValue tag_value = { 0, };
2585 gsize in, out;
2586 gchar *name;
2587 gchar *name_utf8 = NULL;
2588 gchar *value;
2590 /* Descriptor */
2591 if (!gst_asf_demux_get_string (&name, &name_len, &data, &size))
2592 goto not_enough_data;
2594 if (size < 2) {
2595 g_free (name);
2596 goto not_enough_data;
2597 }
2598 /* Descriptor Value Data Type */
2599 datatype = gst_asf_demux_get_uint16 (&data, &size);
2601 /* Descriptor Value (not really a string, but same thing reading-wise) */
2602 if (!gst_asf_demux_get_string (&value, &value_len, &data, &size)) {
2603 g_free (name);
2604 goto not_enough_data;
2605 }
2607 name_utf8 =
2608 g_convert (name, name_len, "UTF-8", "UTF-16LE", &in, &out, NULL);
2610 if (name_utf8 != NULL) {
2611 GST_DEBUG ("Found tag/metadata %s", name_utf8);
2613 gst_tag_name = gst_asf_demux_get_gst_tag_from_tag_name (name_utf8);
2614 GST_DEBUG ("gst_tag_name %s", GST_STR_NULL (gst_tag_name));
2616 switch (datatype) {
2617 case ASF_DEMUX_DATA_TYPE_UTF16LE_STRING:{
2618 gchar *value_utf8;
2620 value_utf8 = g_convert (value, value_len, "UTF-8", "UTF-16LE",
2621 &in, &out, NULL);
2623 /* get rid of tags with empty value */
2624 if (value_utf8 != NULL && *value_utf8 != '\0') {
2625 GST_DEBUG ("string value %s", value_utf8);
2627 value_utf8[out] = '\0';
2629 if (gst_tag_name != NULL) {
2630 if (strcmp (gst_tag_name, GST_TAG_DATE) == 0) {
2631 guint year = atoi (value_utf8);
2633 if (year > 0) {
2634 GDate *date = g_date_new_dmy (1, 1, year);
2636 g_value_init (&tag_value, GST_TYPE_DATE);
2637 gst_value_set_date (&tag_value, date);
2638 g_date_free (date);
2639 }
2640 } else if (strcmp (gst_tag_name, GST_TAG_GENRE) == 0) {
2641 guint id3v1_genre_id;
2642 const gchar *genre_str;
2644 if (sscanf (value_utf8, "(%u)", &id3v1_genre_id) == 1 &&
2645 ((genre_str = gst_tag_id3_genre_get (id3v1_genre_id)))) {
2646 GST_DEBUG ("Genre: %s -> %s", value_utf8, genre_str);
2647 g_free (value_utf8);
2648 value_utf8 = g_strdup (genre_str);
2649 }
2650 } else {
2651 GType tag_type;
2653 /* convert tag from string to other type if required */
2654 tag_type = gst_tag_get_type (gst_tag_name);
2655 g_value_init (&tag_value, tag_type);
2656 if (!gst_value_deserialize (&tag_value, value_utf8)) {
2657 GValue from_val = { 0, };
2659 g_value_init (&from_val, G_TYPE_STRING);
2660 g_value_set_string (&from_val, value_utf8);
2661 if (!g_value_transform (&from_val, &tag_value)) {
2662 GST_WARNING_OBJECT (demux,
2663 "Could not transform string tag to " "%s tag type %s",
2664 gst_tag_name, g_type_name (tag_type));
2665 g_value_unset (&tag_value);
2666 }
2667 g_value_unset (&from_val);
2668 }
2669 }
2670 } else {
2671 /* metadata ! */
2672 GST_DEBUG ("Setting metadata");
2673 g_value_init (&tag_value, G_TYPE_STRING);
2674 g_value_set_string (&tag_value, value_utf8);
2675 }
2676 } else if (value_utf8 == NULL) {
2677 GST_WARNING ("Failed to convert string value to UTF8, skipping");
2678 } else {
2679 GST_DEBUG ("Skipping empty string value for %s",
2680 GST_STR_NULL (gst_tag_name));
2681 }
2682 g_free (value_utf8);
2683 break;
2684 }
2685 case ASF_DEMUX_DATA_TYPE_BYTE_ARRAY:{
2686 if (gst_tag_name) {
2687 if (!g_str_equal (gst_tag_name, GST_TAG_IMAGE)) {
2688 GST_FIXME ("Unhandled byte array tag %s",
2689 GST_STR_NULL (gst_tag_name));
2690 break;
2691 } else {
2692 asf_demux_parse_picture_tag (taglist, (guint8 *) value,
2693 value_len);
2694 }
2695 }
2696 break;
2697 }
2698 case ASF_DEMUX_DATA_TYPE_DWORD:{
2699 guint uint_val = GST_READ_UINT32_LE (value);
2701 /* this is the track number */
2702 g_value_init (&tag_value, G_TYPE_UINT);
2704 /* WM/Track counts from 0 */
2705 if (!strcmp (name_utf8, "WM/Track"))
2706 ++uint_val;
2708 g_value_set_uint (&tag_value, uint_val);
2709 break;
2710 }
2711 default:{
2712 GST_DEBUG ("Skipping tag %s of type %d", gst_tag_name, datatype);
2713 break;
2714 }
2715 }
2717 if (G_IS_VALUE (&tag_value)) {
2718 if (gst_tag_name) {
2719 GstTagMergeMode merge_mode = GST_TAG_MERGE_APPEND;
2721 /* WM/TrackNumber is more reliable than WM/Track, since the latter
2722 * is supposed to have a 0 base but is often wrongly written to start
2723 * from 1 as well, so prefer WM/TrackNumber when we have it: either
2724 * replace the value added earlier from WM/Track or put it first in
2725 * the list, so that it will get picked up by _get_uint() */
2726 if (strcmp (name_utf8, "WM/TrackNumber") == 0)
2727 merge_mode = GST_TAG_MERGE_REPLACE;
2729 gst_tag_list_add_values (taglist, merge_mode, gst_tag_name,
2730 &tag_value, NULL);
2731 } else {
2732 GST_DEBUG ("Setting global metadata %s", name_utf8);
2733 gst_structure_set_value (demux->global_metadata, name_utf8,
2734 &tag_value);
2735 }
2737 g_value_unset (&tag_value);
2738 }
2739 }
2741 g_free (name);
2742 g_free (value);
2743 g_free (name_utf8);
2744 }
2746 gst_asf_demux_add_global_tags (demux, taglist);
2748 return GST_FLOW_OK;
2750 /* Errors */
2751 not_enough_data:
2752 {
2753 GST_WARNING ("Unexpected end of data parsing ext content desc object");
2754 gst_tag_list_free (taglist);
2755 return GST_FLOW_OK; /* not really fatal */
2756 }
2757 }
2759 static GstStructure *
2760 gst_asf_demux_get_metadata_for_stream (GstASFDemux * demux, guint stream_num)
2761 {
2762 gchar sname[32];
2763 guint i;
2765 g_snprintf (sname, sizeof (sname), "stream-%u", stream_num);
2767 for (i = 0; i < gst_caps_get_size (demux->metadata); ++i) {
2768 GstStructure *s;
2770 s = gst_caps_get_structure (demux->metadata, i);
2771 if (gst_structure_has_name (s, sname))
2772 return s;
2773 }
2775 gst_caps_append_structure (demux->metadata, gst_structure_empty_new (sname));
2777 /* try lookup again; demux->metadata took ownership of the structure, so we
2778 * can't really make any assumptions about what happened to it, so we can't
2779 * just return it directly after appending it */
2780 return gst_asf_demux_get_metadata_for_stream (demux, stream_num);
2781 }
2783 static GstFlowReturn
2784 gst_asf_demux_process_metadata (GstASFDemux * demux, guint8 * data,
2785 guint64 size)
2786 {
2787 guint16 blockcount, i;
2789 GST_INFO_OBJECT (demux, "object is a metadata object");
2791 /* Content Descriptor Count */
2792 if (size < 2)
2793 goto not_enough_data;
2795 blockcount = gst_asf_demux_get_uint16 (&data, &size);
2797 for (i = 0; i < blockcount; ++i) {
2798 GstStructure *s;
2799 guint16 stream_num, name_len, data_type, lang_idx G_GNUC_UNUSED;
2800 guint32 data_len, ival;
2801 gchar *name_utf8;
2803 if (size < (2 + 2 + 2 + 2 + 4))
2804 goto not_enough_data;
2806 lang_idx = gst_asf_demux_get_uint16 (&data, &size);
2807 stream_num = gst_asf_demux_get_uint16 (&data, &size);
2808 name_len = gst_asf_demux_get_uint16 (&data, &size);
2809 data_type = gst_asf_demux_get_uint16 (&data, &size);
2810 data_len = gst_asf_demux_get_uint32 (&data, &size);
2812 if (size < name_len + data_len)
2813 goto not_enough_data;
2815 /* convert name to UTF-8 */
2816 name_utf8 = g_convert ((gchar *) data, name_len, "UTF-8", "UTF-16LE",
2817 NULL, NULL, NULL);
2818 gst_asf_demux_skip_bytes (name_len, &data, &size);
2820 if (name_utf8 == NULL) {
2821 GST_WARNING ("Failed to convert value name to UTF8, skipping");
2822 gst_asf_demux_skip_bytes (data_len, &data, &size);
2823 continue;
2824 }
2826 if (data_type != ASF_DEMUX_DATA_TYPE_DWORD) {
2827 gst_asf_demux_skip_bytes (data_len, &data, &size);
2828 g_free (name_utf8);
2829 continue;
2830 }
2832 /* read DWORD */
2833 if (size < 4) {
2834 g_free (name_utf8);
2835 goto not_enough_data;
2836 }
2838 ival = gst_asf_demux_get_uint32 (&data, &size);
2840 /* skip anything else there may be, just in case */
2841 gst_asf_demux_skip_bytes (data_len - 4, &data, &size);
2843 s = gst_asf_demux_get_metadata_for_stream (demux, stream_num);
2844 gst_structure_set (s, name_utf8, G_TYPE_INT, ival, NULL);
2845 g_free (name_utf8);
2846 }
2848 GST_INFO_OBJECT (demux, "metadata = %" GST_PTR_FORMAT, demux->metadata);
2849 return GST_FLOW_OK;
2851 /* Errors */
2852 not_enough_data:
2853 {
2854 GST_WARNING ("Unexpected end of data parsing metadata object");
2855 return GST_FLOW_OK; /* not really fatal */
2856 }
2857 }
2859 static GstFlowReturn
2860 gst_asf_demux_process_header (GstASFDemux * demux, guint8 * data, guint64 size)
2861 {
2862 GstFlowReturn ret = GST_FLOW_OK;
2863 guint32 i, num_objects;
2864 guint8 unknown G_GNUC_UNUSED;
2866 /* Get the rest of the header's header */
2867 if (size < (4 + 1 + 1))
2868 goto not_enough_data;
2870 num_objects = gst_asf_demux_get_uint32 (&data, &size);
2871 unknown = gst_asf_demux_get_uint8 (&data, &size);
2872 unknown = gst_asf_demux_get_uint8 (&data, &size);
2874 GST_INFO_OBJECT (demux, "object is a header with %u parts", num_objects);
2876 /* Loop through the header's objects, processing those */
2877 for (i = 0; i < num_objects; ++i) {
2878 GST_INFO_OBJECT (demux, "reading header part %u", i);
2879 ret = gst_asf_demux_process_object (demux, &data, &size);
2880 if (ret != GST_FLOW_OK) {
2881 GST_WARNING ("process_object returned %s", gst_asf_get_flow_name (ret));
2882 break;
2883 }
2884 }
2886 return ret;
2888 not_enough_data:
2889 {
2890 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
2891 ("short read parsing HEADER object"));
2892 return GST_FLOW_ERROR;
2893 }
2894 }
2896 static GstFlowReturn
2897 gst_asf_demux_process_file (GstASFDemux * demux, guint8 * data, guint64 size)
2898 {
2899 guint64 creation_time G_GNUC_UNUSED;
2900 guint64 file_size G_GNUC_UNUSED;
2901 guint64 send_time G_GNUC_UNUSED;
2902 guint64 packets_count, play_time, preroll;
2903 guint32 flags, min_pktsize, max_pktsize, min_bitrate G_GNUC_UNUSED;
2905 if (size < (16 + 8 + 8 + 8 + 8 + 8 + 8 + 4 + 4 + 4 + 4))
2906 goto not_enough_data;
2908 gst_asf_demux_skip_bytes (16, &data, &size); /* skip GUID */
2909 file_size = gst_asf_demux_get_uint64 (&data, &size);
2910 creation_time = gst_asf_demux_get_uint64 (&data, &size);
2911 packets_count = gst_asf_demux_get_uint64 (&data, &size);
2912 play_time = gst_asf_demux_get_uint64 (&data, &size);
2913 send_time = gst_asf_demux_get_uint64 (&data, &size);
2914 preroll = gst_asf_demux_get_uint64 (&data, &size);
2915 flags = gst_asf_demux_get_uint32 (&data, &size);
2916 min_pktsize = gst_asf_demux_get_uint32 (&data, &size);
2917 max_pktsize = gst_asf_demux_get_uint32 (&data, &size);
2918 min_bitrate = gst_asf_demux_get_uint32 (&data, &size);
2920 demux->broadcast = ! !(flags & 0x01);
2921 demux->seekable = ! !(flags & 0x02);
2923 GST_DEBUG_OBJECT (demux, "min_pktsize = %u", min_pktsize);
2924 GST_DEBUG_OBJECT (demux, "flags::broadcast = %d", demux->broadcast);
2925 GST_DEBUG_OBJECT (demux, "flags::seekable = %d", demux->seekable);
2927 if (demux->broadcast) {
2928 /* these fields are invalid if the broadcast flag is set */
2929 play_time = 0;
2930 file_size = 0;
2931 }
2933 if (min_pktsize != max_pktsize)
2934 goto non_fixed_packet_size;
2936 demux->packet_size = max_pktsize;
2938 /* FIXME: do we need send_time as well? what is it? */
2939 if ((play_time * 100) >= (preroll * GST_MSECOND))
2940 demux->play_time = (play_time * 100) - (preroll * GST_MSECOND);
2941 else
2942 demux->play_time = 0;
2944 demux->preroll = preroll * GST_MSECOND;
2946 /* initial latency */
2947 demux->latency = demux->preroll;
2949 if (demux->play_time == 0)
2950 demux->seekable = FALSE;
2952 GST_DEBUG_OBJECT (demux, "play_time %" GST_TIME_FORMAT,
2953 GST_TIME_ARGS (demux->play_time));
2954 GST_DEBUG_OBJECT (demux, "preroll %" GST_TIME_FORMAT,
2955 GST_TIME_ARGS (demux->preroll));
2957 if (demux->play_time > 0) {
2958 gst_segment_set_duration (&demux->segment, GST_FORMAT_TIME,
2959 demux->play_time);
2960 }
2962 GST_INFO ("object is a file with %" G_GUINT64_FORMAT " data packets",
2963 packets_count);
2964 GST_INFO ("preroll = %" G_GUINT64_FORMAT, demux->preroll);
2966 return GST_FLOW_OK;
2968 /* ERRORS */
2969 non_fixed_packet_size:
2970 {
2971 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
2972 ("packet size must be fixed"));
2973 return GST_FLOW_ERROR;
2974 }
2975 not_enough_data:
2976 {
2977 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
2978 ("short read parsing FILE object"));
2979 return GST_FLOW_ERROR;
2980 }
2981 }
2983 /* Content Description Object */
2984 static GstFlowReturn
2985 gst_asf_demux_process_comment (GstASFDemux * demux, guint8 * data, guint64 size)
2986 {
2987 struct
2988 {
2989 const gchar *gst_tag;
2990 guint16 val_length;
2991 gchar *val_utf8;
2992 } tags[5] = {
2993 {
2994 GST_TAG_TITLE, 0, NULL}, {
2995 GST_TAG_ARTIST, 0, NULL}, {
2996 GST_TAG_COPYRIGHT, 0, NULL}, {
2997 GST_TAG_DESCRIPTION, 0, NULL}, {
2998 GST_TAG_COMMENT, 0, NULL}
2999 };
3000 GstTagList *taglist;
3001 GValue value = { 0 };
3002 gsize in, out;
3003 gint i = -1;
3005 GST_INFO_OBJECT (demux, "object is a comment");
3007 if (size < (2 + 2 + 2 + 2 + 2))
3008 goto not_enough_data;
3010 tags[0].val_length = gst_asf_demux_get_uint16 (&data, &size);
3011 tags[1].val_length = gst_asf_demux_get_uint16 (&data, &size);
3012 tags[2].val_length = gst_asf_demux_get_uint16 (&data, &size);
3013 tags[3].val_length = gst_asf_demux_get_uint16 (&data, &size);
3014 tags[4].val_length = gst_asf_demux_get_uint16 (&data, &size);
3016 GST_DEBUG_OBJECT (demux, "Comment lengths: title=%d author=%d copyright=%d "
3017 "description=%d rating=%d", tags[0].val_length, tags[1].val_length,
3018 tags[2].val_length, tags[3].val_length, tags[4].val_length);
3020 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
3021 if (size < tags[i].val_length)
3022 goto not_enough_data;
3024 /* might be just '/0', '/0'... */
3025 if (tags[i].val_length > 2 && tags[i].val_length % 2 == 0) {
3026 /* convert to UTF-8 */
3027 tags[i].val_utf8 = g_convert ((gchar *) data, tags[i].val_length,
3028 "UTF-8", "UTF-16LE", &in, &out, NULL);
3029 }
3030 gst_asf_demux_skip_bytes (tags[i].val_length, &data, &size);
3031 }
3033 /* parse metadata into taglist */
3034 taglist = gst_tag_list_new ();
3035 g_value_init (&value, G_TYPE_STRING);
3036 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
3037 if (tags[i].val_utf8 && strlen (tags[i].val_utf8) > 0 && tags[i].gst_tag) {
3038 g_value_set_string (&value, tags[i].val_utf8);
3039 gst_tag_list_add_values (taglist, GST_TAG_MERGE_APPEND,
3040 tags[i].gst_tag, &value, NULL);
3041 }
3042 }
3043 g_value_unset (&value);
3045 gst_asf_demux_add_global_tags (demux, taglist);
3047 for (i = 0; i < G_N_ELEMENTS (tags); ++i)
3048 g_free (tags[i].val_utf8);
3050 return GST_FLOW_OK;
3052 not_enough_data:
3053 {
3054 GST_WARNING_OBJECT (demux, "unexpectedly short of data while processing "
3055 "comment tag section %d, skipping comment object", i);
3056 for (i = 0; i < G_N_ELEMENTS (tags); i++)
3057 g_free (tags[i].val_utf8);
3058 return GST_FLOW_OK; /* not really fatal */
3059 }
3060 }
3062 static GstFlowReturn
3063 gst_asf_demux_process_bitrate_props_object (GstASFDemux * demux, guint8 * data,
3064 guint64 size)
3065 {
3066 guint16 num_streams, i;
3067 AsfStream *stream;
3069 if (size < 2)
3070 goto not_enough_data;
3072 num_streams = gst_asf_demux_get_uint16 (&data, &size);
3074 GST_INFO ("object is a bitrate properties object with %u streams",
3075 num_streams);
3077 if (size < (num_streams * (2 + 4)))
3078 goto not_enough_data;
3080 for (i = 0; i < num_streams; ++i) {
3081 guint32 bitrate;
3082 guint16 stream_id;
3084 stream_id = gst_asf_demux_get_uint16 (&data, &size);
3085 bitrate = gst_asf_demux_get_uint32 (&data, &size);
3087 if (stream_id < GST_ASF_DEMUX_NUM_STREAM_IDS) {
3088 GST_DEBUG_OBJECT (demux, "bitrate of stream %u = %u", stream_id, bitrate);
3089 stream = gst_asf_demux_get_stream (demux, stream_id);
3090 if (stream) {
3091 if (stream->pending_tags == NULL)
3092 stream->pending_tags = gst_tag_list_new ();
3093 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
3094 GST_TAG_BITRATE, bitrate, NULL);
3095 } else {
3096 GST_WARNING_OBJECT (demux, "Stream id %u wasn't found", stream_id);
3097 }
3098 } else {
3099 GST_WARNING ("stream id %u is too large", stream_id);
3100 }
3101 }
3103 return GST_FLOW_OK;
3105 not_enough_data:
3106 {
3107 GST_WARNING_OBJECT (demux, "short read parsing bitrate props object!");
3108 return GST_FLOW_OK; /* not really fatal */
3109 }
3110 }
3112 static GstFlowReturn
3113 gst_asf_demux_process_header_ext (GstASFDemux * demux, guint8 * data,
3114 guint64 size)
3115 {
3116 GstFlowReturn ret = GST_FLOW_OK;
3117 guint64 hdr_size;
3119 /* Get the rest of the header's header */
3120 if (size < (16 + 2 + 4))
3121 goto not_enough_data;
3123 /* skip GUID and two other bytes */
3124 gst_asf_demux_skip_bytes (16 + 2, &data, &size);
3125 hdr_size = gst_asf_demux_get_uint32 (&data, &size);
3127 GST_INFO ("extended header object with a size of %u bytes", (guint) size);
3129 /* FIXME: does data_size include the rest of the header that we have read? */
3130 if (hdr_size > size)
3131 goto not_enough_data;
3133 while (hdr_size > 0) {
3134 ret = gst_asf_demux_process_object (demux, &data, &hdr_size);
3135 if (ret != GST_FLOW_OK)
3136 break;
3137 }
3139 return ret;
3141 not_enough_data:
3142 {
3143 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3144 ("short read parsing extended header object"));
3145 return GST_FLOW_ERROR;
3146 }
3147 }
3149 static GstFlowReturn
3150 gst_asf_demux_process_language_list (GstASFDemux * demux, guint8 * data,
3151 guint64 size)
3152 {
3153 guint i;
3155 if (size < 2)
3156 goto not_enough_data;
3158 if (demux->languages) {
3159 GST_WARNING ("More than one LANGUAGE_LIST object in stream");
3160 g_strfreev (demux->languages);
3161 demux->languages = NULL;
3162 demux->num_languages = 0;
3163 }
3165 demux->num_languages = gst_asf_demux_get_uint16 (&data, &size);
3166 GST_LOG ("%u languages:", demux->num_languages);
3168 demux->languages = g_new0 (gchar *, demux->num_languages + 1);
3169 for (i = 0; i < demux->num_languages; ++i) {
3170 guint8 len, *lang_data = NULL;
3172 if (size < 1)
3173 goto not_enough_data;
3174 len = gst_asf_demux_get_uint8 (&data, &size);
3175 if (gst_asf_demux_get_bytes (&lang_data, len, &data, &size)) {
3176 gchar *utf8;
3178 utf8 = g_convert ((gchar *) lang_data, len, "UTF-8", "UTF-16LE", NULL,
3179 NULL, NULL);
3181 /* truncate "en-us" etc. to just "en" */
3182 if (utf8 && strlen (utf8) >= 5 && (utf8[2] == '-' || utf8[2] == '_')) {
3183 utf8[2] = '\0';
3184 }
3185 GST_DEBUG ("[%u] %s", i, GST_STR_NULL (utf8));
3186 demux->languages[i] = utf8;
3187 g_free (lang_data);
3188 } else {
3189 goto not_enough_data;
3190 }
3191 }
3193 return GST_FLOW_OK;
3195 not_enough_data:
3196 {
3197 GST_WARNING_OBJECT (demux, "short read parsing language list object!");
3198 g_free (demux->languages);
3199 demux->languages = NULL;
3200 return GST_FLOW_OK; /* not fatal */
3201 }
3202 }
3204 static GstFlowReturn
3205 gst_asf_demux_process_simple_index (GstASFDemux * demux, guint8 * data,
3206 guint64 size)
3207 {
3208 GstClockTime interval;
3209 guint32 count, i;
3211 if (size < (16 + 8 + 4 + 4))
3212 goto not_enough_data;
3214 /* skip file id */
3215 gst_asf_demux_skip_bytes (16, &data, &size);
3216 interval = gst_asf_demux_get_uint64 (&data, &size) * (GstClockTime) 100;
3217 gst_asf_demux_skip_bytes (4, &data, &size);
3218 count = gst_asf_demux_get_uint32 (&data, &size);
3219 if (count > 0) {
3220 demux->sidx_interval = interval;
3221 demux->sidx_num_entries = count;
3222 g_free (demux->sidx_entries);
3223 demux->sidx_entries = g_new0 (AsfSimpleIndexEntry, count);
3225 for (i = 0; i < count; ++i) {
3226 if (G_UNLIKELY (size <= 6))
3227 break;
3228 demux->sidx_entries[i].packet = gst_asf_demux_get_uint32 (&data, &size);
3229 demux->sidx_entries[i].count = gst_asf_demux_get_uint16 (&data, &size);
3230 GST_LOG_OBJECT (demux, "%" GST_TIME_FORMAT " = packet %4u count : %2d",
3231 GST_TIME_ARGS (i * interval), demux->sidx_entries[i].packet,
3232 demux->sidx_entries[i].count);
3233 }
3234 } else {
3235 GST_DEBUG_OBJECT (demux, "simple index object with 0 entries");
3236 }
3238 return GST_FLOW_OK;
3240 not_enough_data:
3241 {
3242 GST_WARNING_OBJECT (demux, "short read parsing simple index object!");
3243 return GST_FLOW_OK; /* not fatal */
3244 }
3245 }
3247 static GstFlowReturn
3248 gst_asf_demux_process_advanced_mutual_exclusion (GstASFDemux * demux,
3249 guint8 * data, guint64 size)
3250 {
3251 ASFGuid guid;
3252 guint16 num, i;
3253 guint8 *mes;
3255 if (size < 16 + 2 + (2 * 2))
3256 goto not_enough_data;
3258 gst_asf_demux_get_guid (&guid, &data, &size);
3259 num = gst_asf_demux_get_uint16 (&data, &size);
3261 if (num < 2) {
3262 GST_WARNING_OBJECT (demux, "nonsensical mutually exclusive streams count");
3263 return GST_FLOW_OK;
3264 }
3266 if (size < (num * sizeof (guint16)))
3267 goto not_enough_data;
3269 /* read mutually exclusive stream numbers */
3270 mes = g_new (guint8, num + 1);
3271 for (i = 0; i < num; ++i) {
3272 mes[i] = gst_asf_demux_get_uint16 (&data, &size) & 0x7f;
3273 GST_LOG_OBJECT (demux, "mutually exclusive: stream #%d", mes[i]);
3274 }
3276 /* add terminator so we can easily get the count or know when to stop */
3277 mes[i] = (guint8) - 1;
3279 demux->mut_ex_streams = g_slist_append (demux->mut_ex_streams, mes);
3281 return GST_FLOW_OK;
3283 /* Errors */
3284 not_enough_data:
3285 {
3286 GST_WARNING_OBJECT (demux, "short read parsing advanced mutual exclusion");
3287 return GST_FLOW_OK; /* not absolutely fatal */
3288 }
3289 }
3291 static GstFlowReturn
3292 gst_asf_demux_process_ext_stream_props (GstASFDemux * demux, guint8 * data,
3293 guint64 size)
3294 {
3295 AsfStreamExtProps esp;
3296 AsfStream *stream = NULL;
3297 AsfObject stream_obj;
3298 guint16 stream_name_count;
3299 guint16 num_payload_ext;
3300 guint64 len;
3301 guint8 *stream_obj_data = NULL;
3302 guint8 *data_start;
3303 guint obj_size;
3304 guint i, stream_num;
3306 data_start = data;
3307 obj_size = (guint) size;
3309 if (size < 64)
3310 goto not_enough_data;
3312 esp.valid = TRUE;
3313 esp.start_time = gst_asf_demux_get_uint64 (&data, &size) * GST_MSECOND;
3314 esp.end_time = gst_asf_demux_get_uint64 (&data, &size) * GST_MSECOND;
3315 esp.data_bitrate = gst_asf_demux_get_uint32 (&data, &size);
3316 esp.buffer_size = gst_asf_demux_get_uint32 (&data, &size);
3317 esp.intial_buf_fullness = gst_asf_demux_get_uint32 (&data, &size);
3318 esp.data_bitrate2 = gst_asf_demux_get_uint32 (&data, &size);
3319 esp.buffer_size2 = gst_asf_demux_get_uint32 (&data, &size);
3320 esp.intial_buf_fullness2 = gst_asf_demux_get_uint32 (&data, &size);
3321 esp.max_obj_size = gst_asf_demux_get_uint32 (&data, &size);
3322 esp.flags = gst_asf_demux_get_uint32 (&data, &size);
3323 stream_num = gst_asf_demux_get_uint16 (&data, &size);
3324 esp.lang_idx = gst_asf_demux_get_uint16 (&data, &size);
3325 esp.avg_time_per_frame = gst_asf_demux_get_uint64 (&data, &size);
3326 stream_name_count = gst_asf_demux_get_uint16 (&data, &size);
3327 num_payload_ext = gst_asf_demux_get_uint16 (&data, &size);
3329 GST_INFO ("start_time = %" GST_TIME_FORMAT,
3330 GST_TIME_ARGS (esp.start_time));
3331 GST_INFO ("end_time = %" GST_TIME_FORMAT,
3332 GST_TIME_ARGS (esp.end_time));
3333 GST_INFO ("flags = %08x", esp.flags);
3334 GST_INFO ("average time per frame = %" GST_TIME_FORMAT,
3335 GST_TIME_ARGS (esp.avg_time_per_frame * 100));
3336 GST_INFO ("stream number = %u", stream_num);
3337 GST_INFO ("stream language ID idx = %u (%s)", esp.lang_idx,
3338 (esp.lang_idx < demux->num_languages) ?
3339 GST_STR_NULL (demux->languages[esp.lang_idx]) : "??");
3340 GST_INFO ("stream name count = %u", stream_name_count);
3342 /* read stream names */
3343 for (i = 0; i < stream_name_count; ++i) {
3344 guint16 stream_lang_idx G_GNUC_UNUSED;
3345 gchar *stream_name = NULL;
3347 if (size < 2)
3348 goto not_enough_data;
3349 stream_lang_idx = gst_asf_demux_get_uint16 (&data, &size);
3350 if (!gst_asf_demux_get_string (&stream_name, NULL, &data, &size))
3351 goto not_enough_data;
3352 GST_INFO ("stream name %d: %s", i, GST_STR_NULL (stream_name));
3353 g_free (stream_name); /* TODO: store names in struct */
3354 }
3356 /* read payload extension systems stuff */
3357 GST_LOG ("payload extension systems count = %u", num_payload_ext);
3359 if (num_payload_ext > 0)
3360 esp.payload_extensions = g_new0 (AsfPayloadExtension, num_payload_ext + 1);
3361 else
3362 esp.payload_extensions = NULL;
3364 for (i = 0; i < num_payload_ext; ++i) {
3365 AsfPayloadExtension ext;
3366 ASFGuid ext_guid;
3367 guint32 sys_info_len;
3369 if (size < 16 + 2 + 4)
3370 goto not_enough_data;
3372 gst_asf_demux_get_guid (&ext_guid, &data, &size);
3373 ext.id = gst_asf_demux_identify_guid (asf_payload_ext_guids, &ext_guid);
3374 ext.len = gst_asf_demux_get_uint16 (&data, &size);
3376 sys_info_len = gst_asf_demux_get_uint32 (&data, &size);
3377 GST_LOG ("payload systems info len = %u", sys_info_len);
3378 if (!gst_asf_demux_skip_bytes (sys_info_len, &data, &size))
3379 goto not_enough_data;
3381 esp.payload_extensions[i] = ext;
3382 }
3384 GST_LOG ("bytes read: %u/%u", (guint) (data - data_start), obj_size);
3386 /* there might be an optional STREAM_INFO object here now; if not, we
3387 * should have parsed the corresponding stream info object already (since
3388 * we are parsing the extended stream properties objects delayed) */
3389 if (size == 0) {
3390 stream = gst_asf_demux_get_stream (demux, stream_num);
3391 goto done;
3392 }
3394 /* get size of the stream object */
3395 if (!asf_demux_peek_object (demux, data, size, &stream_obj, TRUE))
3396 goto not_enough_data;
3398 if (stream_obj.id != ASF_OBJ_STREAM)
3399 goto expected_stream_object;
3401 if (stream_obj.size < ASF_OBJECT_HEADER_SIZE ||
3402 stream_obj.size > (10 * 1024 * 1024))
3403 goto not_enough_data;
3405 gst_asf_demux_skip_bytes (ASF_OBJECT_HEADER_SIZE, &data, &size);
3407 /* process this stream object later after all the other 'normal' ones
3408 * have been processed (since the others are more important/non-hidden) */
3409 len = stream_obj.size - ASF_OBJECT_HEADER_SIZE;
3410 if (!gst_asf_demux_get_bytes (&stream_obj_data, len, &data, &size))
3411 goto not_enough_data;
3413 /* parse stream object */
3414 stream = gst_asf_demux_parse_stream_object (demux, stream_obj_data, len);
3415 g_free (stream_obj_data);
3417 done:
3419 if (stream) {
3420 stream->ext_props = esp;
3422 /* try to set the framerate */
3423 if (stream->is_video && stream->caps) {
3424 GValue framerate = { 0 };
3425 GstStructure *s;
3426 gint num, denom;
3428 g_value_init (&framerate, GST_TYPE_FRACTION);
3430 num = GST_SECOND / 100;
3431 denom = esp.avg_time_per_frame;
3432 if (denom == 0) {
3433 /* avoid division by 0, assume 25/1 framerate */
3434 denom = GST_SECOND / 2500;
3435 }
3437 gst_value_set_fraction (&framerate, num, denom);
3439 stream->caps = gst_caps_make_writable (stream->caps);
3440 s = gst_caps_get_structure (stream->caps, 0);
3441 gst_structure_set_value (s, "framerate", &framerate);
3442 g_value_unset (&framerate);
3443 GST_DEBUG_OBJECT (demux, "setting framerate of %d/%d = %f",
3444 num, denom, ((gdouble) num) / denom);
3445 }
3447 /* add language info now if we have it */
3448 if (stream->ext_props.lang_idx < demux->num_languages) {
3449 if (stream->pending_tags == NULL)
3450 stream->pending_tags = gst_tag_list_new ();
3451 GST_LOG_OBJECT (demux, "stream %u has language '%s'", stream->id,
3452 demux->languages[stream->ext_props.lang_idx]);
3453 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_APPEND,
3454 GST_TAG_LANGUAGE_CODE, demux->languages[stream->ext_props.lang_idx],
3455 NULL);
3456 }
3457 } else {
3458 GST_WARNING_OBJECT (demux, "Ext. stream properties for unknown stream");
3459 }
3461 return GST_FLOW_OK;
3463 /* Errors */
3464 not_enough_data:
3465 {
3466 GST_WARNING_OBJECT (demux, "short read parsing ext stream props object!");
3467 return GST_FLOW_OK; /* not absolutely fatal */
3468 }
3469 expected_stream_object:
3470 {
3471 GST_WARNING_OBJECT (demux, "error parsing extended stream properties "
3472 "object: expected embedded stream object, but got %s object instead!",
3473 gst_asf_get_guid_nick (asf_object_guids, stream_obj.id));
3474 return GST_FLOW_OK; /* not absolutely fatal */
3475 }
3476 }
3478 static const gchar *
3479 gst_asf_demux_push_obj (GstASFDemux * demux, guint32 obj_id)
3480 {
3481 const gchar *nick;
3483 nick = gst_asf_get_guid_nick (asf_object_guids, obj_id);
3484 if (g_str_has_prefix (nick, "ASF_OBJ_"))
3485 nick += strlen ("ASF_OBJ_");
3487 if (demux->objpath == NULL) {
3488 demux->objpath = g_strdup (nick);
3489 } else {
3490 gchar *newpath;
3492 newpath = g_strdup_printf ("%s/%s", demux->objpath, nick);
3493 g_free (demux->objpath);
3494 demux->objpath = newpath;
3495 }
3497 return (const gchar *) demux->objpath;
3498 }
3500 static void
3501 gst_asf_demux_pop_obj (GstASFDemux * demux)
3502 {
3503 gchar *s;
3505 if ((s = g_strrstr (demux->objpath, "/"))) {
3506 *s = '\0';
3507 } else {
3508 g_free (demux->objpath);
3509 demux->objpath = NULL;
3510 }
3511 }
3513 static void
3514 gst_asf_demux_process_queued_extended_stream_objects (GstASFDemux * demux)
3515 {
3516 GSList *l;
3517 guint i;
3519 /* Parse the queued extended stream property objects and add the info
3520 * to the existing streams or add the new embedded streams, but without
3521 * activating them yet */
3522 GST_LOG_OBJECT (demux, "%u queued extended stream properties objects",
3523 g_slist_length (demux->ext_stream_props));
3525 for (l = demux->ext_stream_props, i = 0; l != NULL; l = l->next, ++i) {
3526 GstBuffer *buf = GST_BUFFER (l->data);
3528 GST_LOG_OBJECT (demux, "parsing ext. stream properties object #%u", i);
3529 gst_asf_demux_process_ext_stream_props (demux, GST_BUFFER_DATA (buf),
3530 GST_BUFFER_SIZE (buf));
3531 gst_buffer_unref (buf);
3532 }
3533 g_slist_free (demux->ext_stream_props);
3534 demux->ext_stream_props = NULL;
3535 }
3537 #if 0
3538 static void
3539 gst_asf_demux_activate_ext_props_streams (GstASFDemux * demux)
3540 {
3541 guint i, j;
3543 for (i = 0; i < demux->num_streams; ++i) {
3544 AsfStream *stream;
3545 gboolean is_hidden;
3546 GSList *x;
3548 stream = &demux->stream[i];
3550 GST_LOG_OBJECT (demux, "checking stream %2u", stream->id);
3552 if (stream->active) {
3553 GST_LOG_OBJECT (demux, "stream %2u is already activated", stream->id);
3554 continue;
3555 }
3557 is_hidden = FALSE;
3558 for (x = demux->mut_ex_streams; x != NULL; x = x->next) {
3559 guint8 *mes;
3561 /* check for each mutual exclusion whether it affects this stream */
3562 for (mes = (guint8 *) x->data; mes != NULL && *mes != 0xff; ++mes) {
3563 if (*mes == stream->id) {
3564 /* if yes, check if we've already added streams that are mutually
3565 * exclusive with the stream we're about to add */
3566 for (mes = (guint8 *) x->data; mes != NULL && *mes != 0xff; ++mes) {
3567 for (j = 0; j < demux->num_streams; ++j) {
3568 /* if the broadcast flag is set, assume the hidden streams aren't
3569 * actually streamed and hide them (or playbin won't work right),
3570 * otherwise assume their data is available */
3571 if (demux->stream[j].id == *mes && demux->broadcast) {
3572 is_hidden = TRUE;
3573 GST_LOG_OBJECT (demux, "broadcast stream ID %d to be added is "
3574 "mutually exclusive with already existing stream ID %d, "
3575 "hiding stream", stream->id, demux->stream[j].id);
3576 goto next;
3577 }
3578 }
3579 }
3580 break;
3581 }
3582 }
3583 }
3585 next:
3587 /* FIXME: we should do stream activation based on preroll data in
3588 * streaming mode too */
3589 if (demux->streaming && !is_hidden)
3590 gst_asf_demux_activate_stream (demux, stream);
3591 }
3592 }
3593 #endif
3595 static GstFlowReturn
3596 gst_asf_demux_process_object (GstASFDemux * demux, guint8 ** p_data,
3597 guint64 * p_size)
3598 {
3599 GstFlowReturn ret = GST_FLOW_OK;
3600 AsfObject obj;
3601 guint64 obj_data_size;
3603 if (*p_size < ASF_OBJECT_HEADER_SIZE)
3604 return ASF_FLOW_NEED_MORE_DATA;
3606 asf_demux_peek_object (demux, *p_data, ASF_OBJECT_HEADER_SIZE, &obj, TRUE);
3607 gst_asf_demux_skip_bytes (ASF_OBJECT_HEADER_SIZE, p_data, p_size);
3609 obj_data_size = obj.size - ASF_OBJECT_HEADER_SIZE;
3611 if (*p_size < obj_data_size)
3612 return ASF_FLOW_NEED_MORE_DATA;
3614 gst_asf_demux_push_obj (demux, obj.id);
3616 GST_INFO ("%s: size %" G_GUINT64_FORMAT, demux->objpath, obj.size);
3618 switch (obj.id) {
3619 case ASF_OBJ_STREAM:
3620 gst_asf_demux_parse_stream_object (demux, *p_data, obj_data_size);
3621 ret = GST_FLOW_OK;
3622 break;
3623 case ASF_OBJ_FILE:
3624 ret = gst_asf_demux_process_file (demux, *p_data, obj_data_size);
3625 break;
3626 case ASF_OBJ_HEADER:
3627 ret = gst_asf_demux_process_header (demux, *p_data, obj_data_size);
3628 break;
3629 case ASF_OBJ_COMMENT:
3630 ret = gst_asf_demux_process_comment (demux, *p_data, obj_data_size);
3631 break;
3632 case ASF_OBJ_HEAD1:
3633 ret = gst_asf_demux_process_header_ext (demux, *p_data, obj_data_size);
3634 break;
3635 case ASF_OBJ_BITRATE_PROPS:
3636 ret =
3637 gst_asf_demux_process_bitrate_props_object (demux, *p_data,
3638 obj_data_size);
3639 break;
3640 case ASF_OBJ_EXT_CONTENT_DESC:
3641 ret =
3642 gst_asf_demux_process_ext_content_desc (demux, *p_data,
3643 obj_data_size);
3644 break;
3645 case ASF_OBJ_METADATA_OBJECT:
3646 ret = gst_asf_demux_process_metadata (demux, *p_data, obj_data_size);
3647 break;
3648 case ASF_OBJ_EXTENDED_STREAM_PROPS:{
3649 GstBuffer *buf;
3651 /* process these later, we might not have parsed the corresponding
3652 * stream object yet */
3653 GST_LOG ("%s: queued for later parsing", demux->objpath);
3654 buf = gst_buffer_new_and_alloc (obj_data_size);
3655 memcpy (GST_BUFFER_DATA (buf), *p_data, obj_data_size);
3656 demux->ext_stream_props = g_slist_append (demux->ext_stream_props, buf);
3657 ret = GST_FLOW_OK;
3658 break;
3659 }
3660 case ASF_OBJ_LANGUAGE_LIST:
3661 ret = gst_asf_demux_process_language_list (demux, *p_data, obj_data_size);
3662 break;
3663 case ASF_OBJ_ADVANCED_MUTUAL_EXCLUSION:
3664 ret = gst_asf_demux_process_advanced_mutual_exclusion (demux, *p_data,
3665 obj_data_size);
3666 break;
3667 case ASF_OBJ_SIMPLE_INDEX:
3668 ret = gst_asf_demux_process_simple_index (demux, *p_data, obj_data_size);
3669 break;
3670 case ASF_OBJ_CONTENT_ENCRYPTION:
3671 case ASF_OBJ_EXT_CONTENT_ENCRYPTION:
3672 case ASF_OBJ_DIGITAL_SIGNATURE_OBJECT:
3673 case ASF_OBJ_UNKNOWN_ENCRYPTION_OBJECT:
3674 goto error_encrypted;
3675 case ASF_OBJ_CONCEAL_NONE:
3676 case ASF_OBJ_HEAD2:
3677 case ASF_OBJ_UNDEFINED:
3678 case ASF_OBJ_CODEC_COMMENT:
3679 case ASF_OBJ_INDEX:
3680 case ASF_OBJ_PADDING:
3681 case ASF_OBJ_BITRATE_MUTEX:
3682 case ASF_OBJ_COMPATIBILITY:
3683 case ASF_OBJ_INDEX_PLACEHOLDER:
3684 case ASF_OBJ_INDEX_PARAMETERS:
3685 case ASF_OBJ_STREAM_PRIORITIZATION:
3686 case ASF_OBJ_SCRIPT_COMMAND:
3687 default:
3688 /* Unknown/unhandled object, skip it and hope for the best */
3689 GST_INFO ("%s: skipping object", demux->objpath);
3690 ret = GST_FLOW_OK;
3691 break;
3692 }
3694 /* this can't fail, we checked the number of bytes available before */
3695 gst_asf_demux_skip_bytes (obj_data_size, p_data, p_size);
3697 GST_LOG ("%s: ret = %s", demux->objpath, gst_asf_get_flow_name (ret));
3699 gst_asf_demux_pop_obj (demux);
3701 return ret;
3703 /* ERRORS */
3704 error_encrypted:
3705 {
3706 GST_ELEMENT_ERROR (demux, STREAM, DECRYPT, (NULL), (NULL));
3707 return GST_FLOW_ERROR;
3708 }
3709 }
3711 static void
3712 gst_asf_demux_descramble_buffer (GstASFDemux * demux, AsfStream * stream,
3713 GstBuffer ** p_buffer)
3714 {
3715 GstBuffer *descrambled_buffer;
3716 GstBuffer *scrambled_buffer;
3717 GstBuffer *sub_buffer;
3718 guint offset;
3719 guint off;
3720 guint row;
3721 guint col;
3722 guint idx;
3724 /* descrambled_buffer is initialised in the first iteration */
3725 descrambled_buffer = NULL;
3726 scrambled_buffer = *p_buffer;
3728 if (GST_BUFFER_SIZE (scrambled_buffer) < demux->ds_packet_size * demux->span)
3729 return;
3731 for (offset = 0; offset < GST_BUFFER_SIZE (scrambled_buffer);
3732 offset += demux->ds_chunk_size) {
3733 off = offset / demux->ds_chunk_size;
3734 row = off / demux->span;
3735 col = off % demux->span;
3736 idx = row + col * demux->ds_packet_size / demux->ds_chunk_size;
3737 GST_DEBUG ("idx=%u, row=%u, col=%u, off=%u, ds_chunk_size=%u", idx, row,
3738 col, off, demux->ds_chunk_size);
3739 GST_DEBUG ("scrambled buffer size=%u, span=%u, packet_size=%u",
3740 GST_BUFFER_SIZE (scrambled_buffer), demux->span, demux->ds_packet_size);
3741 GST_DEBUG ("GST_BUFFER_SIZE (scrambled_buffer) = %u",
3742 GST_BUFFER_SIZE (scrambled_buffer));
3743 sub_buffer =
3744 gst_buffer_create_sub (scrambled_buffer, idx * demux->ds_chunk_size,
3745 demux->ds_chunk_size);
3746 if (!offset) {
3747 descrambled_buffer = sub_buffer;
3748 } else {
3749 descrambled_buffer = gst_buffer_join (descrambled_buffer, sub_buffer);
3750 }
3751 }
3753 gst_buffer_copy_metadata (descrambled_buffer, scrambled_buffer,
3754 GST_BUFFER_COPY_TIMESTAMPS);
3756 /* FIXME/CHECK: do we need to transfer buffer flags here too? */
3758 gst_buffer_unref (scrambled_buffer);
3759 *p_buffer = descrambled_buffer;
3760 }
3762 static gboolean
3763 gst_asf_demux_element_send_event (GstElement * element, GstEvent * event)
3764 {
3765 GstASFDemux *demux = GST_ASF_DEMUX (element);
3766 gint i;
3768 GST_DEBUG ("handling element event of type %s", GST_EVENT_TYPE_NAME (event));
3770 for (i = 0; i < demux->num_streams; ++i) {
3771 gst_event_ref (event);
3772 if (gst_asf_demux_handle_src_event (demux->stream[i].pad, event)) {
3773 gst_event_unref (event);
3774 return TRUE;
3775 }
3776 }
3778 gst_event_unref (event);
3779 return FALSE;
3780 }
3782 /* takes ownership of the passed event */
3783 static gboolean
3784 gst_asf_demux_send_event_unlocked (GstASFDemux * demux, GstEvent * event)
3785 {
3786 gboolean ret = TRUE;
3787 gint i;
3789 GST_DEBUG_OBJECT (demux, "sending %s event to all source pads",
3790 GST_EVENT_TYPE_NAME (event));
3792 for (i = 0; i < demux->num_streams; ++i) {
3793 gst_event_ref (event);
3794 ret &= gst_pad_push_event (demux->stream[i].pad, event);
3795 }
3796 gst_event_unref (event);
3797 return ret;
3798 }
3800 static const GstQueryType *
3801 gst_asf_demux_get_src_query_types (GstPad * pad)
3802 {
3803 static const GstQueryType types[] = {
3804 GST_QUERY_POSITION,
3805 GST_QUERY_DURATION,
3806 GST_QUERY_SEEKING,
3807 0
3808 };
3810 return types;
3811 }
3813 static gboolean
3814 gst_asf_demux_handle_src_query (GstPad * pad, GstQuery * query)
3815 {
3816 GstASFDemux *demux;
3817 gboolean res = FALSE;
3819 demux = GST_ASF_DEMUX (gst_pad_get_parent (pad));
3821 GST_DEBUG ("handling %s query",
3822 gst_query_type_get_name (GST_QUERY_TYPE (query)));
3824 switch (GST_QUERY_TYPE (query)) {
3825 case GST_QUERY_DURATION:
3826 {
3827 GstFormat format;
3829 gst_query_parse_duration (query, &format, NULL);
3831 if (format != GST_FORMAT_TIME) {
3832 GST_LOG ("only support duration queries in TIME format");
3833 break;
3834 }
3836 GST_OBJECT_LOCK (demux);
3838 if (demux->segment.duration != GST_CLOCK_TIME_NONE) {
3839 GST_LOG ("returning duration: %" GST_TIME_FORMAT,
3840 GST_TIME_ARGS (demux->segment.duration));
3842 gst_query_set_duration (query, GST_FORMAT_TIME,
3843 demux->segment.duration);
3845 res = TRUE;
3846 } else {
3847 GST_LOG ("duration not known yet");
3848 }
3850 GST_OBJECT_UNLOCK (demux);
3851 break;
3852 }
3854 case GST_QUERY_POSITION:{
3855 GstFormat format;
3857 gst_query_parse_position (query, &format, NULL);
3859 if (format != GST_FORMAT_TIME) {
3860 GST_LOG ("only support position queries in TIME format");
3861 break;
3862 }
3864 GST_OBJECT_LOCK (demux);
3866 if (demux->segment.last_stop != GST_CLOCK_TIME_NONE) {
3867 GST_LOG ("returning position: %" GST_TIME_FORMAT,
3868 GST_TIME_ARGS (demux->segment.last_stop));
3870 gst_query_set_position (query, GST_FORMAT_TIME,
3871 demux->segment.last_stop);
3873 res = TRUE;
3874 } else {
3875 GST_LOG ("position not known yet");
3876 }
3878 GST_OBJECT_UNLOCK (demux);
3879 break;
3880 }
3882 case GST_QUERY_SEEKING:{
3883 GstFormat format;
3885 gst_query_parse_seeking (query, &format, NULL, NULL, NULL);
3886 if (format == GST_FORMAT_TIME) {
3887 gint64 duration;
3889 GST_OBJECT_LOCK (demux);
3890 duration = demux->segment.duration;
3891 GST_OBJECT_UNLOCK (demux);
3893 if (!demux->streaming || !demux->seekable) {
3894 gst_query_set_seeking (query, GST_FORMAT_TIME, demux->seekable, 0,
3895 duration);
3896 res = TRUE;
3897 } else {
3898 GstFormat fmt;
3899 gboolean seekable;
3901 /* try downstream first in TIME */
3902 res = gst_pad_query_default (pad, query);
3904 gst_query_parse_seeking (query, &fmt, &seekable, NULL, NULL);
3905 GST_LOG_OBJECT (demux, "upstream %s seekable %d",
3906 GST_STR_NULL (gst_format_get_name (fmt)), seekable);
3907 /* if no luck, maybe in BYTES */
3908 if (!seekable || fmt != GST_FORMAT_TIME) {
3909 GstQuery *q;
3911 q = gst_query_new_seeking (GST_FORMAT_BYTES);
3912 if ((res = gst_pad_peer_query (demux->sinkpad, q))) {
3913 gst_query_parse_seeking (q, &fmt, &seekable, NULL, NULL);
3914 GST_LOG_OBJECT (demux, "upstream %s seekable %d",
3915 GST_STR_NULL (gst_format_get_name (fmt)), seekable);
3916 if (fmt != GST_FORMAT_BYTES)
3917 seekable = FALSE;
3918 }
3919 gst_query_unref (q);
3920 gst_query_set_seeking (query, GST_FORMAT_TIME, seekable, 0,
3921 duration);
3922 res = TRUE;
3923 }
3924 }
3925 } else
3926 GST_LOG_OBJECT (demux, "only support seeking in TIME format");
3927 break;
3928 }
3930 case GST_QUERY_LATENCY:
3931 {
3932 gboolean live;
3933 GstClockTime min, max;
3935 /* preroll delay does not matter in non-live pipeline,
3936 * but we might end up in a live (rtsp) one ... */
3938 /* first forward */
3939 res = gst_pad_query_default (pad, query);
3940 if (!res)
3941 break;
3943 gst_query_parse_latency (query, &live, &min, &max);
3945 GST_DEBUG_OBJECT (demux, "Peer latency: live %d, min %"
3946 GST_TIME_FORMAT " max %" GST_TIME_FORMAT, live,
3947 GST_TIME_ARGS (min), GST_TIME_ARGS (max));
3949 GST_OBJECT_LOCK (demux);
3950 if (min != -1)
3951 min += demux->latency;
3952 if (max != -1)
3953 max += demux->latency;
3954 GST_OBJECT_UNLOCK (demux);
3956 gst_query_set_latency (query, live, min, max);
3957 break;
3958 }
3959 default:
3960 res = gst_pad_query_default (pad, query);
3961 break;
3962 }
3964 gst_object_unref (demux);
3965 return res;
3966 }
3968 static GstStateChangeReturn
3969 gst_asf_demux_change_state (GstElement * element, GstStateChange transition)
3970 {
3971 GstASFDemux *demux = GST_ASF_DEMUX (element);
3972 GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
3974 switch (transition) {
3975 case GST_STATE_CHANGE_NULL_TO_READY:{
3976 gst_segment_init (&demux->segment, GST_FORMAT_TIME);
3977 demux->need_newsegment = TRUE;
3978 demux->segment_running = FALSE;
3979 demux->accurate = FALSE;
3980 demux->adapter = gst_adapter_new ();
3981 demux->metadata = gst_caps_new_empty ();
3982 demux->global_metadata = gst_structure_empty_new ("metadata");
3983 demux->data_size = 0;
3984 demux->data_offset = 0;
3985 demux->index_offset = 0;
3986 demux->base_offset = 0;
3987 break;
3988 }
3989 default:
3990 break;
3991 }
3993 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
3994 if (ret == GST_STATE_CHANGE_FAILURE)
3995 return ret;
3997 switch (transition) {
3998 case GST_STATE_CHANGE_PAUSED_TO_READY:
3999 case GST_STATE_CHANGE_READY_TO_NULL:
4000 gst_asf_demux_reset (demux, FALSE);
4001 break;
4002 default:
4003 break;
4004 }
4006 return ret;
4007 }