mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-30 13:41:48 +00:00
mad: remove plugin
We have better replacements such as the mpg123 plugin. The main reason to keep around mad was for 'freeform' mp3 support, but mpg123 can handle those too nowadays. Also, mad is GPL and has been unmaintained for years. https://bugzilla.gnome.org/show_bug.cgi?id=776140
This commit is contained in:
parent
f1146144eb
commit
2f767fb24a
12 changed files with 1 additions and 759 deletions
|
@ -160,9 +160,6 @@
|
|||
/* Define to enable lame mp3 encoder library (used by lame). */
|
||||
#mesondefine HAVE_LAME
|
||||
|
||||
/* Define to enable mad mp3 decoder (used by mad). */
|
||||
#mesondefine HAVE_MAD
|
||||
|
||||
/* Define to 1 if you have the <malloc.h> header file. */
|
||||
#mesondefine HAVE_MALLOC_H
|
||||
|
||||
|
|
21
configure.ac
21
configure.ac
|
@ -19,7 +19,7 @@ dnl check if this is a release version
|
|||
AS_NANO(GST_GIT="no", GST_GIT="yes")
|
||||
|
||||
dnl can autoconf find the source ?
|
||||
AC_CONFIG_SRCDIR([ext/mad/gstmad.c])
|
||||
AC_CONFIG_SRCDIR([gst/asfdemux/gstasfdemux.c])
|
||||
|
||||
dnl define the output header for config
|
||||
AC_CONFIG_HEADERS(config.h)
|
||||
|
@ -319,23 +319,6 @@ AG_GST_CHECK_FEATURE(LAME, [lame mp3 encoder library], lame, [
|
|||
])
|
||||
])
|
||||
|
||||
dnl *** mad ***
|
||||
translit(dnm, m, l) AM_CONDITIONAL(USE_MAD, true)
|
||||
AG_GST_CHECK_FEATURE(MAD, [mad mp3 decoder], mad, [
|
||||
|
||||
dnl check with pkg-config first
|
||||
AG_GST_PKG_CHECK_MODULES(MAD, mad >= 0.15)
|
||||
MAD_LIBS="$MAD_LIBS"
|
||||
if test "x$HAVE_MAD" = "xno"; then
|
||||
dnl fall back to oldskool detection
|
||||
AC_CHECK_HEADER(mad.h, [
|
||||
AC_CHECK_LIB(mad, mad_decoder_finish,
|
||||
HAVE_MAD="yes" MAD_LIBS="-lmad")
|
||||
])
|
||||
fi
|
||||
])
|
||||
AC_SUBST(MAD_LIBS)
|
||||
|
||||
dnl *** mpeg2dec ***
|
||||
translit(dnm, m, l) AM_CONDITIONAL(USE_MPEG2DEC, true)
|
||||
AG_GST_CHECK_FEATURE(MPEG2DEC, [mpeg2dec], mpeg2dec, [
|
||||
|
@ -395,7 +378,6 @@ AM_CONDITIONAL(USE_AMRWB, false)
|
|||
AM_CONDITIONAL(USE_CDIO, false)
|
||||
AM_CONDITIONAL(USE_DVDREAD, false)
|
||||
AM_CONDITIONAL(USE_LAME, false)
|
||||
AM_CONDITIONAL(USE_MAD, false)
|
||||
AM_CONDITIONAL(USE_MPEG2DEC, false)
|
||||
AM_CONDITIONAL(USE_MPG123, false)
|
||||
AM_CONDITIONAL(USE_SIDPLAY, false)
|
||||
|
@ -480,7 +462,6 @@ ext/amrwbdec/Makefile
|
|||
ext/cdio/Makefile
|
||||
ext/dvdread/Makefile
|
||||
ext/lame/Makefile
|
||||
ext/mad/Makefile
|
||||
ext/mpeg2dec/Makefile
|
||||
ext/mpg123/Makefile
|
||||
ext/sidplay/Makefile
|
||||
|
|
|
@ -60,7 +60,6 @@ EXTRA_HFILES = \
|
|||
$(top_srcdir)/ext/amrwbdec/amrwbdec.h \
|
||||
$(top_srcdir)/ext/cdio/gstcdiocddasrc.h \
|
||||
$(top_srcdir)/ext/lame/gstlamemp3enc.h \
|
||||
$(top_srcdir)/ext/mad/gstmad.h \
|
||||
$(top_srcdir)/ext/sidplay/gstsiddec.h \
|
||||
$(top_srcdir)/ext/twolame/gsttwolamemp2enc.h \
|
||||
$(top_srcdir)/ext/x264/gstx264enc.h \
|
||||
|
|
|
@ -23,7 +23,6 @@
|
|||
<xi:include href="xml/element-amrwbdec.xml" />
|
||||
<xi:include href="xml/element-cdiocddasrc.xml" />
|
||||
<xi:include href="xml/element-lamemp3enc.xml" />
|
||||
<xi:include href="xml/element-mad.xml" />
|
||||
<xi:include href="xml/element-mpg123audiodec.xml" />
|
||||
<xi:include href="xml/element-rademux.xml" />
|
||||
<xi:include href="xml/element-rmdemux.xml" />
|
||||
|
@ -47,7 +46,6 @@
|
|||
<xi:include href="xml/plugin-dvdread.xml" />
|
||||
<xi:include href="xml/plugin-dvdsub.xml" />
|
||||
<xi:include href="xml/plugin-lame.xml" />
|
||||
<xi:include href="xml/plugin-mad.xml" />
|
||||
<xi:include href="xml/plugin-mpeg2dec.xml" />
|
||||
<xi:include href="xml/plugin-mpg123.xml" />
|
||||
<xi:include href="xml/plugin-realmedia.xml" />
|
||||
|
|
|
@ -92,20 +92,6 @@ gst_lamemp3enc_get_type
|
|||
gst_lamemp3enc_register
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<FILE>element-mad</FILE>
|
||||
<TITLE>mad</TITLE>
|
||||
GstMad
|
||||
<SUBSECTION Standard>
|
||||
GstMadClass
|
||||
GST_MAD
|
||||
GST_MAD_CLASS
|
||||
GST_IS_MAD
|
||||
GST_IS_MAD_CLASS
|
||||
GST_TYPE_MAD
|
||||
gst_mad_get_type
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<FILE>element-mpg123audiodec</FILE>
|
||||
<TITLE>mpg123audiodec</TITLE>
|
||||
|
|
|
@ -1,34 +0,0 @@
|
|||
<plugin>
|
||||
<name>mad</name>
|
||||
<description>mp3 decoding based on the mad library</description>
|
||||
<filename>../../ext/mad/.libs/libgstmad.so</filename>
|
||||
<basename>libgstmad.so</basename>
|
||||
<version>1.10.0</version>
|
||||
<license>GPL</license>
|
||||
<source>gst-plugins-ugly</source>
|
||||
<package>GStreamer Ugly Plug-ins source release</package>
|
||||
<origin>Unknown package origin</origin>
|
||||
<elements>
|
||||
<element>
|
||||
<name>mad</name>
|
||||
<longname>mad mp3 decoder</longname>
|
||||
<class>Codec/Decoder/Audio</class>
|
||||
<description>Uses mad code to decode mp3 streams</description>
|
||||
<author>Wim Taymans <wim.taymans@gmail.com></author>
|
||||
<pads>
|
||||
<caps>
|
||||
<name>sink</name>
|
||||
<direction>sink</direction>
|
||||
<presence>always</presence>
|
||||
<details>audio/mpeg, mpegversion=(int)1, layer=(int)[ 1, 3 ], rate=(int){ 8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000 }, channels=(int)[ 1, 2 ]</details>
|
||||
</caps>
|
||||
<caps>
|
||||
<name>src</name>
|
||||
<direction>source</direction>
|
||||
<presence>always</presence>
|
||||
<details>audio/x-raw, format=(string)S32LE, layout=(string)interleaved, rate=(int){ 8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000 }, channels=(int)[ 1, 2 ]</details>
|
||||
</caps>
|
||||
</pads>
|
||||
</element>
|
||||
</elements>
|
||||
</plugin>
|
|
@ -34,12 +34,6 @@ else
|
|||
LAME_DIR =
|
||||
endif
|
||||
|
||||
if USE_MAD
|
||||
MAD_DIR = mad
|
||||
else
|
||||
MAD_DIR =
|
||||
endif
|
||||
|
||||
if USE_MPEG2DEC
|
||||
MPEG2DEC_DIR = mpeg2dec
|
||||
else
|
||||
|
@ -77,7 +71,6 @@ SUBDIRS = \
|
|||
$(CDIO_DIR) \
|
||||
$(DVDREAD_DIR) \
|
||||
$(LAME_DIR) \
|
||||
$(MAD_DIR) \
|
||||
$(MPEG2DEC_DIR) \
|
||||
$(MPG123_DIR) \
|
||||
$(SIDPLAY_DIR) \
|
||||
|
@ -91,7 +84,6 @@ DIST_SUBDIRS = \
|
|||
cdio \
|
||||
dvdread \
|
||||
lame \
|
||||
mad \
|
||||
mpeg2dec \
|
||||
mpg123 \
|
||||
sidplay \
|
||||
|
|
|
@ -1,14 +0,0 @@
|
|||
plugin_LTLIBRARIES = libgstmad.la
|
||||
|
||||
libgstmad_la_SOURCES = gstmad.c
|
||||
|
||||
libgstmad_la_CFLAGS = \
|
||||
$(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) $(GST_CFLAGS) \
|
||||
$(MAD_CFLAGS)
|
||||
libgstmad_la_LIBADD = \
|
||||
$(GST_PLUGINS_BASE_LIBS) $(GST_BASE_LIBS) -lgstaudio-$(GST_API_VERSION) \
|
||||
$(GST_BASE_LIBS) $(GST_LIBS) $(MAD_LIBS)
|
||||
libgstmad_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
|
||||
libgstmad_la_LIBTOOLFLAGS = $(GST_PLUGIN_LIBTOOLFLAGS)
|
||||
|
||||
noinst_HEADERS = gstmad.h
|
565
ext/mad/gstmad.c
565
ext/mad/gstmad.c
|
@ -1,565 +0,0 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/**
|
||||
* SECTION:element-mad
|
||||
* @see_also: lame
|
||||
*
|
||||
* MP3 audio decoder. Note that while the mad plugin code is licensed under
|
||||
* the LGPL, the libmad library itself is GPL licensed, so the effective
|
||||
* runtime license of using the mad element is GPL.
|
||||
*
|
||||
* The mpg123audiodec and avdec_mp3 decoder elements are LGPL licensed and
|
||||
* also tend to use less CPU for decoding.
|
||||
*
|
||||
* In general it doesn't matter which MP3 decoder you use, the main advantage
|
||||
* of the mad decoder is that it also supports so-called 'freeform' mp3s which
|
||||
* are mp3s with a bitrate higher than what the standard usually allows.
|
||||
*
|
||||
* <refsect2>
|
||||
* <title>Example pipelines</title>
|
||||
* |[
|
||||
* gst-launch-1.0 filesrc location=music.mp3 ! mpegaudioparse ! mad ! audioconvert ! audioresample ! autoaudiosink
|
||||
* ]| Decode and play an mp3 file
|
||||
* </refsect2>
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "gstmad.h"
|
||||
#include <gst/audio/audio.h>
|
||||
|
||||
enum
|
||||
{
|
||||
ARG_0,
|
||||
ARG_HALF,
|
||||
ARG_IGNORE_CRC
|
||||
};
|
||||
|
||||
GST_DEBUG_CATEGORY_STATIC (mad_debug);
|
||||
#define GST_CAT_DEFAULT mad_debug
|
||||
|
||||
static GstStaticPadTemplate mad_src_template_factory =
|
||||
GST_STATIC_PAD_TEMPLATE ("src",
|
||||
GST_PAD_SRC,
|
||||
GST_PAD_ALWAYS,
|
||||
GST_STATIC_CAPS ("audio/x-raw, "
|
||||
"format = (string) " GST_AUDIO_NE (S32) ", "
|
||||
"layout = (string) interleaved, "
|
||||
"rate = (int) { 8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000 }, "
|
||||
"channels = (int) [ 1, 2 ]")
|
||||
);
|
||||
|
||||
/* FIXME: make three caps, for mpegversion 1, 2 and 2.5 */
|
||||
static GstStaticPadTemplate mad_sink_template_factory =
|
||||
GST_STATIC_PAD_TEMPLATE ("sink",
|
||||
GST_PAD_SINK,
|
||||
GST_PAD_ALWAYS,
|
||||
GST_STATIC_CAPS ("audio/mpeg, "
|
||||
"mpegversion = (int) 1, "
|
||||
"layer = (int) [ 1, 3 ], "
|
||||
"rate = (int) { 8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000 }, "
|
||||
"channels = (int) [ 1, 2 ]")
|
||||
);
|
||||
|
||||
|
||||
static gboolean gst_mad_start (GstAudioDecoder * dec);
|
||||
static gboolean gst_mad_stop (GstAudioDecoder * dec);
|
||||
static GstFlowReturn gst_mad_parse (GstAudioDecoder * dec,
|
||||
GstAdapter * adapter, gint * offset, gint * length);
|
||||
static GstFlowReturn gst_mad_handle_frame (GstAudioDecoder * dec,
|
||||
GstBuffer * buffer);
|
||||
static void gst_mad_flush (GstAudioDecoder * dec, gboolean hard);
|
||||
|
||||
static void gst_mad_set_property (GObject * object, guint prop_id,
|
||||
const GValue * value, GParamSpec * pspec);
|
||||
static void gst_mad_get_property (GObject * object, guint prop_id,
|
||||
GValue * value, GParamSpec * pspec);
|
||||
|
||||
#define parent_class gst_mad_parent_class
|
||||
G_DEFINE_TYPE (GstMad, gst_mad, GST_TYPE_AUDIO_DECODER);
|
||||
|
||||
static void
|
||||
gst_mad_class_init (GstMadClass * klass)
|
||||
{
|
||||
GObjectClass *gobject_class = (GObjectClass *) klass;
|
||||
GstElementClass *element_class = (GstElementClass *) klass;
|
||||
GstAudioDecoderClass *base_class = (GstAudioDecoderClass *) klass;
|
||||
|
||||
gobject_class->set_property = gst_mad_set_property;
|
||||
gobject_class->get_property = gst_mad_get_property;
|
||||
|
||||
/* init properties */
|
||||
/* currently, string representations are used, we might want to change that */
|
||||
/* FIXME: descriptions need to be more technical,
|
||||
* default values and ranges need to be selected right */
|
||||
g_object_class_install_property (gobject_class, ARG_HALF,
|
||||
g_param_spec_boolean ("half", "Half", "Generate PCM at 1/2 sample rate",
|
||||
FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||
g_object_class_install_property (gobject_class, ARG_IGNORE_CRC,
|
||||
g_param_spec_boolean ("ignore-crc", "Ignore CRC", "Ignore CRC errors",
|
||||
TRUE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
gst_element_class_add_static_pad_template (element_class,
|
||||
&mad_sink_template_factory);
|
||||
gst_element_class_add_static_pad_template (element_class,
|
||||
&mad_src_template_factory);
|
||||
|
||||
gst_element_class_set_static_metadata (element_class, "mad mp3 decoder",
|
||||
"Codec/Decoder/Audio",
|
||||
"Uses mad code to decode mp3 streams",
|
||||
"Wim Taymans <wim.taymans@gmail.com>");
|
||||
|
||||
base_class->start = GST_DEBUG_FUNCPTR (gst_mad_start);
|
||||
base_class->stop = GST_DEBUG_FUNCPTR (gst_mad_stop);
|
||||
base_class->parse = GST_DEBUG_FUNCPTR (gst_mad_parse);
|
||||
base_class->handle_frame = GST_DEBUG_FUNCPTR (gst_mad_handle_frame);
|
||||
base_class->flush = GST_DEBUG_FUNCPTR (gst_mad_flush);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_mad_init (GstMad * mad)
|
||||
{
|
||||
GstAudioDecoder *dec;
|
||||
|
||||
dec = GST_AUDIO_DECODER (mad);
|
||||
gst_audio_decoder_set_tolerance (dec, 20 * GST_MSECOND);
|
||||
gst_audio_decoder_set_use_default_pad_acceptcaps (dec, TRUE);
|
||||
GST_PAD_SET_ACCEPT_TEMPLATE (GST_AUDIO_DECODER_SINK_PAD (dec));
|
||||
|
||||
mad->half = FALSE;
|
||||
mad->ignore_crc = TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_mad_start (GstAudioDecoder * dec)
|
||||
{
|
||||
GstMad *mad = GST_MAD (dec);
|
||||
guint options = 0;
|
||||
|
||||
GST_DEBUG_OBJECT (dec, "start");
|
||||
mad_stream_init (&mad->stream);
|
||||
mad_frame_init (&mad->frame);
|
||||
mad_synth_init (&mad->synth);
|
||||
mad->rate = 0;
|
||||
mad->channels = 0;
|
||||
mad->caps_set = FALSE;
|
||||
mad->frame.header.samplerate = 0;
|
||||
if (mad->ignore_crc)
|
||||
options |= MAD_OPTION_IGNORECRC;
|
||||
if (mad->half)
|
||||
options |= MAD_OPTION_HALFSAMPLERATE;
|
||||
mad_stream_options (&mad->stream, options);
|
||||
mad->header.mode = -1;
|
||||
mad->header.emphasis = -1;
|
||||
mad->eos = FALSE;
|
||||
|
||||
/* call upon legacy upstream byte support (e.g. seeking) */
|
||||
gst_audio_decoder_set_estimate_rate (dec, TRUE);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_mad_stop (GstAudioDecoder * dec)
|
||||
{
|
||||
GstMad *mad = GST_MAD (dec);
|
||||
|
||||
GST_DEBUG_OBJECT (dec, "stop");
|
||||
mad_synth_finish (&mad->synth);
|
||||
mad_frame_finish (&mad->frame);
|
||||
mad_stream_finish (&mad->stream);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static inline gint32
|
||||
scale (mad_fixed_t sample)
|
||||
{
|
||||
#if MAD_F_FRACBITS < 28
|
||||
/* round */
|
||||
sample += (1L << (28 - MAD_F_FRACBITS - 1));
|
||||
#endif
|
||||
|
||||
/* clip */
|
||||
if (sample >= MAD_F_ONE)
|
||||
sample = MAD_F_ONE - 1;
|
||||
else if (sample < -MAD_F_ONE)
|
||||
sample = -MAD_F_ONE;
|
||||
|
||||
#if MAD_F_FRACBITS < 28
|
||||
/* quantize */
|
||||
sample >>= (28 - MAD_F_FRACBITS);
|
||||
#endif
|
||||
|
||||
/* convert from 29 bits to 32 bits */
|
||||
return (gint32) (sample << 3);
|
||||
}
|
||||
|
||||
/* internal function to check if the header has changed and thus the
|
||||
* caps need to be reset. Only call during normal mode, not resyncing */
|
||||
static void
|
||||
gst_mad_check_caps_reset (GstMad * mad)
|
||||
{
|
||||
guint nchannels;
|
||||
guint rate;
|
||||
|
||||
nchannels = MAD_NCHANNELS (&mad->frame.header);
|
||||
|
||||
#if MAD_VERSION_MINOR <= 12
|
||||
rate = mad->header.sfreq;
|
||||
#else
|
||||
rate = mad->frame.header.samplerate;
|
||||
#endif
|
||||
|
||||
/* rate and channels are not supposed to change in a continuous stream,
|
||||
* so check this first before doing anything */
|
||||
|
||||
/* only set caps if they weren't already set for this continuous stream */
|
||||
if (!gst_pad_has_current_caps (GST_AUDIO_DECODER_SRC_PAD (mad))
|
||||
|| mad->channels != nchannels || mad->rate != rate) {
|
||||
GstAudioInfo info;
|
||||
static const GstAudioChannelPosition chan_pos[2][2] = {
|
||||
{GST_AUDIO_CHANNEL_POSITION_MONO},
|
||||
{GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
|
||||
GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT}
|
||||
};
|
||||
|
||||
if (mad->caps_set) {
|
||||
GST_DEBUG_OBJECT (mad, "Header changed from %d Hz/%d ch to %d Hz/%d ch, "
|
||||
"failed sync after seek ?", mad->rate, mad->channels, rate,
|
||||
nchannels);
|
||||
/* we're conservative on stream changes. However, our *initial* caps
|
||||
* might have been wrong as well - mad ain't perfect in syncing. So,
|
||||
* we count caps changes and change if we pass a limit treshold (3). */
|
||||
if (nchannels != mad->pending_channels || rate != mad->pending_rate) {
|
||||
mad->times_pending = 0;
|
||||
mad->pending_channels = nchannels;
|
||||
mad->pending_rate = rate;
|
||||
}
|
||||
if (++mad->times_pending < 3)
|
||||
return;
|
||||
}
|
||||
|
||||
if (mad->stream.options & MAD_OPTION_HALFSAMPLERATE)
|
||||
rate >>= 1;
|
||||
|
||||
/* we set the caps even when the pad is not connected so they
|
||||
* can be gotten for streaminfo */
|
||||
gst_audio_info_init (&info);
|
||||
gst_audio_info_set_format (&info,
|
||||
GST_AUDIO_FORMAT_S32, rate, nchannels, chan_pos[nchannels - 1]);
|
||||
|
||||
gst_audio_decoder_set_output_format (GST_AUDIO_DECODER (mad), &info);
|
||||
|
||||
mad->caps_set = TRUE;
|
||||
mad->channels = nchannels;
|
||||
mad->rate = rate;
|
||||
}
|
||||
}
|
||||
|
||||
static GstFlowReturn
|
||||
gst_mad_parse (GstAudioDecoder * dec, GstAdapter * adapter,
|
||||
gint * _offset, gint * len)
|
||||
{
|
||||
GstMad *mad;
|
||||
GstFlowReturn ret = GST_FLOW_EOS;
|
||||
gint av, size, offset;
|
||||
const guint8 *data;
|
||||
gboolean eos, sync;
|
||||
guint8 *guard = NULL;
|
||||
|
||||
mad = GST_MAD (dec);
|
||||
|
||||
av = gst_adapter_available (adapter);
|
||||
data = gst_adapter_map (adapter, av);
|
||||
|
||||
gst_audio_decoder_get_parse_state (dec, &sync, &eos);
|
||||
GST_LOG_OBJECT (mad, "parse state sync %d, eos %d", sync, eos);
|
||||
|
||||
if (eos) {
|
||||
/* This is one streaming 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
|
||||
*/
|
||||
guard = g_malloc (av + MAD_BUFFER_GUARD);
|
||||
/* let's be nice and not mess with baseclass state and keep hacks local */
|
||||
memcpy (guard, data, av);
|
||||
memset (guard + av, 0, MAD_BUFFER_GUARD);
|
||||
GST_DEBUG_OBJECT (mad, "Added %u zero guard bytes in the adapter; "
|
||||
"using fallback buffer of size %u",
|
||||
MAD_BUFFER_GUARD, av + MAD_BUFFER_GUARD);
|
||||
data = guard;
|
||||
av = av + MAD_BUFFER_GUARD;
|
||||
}
|
||||
|
||||
/* we basically let mad library do parsing,
|
||||
* and translate that back to baseclass.
|
||||
* if a frame is found (and also decoded), subsequent handle_frame
|
||||
* only needs to synthesize it */
|
||||
|
||||
offset = 0;
|
||||
size = 0;
|
||||
|
||||
resume:
|
||||
if (G_UNLIKELY (offset + MAD_BUFFER_GUARD > av))
|
||||
goto exit;
|
||||
|
||||
GST_LOG_OBJECT (mad, "setup mad stream at offset %d (of av %d)", offset, av);
|
||||
mad_stream_buffer (&mad->stream, data + offset, av - offset);
|
||||
/* convey sync idea to mad */
|
||||
mad->stream.sync = sync;
|
||||
/* if we get back here, lost sync anyway */
|
||||
sync = FALSE;
|
||||
|
||||
while (TRUE) {
|
||||
GST_LOG_OBJECT (mad, "decoding the header now");
|
||||
if (mad_header_decode (&mad->frame.header, &mad->stream) == -1) {
|
||||
/* HACK it seems mad reports wrong error when it is trying to determine
|
||||
* free bitrate and scanning for next header */
|
||||
if (mad->stream.error == MAD_ERROR_LOSTSYNC) {
|
||||
const guint8 *ptr = mad->stream.this_frame;
|
||||
guint32 header;
|
||||
|
||||
if (ptr >= data && ptr < data + av) {
|
||||
header = GST_READ_UINT32_BE (ptr);
|
||||
/* looks like possible freeform header with not much data */
|
||||
if (((header & 0xFFE00000) == 0xFFE00000) &&
|
||||
(((header >> 12) & 0xF) == 0x0) && (av < 4096)) {
|
||||
GST_DEBUG_OBJECT (mad, "overriding freeform LOST_SYNC to BUFLEN");
|
||||
mad->stream.error = MAD_ERROR_BUFLEN;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (mad->stream.error == MAD_ERROR_BUFLEN) {
|
||||
GST_LOG_OBJECT (mad, "not enough data, getting more");
|
||||
offset = mad->stream.next_frame - data;
|
||||
break;
|
||||
} else if (mad->stream.error == MAD_ERROR_LOSTSYNC) {
|
||||
GST_LOG_OBJECT (mad, "lost sync");
|
||||
continue;
|
||||
} else {
|
||||
/* probably some bogus header, basically also lost sync */
|
||||
GST_DEBUG_OBJECT (mad, "mad_header_decode had an error: %s",
|
||||
mad_stream_errorstr (&mad->stream));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/* could have a frame now, subsequent will confirm */
|
||||
offset = mad->stream.this_frame - data;
|
||||
size = mad->stream.next_frame - mad->stream.this_frame;
|
||||
g_assert (size);
|
||||
|
||||
GST_LOG_OBJECT (mad, "parsing and decoding one frame now "
|
||||
"(offset %d, size %d)", offset, size);
|
||||
if (mad_frame_decode (&mad->frame, &mad->stream) == -1) {
|
||||
GST_LOG_OBJECT (mad, "got error %d", mad->stream.error);
|
||||
|
||||
/* not enough data, need to wait for next buffer? */
|
||||
if (mad->stream.error == MAD_ERROR_BUFLEN) {
|
||||
/* not really expect this error at this stage anymore
|
||||
* assume bogus frame and bad sync and move along a bit */
|
||||
GST_WARNING_OBJECT (mad, "not enough data (unexpected), moving along");
|
||||
offset++;
|
||||
goto resume;
|
||||
} else if (mad->stream.error == MAD_ERROR_BADDATAPTR) {
|
||||
GST_DEBUG_OBJECT (mad, "bad data ptr, skipping presumed frame");
|
||||
/* flush past presumed frame */
|
||||
offset += size;
|
||||
goto resume;
|
||||
} else {
|
||||
GST_WARNING_OBJECT (mad, "mad_frame_decode had an error: %s",
|
||||
mad_stream_errorstr (&mad->stream));
|
||||
if (!MAD_RECOVERABLE (mad->stream.error)) {
|
||||
/* well, all may be well enough bytes later on ... */
|
||||
GST_AUDIO_DECODER_ERROR (mad, 1, STREAM, DECODE, (NULL),
|
||||
("mad error: %s", mad_stream_errorstr (&mad->stream)), ret);
|
||||
}
|
||||
/* move along and try again */
|
||||
offset++;
|
||||
goto resume;
|
||||
}
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
|
||||
/* so decoded ok, got a frame now */
|
||||
ret = GST_FLOW_OK;
|
||||
break;
|
||||
}
|
||||
|
||||
exit:
|
||||
|
||||
gst_adapter_unmap (adapter);
|
||||
|
||||
*_offset = offset;
|
||||
*len = size;
|
||||
|
||||
/* ensure that if we added some dummy guard bytes above, we don't claim
|
||||
to have used them as they're unknown to the caller. */
|
||||
if (eos) {
|
||||
g_assert (av >= MAD_BUFFER_GUARD);
|
||||
av -= MAD_BUFFER_GUARD;
|
||||
if (*_offset > av)
|
||||
*_offset = av;
|
||||
if (*len > av)
|
||||
*len = av;
|
||||
g_assert (guard);
|
||||
g_free (guard);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static GstFlowReturn
|
||||
gst_mad_handle_frame (GstAudioDecoder * dec, GstBuffer * buffer)
|
||||
{
|
||||
GstMad *mad;
|
||||
GstFlowReturn ret = GST_FLOW_EOS;
|
||||
GstBuffer *outbuffer;
|
||||
guint nsamples;
|
||||
GstMapInfo outmap;
|
||||
gint32 *outdata;
|
||||
mad_fixed_t const *left_ch, *right_ch;
|
||||
|
||||
mad = GST_MAD (dec);
|
||||
|
||||
/* no fancy draining */
|
||||
if (G_UNLIKELY (!buffer))
|
||||
return GST_FLOW_OK;
|
||||
|
||||
/* _parse prepared a frame */
|
||||
nsamples = MAD_NSBSAMPLES (&mad->frame.header) *
|
||||
(mad->stream.options & MAD_OPTION_HALFSAMPLERATE ? 16 : 32);
|
||||
GST_LOG_OBJECT (mad, "mad frame with %d samples", nsamples);
|
||||
|
||||
/* arrange for initial caps before pushing data,
|
||||
* and update later on if needed */
|
||||
gst_mad_check_caps_reset (mad);
|
||||
|
||||
mad_synth_frame (&mad->synth, &mad->frame);
|
||||
left_ch = mad->synth.pcm.samples[0];
|
||||
right_ch = mad->synth.pcm.samples[1];
|
||||
|
||||
outbuffer = gst_buffer_new_and_alloc (nsamples * mad->channels * 4);
|
||||
|
||||
gst_buffer_map (outbuffer, &outmap, GST_MAP_WRITE);
|
||||
outdata = (gint32 *) outmap.data;
|
||||
|
||||
/* output sample(s) in 16-bit signed native-endian PCM */
|
||||
if (mad->channels == 1) {
|
||||
gint count = nsamples;
|
||||
|
||||
while (count--) {
|
||||
*outdata++ = scale (*left_ch++) & 0xffffffff;
|
||||
}
|
||||
} else {
|
||||
gint count = nsamples;
|
||||
|
||||
while (count--) {
|
||||
*outdata++ = scale (*left_ch++) & 0xffffffff;
|
||||
*outdata++ = scale (*right_ch++) & 0xffffffff;
|
||||
}
|
||||
}
|
||||
|
||||
gst_buffer_unmap (outbuffer, &outmap);
|
||||
|
||||
ret = gst_audio_decoder_finish_frame (dec, outbuffer, 1);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_mad_flush (GstAudioDecoder * dec, gboolean hard)
|
||||
{
|
||||
GstMad *mad;
|
||||
|
||||
mad = GST_MAD (dec);
|
||||
if (hard) {
|
||||
mad_frame_mute (&mad->frame);
|
||||
mad_synth_mute (&mad->synth);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gst_mad_set_property (GObject * object, guint prop_id,
|
||||
const GValue * value, GParamSpec * pspec)
|
||||
{
|
||||
GstMad *mad;
|
||||
|
||||
mad = GST_MAD (object);
|
||||
|
||||
switch (prop_id) {
|
||||
case ARG_HALF:
|
||||
mad->half = g_value_get_boolean (value);
|
||||
break;
|
||||
case ARG_IGNORE_CRC:
|
||||
mad->ignore_crc = g_value_get_boolean (value);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gst_mad_get_property (GObject * object, guint prop_id,
|
||||
GValue * value, GParamSpec * pspec)
|
||||
{
|
||||
GstMad *mad;
|
||||
|
||||
mad = GST_MAD (object);
|
||||
|
||||
switch (prop_id) {
|
||||
case ARG_HALF:
|
||||
g_value_set_boolean (value, mad->half);
|
||||
break;
|
||||
case ARG_IGNORE_CRC:
|
||||
g_value_set_boolean (value, mad->ignore_crc);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* plugin initialisation */
|
||||
|
||||
static gboolean
|
||||
plugin_init (GstPlugin * plugin)
|
||||
{
|
||||
GST_DEBUG_CATEGORY_INIT (mad_debug, "mad", 0, "mad mp3 decoding");
|
||||
|
||||
/* FIXME 0.11: rename to something better like madmp3dec or madmpegaudiodec
|
||||
* or so? */
|
||||
return gst_element_register (plugin, "mad", GST_RANK_SECONDARY,
|
||||
gst_mad_get_type ());
|
||||
}
|
||||
|
||||
GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
|
||||
GST_VERSION_MINOR,
|
||||
mad,
|
||||
"mp3 decoding based on the mad library",
|
||||
plugin_init, VERSION, "GPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN);
|
|
@ -1,82 +0,0 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) 2003 Benjamin Otte <in7y118@public.uni-hamburg.de>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef __GST_MAD_H__
|
||||
#define __GST_MAD_H__
|
||||
|
||||
#include <gst/gst.h>
|
||||
#include <gst/tag/tag.h>
|
||||
#include <gst/audio/gstaudiodecoder.h>
|
||||
|
||||
#include <mad.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GST_TYPE_MAD \
|
||||
(gst_mad_get_type())
|
||||
#define GST_MAD(obj) \
|
||||
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_MAD,GstMad))
|
||||
#define GST_MAD_CLASS(klass) \
|
||||
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_MAD,GstMadClass))
|
||||
#define GST_IS_MAD(obj) \
|
||||
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_MAD))
|
||||
#define GST_IS_MAD_CLASS(klass) \
|
||||
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_MAD))
|
||||
|
||||
|
||||
typedef struct _GstMad GstMad;
|
||||
typedef struct _GstMadClass GstMadClass;
|
||||
|
||||
struct _GstMad
|
||||
{
|
||||
GstAudioDecoder element;
|
||||
|
||||
/* state */
|
||||
struct mad_stream stream;
|
||||
struct mad_frame frame;
|
||||
struct mad_synth synth;
|
||||
|
||||
/* info */
|
||||
struct mad_header header;
|
||||
|
||||
/* negotiated format */
|
||||
gint rate, pending_rate;
|
||||
gint channels, pending_channels;
|
||||
gint times_pending;
|
||||
gboolean caps_set; /* used to keep track of whether to change/update caps */
|
||||
|
||||
gboolean eos;
|
||||
|
||||
/* properties */
|
||||
gboolean half;
|
||||
gboolean ignore_crc;
|
||||
};
|
||||
|
||||
struct _GstMadClass
|
||||
{
|
||||
GstAudioDecoderClass parent_class;
|
||||
};
|
||||
|
||||
GType gst_mad_get_type (void);
|
||||
gboolean gst_mad_register (GstPlugin * plugin);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GST_MAD_H__ */
|
|
@ -1,15 +0,0 @@
|
|||
mad_dep = dependency('mad', version : '>= 0.15', required : false)
|
||||
if not mad_dep.found() and cc.has_header_symbol('mad.h', 'mad_decoder_finish')
|
||||
mad_dep = cc.find_library('mad', required : false)
|
||||
endif
|
||||
|
||||
if mad_dep.found()
|
||||
mad = library('gstmad',
|
||||
['gstmad.c'],
|
||||
c_args : ugly_args,
|
||||
include_directories : [configinc],
|
||||
dependencies : [gstaudio_dep, mad_dep],
|
||||
install : true,
|
||||
install_dir : plugins_install_dir,
|
||||
)
|
||||
endif
|
|
@ -4,7 +4,6 @@ subdir('amrwbdec')
|
|||
subdir('cdio')
|
||||
subdir('dvdread')
|
||||
subdir('lame')
|
||||
subdir('mad')
|
||||
subdir('mpeg2dec')
|
||||
subdir('mpg123')
|
||||
#subdir('sidplay') # FIXME
|
||||
|
|
Loading…
Reference in a new issue