58cefd9ec6082dad2d34cb1332640c4e33608adc
1 /* GStreamer
2 * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
3 * Copyright (C) <2003> David A. Schleef <ds@schleef.org>
4 * Copyright (C) <2004> Stephane Loeuillet <gstreamer@leroutier.net>
5 * Copyright (C) <2005> Owen Fraser-Green <owen@discobabe.net>
6 * Copyright (C) <2005> Michael Smith <fluendo.com>
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Library General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Library General Public License for more details.
17 *
18 * You should have received a copy of the GNU Library General Public
19 * License along with this library; if not, write to the
20 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21 * Boston, MA 02111-1307, USA.
22 */
24 #ifdef HAVE_CONFIG_H
25 # include "config.h"
26 #endif
27 #include "rmdemux.h"
28 #include <string.h>
29 #include <ctype.h>
30 #include <zlib.h>
32 #define RMDEMUX_GUINT32_GET(a) GST_READ_UINT32_BE(a)
33 #define RMDEMUX_GUINT16_GET(a) GST_READ_UINT16_BE(a)
34 #define RMDEMUX_FOURCC_GET(a) GST_READ_UINT32_LE(a)
35 #define HEADER_SIZE 10
36 #define DATA_SIZE 8
38 typedef struct _GstRMDemuxIndex GstRMDemuxIndex;
40 struct _GstRMDemuxStream
41 {
42 guint32 subtype;
43 guint32 fourcc;
44 guint32 subformat;
45 guint32 format;
47 int id;
48 GstCaps *caps;
49 GstPad *pad;
50 int timescale;
52 int sample_index;
53 GstRMDemuxIndex *index;
54 int index_length;
55 double frame_rate;
56 guint32 seek_offset;
58 guint16 width;
59 guint16 height;
60 guint16 flavor;
61 guint16 rate; // samplerate
62 guint16 n_channels; // channels
63 guint16 sample_width; // bits_per_sample
64 guint16 leaf_size; // subpacket_size
65 guint32 packet_size; // coded_frame_size
66 guint16 version;
67 guint32 extra_data_size; // codec_data_length
68 guint8 *extra_data; // extras
69 };
71 struct _GstRMDemuxIndex
72 {
73 guint32 offset;
74 GstClockTime timestamp;
75 };
77 static GstElementDetails gst_rmdemux_details = {
78 "RealMedia Demuxer",
79 "Codec/Demuxer",
80 "Demultiplex a RealMedia file into audio and video streams",
81 "David Schleef <ds@schleef.org>"
82 };
84 enum
85 {
86 LAST_SIGNAL
87 };
89 enum
90 {
91 ARG_0
92 };
94 static GstStaticPadTemplate gst_rmdemux_sink_template =
95 GST_STATIC_PAD_TEMPLATE ("sink",
96 GST_PAD_SINK,
97 GST_PAD_ALWAYS,
98 GST_STATIC_CAPS ("application/vnd.rn-realmedia")
99 );
101 static GstStaticPadTemplate gst_rmdemux_videosrc_template =
102 GST_STATIC_PAD_TEMPLATE ("video_%02d",
103 GST_PAD_SRC,
104 GST_PAD_SOMETIMES,
105 GST_STATIC_CAPS_ANY);
107 static GstStaticPadTemplate gst_rmdemux_audiosrc_template =
108 GST_STATIC_PAD_TEMPLATE ("audio_%02d",
109 GST_PAD_SRC,
110 GST_PAD_SOMETIMES,
111 GST_STATIC_CAPS_ANY);
113 GST_DEBUG_CATEGORY_STATIC (rmdemux_debug);
114 #define GST_CAT_DEFAULT rmdemux_debug
116 static GstElementClass *parent_class = NULL;
118 static void gst_rmdemux_class_init (GstRMDemuxClass * klass);
119 static void gst_rmdemux_base_init (GstRMDemuxClass * klass);
120 static void gst_rmdemux_init (GstRMDemux * rmdemux);
121 static void gst_rmdemux_dispose (GObject * object);
122 static GstStateChangeReturn gst_rmdemux_change_state (GstElement * element,
123 GstStateChange transition);
124 static GstFlowReturn gst_rmdemux_chain (GstPad * pad, GstBuffer * buffer);
125 static void gst_rmdemux_loop (GstPad * pad);
126 static gboolean gst_rmdemux_sink_activate (GstPad * sinkpad);
127 static gboolean gst_rmdemux_sink_activate_push (GstPad * sinkpad,
128 gboolean active);
129 static gboolean gst_rmdemux_sink_activate_pull (GstPad * sinkpad,
130 gboolean active);
131 static gboolean gst_rmdemux_sink_event (GstPad * pad, GstEvent * event);
132 static gboolean gst_rmdemux_src_event (GstPad * pad, GstEvent * event);
133 static gboolean gst_rmdemux_send_event (GstRMDemux * rmdemux, GstEvent * event);
134 static const GstQueryType *gst_rmdemux_src_query_types (GstPad * pad);
135 static gboolean gst_rmdemux_src_query (GstPad * pad, GstQuery * query);
136 static gboolean gst_rmdemux_perform_seek (GstRMDemux * rmdemux, gboolean flush);
138 static void gst_rmdemux_parse__rmf (GstRMDemux * rmdemux, const void *data,
139 int length);
140 static void gst_rmdemux_parse_prop (GstRMDemux * rmdemux, const void *data,
141 int length);
142 static GstFlowReturn gst_rmdemux_parse_mdpr (GstRMDemux * rmdemux,
143 const void *data, int length);
144 static guint gst_rmdemux_parse_indx (GstRMDemux * rmdemux, const void *data,
145 int length);
146 static void gst_rmdemux_parse_data (GstRMDemux * rmdemux, const void *data,
147 int length);
148 static void gst_rmdemux_parse_cont (GstRMDemux * rmdemux, const void *data,
149 int length);
150 static GstFlowReturn gst_rmdemux_parse_packet (GstRMDemux * rmdemux,
151 const void *data, guint16 version, guint16 length);
152 static void gst_rmdemux_parse_indx_data (GstRMDemux * rmdemux, const void *data,
153 int length);
155 static GstCaps *gst_rmdemux_src_getcaps (GstPad * pad);
157 static GstRMDemuxStream *gst_rmdemux_get_stream_by_id (GstRMDemux * rmdemux,
158 int id);
160 static GType
161 gst_rmdemux_get_type (void)
162 {
163 static GType rmdemux_type = 0;
165 if (!rmdemux_type) {
166 static const GTypeInfo rmdemux_info = {
167 sizeof (GstRMDemuxClass),
168 (GBaseInitFunc) gst_rmdemux_base_init, NULL,
169 (GClassInitFunc) gst_rmdemux_class_init,
170 NULL, NULL, sizeof (GstRMDemux), 0,
171 (GInstanceInitFunc) gst_rmdemux_init,
172 };
174 rmdemux_type =
175 g_type_register_static (GST_TYPE_ELEMENT, "GstRMDemux", &rmdemux_info,
176 0);
177 }
178 return rmdemux_type;
179 }
181 static void
182 gst_rmdemux_base_init (GstRMDemuxClass * klass)
183 {
184 GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
186 gst_element_class_add_pad_template (element_class,
187 gst_static_pad_template_get (&gst_rmdemux_sink_template));
188 gst_element_class_add_pad_template (element_class,
189 gst_static_pad_template_get (&gst_rmdemux_videosrc_template));
190 gst_element_class_add_pad_template (element_class,
191 gst_static_pad_template_get (&gst_rmdemux_audiosrc_template));
192 gst_element_class_set_details (element_class, &gst_rmdemux_details);
193 }
195 static void
196 gst_rmdemux_class_init (GstRMDemuxClass * klass)
197 {
198 GObjectClass *gobject_class;
199 GstElementClass *gstelement_class;
201 gobject_class = (GObjectClass *) klass;
202 gstelement_class = (GstElementClass *) klass;
204 parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
206 gstelement_class->change_state = gst_rmdemux_change_state;
208 GST_DEBUG_CATEGORY_INIT (rmdemux_debug, "rmdemux",
209 0, "Demuxer for Realmedia streams");
211 gobject_class->dispose = gst_rmdemux_dispose;
212 }
214 static void
215 gst_rmdemux_dispose (GObject * object)
216 {
217 GstRMDemux *rmdemux = GST_RMDEMUX (object);
219 if (rmdemux->adapter) {
220 g_object_unref (rmdemux->adapter);
221 rmdemux->adapter = NULL;
222 }
224 GST_CALL_PARENT (G_OBJECT_CLASS, dispose, (object));
225 }
227 static void
228 gst_rmdemux_init (GstRMDemux * rmdemux)
229 {
230 rmdemux->sinkpad =
231 gst_pad_new_from_template (gst_static_pad_template_get
232 (&gst_rmdemux_sink_template), "sink");
233 gst_pad_set_event_function (rmdemux->sinkpad, gst_rmdemux_sink_event);
234 gst_pad_set_chain_function (rmdemux->sinkpad, gst_rmdemux_chain);
235 gst_pad_set_activate_function (rmdemux->sinkpad, gst_rmdemux_sink_activate);
236 gst_pad_set_activatepull_function (rmdemux->sinkpad,
237 gst_rmdemux_sink_activate_pull);
238 gst_pad_set_activatepush_function (rmdemux->sinkpad,
239 gst_rmdemux_sink_activate_push);
242 gst_element_add_pad (GST_ELEMENT (rmdemux), rmdemux->sinkpad);
244 rmdemux->adapter = gst_adapter_new ();
245 }
247 static gboolean
248 plugin_init (GstPlugin * plugin)
249 {
250 return gst_element_register (plugin, "rmdemux",
251 GST_RANK_PRIMARY, GST_TYPE_RMDEMUX);
252 }
254 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
255 GST_VERSION_MINOR,
256 "rmdemux",
257 "Realmedia stream demuxer",
258 plugin_init, VERSION, "LGPL", GST_PACKAGE, GST_ORIGIN)
261 static gboolean gst_rmdemux_sink_event (GstPad * pad, GstEvent * event)
262 {
263 gboolean ret = TRUE;
265 GstRMDemux *rmdemux = GST_RMDEMUX (GST_PAD_PARENT (pad));
267 switch (GST_EVENT_TYPE (event)) {
268 case GST_EVENT_NEWSEGMENT:
269 GST_LOG_OBJECT (rmdemux, "Event on sink: NEWSEGMENT");
270 gst_event_unref (event);
271 break;
272 default:
273 GST_LOG_OBJECT (rmdemux, "Event on sink: type=%d",
274 GST_EVENT_TYPE (event));
275 ret = gst_pad_event_default (pad, event);
276 break;
277 }
279 return ret;
280 }
282 static gboolean
283 gst_rmdemux_src_event (GstPad * pad, GstEvent * event)
284 {
285 gboolean ret = TRUE;
287 GstRMDemux *rmdemux = GST_RMDEMUX (GST_PAD_PARENT (pad));
289 GST_LOG_OBJECT (rmdemux, "handling src event");
291 switch (GST_EVENT_TYPE (event)) {
292 case GST_EVENT_SEEK:{
293 gboolean running;
294 gboolean flush;
295 GstFormat format;
296 GstSeekFlags flags;
297 GstSeekType cur_type, stop_type;
298 gint64 cur, stop;
300 GST_LOG_OBJECT (rmdemux, "Event on src: SEEK");
301 /* can't seek if we are not seekable, FIXME could pass the
302 * seek query upstream after converting it to bytes using
303 * the average bitrate of the stream. */
304 if (!rmdemux->seekable) {
305 ret = FALSE;
306 GST_DEBUG ("seek on non seekable stream");
307 goto done_unref;
308 }
309 gst_event_parse_seek (event, NULL, &format, &flags,
310 &cur_type, &cur, &stop_type, &stop);
312 /* we can only seek on time */
313 if (format != GST_FORMAT_TIME) {
314 ret = FALSE;
315 GST_DEBUG ("can only seek on TIME");
316 goto done_unref;
317 }
319 GST_LOCK (rmdemux);
321 if (cur_type == GST_SEEK_TYPE_SET)
322 rmdemux->segment_start = cur;
323 else if (cur_type == GST_SEEK_TYPE_CUR)
324 rmdemux->segment_start += cur;
325 else if (cur_type == GST_SEEK_TYPE_END)
326 rmdemux->segment_start = rmdemux->duration + cur;
328 if (stop_type == GST_SEEK_TYPE_SET)
329 rmdemux->segment_stop = stop;
330 else if (cur_type == GST_SEEK_TYPE_CUR)
331 rmdemux->segment_stop += cur;
332 else if (cur_type == GST_SEEK_TYPE_END)
333 rmdemux->segment_stop = rmdemux->duration + cur;
335 /* Now do a sanity-check */
336 if (rmdemux->segment_stop < rmdemux->segment_start) {
337 GST_UNLOCK (rmdemux);
338 ret = FALSE;
339 GST_DEBUG_OBJECT (rmdemux, "Seek had stop " G_GUINT64_FORMAT " < start "
340 G_GUINT64_FORMAT ", cannot perform seek",
341 rmdemux->segment_stop, rmdemux->segment_start);
342 goto done_unref;
343 }
345 rmdemux->segment_play = !!(flags & GST_SEEK_FLAG_SEGMENT);
346 flush = !!(flags & GST_SEEK_FLAG_FLUSH);
347 gst_event_unref (event);
349 GST_DEBUG ("segment positions set to %" GST_TIME_FORMAT "-%"
350 GST_TIME_FORMAT, GST_TIME_ARGS (rmdemux->segment_start),
351 GST_TIME_ARGS (rmdemux->segment_stop));
353 /* check if we can do the seek now */
354 running = rmdemux->running;
355 GST_UNLOCK (rmdemux);
357 /* now do the seek */
358 if (running) {
359 ret = gst_rmdemux_perform_seek (rmdemux, flush);
360 } else
361 ret = TRUE;
362 break;
363 }
364 default:
365 GST_LOG_OBJECT (rmdemux, "Event on src: type=%d", GST_EVENT_TYPE (event));
366 ret = gst_pad_event_default (pad, event);
367 break;
368 }
370 return ret;
372 done_unref:
373 GST_DEBUG ("error handling event");
374 gst_event_unref (event);
375 return ret;
376 }
378 /* Validate that this looks like a reasonable point to seek to */
379 static gboolean
380 gst_rmdemux_validate_offset (GstRMDemux * rmdemux)
381 {
382 GstBuffer *buffer;
383 GstFlowReturn flowret;
384 guint16 version, length;
385 gboolean ret = TRUE;
387 flowret = gst_pad_pull_range (rmdemux->sinkpad, rmdemux->offset, 4, &buffer);
389 if (flowret != GST_FLOW_OK) {
390 GST_DEBUG_OBJECT (rmdemux, "Failed to pull data at offset %d",
391 rmdemux->offset);
392 return FALSE;
393 }
394 // TODO: Can we also be seeking to a 'DATA' chunk header? Check this.
395 // Also, for the case we currently handle, can we check any more? It's pretty
396 // sucky to not be validating a little more heavily than this...
397 /* This should now be the start of a data packet header. That begins with
398 * a 2-byte 'version' field, which has to be 0 or 1, then a length. I'm not
399 * certain what values are valid for length, but it must always be at least
400 * 4 bytes, and we can check that it won't take us past our known total size
401 */
403 version = RMDEMUX_GUINT16_GET (GST_BUFFER_DATA (buffer));
404 if (version != 0 && version != 1) {
405 GST_DEBUG_OBJECT (rmdemux, "Expected version 0 or 1, got %d",
406 (int) version);
407 ret = FALSE;
408 }
410 length = RMDEMUX_GUINT16_GET (GST_BUFFER_DATA (buffer) + 2);
411 // TODO: Also check against total stream length
412 if (length < 4) {
413 GST_DEBUG_OBJECT (rmdemux, "Expected length >= 4, got %d", (int) length);
414 ret = FALSE;
415 }
417 if (ret) {
418 rmdemux->offset += 4;
419 gst_adapter_clear (rmdemux->adapter);
420 gst_adapter_push (rmdemux->adapter, buffer);
421 } else {
422 GST_WARNING_OBJECT (rmdemux, "Failed to validate seek offset at %d",
423 rmdemux->offset);
424 }
426 return ret;
427 }
429 static gboolean
430 find_seek_offset_bytes (GstRMDemux * rmdemux, guint target)
431 {
432 int i, n;
433 gboolean ret = FALSE;
435 for (n = 0; n < rmdemux->n_streams; n++) {
436 GstRMDemuxStream *stream;
438 stream = rmdemux->streams[n];
440 /* Search backwards through this stream's index until we find the first
441 * timestamp before our target time */
442 for (i = stream->index_length - 1; i >= 0; i--) {
443 if (stream->index[i].offset <= target) {
444 /* Set the seek_offset for the stream so we don't bother parsing it
445 * until we've passed that point */
446 stream->seek_offset = stream->index[i].offset;
447 rmdemux->offset = stream->index[i].offset;
448 ret = TRUE;
449 break;
450 }
451 }
452 }
453 return ret;
454 }
456 static gboolean
457 find_seek_offset_time (GstRMDemux * rmdemux, GstClockTime time)
458 {
459 int i, n;
460 gboolean ret = FALSE;
461 GstClockTime earliest = GST_CLOCK_TIME_NONE;
463 for (n = 0; n < rmdemux->n_streams; n++) {
464 GstRMDemuxStream *stream;
466 stream = rmdemux->streams[n];
468 /* Search backwards through this stream's index until we find the first
469 * timestamp before our target time */
470 for (i = stream->index_length - 1; i >= 0; i--) {
471 if (stream->index[i].timestamp <= time) {
472 /* Set the seek_offset for the stream so we don't bother parsing it
473 * until we've passed that point */
474 stream->seek_offset = stream->index[i].offset;
476 /* If it's also the earliest timestamp we've seen of all streams, then
477 * that's our target!
478 */
479 if (earliest == GST_CLOCK_TIME_NONE ||
480 stream->index[i].timestamp < earliest) {
481 earliest = stream->index[i].timestamp;
482 rmdemux->offset = stream->index[i].offset;
483 GST_DEBUG_OBJECT (rmdemux,
484 "We're looking for %" GST_TIME_FORMAT
485 " and we found that stream %d has the latest index at %"
486 GST_TIME_FORMAT, GST_TIME_ARGS (rmdemux->segment_start), n,
487 GST_TIME_ARGS (earliest));
488 }
490 ret = TRUE;
492 break;
493 }
494 }
495 }
496 return ret;
497 }
499 static gboolean
500 gst_rmdemux_perform_seek (GstRMDemux * rmdemux, gboolean flush)
501 {
502 gboolean validated;
503 gboolean ret = TRUE;
505 /* nothing configured, play complete file */
506 if (rmdemux->segment_start == GST_CLOCK_TIME_NONE)
507 rmdemux->segment_start = 0;
508 if (rmdemux->segment_stop == GST_CLOCK_TIME_NONE)
509 rmdemux->segment_stop = rmdemux->duration;
511 rmdemux->segment_start = CLAMP (rmdemux->segment_start, 0, rmdemux->duration);
512 rmdemux->segment_stop = CLAMP (rmdemux->segment_stop, 0, rmdemux->duration);
514 /* first step is to unlock the streaming thread if it is
515 * blocked in a chain call, we do this by starting the flush. */
516 if (flush) {
517 gboolean res;
519 res = gst_pad_push_event (rmdemux->sinkpad, gst_event_new_flush_start ());
520 if (!res) {
521 GST_WARNING_OBJECT (rmdemux, "Failed to push event upstream!");
522 }
524 res = gst_rmdemux_send_event (rmdemux, gst_event_new_flush_start ());
525 if (!res) {
526 GST_WARNING_OBJECT (rmdemux, "Failed to push event downstream!");
527 }
528 } else {
529 gst_pad_pause_task (rmdemux->sinkpad);
530 }
532 GST_LOG_OBJECT (rmdemux, "Done starting flushes");
534 /* now grab the stream lock so that streaming cannot continue, for
535 * non flushing seeks when the element is in PAUSED this could block
536 * forever. */
537 GST_STREAM_LOCK (rmdemux->sinkpad);
539 GST_LOG_OBJECT (rmdemux, "Took streamlock");
541 /* we need to stop flushing on the sinkpad as we're going to use it
542 * next. We can do this as we have the STREAM lock now. */
543 gst_pad_push_event (rmdemux->sinkpad, gst_event_new_flush_stop ());
545 GST_LOG_OBJECT (rmdemux, "Pushed FLUSH_STOP event");
547 /* For each stream, find the first index offset equal to or before our seek
548 * target. Of these, find the smallest offset. That's where we seek to.
549 *
550 * Then we pull 4 bytes from that offset, validate that we've seeked to a
551 * DATA chunk (with the DATA fourcc).
552 * If that fails, restart, with the seek target set to one less than the
553 * offset we just tried. If we run out of places to try, treat that as a fatal
554 * error.
555 */
556 if (!find_seek_offset_time (rmdemux, rmdemux->segment_start)) {
557 GST_LOG_OBJECT (rmdemux, "Failed to find seek offset by time");
558 ret = FALSE;
559 goto done;
560 }
562 GST_LOG_OBJECT (rmdemux, "Validating offset %u", rmdemux->offset);
563 validated = gst_rmdemux_validate_offset (rmdemux);
564 while (!validated) {
565 GST_INFO_OBJECT (rmdemux, "Failed to validate offset at %u",
566 rmdemux->offset);
567 if (!find_seek_offset_bytes (rmdemux, rmdemux->offset - 1)) {
568 ret = FALSE;
569 goto done;
570 }
571 validated = gst_rmdemux_validate_offset (rmdemux);
572 }
574 GST_LOG_OBJECT (rmdemux, "Found final offset. Excellent!");
576 /* now we have a new position, prepare for streaming again */
577 {
578 GstEvent *event;
580 /* Reset the demuxer state */
581 rmdemux->state = RMDEMUX_STATE_DATA_PACKET;
582 rmdemux->cur_timestamp = GST_CLOCK_TIME_NONE;
584 if (flush)
585 gst_rmdemux_send_event (rmdemux, gst_event_new_flush_stop ());
587 /* create the discont event we are going to send out */
588 event = gst_event_new_newsegment (FALSE, 1.0,
589 GST_FORMAT_TIME, (gint64) rmdemux->segment_start,
590 (gint64) rmdemux->segment_stop, rmdemux->segment_start);
592 GST_DEBUG_OBJECT (rmdemux,
593 "sending NEWSEGMENT event to all src pads with segment_start= %"
594 GST_TIME_FORMAT, GST_TIME_ARGS (rmdemux->segment_start));
595 gst_rmdemux_send_event (rmdemux, event);
597 /* notify start of new segment */
598 if (rmdemux->segment_play) {
599 gst_element_post_message (GST_ELEMENT (rmdemux),
600 gst_message_new_segment_start (GST_OBJECT (rmdemux), GST_FORMAT_TIME,
601 rmdemux->segment_start));
602 }
603 /* restart our task since it might have been stopped when we did the
604 * flush. */
605 gst_pad_start_task (rmdemux->sinkpad, (GstTaskFunction) gst_rmdemux_loop,
606 rmdemux->sinkpad);
607 }
609 done:
611 /* streaming can continue now */
612 GST_STREAM_UNLOCK (rmdemux->sinkpad);
614 return ret;
615 }
618 static gboolean
619 gst_rmdemux_src_query (GstPad * pad, GstQuery * query)
620 {
621 gboolean res = TRUE;
622 GstRMDemux *rmdemux;
624 rmdemux = GST_RMDEMUX (GST_PAD_PARENT (pad));
626 switch (GST_QUERY_TYPE (query)) {
627 case GST_QUERY_POSITION:
628 GST_DEBUG_OBJECT (rmdemux, "src_query position");
629 gst_query_set_position (query, GST_FORMAT_TIME, -1); //rmdemux->cur_timestamp,
630 break;
631 case GST_QUERY_DURATION:
632 GST_DEBUG_OBJECT (rmdemux, "src_query duration");
633 gst_query_set_duration (query, GST_FORMAT_TIME, //rmdemux->cur_timestamp,
634 rmdemux->duration);
635 break;
636 default:
637 res = FALSE;
638 break;
639 }
641 return res;
642 }
644 static const GstQueryType *
645 gst_rmdemux_src_query_types (GstPad * pad)
646 {
647 static const GstQueryType query_types[] = {
648 GST_QUERY_POSITION,
649 GST_QUERY_DURATION,
650 0
651 };
653 return query_types;
654 }
656 static GstStateChangeReturn
657 gst_rmdemux_change_state (GstElement * element, GstStateChange transition)
658 {
659 GstRMDemux *rmdemux = GST_RMDEMUX (element);
660 GstStateChangeReturn res;
662 switch (transition) {
663 case GST_STATE_CHANGE_NULL_TO_READY:
664 break;
665 case GST_STATE_CHANGE_READY_TO_PAUSED:
666 rmdemux->state = RMDEMUX_STATE_HEADER;
667 rmdemux->have_pads = FALSE;
668 rmdemux->segment_start = GST_CLOCK_TIME_NONE;
669 rmdemux->segment_stop = GST_CLOCK_TIME_NONE;
670 rmdemux->segment_play = FALSE;
671 rmdemux->running = FALSE;
672 rmdemux->cur_timestamp = GST_CLOCK_TIME_NONE;
673 break;
674 case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
675 break;
676 default:
677 break;
678 }
680 res = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
682 switch (transition) {
683 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
684 break;
685 case GST_STATE_CHANGE_PAUSED_TO_READY:
686 gst_adapter_clear (rmdemux->adapter);
687 GST_LOCK (rmdemux);
688 rmdemux->running = FALSE;
689 GST_UNLOCK (rmdemux);
690 break;
691 case GST_STATE_CHANGE_READY_TO_NULL:
692 break;
693 default:
694 break;
695 }
697 return res;
698 }
700 static GstCaps *
701 gst_rmdemux_src_getcaps (GstPad * pad)
702 {
703 guint n;
704 GstRMDemux *rmdemux = GST_RMDEMUX (GST_PAD_PARENT (pad));
706 GST_DEBUG_OBJECT (rmdemux, "getcaps");
708 for (n = 0; n < rmdemux->n_streams; n++) {
709 if (rmdemux->streams[n] != NULL && rmdemux->streams[n]->pad == pad) {
710 return gst_caps_copy (rmdemux->streams[n]->caps);
711 }
712 }
714 /* Base case */
715 return gst_caps_new_empty ();
716 }
718 /* this function is called when the pad is activated and should start
719 * processing data.
720 *
721 * We check if we can do random access to decide if we work push or
722 * pull based.
723 */
724 static gboolean
725 gst_rmdemux_sink_activate (GstPad * sinkpad)
726 {
727 if (gst_pad_check_pull_range (sinkpad)) {
728 return gst_pad_activate_pull (sinkpad, TRUE);
729 } else {
730 return gst_pad_activate_push (sinkpad, TRUE);
731 }
732 }
734 /* this function gets called when we activate ourselves in push mode.
735 * We cannot seek (ourselves) in the stream */
736 static gboolean
737 gst_rmdemux_sink_activate_push (GstPad * pad, gboolean active)
738 {
739 GstRMDemux *rmdemux;
741 rmdemux = GST_RMDEMUX (GST_PAD_PARENT (pad));
743 GST_DEBUG_OBJECT (rmdemux, "activate_push");
745 rmdemux->seekable = FALSE;
747 return TRUE;
748 }
750 /* this function gets called when we activate ourselves in pull mode.
751 * We can perform random access to the resource and we start a task
752 * to start reading */
753 static gboolean
754 gst_rmdemux_sink_activate_pull (GstPad * pad, gboolean active)
755 {
756 GstRMDemux *rmdemux;
758 rmdemux = GST_RMDEMUX (GST_PAD_PARENT (pad));
760 GST_DEBUG_OBJECT (rmdemux, "activate_pull");
762 if (active) {
763 rmdemux->seekable = TRUE;
764 rmdemux->offset = 0;
765 rmdemux->loop_state = RMDEMUX_LOOP_STATE_HEADER;
766 rmdemux->data_offset = G_MAXUINT;
768 return gst_pad_start_task (pad, (GstTaskFunction) gst_rmdemux_loop, pad);
769 } else {
770 return gst_pad_stop_task (pad);
771 }
772 }
774 /* random access mode - just pass over to our chain function */
775 static void
776 gst_rmdemux_loop (GstPad * pad)
777 {
778 GstRMDemux *rmdemux;
779 GstBuffer *buffer;
780 GstFlowReturn ret = GST_FLOW_OK;
781 guint size;
783 rmdemux = GST_RMDEMUX (GST_PAD_PARENT (pad));
785 GST_DEBUG_OBJECT (rmdemux, "loop with state=%d and offset=0x%x",
786 rmdemux->loop_state, rmdemux->offset);
788 switch (rmdemux->state) {
789 case RMDEMUX_STATE_HEADER:
790 size = HEADER_SIZE;
791 break;
792 case RMDEMUX_STATE_HEADER_DATA:
793 size = DATA_SIZE;
794 break;
795 case RMDEMUX_STATE_DATA_PACKET:
796 size = rmdemux->avg_packet_size;
797 break;
798 case RMDEMUX_STATE_EOS:
799 GST_LOG_OBJECT (rmdemux, "At EOS, pausing task");
800 goto need_pause;
801 default:
802 GST_LOG_OBJECT (rmdemux, "Default: requires %d bytes (state is %d)",
803 (int) rmdemux->size, rmdemux->state);
804 size = rmdemux->size;
805 }
807 ret = gst_pad_pull_range (pad, rmdemux->offset, size, &buffer);
808 if (ret != GST_FLOW_OK) {
809 if (rmdemux->offset == rmdemux->index_offset) {
810 /* The index isn't available so forget about it */
811 rmdemux->loop_state = RMDEMUX_LOOP_STATE_DATA;
812 rmdemux->offset = rmdemux->data_offset;
813 GST_LOCK (rmdemux);
814 rmdemux->running = TRUE;
815 rmdemux->seekable = FALSE;
816 GST_UNLOCK (rmdemux);
817 return;
818 } else {
819 GST_DEBUG_OBJECT (rmdemux,
820 "Unable to pull %d bytes at offset %p (pull_range returned %d, state is %d)",
821 (int) size, rmdemux->offset, ret, GST_STATE (rmdemux));
822 goto need_pause;
823 }
824 }
826 size = GST_BUFFER_SIZE (buffer);
828 /* Defer to the chain function */
829 ret = gst_rmdemux_chain (pad, buffer);
830 if (ret != GST_FLOW_OK) {
831 GST_DEBUG_OBJECT (rmdemux, "Chain flow failed at %p", rmdemux->offset);
832 goto need_pause;
833 }
835 rmdemux->offset += size;
837 switch (rmdemux->loop_state) {
838 case RMDEMUX_LOOP_STATE_HEADER:
839 if (rmdemux->offset >= rmdemux->data_offset) {
840 /* It's the end of the header */
841 rmdemux->loop_state = RMDEMUX_LOOP_STATE_INDEX;
842 rmdemux->offset = rmdemux->index_offset;
843 }
844 break;
845 case RMDEMUX_LOOP_STATE_INDEX:
846 if (rmdemux->state == RMDEMUX_STATE_HEADER) {
847 if (rmdemux->index_offset == 0) {
848 /* We've read the last index */
849 rmdemux->loop_state = RMDEMUX_LOOP_STATE_DATA;
850 rmdemux->offset = rmdemux->data_offset;
851 GST_LOCK (rmdemux);
852 rmdemux->running = TRUE;
853 GST_UNLOCK (rmdemux);
854 } else {
855 /* Get the next index */
856 rmdemux->offset = rmdemux->index_offset;
857 }
858 }
859 break;
860 case RMDEMUX_LOOP_STATE_DATA:
861 break;
862 }
864 return;
866 need_pause:
867 {
868 GST_LOG_OBJECT (rmdemux, "pausing task");
869 gst_pad_pause_task (pad);
870 if (GST_FLOW_IS_FATAL (ret)) {
871 gst_rmdemux_send_event (rmdemux, gst_event_new_eos ());
872 /* FIXME: add translations */
873 GST_ELEMENT_ERROR (rmdemux, STREAM, FAILED,
874 (("Internal data stream error.")),
875 ("stream stopped, reason %d", ret));
876 }
877 return;
878 }
879 }
881 static gboolean
882 gst_rmdemux_fourcc_isplausible (guint32 fourcc)
883 {
884 int i;
886 for (i = 0; i < 4; i++) {
887 if (!isprint ((int) ((unsigned char *) (&fourcc))[i])) {
888 return FALSE;
889 }
890 }
891 return TRUE;
892 }
894 static GstFlowReturn
895 gst_rmdemux_chain (GstPad * pad, GstBuffer * buffer)
896 {
897 GstFlowReturn ret = GST_FLOW_OK;
898 const guint8 *data;
899 guint16 version;
901 GstRMDemux *rmdemux = GST_RMDEMUX (GST_PAD_PARENT (pad));
903 GST_LOG_OBJECT (rmdemux, "Chaining buffer of size %d",
904 GST_BUFFER_SIZE (buffer));
906 gst_adapter_push (rmdemux->adapter, buffer);
908 while (TRUE) {
909 GST_LOG_OBJECT (rmdemux, "looping in chain");
910 switch (rmdemux->state) {
911 case RMDEMUX_STATE_HEADER:
912 {
913 if (gst_adapter_available (rmdemux->adapter) < HEADER_SIZE)
914 goto unlock;
916 data = gst_adapter_peek (rmdemux->adapter, HEADER_SIZE);
918 rmdemux->object_id = RMDEMUX_FOURCC_GET (data + 0);
919 rmdemux->size = RMDEMUX_GUINT32_GET (data + 4) - HEADER_SIZE;
920 rmdemux->object_version = RMDEMUX_GUINT16_GET (data + 8);
922 /* Sanity-check. We assume that the FOURCC is printable ASCII */
923 if (!gst_rmdemux_fourcc_isplausible (rmdemux->object_id)) {
924 /* Failed. Remain in HEADER state, try again... We flush only
925 * the actual FOURCC, not the entire header, because we could
926 * need to resync anywhere at all... really, this should never
927 * happen. */
928 GST_WARNING_OBJECT (rmdemux, "Bogus looking header, unprintable "
929 "FOURCC");
930 gst_adapter_flush (rmdemux->adapter, 4);
932 break;
933 }
935 GST_LOG_OBJECT (rmdemux, "header found with object_id=%"
936 GST_FOURCC_FORMAT
937 " size=%08x object_version=%d",
938 GST_FOURCC_ARGS (rmdemux->object_id), rmdemux->size,
939 rmdemux->object_version);
941 gst_adapter_flush (rmdemux->adapter, HEADER_SIZE);
943 switch (rmdemux->object_id) {
944 case GST_MAKE_FOURCC ('.', 'R', 'M', 'F'):
945 rmdemux->state = RMDEMUX_STATE_HEADER_RMF;
946 break;
947 case GST_MAKE_FOURCC ('P', 'R', 'O', 'P'):
948 rmdemux->state = RMDEMUX_STATE_HEADER_PROP;
949 break;
950 case GST_MAKE_FOURCC ('M', 'D', 'P', 'R'):
951 rmdemux->state = RMDEMUX_STATE_HEADER_MDPR;
952 break;
953 case GST_MAKE_FOURCC ('I', 'N', 'D', 'X'):
954 rmdemux->state = RMDEMUX_STATE_HEADER_INDX;
955 break;
956 case GST_MAKE_FOURCC ('D', 'A', 'T', 'A'):
957 rmdemux->state = RMDEMUX_STATE_HEADER_DATA;
958 break;
959 case GST_MAKE_FOURCC ('C', 'O', 'N', 'T'):
960 rmdemux->state = RMDEMUX_STATE_HEADER_CONT;
961 break;
962 default:
963 rmdemux->state = RMDEMUX_STATE_HEADER_UNKNOWN;
964 break;
965 }
966 break;
967 }
968 case RMDEMUX_STATE_HEADER_UNKNOWN:
969 {
970 if (gst_adapter_available (rmdemux->adapter) < rmdemux->size)
971 goto unlock;
973 GST_WARNING_OBJECT (rmdemux, "Unknown object_id %" GST_FOURCC_FORMAT,
974 GST_FOURCC_ARGS (rmdemux->object_id));
976 gst_adapter_flush (rmdemux->adapter, rmdemux->size);
977 rmdemux->state = RMDEMUX_STATE_HEADER;
978 break;
979 }
980 case RMDEMUX_STATE_HEADER_RMF:
981 {
982 if (gst_adapter_available (rmdemux->adapter) < rmdemux->size)
983 goto unlock;
985 if ((rmdemux->object_version == 0) || (rmdemux->object_version == 1)) {
986 data = gst_adapter_peek (rmdemux->adapter, rmdemux->size);
988 gst_rmdemux_parse__rmf (rmdemux, data, rmdemux->size);
989 }
991 gst_adapter_flush (rmdemux->adapter, rmdemux->size);
992 rmdemux->state = RMDEMUX_STATE_HEADER;
993 break;
994 }
995 case RMDEMUX_STATE_HEADER_PROP:
996 {
997 if (gst_adapter_available (rmdemux->adapter) < rmdemux->size)
998 goto unlock;
999 data = gst_adapter_peek (rmdemux->adapter, rmdemux->size);
1001 gst_rmdemux_parse_prop (rmdemux, data, rmdemux->size);
1003 gst_adapter_flush (rmdemux->adapter, rmdemux->size);
1004 rmdemux->state = RMDEMUX_STATE_HEADER;
1005 break;
1006 }
1007 case RMDEMUX_STATE_HEADER_MDPR:
1008 {
1009 if (gst_adapter_available (rmdemux->adapter) < rmdemux->size)
1010 goto unlock;
1011 data = gst_adapter_peek (rmdemux->adapter, rmdemux->size);
1013 ret = gst_rmdemux_parse_mdpr (rmdemux, data, rmdemux->size);
1015 gst_adapter_flush (rmdemux->adapter, rmdemux->size);
1016 rmdemux->state = RMDEMUX_STATE_HEADER;
1017 break;
1018 }
1019 case RMDEMUX_STATE_HEADER_CONT:
1020 {
1021 if (gst_adapter_available (rmdemux->adapter) < rmdemux->size)
1022 goto unlock;
1023 data = gst_adapter_peek (rmdemux->adapter, rmdemux->size);
1025 gst_rmdemux_parse_cont (rmdemux, data, rmdemux->size);
1027 gst_adapter_flush (rmdemux->adapter, rmdemux->size);
1028 rmdemux->state = RMDEMUX_STATE_HEADER;
1029 break;
1030 }
1031 case RMDEMUX_STATE_HEADER_DATA:
1032 {
1033 /* If we haven't already done so then signal there are no more pads */
1034 if (!rmdemux->have_pads) {
1035 gst_element_no_more_pads (GST_ELEMENT (rmdemux));
1036 rmdemux->have_pads = TRUE;
1038 GST_LOG_OBJECT (rmdemux, "no more pads.");
1039 gst_rmdemux_send_event (rmdemux,
1040 gst_event_new_newsegment (FALSE, 1.0, GST_FORMAT_TIME, (gint64) 0,
1041 (gint64) - 1, 0));
1042 }
1044 /* The actual header is only 8 bytes */
1045 rmdemux->size = DATA_SIZE;
1046 GST_DEBUG_OBJECT (rmdemux, "data available %d",
1047 gst_adapter_available (rmdemux->adapter));
1048 if (gst_adapter_available (rmdemux->adapter) < rmdemux->size)
1049 goto unlock;
1051 data = gst_adapter_peek (rmdemux->adapter, rmdemux->size);
1053 gst_rmdemux_parse_data (rmdemux, data, rmdemux->size);
1055 gst_adapter_flush (rmdemux->adapter, rmdemux->size);
1057 rmdemux->state = RMDEMUX_STATE_DATA_PACKET;
1058 break;
1059 }
1060 case RMDEMUX_STATE_HEADER_INDX:
1061 {
1062 if (gst_adapter_available (rmdemux->adapter) < rmdemux->size)
1063 goto unlock;
1064 data = gst_adapter_peek (rmdemux->adapter, rmdemux->size);
1066 rmdemux->size = gst_rmdemux_parse_indx (rmdemux, data, rmdemux->size);
1068 /* Only flush the header */
1069 gst_adapter_flush (rmdemux->adapter, HEADER_SIZE);
1071 rmdemux->state = RMDEMUX_STATE_INDX_DATA;
1072 break;
1073 }
1074 case RMDEMUX_STATE_INDX_DATA:
1075 {
1076 /* There's not always an data to get... */
1077 if (rmdemux->size > 0) {
1078 if (gst_adapter_available (rmdemux->adapter) < rmdemux->size)
1079 goto unlock;
1081 data = gst_adapter_peek (rmdemux->adapter, rmdemux->size);
1083 gst_rmdemux_parse_indx_data (rmdemux, data, rmdemux->size);
1085 gst_adapter_flush (rmdemux->adapter, rmdemux->size);
1086 }
1088 rmdemux->state = RMDEMUX_STATE_HEADER;
1089 break;
1090 }
1091 case RMDEMUX_STATE_DATA_PACKET:
1092 {
1093 if (gst_adapter_available (rmdemux->adapter) < 2)
1094 goto unlock;
1096 data = gst_adapter_peek (rmdemux->adapter, 2);
1097 version = RMDEMUX_GUINT16_GET (data);
1098 GST_DEBUG_OBJECT (rmdemux, "Data packet with version=%d", version);
1100 if (version == 0 || version == 1) {
1101 guint16 length;
1103 if (gst_adapter_available (rmdemux->adapter) < 4)
1104 goto unlock;
1105 data = gst_adapter_peek (rmdemux->adapter, 4);
1107 length = RMDEMUX_GUINT16_GET (data + 2);
1108 if (length < 4) {
1109 /* Invalid, just drop it */
1110 gst_adapter_flush (rmdemux->adapter, 4);
1111 } else {
1112 if (gst_adapter_available (rmdemux->adapter) < length)
1113 goto unlock;
1114 data = gst_adapter_peek (rmdemux->adapter, length);
1116 gst_rmdemux_parse_packet (rmdemux, data + 4, version, length - 4);
1117 rmdemux->chunk_index++;
1119 gst_adapter_flush (rmdemux->adapter, length);
1120 }
1122 if (rmdemux->chunk_index == rmdemux->n_chunks || length == 0)
1123 rmdemux->state = RMDEMUX_STATE_HEADER;
1124 } else {
1125 /* Stream done */
1126 gst_adapter_flush (rmdemux->adapter, 2);
1128 if (rmdemux->data_offset == 0) {
1129 GST_LOG_OBJECT (rmdemux,
1130 "No further data, internal demux state EOS");
1131 rmdemux->state = RMDEMUX_STATE_EOS;
1132 } else
1133 rmdemux->state = RMDEMUX_STATE_HEADER;
1134 }
1135 break;
1136 }
1137 case RMDEMUX_STATE_EOS:
1138 gst_rmdemux_send_event (rmdemux, gst_event_new_eos ());
1139 goto unlock;
1140 default:
1141 GST_WARNING_OBJECT (rmdemux, "Unhandled state %d", rmdemux->state);
1142 goto unlock;
1143 }
1146 }
1148 unlock:
1149 return ret;
1150 }
1152 static GstRMDemuxStream *
1153 gst_rmdemux_get_stream_by_id (GstRMDemux * rmdemux, int id)
1154 {
1155 int i;
1157 for (i = 0; i < rmdemux->n_streams; i++) {
1158 GstRMDemuxStream *stream;
1160 stream = rmdemux->streams[i];
1161 if (stream->id == id) {
1162 return stream;
1163 }
1164 }
1166 return NULL;
1167 }
1169 static gboolean
1170 gst_rmdemux_send_event (GstRMDemux * rmdemux, GstEvent * event)
1171 {
1172 int i;
1173 gboolean ret = TRUE;
1175 for (i = 0; i < rmdemux->n_streams; i++) {
1176 GstRMDemuxStream *stream;
1178 stream = rmdemux->streams[i];
1180 GST_DEBUG_OBJECT (rmdemux, "Pushing event to stream %d", i);
1182 gst_event_ref (event);
1183 ret = gst_pad_push_event (stream->pad, event);
1184 if (!ret)
1185 break;
1186 }
1187 gst_event_unref (event);
1189 return ret;
1190 }
1192 GstFlowReturn
1193 gst_rmdemux_add_stream (GstRMDemux * rmdemux, GstRMDemuxStream * stream)
1194 {
1195 GstFlowReturn ret = GST_FLOW_OK;
1196 int version = 0;
1198 if (stream->subtype == GST_RMDEMUX_STREAM_VIDEO) {
1199 char *name = g_strdup_printf ("video_%02d", rmdemux->n_video_streams);
1201 stream->pad =
1202 gst_pad_new_from_template (gst_static_pad_template_get
1203 (&gst_rmdemux_videosrc_template), name);
1204 g_free (name);
1206 switch (stream->fourcc) {
1207 case GST_RM_VDO_RV10:
1208 version = 1;
1209 break;
1210 case GST_RM_VDO_RV20:
1211 version = 2;
1212 break;
1213 case GST_RM_VDO_RV30:
1214 version = 3;
1215 break;
1216 case GST_RM_VDO_RV40:
1217 version = 4;
1218 break;
1219 default:
1220 GST_WARNING_OBJECT (rmdemux, "Unknown video FOURCC code");
1221 }
1223 if (version) {
1224 stream->caps =
1225 gst_caps_new_simple ("video/x-pn-realvideo", "rmversion", G_TYPE_INT,
1226 (int) version,
1227 "format", G_TYPE_INT,
1228 (int) stream->format,
1229 "subformat", G_TYPE_INT, (int) stream->subformat, NULL);
1230 }
1232 if (stream->caps) {
1233 gst_caps_set_simple (stream->caps,
1234 "width", G_TYPE_INT, stream->width,
1235 "height", G_TYPE_INT, stream->height,
1236 "framerate", G_TYPE_DOUBLE, stream->frame_rate, NULL);
1237 }
1238 rmdemux->n_video_streams++;
1240 } else if (stream->subtype == GST_RMDEMUX_STREAM_AUDIO) {
1241 char *name = g_strdup_printf ("audio_%02d", rmdemux->n_audio_streams);
1243 stream->pad =
1244 gst_pad_new_from_template (gst_static_pad_template_get
1245 (&gst_rmdemux_audiosrc_template), name);
1246 GST_LOG_OBJECT (rmdemux, "Created audio pad \"%s\"", name);
1247 g_free (name);
1248 switch (stream->fourcc) {
1249 /* Older RealAudio Codecs */
1250 case GST_RM_AUD_14_4:
1251 version = 1;
1252 break;
1254 case GST_RM_AUD_28_8:
1255 version = 2;
1256 break;
1258 /* DolbyNet (Dolby AC3, low bitrate) */
1259 case GST_RM_AUD_DNET:
1260 stream->caps =
1261 gst_caps_new_simple ("audio/x-ac3", "rate", G_TYPE_INT,
1262 (int) stream->rate, NULL);
1263 break;
1265 /* RealAudio 10 (AAC) */
1266 case GST_RM_AUD_RAAC:
1267 version = 10;
1268 break;
1270 /* MPEG-4 based */
1271 case GST_RM_AUD_RACP:
1272 stream->caps =
1273 gst_caps_new_simple ("audio/mpeg", "mpegversion", G_TYPE_INT,
1274 (int) 4, NULL);
1275 break;
1277 /* Sony ATRAC3 */
1278 case GST_RM_AUD_ATRC:
1279 stream->caps = gst_caps_new_simple ("audio/x-vnd.sony.atrac3", NULL);
1280 break;
1282 /* RealAudio G2 audio */
1283 case GST_RM_AUD_COOK:
1284 version = 8;
1285 break;
1287 /* RALF is lossless */
1288 case GST_RM_AUD_RALF:
1289 GST_DEBUG_OBJECT (rmdemux, "RALF");
1290 stream->caps = gst_caps_new_simple ("audio/x-ralf-mpeg4-generic", NULL);
1291 break;
1293 /* Sipro/ACELP.NET Voice Codec (MIME unknown) */
1294 case GST_RM_AUD_SIPR:
1295 stream->caps = gst_caps_new_simple ("audio/x-sipro", NULL);
1296 break;
1298 default:
1299 GST_WARNING_OBJECT (rmdemux,
1300 "Unknown audio FOURCC code \"%" GST_FOURCC_FORMAT "\"",
1301 stream->fourcc);
1302 break;
1303 }
1305 if (version) {
1306 stream->caps =
1307 gst_caps_new_simple ("audio/x-pn-realaudio", "raversion", G_TYPE_INT,
1308 (int) version, NULL);
1309 }
1311 if (stream->caps) {
1312 gst_caps_set_simple (stream->caps,
1313 "flavor", G_TYPE_INT, (int) stream->flavor,
1314 "rate", G_TYPE_INT, (int) stream->rate,
1315 "channels", G_TYPE_INT, (int) stream->n_channels,
1316 "width", G_TYPE_INT, (int) stream->sample_width,
1317 "leaf_size", G_TYPE_INT, (int) stream->leaf_size,
1318 "packet_size", G_TYPE_INT, (int) stream->packet_size,
1319 "height", G_TYPE_INT, (int) stream->height, NULL);
1320 }
1321 rmdemux->n_audio_streams++;
1322 } else {
1323 GST_WARNING_OBJECT (rmdemux, "not adding stream of type %d",
1324 stream->subtype);
1325 goto beach;
1326 }
1328 GST_PAD_ELEMENT_PRIVATE (stream->pad) = stream;
1329 rmdemux->streams[rmdemux->n_streams] = stream;
1330 rmdemux->n_streams++;
1331 GST_LOG_OBJECT (rmdemux, "n_streams is now %d", rmdemux->n_streams);
1333 if (stream->pad && stream->caps) {
1334 GST_DEBUG_OBJECT (rmdemux, "setting caps: %p", stream->caps);
1336 gst_pad_set_caps (stream->pad, stream->caps);
1337 gst_caps_unref (stream->caps);
1339 gst_pad_set_getcaps_function (stream->pad,
1340 GST_DEBUG_FUNCPTR (gst_rmdemux_src_getcaps));
1341 gst_pad_set_event_function (stream->pad,
1342 GST_DEBUG_FUNCPTR (gst_rmdemux_src_event));
1343 gst_pad_set_query_type_function (stream->pad,
1344 GST_DEBUG_FUNCPTR (gst_rmdemux_src_query_types));
1345 gst_pad_set_query_function (stream->pad,
1346 GST_DEBUG_FUNCPTR (gst_rmdemux_src_query));
1348 GST_DEBUG_OBJECT (rmdemux, "adding pad %p to rmdemux %p", stream->pad,
1349 rmdemux);
1350 gst_element_add_pad (GST_ELEMENT (rmdemux), stream->pad);
1352 gst_pad_push_event (stream->pad,
1353 gst_event_new_newsegment (FALSE, 1.0, GST_FORMAT_TIME, (gint64) 0,
1354 (gint64) - 1, 0));
1356 /* If there's some extra data then send it as the first packet */
1357 if (stream->extra_data_size > 0) {
1358 GstBuffer *buffer;
1360 if ((ret = gst_pad_alloc_buffer
1361 (stream->pad, GST_BUFFER_OFFSET_NONE, stream->extra_data_size,
1362 stream->caps, &buffer))
1363 != GST_FLOW_OK) {
1364 GST_WARNING_OBJECT (rmdemux, "failed to alloc extra_data src "
1365 "buffer for stream %d", stream->id);
1366 goto beach;
1367 }
1369 memcpy (GST_BUFFER_DATA (buffer), stream->extra_data,
1370 stream->extra_data_size);
1372 GST_DEBUG_OBJECT (rmdemux, "Pushing extra_data of size %d to pad",
1373 stream->extra_data_size);
1374 ret = gst_pad_push (stream->pad, buffer);
1375 }
1376 }
1378 beach:
1379 return ret;
1380 }
1382 G_GNUC_UNUSED static void
1383 re_hexdump_bytes (guint8 * ptr, int len, int offset)
1384 {
1385 guint8 *end = ptr + len;
1386 int i;
1388 while (1) {
1389 if (ptr >= end)
1390 return;
1391 g_print ("%08x: ", offset);
1392 for (i = 0; i < 16; i++) {
1393 if (ptr + i >= end) {
1394 g_print (" ");
1395 } else {
1396 g_print ("%02x ", ptr[i]);
1397 }
1398 }
1399 for (i = 0; i < 16; i++) {
1400 if (ptr + i >= end) {
1401 g_print (" ");
1402 } else {
1403 g_print ("%c", g_ascii_isprint (ptr[i]) ? ptr[i] : '.');
1404 }
1405 }
1406 g_print ("\n");
1407 ptr += 16;
1408 offset += 16;
1409 }
1410 }
1412 static char *
1413 re_get_pascal_string (const guint8 * ptr)
1414 {
1415 int length;
1417 length = ptr[0];
1418 return g_strndup ((char *) ptr + 1, length);
1419 }
1421 static int
1422 re_skip_pascal_string (const guint8 * ptr)
1423 {
1424 int length;
1426 length = ptr[0];
1428 return length + 1;
1429 }
1431 static void
1432 gst_rmdemux_parse__rmf (GstRMDemux * rmdemux, const void *data, int length)
1433 {
1434 GST_LOG_OBJECT (rmdemux, "file_version: %d", RMDEMUX_GUINT32_GET (data));
1435 GST_LOG_OBJECT (rmdemux, "num_headers: %d", RMDEMUX_GUINT32_GET (data + 4));
1436 }
1438 static void
1439 gst_rmdemux_parse_prop (GstRMDemux * rmdemux, const void *data, int length)
1440 {
1441 GST_LOG_OBJECT (rmdemux, "max bitrate: %d", RMDEMUX_GUINT32_GET (data));
1442 GST_LOG_OBJECT (rmdemux, "avg bitrate: %d", RMDEMUX_GUINT32_GET (data + 4));
1443 GST_LOG_OBJECT (rmdemux, "max packet size: %d",
1444 RMDEMUX_GUINT32_GET (data + 8));
1445 rmdemux->avg_packet_size = RMDEMUX_GUINT32_GET (data + 12);
1446 GST_LOG_OBJECT (rmdemux, "avg packet size: %d", rmdemux->avg_packet_size);
1447 rmdemux->num_packets = RMDEMUX_GUINT32_GET (data + 16);
1448 GST_LOG_OBJECT (rmdemux, "number of packets: %d", rmdemux->num_packets);
1450 GST_LOG_OBJECT (rmdemux, "duration: %d", RMDEMUX_GUINT32_GET (data + 20));
1451 rmdemux->duration = RMDEMUX_GUINT32_GET (data + 20) * GST_MSECOND;
1453 GST_LOG_OBJECT (rmdemux, "preroll: %d", RMDEMUX_GUINT32_GET (data + 24));
1454 rmdemux->index_offset = RMDEMUX_GUINT32_GET (data + 28);
1455 GST_LOG_OBJECT (rmdemux, "offset of INDX section: 0x%08x",
1456 rmdemux->index_offset);
1457 rmdemux->data_offset = RMDEMUX_GUINT32_GET (data + 32);
1458 GST_LOG_OBJECT (rmdemux, "offset of DATA section: 0x%08x",
1459 rmdemux->data_offset);
1460 GST_LOG_OBJECT (rmdemux, "n streams: %d", RMDEMUX_GUINT16_GET (data + 36));
1461 GST_LOG_OBJECT (rmdemux, "flags: 0x%04x", RMDEMUX_GUINT16_GET (data + 38));
1462 }
1464 static GstFlowReturn
1465 gst_rmdemux_parse_mdpr (GstRMDemux * rmdemux, const void *data, int length)
1466 {
1467 GstRMDemuxStream *stream;
1468 char *stream1_type_string;
1469 char *stream2_type_string;
1470 int stream_type;
1471 int offset;
1473 //re_hexdump_bytes ((guint8 *) data, length, 0);
1475 stream = g_new0 (GstRMDemuxStream, 1);
1477 stream->id = RMDEMUX_GUINT16_GET (data);
1478 stream->index = NULL;
1479 stream->seek_offset = 0;
1480 GST_LOG_OBJECT (rmdemux, "stream_number=%d", stream->id);
1482 offset = 30;
1483 stream_type = GST_RMDEMUX_STREAM_UNKNOWN;
1484 stream1_type_string = re_get_pascal_string (data + offset);
1485 offset += re_skip_pascal_string (data + offset);
1486 stream2_type_string = re_get_pascal_string (data + offset);
1487 offset += re_skip_pascal_string (data + offset);
1489 /* stream1_type_string for audio and video stream is a "put_whatever_you_want" field :
1490 observed values :
1491 - "[The ]Video/Audio Stream" (File produced by an official Real encoder)
1492 - "RealVideoPremierePlugIn-VIDEO/AUDIO" (File produced by Abobe Premiere)
1494 so, we should not rely on it to know which stream type it is
1495 */
1497 GST_LOG_OBJECT (rmdemux, "stream type: %s", stream1_type_string);
1498 GST_LOG_OBJECT (rmdemux, "MIME type=%s", stream2_type_string);
1500 if (strcmp (stream2_type_string, "video/x-pn-realvideo") == 0) {
1501 stream_type = GST_RMDEMUX_STREAM_VIDEO;
1502 } else if (strcmp (stream2_type_string, "audio/x-pn-realaudio") == 0) {
1503 stream_type = GST_RMDEMUX_STREAM_AUDIO;
1504 } else if (strcmp (stream2_type_string, "audio/x-ralf-mpeg4-generic") == 0) {
1505 /* Another audio type found in the real testsuite */
1506 stream_type = GST_RMDEMUX_STREAM_AUDIO;
1507 } else if (strcmp (stream1_type_string, "") == 0 &&
1508 strcmp (stream2_type_string, "logical-fileinfo") == 0) {
1509 stream_type = GST_RMDEMUX_STREAM_FILEINFO;
1510 } else {
1511 stream_type = GST_RMDEMUX_STREAM_UNKNOWN;
1512 GST_WARNING_OBJECT (rmdemux, "unknown stream type \"%s\",\"%s\"",
1513 stream1_type_string, stream2_type_string);
1514 }
1515 g_free (stream1_type_string);
1516 g_free (stream2_type_string);
1518 offset += 4;
1520 stream->subtype = stream_type;
1521 switch (stream_type) {
1523 case GST_RMDEMUX_STREAM_VIDEO:
1524 /* RV10/RV20/RV30/RV40 => video/x-pn-realvideo, version=1,2,3,4 */
1525 stream->fourcc = RMDEMUX_FOURCC_GET (data + offset + 8);
1526 stream->width = RMDEMUX_GUINT16_GET (data + offset + 12);
1527 stream->height = RMDEMUX_GUINT16_GET (data + offset + 14);
1528 stream->rate = RMDEMUX_GUINT16_GET (data + offset + 16);
1529 stream->subformat = RMDEMUX_GUINT32_GET (data + offset + 26);
1530 stream->format = RMDEMUX_GUINT32_GET (data + offset + 30);
1531 stream->extra_data_size = length - (offset + 34);
1532 stream->extra_data = (guint8 *) data + offset + 34;
1533 stream->frame_rate = (double) RMDEMUX_GUINT16_GET (data + offset + 22) +
1534 ((double) RMDEMUX_GUINT16_GET (data + offset + 24) / 65536.0);
1536 GST_DEBUG_OBJECT (rmdemux,
1537 "Video stream with fourcc=%" GST_FOURCC_FORMAT
1538 " width=%d height=%d rate=%d frame_rate=%f subformat=%x format=%x extra_data_size=%d",
1539 GST_FOURCC_ARGS (stream->fourcc), stream->width, stream->height,
1540 stream->rate, stream->frame_rate, stream->subformat, stream->format,
1541 stream->extra_data_size);
1542 break;
1543 case GST_RMDEMUX_STREAM_AUDIO:{
1544 stream->version = RMDEMUX_GUINT16_GET (data + offset + 4);
1545 stream->flavor = RMDEMUX_GUINT16_GET (data + offset + 22);
1546 stream->packet_size = RMDEMUX_GUINT32_GET (data + offset + 24);
1547 stream->leaf_size = RMDEMUX_GUINT16_GET (data + offset + 44);
1548 stream->height = RMDEMUX_GUINT16_GET (data + offset + 40);
1550 switch (stream->version) {
1551 case 4:
1552 stream->rate = RMDEMUX_GUINT16_GET (data + offset + 48);
1553 stream->sample_width = RMDEMUX_GUINT16_GET (data + offset + 52);
1554 stream->n_channels = RMDEMUX_GUINT16_GET (data + offset + 54);
1555 stream->fourcc = RMDEMUX_FOURCC_GET (data + offset + 62);
1556 stream->extra_data_size = 16;
1557 stream->extra_data = (guint8 *) data + offset + 71;
1558 break;
1559 case 5:
1560 stream->rate = RMDEMUX_GUINT16_GET (data + offset + 54);
1561 stream->sample_width = RMDEMUX_GUINT16_GET (data + offset + 58);
1562 stream->n_channels = RMDEMUX_GUINT16_GET (data + offset + 60);
1563 stream->fourcc = RMDEMUX_FOURCC_GET (data + offset + 66);
1564 stream->extra_data_size = RMDEMUX_GUINT32_GET (data + offset + 74);
1565 stream->extra_data = (guint8 *) data + offset + 78;
1566 break;
1567 }
1569 /* 14_4, 28_8, cook, dnet, sipr, raac, racp, ralf, atrc */
1570 GST_DEBUG_OBJECT (rmdemux,
1571 "Audio stream with rate=%d sample_width=%d n_channels=%d",
1572 stream->rate, stream->sample_width, stream->n_channels);
1574 break;
1575 }
1576 case GST_RMDEMUX_STREAM_FILEINFO:
1577 {
1578 int element_nb;
1580 /* Length of this section */
1581 GST_DEBUG_OBJECT (rmdemux, "length2: 0x%08x",
1582 RMDEMUX_GUINT32_GET (data + offset));
1583 offset += 4;
1585 /* Unknown : 00 00 00 00 */
1586 offset += 4;
1588 /* Number of variables that would follow (loop iterations) */
1589 element_nb = RMDEMUX_GUINT32_GET (data + offset);
1590 offset += 4;
1592 while (element_nb) {
1593 /* Category Id : 00 00 00 XX 00 00 */
1594 offset += 6;
1596 /* Variable Name */
1597 offset += re_skip_pascal_string (data + offset);
1599 /* Variable Value Type */
1600 /* 00 00 00 00 00 => integer/boolean, preceded by length */
1601 /* 00 00 00 02 00 => pascal string, preceded by length, no trailing \0 */
1602 offset += 5;
1604 /* Variable Value */
1605 offset += re_skip_pascal_string (data + offset);
1607 element_nb--;
1608 }
1609 }
1610 break;
1611 case GST_RMDEMUX_STREAM_UNKNOWN:
1612 default:
1613 break;
1614 }
1616 return gst_rmdemux_add_stream (rmdemux, stream);
1617 }
1619 static guint
1620 gst_rmdemux_parse_indx (GstRMDemux * rmdemux, const void *data, int length)
1621 {
1622 int n;
1623 int id;
1625 n = RMDEMUX_GUINT32_GET (data);
1626 id = RMDEMUX_GUINT16_GET (data + 4);
1627 rmdemux->index_offset = RMDEMUX_GUINT32_GET (data + 6);
1629 GST_DEBUG_OBJECT (rmdemux, "Number of indices=%d Stream ID=%d length=%d", n,
1630 id, length);
1632 /* Point to the next index_stream */
1633 rmdemux->index_stream = gst_rmdemux_get_stream_by_id (rmdemux, id);
1635 /* Return the length of the index */
1636 return 14 * n;
1637 }
1639 static void
1640 gst_rmdemux_parse_indx_data (GstRMDemux * rmdemux, const void *data, int length)
1641 {
1642 int i;
1643 int n;
1644 GstRMDemuxIndex *index;
1646 /* The number of index records */
1647 n = length / 14;
1649 if (rmdemux->index_stream == NULL)
1650 return;
1652 index = g_malloc (sizeof (GstRMDemuxIndex) * n);
1653 rmdemux->index_stream->index = index;
1654 rmdemux->index_stream->index_length = n;
1656 for (i = 0; i < n; i++) {
1657 index[i].timestamp = RMDEMUX_GUINT32_GET (data + 2) * GST_MSECOND;
1658 index[i].offset = RMDEMUX_GUINT32_GET (data + 6);
1660 GST_DEBUG_OBJECT (rmdemux, "Index found for timestamp=%f (at offset=%x)",
1661 (float) index[i].timestamp / GST_SECOND, index[i].offset);
1662 data += 14;
1663 }
1664 }
1666 static void
1667 gst_rmdemux_parse_data (GstRMDemux * rmdemux, const void *data, int length)
1668 {
1669 rmdemux->n_chunks = RMDEMUX_GUINT32_GET (data);
1670 rmdemux->data_offset = RMDEMUX_GUINT32_GET (data + 4);
1671 rmdemux->chunk_index = 0;
1672 GST_DEBUG_OBJECT (rmdemux,
1673 "Data chunk found with %d packets (next data at %p)", rmdemux->n_chunks,
1674 rmdemux->data_offset);
1675 }
1677 static void
1678 gst_rmdemux_parse_cont (GstRMDemux * rmdemux, const void *data, int length)
1679 {
1680 gchar *title = (gchar *) re_get_pascal_string (data);
1682 GST_DEBUG_OBJECT (rmdemux, "File Content : (CONT) %s", title);
1683 g_free (title);
1684 }
1686 static GstFlowReturn
1687 gst_rmdemux_parse_packet (GstRMDemux * rmdemux, const void *data,
1688 guint16 version, guint16 length)
1689 {
1690 guint16 id;
1691 GstRMDemuxStream *stream;
1692 GstBuffer *buffer;
1693 guint16 packet_size;
1694 GstFlowReturn ret = GST_FLOW_OK;
1696 id = RMDEMUX_GUINT16_GET (data);
1697 rmdemux->cur_timestamp = RMDEMUX_GUINT32_GET (data + 2) * GST_MSECOND;
1699 GST_DEBUG_OBJECT (rmdemux,
1700 "Parsing a packet for stream=%d, timestamp=" GST_TIME_FORMAT
1701 ", version=%d", id, GST_TIME_ARGS (rmdemux->cur_timestamp), version);
1703 // TODO: This is skipping over either 2 or 3 bytes (version dependent)
1704 // without even reading it. What are these for?
1705 if (version == 0) {
1706 data += 8;
1707 packet_size = length - 8;
1708 } else {
1709 data += 9;
1710 packet_size = length - 9;
1711 }
1713 stream = gst_rmdemux_get_stream_by_id (rmdemux, id);
1715 if (!stream) {
1716 GST_WARNING_OBJECT (rmdemux, "No stream for stream id %d in parsing "
1717 "data packet", id);
1718 goto beach;
1719 }
1721 if ((rmdemux->offset + packet_size) > stream->seek_offset &&
1722 stream && stream->pad) {
1723 if ((ret = gst_pad_alloc_buffer (stream->pad, GST_BUFFER_OFFSET_NONE,
1724 packet_size, stream->caps, &buffer)) != GST_FLOW_OK) {
1725 GST_WARNING_OBJECT (rmdemux, "failed to alloc src buffer for stream %d",
1726 id);
1727 return ret;
1728 }
1730 memcpy (GST_BUFFER_DATA (buffer), (guint8 *) data, packet_size);
1731 GST_BUFFER_TIMESTAMP (buffer) = rmdemux->cur_timestamp;
1733 GST_DEBUG_OBJECT (rmdemux, "Pushing buffer of size %d to pad", packet_size);
1734 ret = gst_pad_push (stream->pad, buffer);
1735 } else {
1736 GST_DEBUG_OBJECT (rmdemux,
1737 "Stream %d is skipping: seek_offset=%d, offset=%d, packet_size",
1738 stream->id, stream->seek_offset, rmdemux->offset, packet_size);
1739 }
1741 beach:
1742 return ret;
1743 }