• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* GStreamer Musepack decoder plugin
2  * Copyright (C) 2004 Ronald Bultje <rbultje@ronald.bitfreak.net>
3  * Copyright (C) 2006 Tim-Philipp Müller <tim centricular net>
4  * Copyright (C) 2008 Sebastian Dröge <slomo@circular-chaos.org>
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public
17  * License along with this library; if not, write to the
18  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
19  * Boston, MA 02110-1301, USA.
20  */
21 
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25 
26 #include "gstmusepackdec.h"
27 #include "gstmusepackreader.h"
28 
29 GST_DEBUG_CATEGORY (musepackdec_debug);
30 #define GST_CAT_DEFAULT musepackdec_debug
31 
32 static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
33     GST_PAD_SINK,
34     GST_PAD_ALWAYS,
35     GST_STATIC_CAPS ("audio/x-musepack, streamversion = (int) { 7, 8 }")
36     );
37 
38 #ifdef MPC_FIXED_POINT
39 # if G_BYTE_ORDER == G_LITTLE_ENDIAN
40 #  define GST_MPC_FORMAT "S32LE"
41 # else
42 #  define GST_MPC_FORMAT "S32BE"
43 # endif
44 #else
45 # if G_BYTE_ORDER == G_LITTLE_ENDIAN
46 #  define GST_MPC_FORMAT "F32LE"
47 # else
48 #  define GST_MPC_FORMAT "F32BE"
49 # endif
50 #endif
51 
52 static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src",
53     GST_PAD_SRC,
54     GST_PAD_ALWAYS,
55     GST_STATIC_CAPS ("audio/x-raw, "
56         "format = (string) " GST_MPC_FORMAT ", "
57         "layout = (string) interleaved, "
58         "rate = (int) [ 8000, 96000 ], " "channels = (int) [ 1, 2 ]")
59     );
60 
61 static void gst_musepackdec_dispose (GObject * obj);
62 
63 static gboolean gst_musepackdec_src_event (GstPad * pad, GstObject * parent,
64     GstEvent * event);
65 static gboolean gst_musepackdec_src_query (GstPad * pad, GstObject * parent,
66     GstQuery * query);
67 static gboolean gst_musepackdec_sink_activate (GstPad * sinkpad,
68     GstObject * parent);
69 static gboolean gst_musepackdec_sink_activate_mode (GstPad * sinkpad,
70     GstObject * parent, GstPadMode mode, gboolean active);
71 
72 static void gst_musepackdec_loop (GstPad * sinkpad);
73 static GstStateChangeReturn
74 gst_musepackdec_change_state (GstElement * element, GstStateChange transition);
75 
76 #define parent_class gst_musepackdec_parent_class
77 G_DEFINE_TYPE_WITH_CODE (GstMusepackDec, gst_musepackdec, GST_TYPE_ELEMENT,
78     GST_DEBUG_CATEGORY_INIT (musepackdec_debug, "musepackdec", 0,
79         "mpc decoder");
80     );
81 GST_ELEMENT_REGISTER_DEFINE (musepackdec, "musepackdec",
82     GST_RANK_PRIMARY, GST_TYPE_MUSEPACK_DEC);
83 static void
gst_musepackdec_class_init(GstMusepackDecClass * klass)84 gst_musepackdec_class_init (GstMusepackDecClass * klass)
85 {
86   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
87   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
88 
89   gst_element_class_add_static_pad_template (element_class, &src_template);
90   gst_element_class_add_static_pad_template (element_class, &sink_template);
91 
92   gst_element_class_set_static_metadata (element_class, "Musepack decoder",
93       "Codec/Decoder/Audio",
94       "Musepack decoder", "Ronald Bultje <rbultje@ronald.bitfreak.net>");
95 
96   gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_musepackdec_dispose);
97 
98   element_class->change_state =
99       GST_DEBUG_FUNCPTR (gst_musepackdec_change_state);
100 }
101 
102 static void
gst_musepackdec_init(GstMusepackDec * musepackdec)103 gst_musepackdec_init (GstMusepackDec * musepackdec)
104 {
105   musepackdec->offset = 0;
106   musepackdec->rate = 0;
107   musepackdec->bps = 0;
108 
109   musepackdec->r = g_new (mpc_reader, 1);
110 
111   musepackdec->sinkpad =
112       gst_pad_new_from_static_template (&sink_template, "sink");
113   gst_pad_set_activate_function (musepackdec->sinkpad,
114       GST_DEBUG_FUNCPTR (gst_musepackdec_sink_activate));
115   gst_pad_set_activatemode_function (musepackdec->sinkpad,
116       GST_DEBUG_FUNCPTR (gst_musepackdec_sink_activate_mode));
117   gst_element_add_pad (GST_ELEMENT (musepackdec), musepackdec->sinkpad);
118 
119   musepackdec->srcpad = gst_pad_new_from_static_template (&src_template, "src");
120   gst_pad_set_event_function (musepackdec->srcpad,
121       GST_DEBUG_FUNCPTR (gst_musepackdec_src_event));
122   gst_pad_set_query_function (musepackdec->srcpad,
123       GST_DEBUG_FUNCPTR (gst_musepackdec_src_query));
124   gst_pad_use_fixed_caps (musepackdec->srcpad);
125   gst_element_add_pad (GST_ELEMENT (musepackdec), musepackdec->srcpad);
126 }
127 
128 static void
gst_musepackdec_dispose(GObject * obj)129 gst_musepackdec_dispose (GObject * obj)
130 {
131   GstMusepackDec *musepackdec = GST_MUSEPACK_DEC (obj);
132 
133   g_free (musepackdec->r);
134   musepackdec->r = NULL;
135 
136   if (musepackdec->d) {
137     mpc_demux_exit (musepackdec->d);
138     musepackdec->d = NULL;
139   }
140 
141   G_OBJECT_CLASS (parent_class)->dispose (obj);
142 }
143 
144 static void
gst_musepackdec_send_newsegment(GstMusepackDec * dec)145 gst_musepackdec_send_newsegment (GstMusepackDec * dec)
146 {
147   GstSegment os = dec->segment;
148 
149   os.format = GST_FORMAT_TIME;
150   os.start = gst_util_uint64_scale_int (os.start, GST_SECOND, dec->rate);
151   if (os.stop)
152     os.stop = gst_util_uint64_scale_int (os.stop, GST_SECOND, dec->rate);
153   os.time = gst_util_uint64_scale_int (os.time, GST_SECOND, dec->rate);
154 
155   GST_DEBUG_OBJECT (dec, "sending newsegment from %" GST_TIME_FORMAT
156       " to %" GST_TIME_FORMAT ", rate = %.1f", GST_TIME_ARGS (os.start),
157       GST_TIME_ARGS (os.stop), os.rate);
158 
159   gst_pad_push_event (dec->srcpad, gst_event_new_segment (&os));
160 }
161 
162 static gboolean
gst_musepackdec_handle_seek_event(GstMusepackDec * dec,GstEvent * event)163 gst_musepackdec_handle_seek_event (GstMusepackDec * dec, GstEvent * event)
164 {
165   GstSeekType start_type, stop_type;
166   GstSeekFlags flags;
167   GstSegment segment;
168   GstFormat format;
169   gboolean flush;
170   gdouble rate;
171   gint64 start, stop;
172   gint samplerate;
173 
174   gst_event_parse_seek (event, &rate, &format, &flags, &start_type, &start,
175       &stop_type, &stop);
176 
177   if (format != GST_FORMAT_TIME && format != GST_FORMAT_DEFAULT) {
178     GST_DEBUG_OBJECT (dec, "seek failed: only TIME or DEFAULT format allowed");
179     return FALSE;
180   }
181 
182   samplerate = g_atomic_int_get (&dec->rate);
183 
184   if (format == GST_FORMAT_TIME) {
185     if (start_type != GST_SEEK_TYPE_NONE)
186       start = gst_util_uint64_scale_int (start, samplerate, GST_SECOND);
187     if (stop_type != GST_SEEK_TYPE_NONE)
188       stop = gst_util_uint64_scale_int (stop, samplerate, GST_SECOND);
189   }
190 
191   flush = ((flags & GST_SEEK_FLAG_FLUSH) == GST_SEEK_FLAG_FLUSH);
192 
193   if (flush)
194     gst_pad_push_event (dec->srcpad, gst_event_new_flush_start ());
195   else
196     gst_pad_pause_task (dec->sinkpad);  /* not _stop_task()? */
197 
198   GST_PAD_STREAM_LOCK (dec->sinkpad);
199 
200   /* operate on segment copy until we know the seek worked */
201   segment = dec->segment;
202 
203   gst_segment_do_seek (&segment, rate, GST_FORMAT_DEFAULT,
204       flags, start_type, start, stop_type, stop, NULL);
205 
206   gst_pad_push_event (dec->sinkpad, gst_event_new_flush_stop (TRUE));
207 
208   GST_DEBUG_OBJECT (dec, "segment: [%" G_GINT64_FORMAT "-%" G_GINT64_FORMAT
209       "] = [%" GST_TIME_FORMAT "-%" GST_TIME_FORMAT "]",
210       segment.start, segment.stop,
211       GST_TIME_ARGS (segment.start * GST_SECOND / dec->rate),
212       GST_TIME_ARGS (segment.stop * GST_SECOND / dec->rate));
213 
214   GST_DEBUG_OBJECT (dec, "performing seek to sample %" G_GINT64_FORMAT,
215       segment.start);
216 
217   if (segment.start >= segment.duration) {
218     GST_WARNING_OBJECT (dec, "seek out of bounds");
219     goto failed;
220   }
221   if (mpc_demux_seek_sample (dec->d, segment.start) != MPC_STATUS_OK)
222     goto failed;
223 
224   if ((flags & GST_SEEK_FLAG_SEGMENT) == GST_SEEK_FLAG_SEGMENT) {
225     GST_DEBUG_OBJECT (dec, "posting SEGMENT_START message");
226 
227     gst_element_post_message (GST_ELEMENT (dec),
228         gst_message_new_segment_start (GST_OBJECT (dec), GST_FORMAT_TIME,
229             gst_util_uint64_scale_int (segment.start, GST_SECOND, dec->rate)));
230   }
231 
232   if (flush) {
233     gst_pad_push_event (dec->srcpad, gst_event_new_flush_stop (TRUE));
234   }
235 
236   segment.position = segment.start;
237   dec->segment = segment;
238   gst_musepackdec_send_newsegment (dec);
239 
240   GST_DEBUG_OBJECT (dec, "seek successful");
241 
242   gst_pad_start_task (dec->sinkpad,
243       (GstTaskFunction) gst_musepackdec_loop, dec->sinkpad, NULL);
244 
245   GST_PAD_STREAM_UNLOCK (dec->sinkpad);
246 
247   return TRUE;
248 
249 failed:
250   {
251     GST_WARNING_OBJECT (dec, "seek failed");
252     GST_PAD_STREAM_UNLOCK (dec->sinkpad);
253     return FALSE;
254   }
255 }
256 
257 static gboolean
gst_musepackdec_src_event(GstPad * pad,GstObject * parent,GstEvent * event)258 gst_musepackdec_src_event (GstPad * pad, GstObject * parent, GstEvent * event)
259 {
260   GstMusepackDec *dec;
261   gboolean res;
262 
263   dec = GST_MUSEPACK_DEC (parent);
264 
265   GST_DEBUG_OBJECT (dec, "handling %s event", GST_EVENT_TYPE_NAME (event));
266 
267   switch (GST_EVENT_TYPE (event)) {
268     case GST_EVENT_SEEK:
269       res = gst_musepackdec_handle_seek_event (dec, event);
270       break;
271     default:
272       res = gst_pad_event_default (pad, parent, event);
273       break;
274   }
275 
276   return res;
277 }
278 
279 static gboolean
gst_musepackdec_src_query(GstPad * pad,GstObject * parent,GstQuery * query)280 gst_musepackdec_src_query (GstPad * pad, GstObject * parent, GstQuery * query)
281 {
282   GstMusepackDec *musepackdec = GST_MUSEPACK_DEC (parent);
283   GstFormat format;
284   gboolean res = FALSE;
285   gint samplerate;
286 
287   samplerate = g_atomic_int_get (&musepackdec->rate);
288 
289   switch (GST_QUERY_TYPE (query)) {
290     case GST_QUERY_POSITION:{
291       gint64 cur, cur_off;
292 
293       if (samplerate == 0)
294         goto done;
295 
296       gst_query_parse_position (query, &format, NULL);
297 
298       GST_OBJECT_LOCK (musepackdec);
299       cur_off = musepackdec->segment.position;
300       GST_OBJECT_UNLOCK (musepackdec);
301 
302       if (format == GST_FORMAT_TIME) {
303         cur = gst_util_uint64_scale_int (cur_off, GST_SECOND, samplerate);
304         gst_query_set_position (query, GST_FORMAT_TIME, cur);
305         res = TRUE;
306       } else if (format == GST_FORMAT_DEFAULT) {
307         gst_query_set_position (query, GST_FORMAT_DEFAULT, cur_off);
308         res = TRUE;
309       }
310       break;
311     }
312     case GST_QUERY_DURATION:{
313       gint64 len, len_off;
314 
315       if (samplerate == 0)
316         goto done;
317 
318       gst_query_parse_duration (query, &format, NULL);
319 
320       GST_OBJECT_LOCK (musepackdec);
321       len_off = musepackdec->segment.duration;
322       GST_OBJECT_UNLOCK (musepackdec);
323 
324       if (format == GST_FORMAT_TIME) {
325         len = gst_util_uint64_scale_int (len_off, GST_SECOND, samplerate);
326         gst_query_set_duration (query, GST_FORMAT_TIME, len);
327         res = TRUE;
328       } else if (format == GST_FORMAT_DEFAULT) {
329         gst_query_set_duration (query, GST_FORMAT_DEFAULT, len_off);
330         res = TRUE;
331       }
332       break;
333     }
334     case GST_QUERY_SEEKING:{
335       GstFormat fmt;
336       gint64 len, len_off;
337 
338       res = TRUE;
339       gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL);
340 
341       GST_OBJECT_LOCK (musepackdec);
342       len_off = musepackdec->segment.duration;
343       GST_OBJECT_UNLOCK (musepackdec);
344 
345       if (fmt == GST_FORMAT_TIME) {
346         len = gst_util_uint64_scale_int (len_off, GST_SECOND, samplerate);
347         gst_query_set_seeking (query, fmt, TRUE, 0, len);
348       } else if (fmt == GST_FORMAT_DEFAULT) {
349         gst_query_set_seeking (query, fmt, TRUE, 0, len_off);
350       } else {
351         gst_query_set_seeking (query, fmt, FALSE, -1, -1);
352       }
353       break;
354     }
355     default:
356       res = gst_pad_query_default (pad, parent, query);
357       break;
358   }
359 
360 done:
361   return res;
362 }
363 
364 static gboolean
gst_musepack_stream_init(GstMusepackDec * musepackdec)365 gst_musepack_stream_init (GstMusepackDec * musepackdec)
366 {
367   mpc_streaminfo i;
368   GstTagList *tags;
369   GstCaps *caps;
370   gchar *stream_id;
371 
372   /* set up reading */
373   gst_musepack_init_reader (musepackdec->r, musepackdec);
374 
375   musepackdec->d = mpc_demux_init (musepackdec->r);
376   if (!musepackdec->d) {
377     GST_ELEMENT_ERROR (musepackdec, STREAM, WRONG_TYPE, (NULL), (NULL));
378     return FALSE;
379   }
380 
381   mpc_demux_get_info (musepackdec->d, &i);
382 
383   stream_id = gst_pad_create_stream_id (musepackdec->srcpad,
384       GST_ELEMENT_CAST (musepackdec), NULL);
385   gst_pad_push_event (musepackdec->srcpad,
386       gst_event_new_stream_start (stream_id));
387   g_free (stream_id);
388 
389   /* capsnego */
390   caps = gst_caps_new_simple ("audio/x-raw",
391       "format", G_TYPE_STRING, GST_MPC_FORMAT,
392       "layout", G_TYPE_STRING, "interleaved",
393       "channels", G_TYPE_INT, i.channels,
394       "rate", G_TYPE_INT, i.sample_freq, NULL);
395   gst_pad_use_fixed_caps (musepackdec->srcpad);
396   if (!gst_pad_set_caps (musepackdec->srcpad, caps)) {
397     GST_ELEMENT_ERROR (musepackdec, CORE, NEGOTIATION, (NULL), (NULL));
398     return FALSE;
399   }
400 
401   g_atomic_int_set (&musepackdec->bps, 4 * i.channels);
402   g_atomic_int_set (&musepackdec->rate, i.sample_freq);
403 
404   musepackdec->segment.position = 0;
405   musepackdec->segment.duration = mpc_streaminfo_get_length_samples (&i);
406 
407   /* send basic tags */
408   tags = gst_tag_list_new_empty ();
409   gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE,
410       GST_TAG_AUDIO_CODEC, "Musepack", NULL);
411 
412   if (i.encoder[0] != '\0' && i.encoder_version > 0) {
413     gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE,
414         GST_TAG_ENCODER, i.encoder,
415         GST_TAG_ENCODER_VERSION, i.encoder_version, NULL);
416   }
417 
418   if (i.bitrate > 0) {
419     gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE,
420         GST_TAG_BITRATE, i.bitrate, NULL);
421   } else if (i.average_bitrate > 0.0) {
422     gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE,
423         GST_TAG_BITRATE, (guint) i.average_bitrate, NULL);
424   }
425 
426   if (i.gain_title != 0 || i.gain_album != 0) {
427     gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE,
428         GST_TAG_TRACK_GAIN, (gdouble) i.gain_title / 100.0,
429         GST_TAG_ALBUM_GAIN, (gdouble) i.gain_album / 100.0, NULL);
430   }
431 
432   if (i.peak_title != 0 && i.peak_title != 32767 &&
433       i.peak_album != 0 && i.peak_album != 32767) {
434     gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE,
435         GST_TAG_TRACK_PEAK, (gdouble) i.peak_title / 32767.0,
436         GST_TAG_ALBUM_PEAK, (gdouble) i.peak_album / 32767.0, NULL);
437   }
438 
439   GST_LOG_OBJECT (musepackdec, "Posting tags: %" GST_PTR_FORMAT, tags);
440   gst_pad_push_event (musepackdec->srcpad, gst_event_new_tag (tags));
441 
442 
443   return TRUE;
444 }
445 
446 static gboolean
gst_musepackdec_sink_activate(GstPad * sinkpad,GstObject * parent)447 gst_musepackdec_sink_activate (GstPad * sinkpad, GstObject * parent)
448 {
449   GstQuery *query;
450   gboolean pull_mode;
451 
452   query = gst_query_new_scheduling ();
453 
454   if (!gst_pad_peer_query (sinkpad, query)) {
455     gst_query_unref (query);
456     return FALSE;
457   }
458 
459   pull_mode = gst_query_has_scheduling_mode_with_flags (query,
460       GST_PAD_MODE_PULL, GST_SCHEDULING_FLAG_SEEKABLE);
461   gst_query_unref (query);
462 
463   if (!pull_mode)
464     return FALSE;
465 
466   GST_DEBUG_OBJECT (sinkpad, "activating pull");
467   return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PULL, TRUE);
468 }
469 
470 static gboolean
gst_musepackdec_sink_activate_mode(GstPad * sinkpad,GstObject * parent,GstPadMode mode,gboolean active)471 gst_musepackdec_sink_activate_mode (GstPad * sinkpad, GstObject * parent,
472     GstPadMode mode, gboolean active)
473 {
474   gboolean result;
475 
476   switch (mode) {
477     case GST_PAD_MODE_PUSH:
478       result = FALSE;
479       break;
480     case GST_PAD_MODE_PULL:
481       if (active) {
482         result = gst_pad_start_task (sinkpad,
483             (GstTaskFunction) gst_musepackdec_loop, sinkpad, NULL);
484       } else {
485         result = gst_pad_stop_task (sinkpad);
486       }
487       break;
488     default:
489       result = FALSE;
490       break;
491   }
492 
493   return result;
494 }
495 
496 static void
gst_musepackdec_loop(GstPad * sinkpad)497 gst_musepackdec_loop (GstPad * sinkpad)
498 {
499   GstMusepackDec *musepackdec;
500   GstFlowReturn flow;
501   GstBuffer *out;
502   GstMapInfo info;
503   mpc_frame_info frame;
504   mpc_status err;
505   gint num_samples, samplerate, bitspersample;
506 
507   musepackdec = GST_MUSEPACK_DEC (GST_PAD_PARENT (sinkpad));
508 
509   samplerate = g_atomic_int_get (&musepackdec->rate);
510 
511   if (samplerate == 0) {
512     if (!gst_musepack_stream_init (musepackdec))
513       goto pause_task;
514 
515     gst_musepackdec_send_newsegment (musepackdec);
516     samplerate = g_atomic_int_get (&musepackdec->rate);
517   }
518 
519   bitspersample = g_atomic_int_get (&musepackdec->bps);
520 
521   out = gst_buffer_new_allocate (NULL, MPC_DECODER_BUFFER_LENGTH * 4, NULL);
522 
523   gst_buffer_map (out, &info, GST_MAP_READWRITE);
524   frame.buffer = (MPC_SAMPLE_FORMAT *) info.data;
525   err = mpc_demux_decode (musepackdec->d, &frame);
526   gst_buffer_unmap (out, &info);
527 
528   if (err != MPC_STATUS_OK) {
529     GST_ERROR_OBJECT (musepackdec, "Failed to decode sample");
530     GST_ELEMENT_ERROR (musepackdec, STREAM, DECODE, (NULL), (NULL));
531     goto pause_task;
532   } else if (frame.bits == -1) {
533     goto eos_and_pause;
534   }
535 
536   num_samples = frame.samples;
537 
538   gst_buffer_set_size (out, num_samples * bitspersample);
539 
540   GST_BUFFER_OFFSET (out) = musepackdec->segment.position;
541   GST_BUFFER_PTS (out) =
542       gst_util_uint64_scale_int (musepackdec->segment.position,
543       GST_SECOND, samplerate);
544   GST_BUFFER_DURATION (out) =
545       gst_util_uint64_scale_int (num_samples, GST_SECOND, samplerate);
546 
547   musepackdec->segment.position += num_samples;
548 
549   GST_LOG_OBJECT (musepackdec, "Pushing buffer, timestamp %" GST_TIME_FORMAT,
550       GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (out)));
551 
552   flow = gst_pad_push (musepackdec->srcpad, out);
553   if (flow != GST_FLOW_OK) {
554     GST_DEBUG_OBJECT (musepackdec, "Flow: %s", gst_flow_get_name (flow));
555     goto pause_task;
556   }
557 
558   /* check if we're at the end of a configured segment */
559   if (musepackdec->segment.stop != -1 &&
560       musepackdec->segment.position >= musepackdec->segment.stop) {
561     gint64 stop_time;
562 
563     GST_DEBUG_OBJECT (musepackdec, "Reached end of configured segment");
564 
565     if ((musepackdec->segment.flags & GST_SEEK_FLAG_SEGMENT) == 0)
566       goto eos_and_pause;
567 
568     GST_DEBUG_OBJECT (musepackdec, "Posting SEGMENT_DONE message");
569 
570     stop_time = gst_util_uint64_scale_int (musepackdec->segment.stop,
571         GST_SECOND, samplerate);
572 
573     gst_element_post_message (GST_ELEMENT (musepackdec),
574         gst_message_new_segment_done (GST_OBJECT (musepackdec),
575             GST_FORMAT_TIME, stop_time));
576     gst_pad_push_event (musepackdec->srcpad,
577         gst_event_new_segment_done (GST_FORMAT_TIME, stop_time));
578 
579     goto pause_task;
580   }
581 
582   return;
583 
584 eos_and_pause:
585   {
586     GST_DEBUG_OBJECT (musepackdec, "sending EOS event");
587     gst_pad_push_event (musepackdec->srcpad, gst_event_new_eos ());
588     /* fall through to pause */
589   }
590 
591 pause_task:
592   {
593     GST_DEBUG_OBJECT (musepackdec, "Pausing task");
594     gst_pad_pause_task (sinkpad);
595     return;
596   }
597 }
598 
599 static GstStateChangeReturn
gst_musepackdec_change_state(GstElement * element,GstStateChange transition)600 gst_musepackdec_change_state (GstElement * element, GstStateChange transition)
601 {
602   GstMusepackDec *musepackdec = GST_MUSEPACK_DEC (element);
603   GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
604 
605   switch (transition) {
606     case GST_STATE_CHANGE_READY_TO_PAUSED:
607       gst_segment_init (&musepackdec->segment, GST_FORMAT_DEFAULT);
608       musepackdec->segment.position = 0;
609       break;
610     default:
611       break;
612   }
613 
614   if (GST_ELEMENT_CLASS (parent_class)->change_state)
615     ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
616 
617   switch (transition) {
618     case GST_STATE_CHANGE_PAUSED_TO_READY:
619       gst_segment_init (&musepackdec->segment, GST_FORMAT_UNDEFINED);
620       musepackdec->offset = 0;
621       musepackdec->rate = 0;
622       musepackdec->bps = 0;
623       break;
624     default:
625       break;
626   }
627 
628   return ret;
629 
630 }
631 
632 static gboolean
plugin_init(GstPlugin * plugin)633 plugin_init (GstPlugin * plugin)
634 {
635   return GST_ELEMENT_REGISTER (musepackdec, plugin);
636 }
637 
638 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
639     GST_VERSION_MINOR,
640     musepack,
641     "Musepack decoder", plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME,
642     GST_PACKAGE_ORIGIN)
643