mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-27 20:21:24 +00:00
mad: helpfully bodge the last buffer to let mad decode the last frame
If http://www.mars.org/mailman/public/mad-dev/2001-May/000262.html is to be believed, the last buffer must be followed by a number of 0 bytes in order for the last frame to be decoded (at least in some cases). Doing so seems to work here, fixing a missing 1152 samples when using mp3parse before mad (not using mp3parse would yield the correct amount of samples, if there's extra non-MP3 data after (eg, tag data)).
This commit is contained in:
parent
20dcefd5c0
commit
30e29b6fdb
2 changed files with 34 additions and 0 deletions
|
@ -82,6 +82,7 @@ static gboolean gst_mad_parse (GstAudioDecoder * dec, GstAdapter * adapter,
|
||||||
gint * offset, gint * length);
|
gint * offset, gint * length);
|
||||||
static GstFlowReturn gst_mad_handle_frame (GstAudioDecoder * dec,
|
static GstFlowReturn gst_mad_handle_frame (GstAudioDecoder * dec,
|
||||||
GstBuffer * buffer);
|
GstBuffer * buffer);
|
||||||
|
static gboolean gst_mad_event (GstAudioDecoder * dec, GstEvent * event);
|
||||||
static void gst_mad_flush (GstAudioDecoder * dec, gboolean hard);
|
static void gst_mad_flush (GstAudioDecoder * dec, gboolean hard);
|
||||||
|
|
||||||
static void gst_mad_set_property (GObject * object, guint prop_id,
|
static void gst_mad_set_property (GObject * object, guint prop_id,
|
||||||
|
@ -119,6 +120,7 @@ gst_mad_class_init (GstMadClass * klass)
|
||||||
base_class->parse = GST_DEBUG_FUNCPTR (gst_mad_parse);
|
base_class->parse = GST_DEBUG_FUNCPTR (gst_mad_parse);
|
||||||
base_class->handle_frame = GST_DEBUG_FUNCPTR (gst_mad_handle_frame);
|
base_class->handle_frame = GST_DEBUG_FUNCPTR (gst_mad_handle_frame);
|
||||||
base_class->flush = GST_DEBUG_FUNCPTR (gst_mad_flush);
|
base_class->flush = GST_DEBUG_FUNCPTR (gst_mad_flush);
|
||||||
|
base_class->event = GST_DEBUG_FUNCPTR (gst_mad_event);
|
||||||
|
|
||||||
gobject_class->set_property = gst_mad_set_property;
|
gobject_class->set_property = gst_mad_set_property;
|
||||||
gobject_class->get_property = gst_mad_get_property;
|
gobject_class->get_property = gst_mad_get_property;
|
||||||
|
@ -168,6 +170,7 @@ gst_mad_start (GstAudioDecoder * dec)
|
||||||
mad_stream_options (&mad->stream, options);
|
mad_stream_options (&mad->stream, options);
|
||||||
mad->header.mode = -1;
|
mad->header.mode = -1;
|
||||||
mad->header.emphasis = -1;
|
mad->header.emphasis = -1;
|
||||||
|
mad->eos = FALSE;
|
||||||
|
|
||||||
/* call upon legacy upstream byte support (e.g. seeking) */
|
/* call upon legacy upstream byte support (e.g. seeking) */
|
||||||
gst_audio_decoder_set_byte_time (dec, TRUE);
|
gst_audio_decoder_set_byte_time (dec, TRUE);
|
||||||
|
@ -282,6 +285,20 @@ gst_mad_parse (GstAudioDecoder * dec, GstAdapter * adapter,
|
||||||
|
|
||||||
mad = GST_MAD (dec);
|
mad = GST_MAD (dec);
|
||||||
|
|
||||||
|
if (mad->eos) {
|
||||||
|
/* This is one steaming hack right there.
|
||||||
|
* mad will not decode the last frame if it is not followed by
|
||||||
|
* a number of 0 bytes, due to some buffer overflow, which can
|
||||||
|
* not be fixed for reasons I did not inquire into, see
|
||||||
|
* http://www.mars.org/mailman/public/mad-dev/2001-May/000262.html
|
||||||
|
*/
|
||||||
|
GstBuffer *guard = gst_buffer_new_and_alloc (MAD_BUFFER_GUARD);
|
||||||
|
memset (GST_BUFFER_DATA (guard), 0, GST_BUFFER_SIZE (guard));
|
||||||
|
GST_DEBUG_OBJECT (mad, "Discreetly stuffing %u zero bytes in the adapter",
|
||||||
|
GST_BUFFER_SIZE (guard));
|
||||||
|
gst_adapter_push (adapter, guard);
|
||||||
|
}
|
||||||
|
|
||||||
/* we basically let mad library do parsing,
|
/* we basically let mad library do parsing,
|
||||||
* and translate that back to baseclass.
|
* and translate that back to baseclass.
|
||||||
* if a frame is found (and also decoded), subsequent handle_frame
|
* if a frame is found (and also decoded), subsequent handle_frame
|
||||||
|
@ -482,6 +499,21 @@ gst_mad_flush (GstAudioDecoder * dec, gboolean hard)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
gst_mad_event (GstAudioDecoder * dec, GstEvent * event)
|
||||||
|
{
|
||||||
|
GstMad *mad;
|
||||||
|
|
||||||
|
mad = GST_MAD (dec);
|
||||||
|
if (GST_EVENT_TYPE (event) == GST_EVENT_EOS) {
|
||||||
|
GST_DEBUG_OBJECT (mad, "We got EOS, will pad next time");
|
||||||
|
mad->eos = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Let the base class do its usual thing */
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gst_mad_set_property (GObject * object, guint prop_id,
|
gst_mad_set_property (GObject * object, guint prop_id,
|
||||||
const GValue * value, GParamSpec * pspec)
|
const GValue * value, GParamSpec * pspec)
|
||||||
|
|
|
@ -63,6 +63,8 @@ struct _GstMad
|
||||||
gint times_pending;
|
gint times_pending;
|
||||||
gboolean caps_set; /* used to keep track of whether to change/update caps */
|
gboolean caps_set; /* used to keep track of whether to change/update caps */
|
||||||
|
|
||||||
|
gboolean eos;
|
||||||
|
|
||||||
/* properties */
|
/* properties */
|
||||||
gboolean half;
|
gboolean half;
|
||||||
gboolean ignore_crc;
|
gboolean ignore_crc;
|
||||||
|
|
Loading…
Reference in a new issue