1 /* GStreamer RealAudio demuxer
2  * Copyright (C) 2006 Tim-Philipp Müller <tim centricular net>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
17  * Boston, MA 02110-1301, USA.
18  */
19 
20 /**
21  * SECTION:element-rademux
22  *
23  * Demuxes/parses a RealAudio (.ra) file or stream into compressed audio.
24  *
25  * <refsect2>
26  * <title>Example launch line</title>
27  * |[
28  * gst-launch-1.0 filesrc location=interview.ra ! rademux ! avdec_real_288 ! audioconvert ! audioresample ! autoaudiosink
29  * ]| Read a RealAudio file and decode it and output it to the soundcard using
30  * the ALSA element. The .ra file is assumed to contain RealAudio version 2.
31  * |[
32  * gst-launch-1.0 souphttpsrc location=http://www.example.org/interview.ra ! rademux ! ac3parse ! a52dec ! audioconvert ! audioresample ! autoaudiosink
33  * ]| Stream RealAudio data containing AC3 (dnet) compressed audio and decode it
34  * and output it to the soundcard.
35  * </refsect2>
36  */
37 
38 #ifdef HAVE_CONFIG_H
39 #include "config.h"
40 #endif
41 
42 #include "rademux.h"
43 #include "rmdemux.h"
44 #include "rmutils.h"
45 
46 #include <string.h>
47 
48 static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
49     GST_PAD_SINK,
50     GST_PAD_ALWAYS,
51     GST_STATIC_CAPS ("application/x-pn-realaudio")
52     );
53 
54 static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src",
55     GST_PAD_SRC,
56     GST_PAD_SOMETIMES,
57     GST_STATIC_CAPS_ANY);
58 
59 GST_DEBUG_CATEGORY_STATIC (real_audio_demux_debug);
60 #define GST_CAT_DEFAULT real_audio_demux_debug
61 
62 #define gst_real_audio_demux_parent_class parent_class
63 G_DEFINE_TYPE (GstRealAudioDemux, gst_real_audio_demux, GST_TYPE_ELEMENT);
64 
65 static GstStateChangeReturn gst_real_audio_demux_change_state (GstElement * e,
66     GstStateChange transition);
67 static GstFlowReturn gst_real_audio_demux_chain (GstPad * pad,
68     GstObject * parent, GstBuffer * buf);
69 static gboolean gst_real_audio_demux_sink_event (GstPad * pad,
70     GstObject * parent, GstEvent * ev);
71 static gboolean gst_real_audio_demux_src_event (GstPad * pad,
72     GstObject * parent, GstEvent * ev);
73 static gboolean gst_real_audio_demux_src_query (GstPad * pad,
74     GstObject * parent, GstQuery * query);
75 static void gst_real_audio_demux_loop (GstRealAudioDemux * demux);
76 static gboolean gst_real_audio_demux_sink_activate (GstPad * sinkpad,
77     GstObject * parent);
78 static gboolean gst_real_audio_demux_sink_activate_mode (GstPad * sinkpad,
79     GstObject * parent, GstPadMode mode, gboolean active);
80 
81 static void
gst_real_audio_demux_finalize(GObject * obj)82 gst_real_audio_demux_finalize (GObject * obj)
83 {
84   GstRealAudioDemux *demux = GST_REAL_AUDIO_DEMUX (obj);
85 
86   g_object_unref (demux->adapter);
87 
88   G_OBJECT_CLASS (parent_class)->finalize (obj);
89 }
90 
91 static void
gst_real_audio_demux_class_init(GstRealAudioDemuxClass * klass)92 gst_real_audio_demux_class_init (GstRealAudioDemuxClass * klass)
93 {
94   GObjectClass *gobject_class = (GObjectClass *) klass;
95   GstElementClass *gstelement_class = (GstElementClass *) klass;
96 
97   gobject_class->finalize = gst_real_audio_demux_finalize;
98 
99   gst_element_class_add_static_pad_template (gstelement_class, &sink_template);
100   gst_element_class_add_static_pad_template (gstelement_class, &src_template);
101 
102   gst_element_class_set_static_metadata (gstelement_class, "RealAudio Demuxer",
103       "Codec/Demuxer",
104       "Demultiplex a RealAudio file",
105       "Tim-Philipp Müller <tim centricular net>");
106 
107   gstelement_class->change_state =
108       GST_DEBUG_FUNCPTR (gst_real_audio_demux_change_state);
109 
110   GST_DEBUG_CATEGORY_INIT (real_audio_demux_debug, "rademux",
111       0, "Demuxer for RealAudio streams");
112 }
113 
114 static void
gst_real_audio_demux_reset(GstRealAudioDemux * demux)115 gst_real_audio_demux_reset (GstRealAudioDemux * demux)
116 {
117   gst_adapter_clear (demux->adapter);
118 
119   if (demux->srcpad) {
120     GST_DEBUG_OBJECT (demux, "Removing source pad");
121     gst_element_remove_pad (GST_ELEMENT (demux), demux->srcpad);
122     demux->srcpad = NULL;
123   }
124 
125   if (demux->pending_tags) {
126     gst_tag_list_unref (demux->pending_tags);
127     demux->pending_tags = NULL;
128   }
129 
130   demux->state = REAL_AUDIO_DEMUX_STATE_MARKER;
131   demux->ra_version = 0;
132   demux->data_offset = 0;
133   demux->packet_size = 0;
134 
135   demux->sample_rate = 0;
136   demux->sample_width = 0;
137   demux->channels = 0;
138   demux->fourcc = 0;
139 
140   demux->need_newsegment = TRUE;
141 
142   demux->segment_running = FALSE;
143 
144   demux->byterate_num = 0;
145   demux->byterate_denom = 0;
146 
147   demux->duration = 0;
148   demux->upstream_size = 0;
149 
150   demux->offset = 0;
151 
152   demux->have_group_id = FALSE;
153   demux->group_id = G_MAXUINT;
154 
155   gst_adapter_clear (demux->adapter);
156 }
157 
158 static void
gst_real_audio_demux_init(GstRealAudioDemux * demux)159 gst_real_audio_demux_init (GstRealAudioDemux * demux)
160 {
161   demux->sinkpad = gst_pad_new_from_static_template (&sink_template, "sink");
162 
163   gst_pad_set_chain_function (demux->sinkpad,
164       GST_DEBUG_FUNCPTR (gst_real_audio_demux_chain));
165   gst_pad_set_event_function (demux->sinkpad,
166       GST_DEBUG_FUNCPTR (gst_real_audio_demux_sink_event));
167   gst_pad_set_activate_function (demux->sinkpad,
168       GST_DEBUG_FUNCPTR (gst_real_audio_demux_sink_activate));
169   gst_pad_set_activatemode_function (demux->sinkpad,
170       GST_DEBUG_FUNCPTR (gst_real_audio_demux_sink_activate_mode));
171 
172   gst_element_add_pad (GST_ELEMENT (demux), demux->sinkpad);
173 
174   demux->adapter = gst_adapter_new ();
175   gst_real_audio_demux_reset (demux);
176 }
177 
178 static gboolean
gst_real_audio_demux_sink_activate(GstPad * sinkpad,GstObject * parent)179 gst_real_audio_demux_sink_activate (GstPad * sinkpad, GstObject * parent)
180 {
181   GstQuery *query;
182   gboolean pull_mode;
183 
184   query = gst_query_new_scheduling ();
185 
186   if (!gst_pad_peer_query (sinkpad, query)) {
187     gst_query_unref (query);
188     goto activate_push;
189   }
190 
191   pull_mode = gst_query_has_scheduling_mode_with_flags (query,
192       GST_PAD_MODE_PULL, GST_SCHEDULING_FLAG_SEEKABLE);
193   gst_query_unref (query);
194 
195   if (!pull_mode)
196     goto activate_push;
197 
198   GST_DEBUG_OBJECT (sinkpad, "activating pull");
199   return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PULL, TRUE);
200 
201 activate_push:
202   {
203     GST_DEBUG_OBJECT (sinkpad, "activating push");
204     return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PUSH, TRUE);
205   }
206 }
207 
208 static gboolean
gst_real_audio_demux_sink_activate_mode(GstPad * sinkpad,GstObject * parent,GstPadMode mode,gboolean active)209 gst_real_audio_demux_sink_activate_mode (GstPad * sinkpad, GstObject * parent,
210     GstPadMode mode, gboolean active)
211 {
212   gboolean res;
213   GstRealAudioDemux *demux;
214 
215   demux = GST_REAL_AUDIO_DEMUX (parent);
216 
217   switch (mode) {
218     case GST_PAD_MODE_PUSH:
219       demux->seekable = FALSE;
220       res = TRUE;
221       break;
222     case GST_PAD_MODE_PULL:
223       if (active) {
224         demux->seekable = TRUE;
225 
226         res = gst_pad_start_task (sinkpad,
227             (GstTaskFunction) gst_real_audio_demux_loop, demux, NULL);
228       } else {
229         demux->seekable = FALSE;
230         res = gst_pad_stop_task (sinkpad);
231       }
232       break;
233     default:
234       res = FALSE;
235       break;
236   }
237   return res;
238 }
239 
240 static GstFlowReturn
gst_real_audio_demux_parse_marker(GstRealAudioDemux * demux)241 gst_real_audio_demux_parse_marker (GstRealAudioDemux * demux)
242 {
243   guint8 data[6];
244 
245   if (gst_adapter_available (demux->adapter) < 6) {
246     GST_LOG_OBJECT (demux, "need at least 6 bytes, waiting for more data");
247     return GST_FLOW_OK;
248   }
249 
250   gst_adapter_copy (demux->adapter, data, 0, 6);
251   if (memcmp (data, ".ra\375", 4) != 0)
252     goto wrong_format;
253 
254   demux->ra_version = GST_READ_UINT16_BE (data + 4);
255   GST_DEBUG_OBJECT (demux, "ra_version   = %u", demux->ra_version);
256   if (demux->ra_version != 4 && demux->ra_version != 3)
257     goto unsupported_ra_version;
258 
259   gst_adapter_flush (demux->adapter, 6);
260   demux->state = REAL_AUDIO_DEMUX_STATE_HEADER;
261   return GST_FLOW_OK;
262 
263 /* ERRORS */
264 wrong_format:
265   {
266     GST_ELEMENT_ERROR (GST_ELEMENT (demux), STREAM, WRONG_TYPE, (NULL), (NULL));
267     return GST_FLOW_ERROR;
268   }
269 
270 unsupported_ra_version:
271   {
272     GST_ELEMENT_ERROR (GST_ELEMENT (demux), STREAM, DECODE,
273         ("Cannot decode this RealAudio file, please file a bug"),
274         ("ra_version = %u", demux->ra_version));
275     return GST_FLOW_ERROR;
276   }
277 }
278 
279 static GstClockTime
gst_real_demux_get_timestamp_from_offset(GstRealAudioDemux * demux,guint64 offset)280 gst_real_demux_get_timestamp_from_offset (GstRealAudioDemux * demux,
281     guint64 offset)
282 {
283   if (offset >= demux->data_offset && demux->byterate_num > 0 &&
284       demux->byterate_denom > 0) {
285     return gst_util_uint64_scale (offset - demux->data_offset,
286         demux->byterate_denom * GST_SECOND, demux->byterate_num);
287   } else if (offset == demux->data_offset) {
288     return (GstClockTime) 0;
289   } else {
290     return GST_CLOCK_TIME_NONE;
291   }
292 }
293 
294 static gboolean
gst_real_audio_demux_get_data_offset_from_header(GstRealAudioDemux * demux)295 gst_real_audio_demux_get_data_offset_from_header (GstRealAudioDemux * demux)
296 {
297   guint8 data[16];
298 
299   gst_adapter_copy (demux->adapter, data, 0, 16);
300 
301   switch (demux->ra_version) {
302     case 3:
303       demux->data_offset = GST_READ_UINT16_BE (data) + 8;
304       break;
305     case 4:
306       demux->data_offset = GST_READ_UINT32_BE (data + 12) + 16;
307       break;
308     default:
309       demux->data_offset = 0;
310       g_return_val_if_reached (FALSE);
311   }
312 
313   return TRUE;
314 }
315 
316 static GstFlowReturn
gst_real_audio_demux_parse_header(GstRealAudioDemux * demux)317 gst_real_audio_demux_parse_header (GstRealAudioDemux * demux)
318 {
319   const guint8 *data;
320   gchar *codec_name = NULL;
321   GstCaps *caps = NULL;
322   GstEvent *event;
323   gchar *stream_id;
324   guint avail;
325 
326   g_assert (demux->ra_version == 4 || demux->ra_version == 3);
327 
328   avail = gst_adapter_available (demux->adapter);
329   if (avail < 16)
330     return GST_FLOW_OK;
331 
332   if (!gst_real_audio_demux_get_data_offset_from_header (demux))
333     return GST_FLOW_ERROR;      /* shouldn't happen */
334 
335   GST_DEBUG_OBJECT (demux, "data_offset  = %u", demux->data_offset);
336 
337   if (avail + 6 < demux->data_offset) {
338     GST_DEBUG_OBJECT (demux, "Need %u bytes, but only %u available now",
339         demux->data_offset - 6, avail);
340     return GST_FLOW_OK;
341   }
342 
343   data = gst_adapter_map (demux->adapter, demux->data_offset - 6);
344   g_assert (data);
345 
346   switch (demux->ra_version) {
347     case 3:
348       demux->fourcc = GST_RM_AUD_14_4;
349       demux->packet_size = 20;
350       demux->sample_rate = 8000;
351       demux->channels = 1;
352       demux->sample_width = 16;
353       demux->flavour = 1;
354       demux->leaf_size = 0;
355       demux->height = 0;
356       break;
357     case 4:
358       demux->flavour = GST_READ_UINT16_BE (data + 16);
359       /* demux->frame_size = GST_READ_UINT32_BE (data + 36); */
360       demux->leaf_size = GST_READ_UINT16_BE (data + 38);
361       demux->height = GST_READ_UINT16_BE (data + 34);
362       demux->packet_size = GST_READ_UINT32_BE (data + 18);
363       demux->sample_rate = GST_READ_UINT16_BE (data + 42);
364       demux->sample_width = GST_READ_UINT16_BE (data + 46);
365       demux->channels = GST_READ_UINT16_BE (data + 48);
366       demux->fourcc = GST_READ_UINT32_LE (data + 56);
367       demux->pending_tags = gst_rm_utils_read_tags (data + 63,
368           demux->data_offset - 63, gst_rm_utils_read_string8);
369       if (demux->pending_tags)
370         gst_tag_list_set_scope (demux->pending_tags, GST_TAG_SCOPE_GLOBAL);
371       break;
372     default:
373       g_assert_not_reached ();
374 #if 0
375     case 5:
376       demux->flavour = GST_READ_UINT16_BE (data + 16);
377       /* demux->frame_size = GST_READ_UINT32_BE (data + 36); */
378       demux->leaf_size = GST_READ_UINT16_BE (data + 38);
379       demux->height = GST_READ_UINT16_BE (data + 34);
380 
381       demux->sample_rate = GST_READ_UINT16_BE (data + 48);
382       demux->sample_width = GST_READ_UINT16_BE (data + 52);
383       demux->n_channels = GST_READ_UINT16_BE (data + 54);
384       demux->fourcc = RMDEMUX_FOURCC_GET (data + 60);
385       break;
386 #endif
387   }
388 
389   GST_INFO_OBJECT (demux, "packet_size  = %u", demux->packet_size);
390   GST_INFO_OBJECT (demux, "sample_rate  = %u", demux->sample_rate);
391   GST_INFO_OBJECT (demux, "sample_width = %u", demux->sample_width);
392   GST_INFO_OBJECT (demux, "channels     = %u", demux->channels);
393   GST_INFO_OBJECT (demux, "fourcc       = '%" GST_FOURCC_FORMAT "' (%08X)",
394       GST_FOURCC_ARGS (demux->fourcc), demux->fourcc);
395 
396   switch (demux->fourcc) {
397     case GST_RM_AUD_14_4:
398       caps = gst_caps_new_simple ("audio/x-pn-realaudio", "raversion",
399           G_TYPE_INT, 1, NULL);
400       demux->byterate_num = 1000;
401       demux->byterate_denom = 1;
402       break;
403 
404     case GST_RM_AUD_28_8:
405       /* FIXME: needs descrambling */
406       caps = gst_caps_new_simple ("audio/x-pn-realaudio", "raversion",
407           G_TYPE_INT, 2, NULL);
408       break;
409 
410     case GST_RM_AUD_DNET:
411       caps = gst_caps_new_simple ("audio/x-ac3", "rate", G_TYPE_INT,
412           demux->sample_rate, NULL);
413       if (demux->packet_size == 0 || demux->sample_rate == 0)
414         goto broken_file;
415       demux->byterate_num = demux->packet_size * demux->sample_rate;
416       demux->byterate_denom = 1536;
417       break;
418 
419       /* Sipro/ACELP.NET Voice Codec (MIME unknown) */
420     case GST_RM_AUD_SIPR:
421       caps = gst_caps_new_empty_simple ("audio/x-sipro");
422       break;
423 
424     default:
425       GST_WARNING_OBJECT (demux, "unknown fourcc %08X", demux->fourcc);
426       break;
427   }
428 
429   if (caps == NULL)
430     goto unknown_fourcc;
431 
432   gst_caps_set_simple (caps,
433       "flavor", G_TYPE_INT, demux->flavour,
434       "rate", G_TYPE_INT, demux->sample_rate,
435       "channels", G_TYPE_INT, demux->channels,
436       "width", G_TYPE_INT, demux->sample_width,
437       "leaf_size", G_TYPE_INT, demux->leaf_size,
438       "packet_size", G_TYPE_INT, demux->packet_size,
439       "height", G_TYPE_INT, demux->height, NULL);
440 
441   GST_INFO_OBJECT (demux, "Adding source pad, caps %" GST_PTR_FORMAT, caps);
442   demux->srcpad = gst_pad_new_from_static_template (&src_template, "src");
443   gst_pad_set_event_function (demux->srcpad,
444       GST_DEBUG_FUNCPTR (gst_real_audio_demux_src_event));
445   gst_pad_set_query_function (demux->srcpad,
446       GST_DEBUG_FUNCPTR (gst_real_audio_demux_src_query));
447   gst_pad_set_active (demux->srcpad, TRUE);
448   gst_pad_use_fixed_caps (demux->srcpad);
449 
450   stream_id =
451       gst_pad_create_stream_id (demux->srcpad, GST_ELEMENT_CAST (demux), NULL);
452 
453   event = gst_pad_get_sticky_event (demux->sinkpad, GST_EVENT_STREAM_START, 0);
454   if (event) {
455     if (gst_event_parse_group_id (event, &demux->group_id))
456       demux->have_group_id = TRUE;
457     else
458       demux->have_group_id = FALSE;
459     gst_event_unref (event);
460   } else if (!demux->have_group_id) {
461     demux->have_group_id = TRUE;
462     demux->group_id = gst_util_group_id_next ();
463   }
464 
465   event = gst_event_new_stream_start (stream_id);
466   if (demux->have_group_id)
467     gst_event_set_group_id (event, demux->group_id);
468 
469   gst_pad_push_event (demux->srcpad, event);
470   g_free (stream_id);
471 
472   gst_pad_set_caps (demux->srcpad, caps);
473   codec_name = gst_pb_utils_get_codec_description (caps);
474   gst_caps_unref (caps);
475 
476   gst_element_add_pad (GST_ELEMENT (demux), demux->srcpad);
477 
478   if (demux->byterate_num > 0 && demux->byterate_denom > 0) {
479     GstFormat bformat = GST_FORMAT_BYTES;
480     gint64 size_bytes = 0;
481 
482     GST_INFO_OBJECT (demux, "byte rate = %u/%u = %u bytes/sec",
483         demux->byterate_num, demux->byterate_denom,
484         demux->byterate_num / demux->byterate_denom);
485 
486     if (gst_pad_peer_query_duration (demux->sinkpad, bformat, &size_bytes)) {
487       demux->duration =
488           gst_real_demux_get_timestamp_from_offset (demux, size_bytes);
489       demux->upstream_size = size_bytes;
490       GST_INFO_OBJECT (demux, "upstream_size = %" G_GUINT64_FORMAT,
491           demux->upstream_size);
492       GST_INFO_OBJECT (demux, "duration      = %" GST_TIME_FORMAT,
493           GST_TIME_ARGS (demux->duration));
494     }
495   }
496 
497   demux->need_newsegment = TRUE;
498 
499   if (codec_name) {
500     if (demux->pending_tags == NULL) {
501       demux->pending_tags = gst_tag_list_new_empty ();
502       gst_tag_list_set_scope (demux->pending_tags, GST_TAG_SCOPE_GLOBAL);
503     }
504 
505     gst_tag_list_add (demux->pending_tags, GST_TAG_MERGE_REPLACE,
506         GST_TAG_AUDIO_CODEC, codec_name, NULL);
507     g_free (codec_name);
508   }
509 
510   gst_adapter_unmap (demux->adapter);
511   gst_adapter_flush (demux->adapter, demux->data_offset - 6);
512 
513   demux->state = REAL_AUDIO_DEMUX_STATE_DATA;
514   demux->need_newsegment = TRUE;
515 
516   return GST_FLOW_OK;
517 
518 /* ERRORS */
519 unknown_fourcc:
520   {
521     GST_ELEMENT_ERROR (GST_ELEMENT (demux), STREAM, DECODE, (NULL),
522         ("Unknown fourcc '0x%" G_GINT32_MODIFIER "x'", demux->fourcc));
523     return GST_FLOW_ERROR;
524   }
525 broken_file:
526   {
527     GST_ELEMENT_ERROR (GST_ELEMENT (demux), STREAM, DECODE, (NULL),
528         ("Broken file - invalid sample_rate or other header value"));
529     return GST_FLOW_ERROR;
530   }
531 
532 }
533 
534 static GstFlowReturn
gst_real_audio_demux_parse_data(GstRealAudioDemux * demux)535 gst_real_audio_demux_parse_data (GstRealAudioDemux * demux)
536 {
537   GstFlowReturn ret = GST_FLOW_OK;
538   guint avail, unit_size;
539 
540   avail = gst_adapter_available (demux->adapter);
541 
542   if (demux->packet_size > 0)
543     unit_size = demux->packet_size;
544   else
545     unit_size = avail & 0xfffffff0;     /* round down to next multiple of 16 */
546 
547   GST_LOG_OBJECT (demux, "available = %u, unit_size = %u", avail, unit_size);
548 
549   while (ret == GST_FLOW_OK && unit_size > 0 && avail >= unit_size) {
550     GstClockTime ts;
551     GstBuffer *buf;
552 
553     buf = gst_adapter_take_buffer (demux->adapter, unit_size);
554     avail -= unit_size;
555 
556     if (demux->need_newsegment) {
557       gst_pad_push_event (demux->srcpad,
558           gst_event_new_segment (&demux->segment));
559       demux->need_newsegment = FALSE;
560     }
561 
562     if (demux->pending_tags) {
563       gst_pad_push_event (demux->srcpad,
564           gst_event_new_tag (demux->pending_tags));
565       demux->pending_tags = NULL;
566     }
567 
568     if (demux->fourcc == GST_RM_AUD_DNET) {
569       buf = gst_rm_utils_descramble_dnet_buffer (buf);
570     }
571 
572     ts = gst_real_demux_get_timestamp_from_offset (demux, demux->offset);
573     GST_BUFFER_TIMESTAMP (buf) = ts;
574 
575     demux->segment.position = ts;
576 
577     ret = gst_pad_push (demux->srcpad, buf);
578   }
579 
580   return ret;
581 }
582 
583 static GstFlowReturn
gst_real_audio_demux_handle_buffer(GstRealAudioDemux * demux,GstBuffer * buf)584 gst_real_audio_demux_handle_buffer (GstRealAudioDemux * demux, GstBuffer * buf)
585 {
586   GstFlowReturn ret;
587 
588   gst_adapter_push (demux->adapter, buf);
589   buf = NULL;
590 
591   switch (demux->state) {
592     case REAL_AUDIO_DEMUX_STATE_MARKER:{
593       ret = gst_real_audio_demux_parse_marker (demux);
594       if (ret != GST_FLOW_OK || demux->state != REAL_AUDIO_DEMUX_STATE_HEADER)
595         break;
596       /* otherwise fall through */
597     }
598     case REAL_AUDIO_DEMUX_STATE_HEADER:{
599       ret = gst_real_audio_demux_parse_header (demux);
600       if (ret != GST_FLOW_OK || demux->state != REAL_AUDIO_DEMUX_STATE_DATA)
601         break;
602       /* otherwise fall through */
603     }
604     case REAL_AUDIO_DEMUX_STATE_DATA:{
605       ret = gst_real_audio_demux_parse_data (demux);
606       break;
607     }
608     default:
609       g_return_val_if_reached (GST_FLOW_ERROR);
610   }
611 
612   return ret;
613 }
614 
615 static GstFlowReturn
gst_real_audio_demux_chain(GstPad * pad,GstObject * parent,GstBuffer * buf)616 gst_real_audio_demux_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
617 {
618   GstRealAudioDemux *demux;
619 
620   demux = GST_REAL_AUDIO_DEMUX (parent);
621 
622   return gst_real_audio_demux_handle_buffer (demux, buf);
623 }
624 
625 static void
gst_real_audio_demux_loop(GstRealAudioDemux * demux)626 gst_real_audio_demux_loop (GstRealAudioDemux * demux)
627 {
628   GstFlowReturn ret;
629   GstBuffer *buf;
630   guint bytes_needed;
631 
632   /* check how much data we need */
633   switch (demux->state) {
634     case REAL_AUDIO_DEMUX_STATE_MARKER:
635       bytes_needed = 6 + 16;    /* 16 are beginning of header */
636       break;
637     case REAL_AUDIO_DEMUX_STATE_HEADER:
638       if (!gst_real_audio_demux_get_data_offset_from_header (demux))
639         goto parse_header_error;
640       bytes_needed = demux->data_offset - (6 + 16);
641       break;
642     case REAL_AUDIO_DEMUX_STATE_DATA:
643       if (demux->packet_size > 0) {
644         /* TODO: should probably take into account width/height as well? */
645         bytes_needed = demux->packet_size;
646       } else {
647         bytes_needed = 1024;
648       }
649       break;
650     default:
651       g_return_if_reached ();
652   }
653 
654   /* now get the data */
655   GST_LOG_OBJECT (demux, "getting data: %5u bytes @ %8" G_GINT64_MODIFIER "u",
656       bytes_needed, demux->offset);
657 
658   if (demux->upstream_size > 0 && demux->offset >= demux->upstream_size)
659     goto eos;
660 
661   buf = NULL;
662   ret = gst_pad_pull_range (demux->sinkpad, demux->offset, bytes_needed, &buf);
663 
664   if (ret != GST_FLOW_OK)
665     goto pull_range_error;
666 
667   if (gst_buffer_get_size (buf) != bytes_needed)
668     goto pull_range_short_read;
669 
670   ret = gst_real_audio_demux_handle_buffer (demux, buf);
671   if (ret != GST_FLOW_OK)
672     goto handle_flow_error;
673 
674   /* TODO: increase this in chain function too (for timestamps)? */
675   demux->offset += bytes_needed;
676 
677   /* check for the end of the segment */
678   if (demux->segment.stop != -1 && demux->segment.position != -1 &&
679       demux->segment.position > demux->segment.stop) {
680     GST_DEBUG_OBJECT (demux, "reached end of segment");
681     goto eos;
682   }
683 
684   return;
685 
686 /* ERRORS */
687 parse_header_error:
688   {
689     GST_ELEMENT_ERROR (demux, STREAM, DECODE, (NULL), (NULL));
690     goto pause_task;
691   }
692 handle_flow_error:
693   {
694     GST_WARNING_OBJECT (demux, "handle_buf flow: %s", gst_flow_get_name (ret));
695     goto pause_task;
696   }
697 pull_range_error:
698   {
699     GST_WARNING_OBJECT (demux, "pull range flow: %s", gst_flow_get_name (ret));
700     goto pause_task;
701   }
702 pull_range_short_read:
703   {
704     GST_WARNING_OBJECT (demux, "pull range short read: wanted %u bytes, but "
705         "got only %" G_GSIZE_FORMAT " bytes", bytes_needed,
706         gst_buffer_get_size (buf));
707     gst_buffer_unref (buf);
708     goto eos;
709   }
710 eos:
711   {
712     if (demux->state != REAL_AUDIO_DEMUX_STATE_DATA) {
713       GST_WARNING_OBJECT (demux, "reached EOS before finished parsing header");
714       goto parse_header_error;
715     }
716     GST_INFO_OBJECT (demux, "EOS");
717     if ((demux->segment.flags & GST_SEEK_FLAG_SEGMENT) != 0) {
718       gint64 stop;
719 
720       /* for segment playback we need to post when (in stream time)
721        * we stopped, this is either stop (when set) or the duration. */
722       if ((stop = demux->segment.stop) == -1)
723         stop = demux->segment.duration;
724 
725       GST_DEBUG_OBJECT (demux, "sending segment done, at end of segment");
726       gst_element_post_message (GST_ELEMENT (demux),
727           gst_message_new_segment_done (GST_OBJECT (demux), GST_FORMAT_TIME,
728               stop));
729       gst_pad_push_event (demux->srcpad,
730           gst_event_new_segment_done (GST_FORMAT_TIME, stop));
731     } else {
732       /* normal playback, send EOS event downstream */
733       GST_DEBUG_OBJECT (demux, "sending EOS event, at end of stream");
734       gst_pad_push_event (demux->srcpad, gst_event_new_eos ());
735     }
736     goto pause_task;
737   }
738 pause_task:
739   {
740     demux->segment_running = FALSE;
741     gst_pad_pause_task (demux->sinkpad);
742     GST_DEBUG_OBJECT (demux, "pausing task");
743     return;
744   }
745 }
746 
747 static gboolean
gst_real_audio_demux_sink_event(GstPad * pad,GstObject * parent,GstEvent * event)748 gst_real_audio_demux_sink_event (GstPad * pad, GstObject * parent,
749     GstEvent * event)
750 {
751   GstRealAudioDemux *demux;
752   gboolean ret;
753 
754   demux = GST_REAL_AUDIO_DEMUX (parent);
755 
756   switch (GST_EVENT_TYPE (event)) {
757     case GST_EVENT_SEGMENT:{
758       /* FIXME */
759       gst_event_unref (event);
760       demux->need_newsegment = TRUE;
761       ret = TRUE;
762       break;
763     }
764     default:
765       ret = gst_pad_event_default (pad, parent, event);
766       break;
767   }
768   return ret;
769 }
770 
771 static gboolean
gst_real_audio_demux_handle_seek(GstRealAudioDemux * demux,GstEvent * event)772 gst_real_audio_demux_handle_seek (GstRealAudioDemux * demux, GstEvent * event)
773 {
774   GstFormat format;
775   GstSeekFlags flags;
776   GstSeekType cur_type, stop_type;
777   gboolean flush, update;
778   gdouble rate;
779   guint64 seek_pos;
780   gint64 cur, stop;
781 
782   if (!demux->seekable)
783     goto not_seekable;
784 
785   if (demux->byterate_num == 0 || demux->byterate_denom == 0)
786     goto no_bitrate;
787 
788   gst_event_parse_seek (event, &rate, &format, &flags,
789       &cur_type, &cur, &stop_type, &stop);
790 
791   if (format != GST_FORMAT_TIME)
792     goto only_time_format_supported;
793 
794   if (rate <= 0.0)
795     goto cannot_do_backwards_playback;
796 
797   flush = ((flags & GST_SEEK_FLAG_FLUSH) != 0);
798 
799   GST_DEBUG_OBJECT (demux, "flush=%d, rate=%g", flush, rate);
800 
801   /* unlock streaming thread and make streaming stop */
802   if (flush) {
803     gst_pad_push_event (demux->sinkpad, gst_event_new_flush_start ());
804     gst_pad_push_event (demux->srcpad, gst_event_new_flush_start ());
805   } else {
806     gst_pad_pause_task (demux->sinkpad);
807   }
808 
809   GST_PAD_STREAM_LOCK (demux->sinkpad);
810 
811   gst_segment_do_seek (&demux->segment, rate, format, flags,
812       cur_type, cur, stop_type, stop, &update);
813 
814   GST_DEBUG_OBJECT (demux, "segment: %" GST_SEGMENT_FORMAT, &demux->segment);
815 
816   seek_pos = gst_util_uint64_scale (demux->segment.start,
817       demux->byterate_num, demux->byterate_denom * GST_SECOND);
818   if (demux->packet_size > 0) {
819     seek_pos -= seek_pos % demux->packet_size;
820   }
821   seek_pos += demux->data_offset;
822 
823   GST_DEBUG_OBJECT (demux, "seek_pos = %" G_GUINT64_FORMAT, seek_pos);
824 
825   /* stop flushing */
826   gst_pad_push_event (demux->sinkpad, gst_event_new_flush_stop (TRUE));
827   gst_pad_push_event (demux->srcpad, gst_event_new_flush_stop (TRUE));
828 
829   demux->offset = seek_pos;
830   demux->need_newsegment = TRUE;
831 
832   /* notify start of new segment */
833   if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
834     gst_element_post_message (GST_ELEMENT (demux),
835         gst_message_new_segment_start (GST_OBJECT (demux),
836             GST_FORMAT_TIME, demux->segment.position));
837   }
838 
839   demux->segment_running = TRUE;
840   /* restart our task since it might have been stopped when we did the flush */
841   gst_pad_start_task (demux->sinkpad,
842       (GstTaskFunction) gst_real_audio_demux_loop, demux, NULL);
843 
844   /* streaming can continue now */
845   GST_PAD_STREAM_UNLOCK (demux->sinkpad);
846 
847   return TRUE;
848 
849 /* ERRORS */
850 not_seekable:
851   {
852     GST_DEBUG_OBJECT (demux, "seek failed: cannot seek in streaming mode");
853     return FALSE;
854   }
855 no_bitrate:
856   {
857     GST_DEBUG_OBJECT (demux, "seek failed: bitrate unknown");
858     return FALSE;
859   }
860 only_time_format_supported:
861   {
862     GST_DEBUG_OBJECT (demux, "can only seek in TIME format");
863     return FALSE;
864   }
865 cannot_do_backwards_playback:
866   {
867     GST_DEBUG_OBJECT (demux, "can only seek with positive rate, not %lf", rate);
868     return FALSE;
869   }
870 }
871 
872 static gboolean
gst_real_audio_demux_src_event(GstPad * pad,GstObject * parent,GstEvent * event)873 gst_real_audio_demux_src_event (GstPad * pad, GstObject * parent,
874     GstEvent * event)
875 {
876   GstRealAudioDemux *demux;
877   gboolean ret = FALSE;
878 
879   demux = GST_REAL_AUDIO_DEMUX (parent);
880 
881   switch (GST_EVENT_TYPE (event)) {
882     case GST_EVENT_QOS:
883       gst_event_unref (event);
884       break;
885     case GST_EVENT_SEEK:
886       ret = gst_real_audio_demux_handle_seek (demux, event);
887       gst_event_unref (event);
888       break;
889     default:
890       ret = gst_pad_event_default (pad, parent, event);
891       break;
892   }
893 
894   return ret;
895 }
896 
897 static gboolean
gst_real_audio_demux_src_query(GstPad * pad,GstObject * parent,GstQuery * query)898 gst_real_audio_demux_src_query (GstPad * pad, GstObject * parent,
899     GstQuery * query)
900 {
901   GstRealAudioDemux *demux;
902   gboolean ret = FALSE;
903 
904   demux = GST_REAL_AUDIO_DEMUX (parent);
905 
906   switch (GST_QUERY_TYPE (query)) {
907     case GST_QUERY_DURATION:{
908       GstFormat format;
909 
910       gst_query_parse_duration (query, &format, NULL);
911       if (format == GST_FORMAT_TIME && demux->duration > 0) {
912         gst_query_set_duration (query, GST_FORMAT_TIME, demux->duration);
913         ret = TRUE;
914       } else if (format == GST_FORMAT_BYTES && demux->upstream_size > 0) {
915         gst_query_set_duration (query, GST_FORMAT_BYTES,
916             demux->upstream_size - demux->data_offset);
917         ret = TRUE;
918       }
919       break;
920     }
921     case GST_QUERY_SEEKING:{
922       GstFormat format;
923       gboolean seekable;
924 
925       gst_query_parse_seeking (query, &format, NULL, NULL, NULL);
926       seekable = (format == GST_FORMAT_TIME && demux->seekable);
927       gst_query_set_seeking (query, format, seekable, 0,
928           (format == GST_FORMAT_TIME) ? demux->duration : -1);
929       ret = TRUE;
930       break;
931     }
932     case GST_QUERY_SEGMENT:
933     {
934       GstFormat format;
935       gint64 start, stop;
936 
937       format = demux->segment.format;
938 
939       start =
940           gst_segment_to_stream_time (&demux->segment, format,
941           demux->segment.start);
942       if ((stop = demux->segment.stop) == -1)
943         stop = demux->segment.duration;
944       else
945         stop = gst_segment_to_stream_time (&demux->segment, format, stop);
946 
947       gst_query_set_segment (query, demux->segment.rate, format, start, stop);
948       ret = TRUE;
949       break;
950     }
951     default:
952       ret = gst_pad_query_default (pad, parent, query);
953       break;
954   }
955 
956   return ret;
957 }
958 
959 static GstStateChangeReturn
gst_real_audio_demux_change_state(GstElement * element,GstStateChange transition)960 gst_real_audio_demux_change_state (GstElement * element,
961     GstStateChange transition)
962 {
963   GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
964   GstRealAudioDemux *demux = GST_REAL_AUDIO_DEMUX (element);
965 
966   switch (transition) {
967     case GST_STATE_CHANGE_NULL_TO_READY:
968       break;
969     case GST_STATE_CHANGE_READY_TO_PAUSED:
970       demux->state = REAL_AUDIO_DEMUX_STATE_MARKER;
971       demux->segment_running = FALSE;
972       gst_segment_init (&demux->segment, GST_FORMAT_TIME);
973       gst_adapter_clear (demux->adapter);
974       break;
975     case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
976       break;
977     default:
978       break;
979   }
980 
981   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
982 
983   switch (transition) {
984     case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
985       break;
986     case GST_STATE_CHANGE_PAUSED_TO_READY:{
987       gst_real_audio_demux_reset (demux);
988       gst_segment_init (&demux->segment, GST_FORMAT_UNDEFINED);
989       break;
990     }
991     case GST_STATE_CHANGE_READY_TO_NULL:
992       break;
993     default:
994       break;
995   }
996 
997   return ret;
998 }
999 
1000 gboolean
gst_rademux_plugin_init(GstPlugin * plugin)1001 gst_rademux_plugin_init (GstPlugin * plugin)
1002 {
1003   return gst_element_register (plugin, "rademux",
1004       GST_RANK_SECONDARY, GST_TYPE_REAL_AUDIO_DEMUX);
1005 }
1006