[vlc-devel] [PATCH] [WIP] New mpg123 decoder
Ludovic Fauvet
etix at videolan.org
Tue Nov 25 16:31:48 CET 2014
On Mon, Nov 24, 2014, at 13:01, Hugo Beauzée-Luyssen wrote:
>
>
> On Mon, Nov 24, 2014, at 12:19 PM, Ludovic Fauvet wrote:
> > ---
> > NEWS | 1 +
> > configure.ac | 5 +
> > modules/MODULES_LIST | 1 +
> > modules/codec/Makefile.am | 7 +
> > modules/codec/mpg123.c | 328
> > ++++++++++++++++++++++++++++++++++++++++++++++
> > 5 files changed, 342 insertions(+)
> > create mode 100644 modules/codec/mpg123.c
> >
> > diff --git a/NEWS b/NEWS
> > index d109573..1ef4da7 100644
> > --- a/NEWS
> > +++ b/NEWS
> > @@ -20,6 +20,7 @@ Decoder:
> > * Important improvements for the MMAL decoder and output for rPI
> > * Support HEVC hardware decoding using OMX and MediaCodec
> > * Support VP9 and WMV3 decoding using OMX and performance improvements
> > + * New MPEG-1 & 2 audio layer I, II, III + MPEG 2.5 decoder
> >
> > Demuxers:
> > * Support HD-DVD .evo (H.264, VC-1, MPEG-2, PCM, AC-3, E-AC3, MLP, DTS)
> > diff --git a/configure.ac b/configure.ac
> > index 7babe95..f194d07 100644
> > --- a/configure.ac
> > +++ b/configure.ac
> > @@ -2259,6 +2259,11 @@ then
> > fi
> > fi
> >
> > +dnl mpg123 plugin
> > +dnl
> > +dnl
> > +PKG_ENABLE_MODULES_VLC([MPG123], [mpg123], [libmpg123], [libmpg123
> > decoder support], [auto])
> > +
> >
> > AC_ARG_ENABLE(merge-ffmpeg,
> > [ --enable-merge-ffmpeg merge FFmpeg-based plugins (default
> > disabled)],, [
> > diff --git a/modules/MODULES_LIST b/modules/MODULES_LIST
> > index 6d93386..6932ab7 100644
> > --- a/modules/MODULES_LIST
> > +++ b/modules/MODULES_LIST
> > @@ -224,6 +224,7 @@ $Id$
> > * mp4: MP4 file input module
> > * mpc: Musepack decoder
> > * mpeg_audio: MPEG audio parser/packetizer
> > + * mpg123: MPEG-1 & 2 audio layer I, II, III + MPEG 2.5 decoder using
> > mpg123
> > * mpgatofixed32: MPEG-1 & 2 audio layer I,II,III audio decoder using
> > MAD
> > * mpgv: MPEG-I/II Video demuxer
> > * mtp: MTP interface module
> > diff --git a/modules/codec/Makefile.am b/modules/codec/Makefile.am
> > index 0dc451d..5f04bf4 100644
> > --- a/modules/codec/Makefile.am
> > +++ b/modules/codec/Makefile.am
> > @@ -56,6 +56,13 @@ codec_LTLIBRARIES += liblpcm_plugin.la
> > libmpeg_audio_plugin_la_SOURCES = codec/mpeg_audio.c
> > codec_LTLIBRARIES += libmpeg_audio_plugin.la
> >
> > +libmpg123_plugin_la_SOURCES = codec/mpg123.c
> > +libmpg123_plugin_la_CFLAGS = $(AM_CFLAGS) $(MPG123_CFLAGS)
> > +libmpg123_plugin_la_LDFLAGS = $(AM_LDFLAGS) -rpath '$(codecdir)'
> > +libmpg123_plugin_la_LIBADD = $(MPG123_LIBS) -lmpg123
> > +EXTRA_LTLIBRARIES += libmpg123_plugin.la
> > +codec_LTLIBRARIES += $(LTLIBmpg123)
> > +
> > libuleaddvaudio_plugin_la_SOURCES = codec/uleaddvaudio.c
> > codec_LTLIBRARIES += libuleaddvaudio_plugin.la
> >
> > diff --git a/modules/codec/mpg123.c b/modules/codec/mpg123.c
> > new file mode 100644
> > index 0000000..e617ffd
> > --- /dev/null
> > +++ b/modules/codec/mpg123.c
> > @@ -0,0 +1,328 @@
> > +/*****************************************************************************
> > + * mpg123.c: MPEG-1 & 2 audio layer I, II, III + MPEG 2.5 decoder
> > +
> > *****************************************************************************
> > + * Copyright (C) 2001-2014 VLC authors and VideoLAN
> > + *
> > + * Authors: Ludovic Fauvet <etix at videolan.org>
> > + *
> > + * This program is free software; you can redistribute it and/or modify
> > it
> > + * under the terms of the GNU Lesser General Public License as published
> > by
> > + * the Free Software Foundation; either version 2.1 of the License, or
> > + * (at your option) any later version.
> > + *
> > + * This program 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 Lesser General Public License for more details.
> > + *
> > + * You should have received a copy of the GNU Lesser General Public
> > License
> > + * along with this program; if not, write to the Free Software
> > Foundation,
> > + * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
> > +
> > *****************************************************************************/
> > +
> > +/*****************************************************************************
> > +* Preamble
> > +*****************************************************************************/
> > +
> > +#include <mpg123.h>
> > +
>
> Shouldn't this be after config.h so that vlc_fixup is properly used if
> necessary?ss
>
> > +#ifdef HAVE_CONFIG_H
> > +# include "config.h"
> > +#endif
> > +#include <assert.h>
>
> This appears to be unused
>
> > +
> > +#include <vlc_common.h>
> > +#include <vlc_plugin.h>
> > +#include <vlc_aout.h>
> > +#include <vlc_block.h>
> > +#include <vlc_codec.h>
> > +
> > +/*****************************************************************************
> > + * Local prototypes
> > +
> > *****************************************************************************/
> > +static int OpenDecoder ( vlc_object_t * );
> > +static void CloseDecoder( vlc_object_t * );
> > +static block_t *DecodeBlock( decoder_t *, block_t ** );
> > +static int InitMPG123( void );
> > +static void ExitMPG123( void );
> > +
> > +static unsigned int mpg123_refcount = 0;
> > +static vlc_mutex_t mpg123_mutex = VLC_STATIC_MUTEX;
> > +
> > +/*****************************************************************************
> > + * Local structures
> > +
> > *****************************************************************************/
> > +struct decoder_sys_t
> > +{
> > + mpg123_handle * p_handle;
> > + date_t end_date;
> > + int i_rate;
> > +
> > + struct mpg123_frameinfo frame_info;
> > +};
> > +
> > +/*****************************************************************************
> > + * Module descriptor
> > +
> > *****************************************************************************/
> > +vlc_module_begin ()
> > + set_category( CAT_INPUT )
> > + set_subcategory( SUBCAT_INPUT_ACODEC )
> > + set_description( N_("MPEG audio decoder using mpg123") )
> > + set_capability( "decoder", 123 )
> > + set_shortname( N_("mpg123") )
> > + set_callbacks( OpenDecoder, CloseDecoder )
> > +vlc_module_end ()
> > +
> > +/****************************************************************************
> > + * DecodeBlock: the whole thing
> > +
> > ****************************************************************************/
> > +static block_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
> > +{
> > + int i_err;
> > + block_t *p_block = *pp_block;
> > + decoder_sys_t *p_sys = p_dec->p_sys;
> > +
> > + if( !pp_block || !p_block )
> > + return NULL;
> > +
> > + if( p_block->i_buffer == 0 )
> > + return NULL;
> > +
> > + if( !date_Get( &p_sys->end_date ) && p_block->i_pts <=
> > VLC_TS_INVALID )
> > + {
> > + /* We've just started the stream, wait for the first PTS. */
> > + msg_Dbg( p_dec, "waiting for PTS" );
> > + block_Release( p_block );
> > + return NULL;
> > + }
> > +
> > + if( p_block->i_flags & ( BLOCK_FLAG_DISCONTINUITY |
> > BLOCK_FLAG_CORRUPTED ) )
> > + {
> > + date_Set( &p_sys->end_date, 0 );
> > + block_Release( p_block );
> > + return NULL;
> > + }
> > +
> > + /* Feed mpg123 with raw data */
> > + i_err = mpg123_feed( p_sys->p_handle, p_block->p_buffer,
> > + p_block->i_buffer );
> > +
> > + if( i_err != MPG123_OK )
> > + {
> > + msg_Err( p_dec, "mpg123_feed failed: %s", mpg123_plain_strerror(
> > i_err ) );
> > + block_Release( p_block );
> > + return NULL;
> > + }
> > +
> > + /* Get details about the stream */
> > + i_err = mpg123_info( p_sys->p_handle, &p_sys->frame_info );
> > +
> > + if( i_err == MPG123_NEED_MORE )
> > + {
> > + /* Need moar data */
> > + return NULL;
> > + }
> > + else if( i_err != MPG123_OK )
> > + {
> > + msg_Err( p_dec, "mpg123_info failed: %s", mpg123_plain_strerror(
> > i_err ) );
> > + block_Release( p_block );
> > + return NULL;
> > + }
> > +
> > + /* Configure the output */
> > + p_dec->fmt_out.audio.i_frame_length = p_block->i_nb_samples =
> > mpg123_spf( p_sys->p_handle );
> > + p_dec->fmt_out.audio.i_bytes_per_frame = mpg123_outblock(
> > p_sys->p_handle );
> > + p_dec->fmt_out.i_bitrate = p_sys->frame_info.bitrate * 1000;
> > +
> > + switch( p_sys->frame_info.mode )
> > + {
> > + case MPG123_M_STEREO:
> > + case MPG123_M_JOINT:
> > + p_dec->fmt_out.audio.i_channels = 2;
> > + p_dec->fmt_out.audio.i_original_channels = AOUT_CHAN_LEFT |
> > AOUT_CHAN_RIGHT;
> > + break;
> > + case MPG123_M_DUAL:
> > + p_dec->fmt_out.audio.i_channels = 2;
> > + p_dec->fmt_out.audio.i_original_channels = AOUT_CHAN_LEFT |
> > AOUT_CHAN_RIGHT
> > + | AOUT_CHAN_DUALMONO;
> > + break;
> > + case MPG123_M_MONO:
> > + p_dec->fmt_out.audio.i_channels = 1;
> > + p_dec->fmt_out.audio.i_original_channels = AOUT_CHAN_CENTER;
> > + break;
> > + default:
> > + msg_Err( p_dec, "Unknown mode");
> > + block_Release( p_block );
> > + return NULL;
> > + }
> > +
> > + p_dec->fmt_out.audio.i_physical_channels =
> > + p_dec->fmt_out.audio.i_original_channels & AOUT_CHAN_PHYSMASK;
> > +
> > + /* Date management */
> > + if( p_dec->fmt_out.audio.i_rate != p_sys->frame_info.rate )
> > + {
> > + p_dec->fmt_out.audio.i_rate = p_sys->frame_info.rate;
> > + date_Init( &p_sys->end_date, p_dec->fmt_out.audio.i_rate, 1 );
> > + date_Set( &p_sys->end_date, 0 );
> > + }
> > +
> > + if( p_block->i_pts > VLC_TS_INVALID &&
> > + p_block->i_pts != date_Get( &p_sys->end_date ) )
> > + {
> > + date_Set( &p_sys->end_date, p_block->i_pts );
> > + }
> > +
> > + /* Request a new audio buffer */
> > + block_t *p_out = decoder_NewAudioBuffer( p_dec,
> > p_dec->fmt_out.audio.i_frame_length );
> > + if( unlikely( !p_out ) )
> > + {
> > + msg_Err( p_dec, "Oops: No new buffer was returned!" );
> > + return NULL;
> > + }
> > +
> > + /* Configure the buffer */
> > + p_out->i_nb_samples = p_block->i_nb_samples;
> > + p_out->i_dts = p_out->i_pts = date_Get( &p_sys->end_date );
> > + p_out->i_length = date_Increment( &p_sys->end_date,
> > p_block->i_nb_samples )
> > + - p_out->i_pts;
> > +
> > + /* Let mpg123 write directly into the destination buffer */
> > + i_err = mpg123_replace_buffer( p_sys->p_handle, p_out->p_buffer,
> > p_out->i_buffer );
> > + if( i_err != MPG123_OK )
> > + {
> > + msg_Err( p_dec, "could not replace buffer: %s",
> > mpg123_plain_strerror( i_err ) );
> > + block_Release( p_out );
> > + return NULL;
> > + }
> > +
> > + *pp_block = NULL; /* avoid being fed the same packet again */
> > +
> > + /* Do the actual decoding now */
> > + if( ( i_err = mpg123_decode_frame( p_sys->p_handle, NULL, NULL, NULL
> > ) ) != MPG123_OK )
> > + {
> > + msg_Err( p_dec, "mpg123_decode_frame error: %s",
> > mpg123_plain_strerror( i_err ) );
> > + block_Release( p_out );
> > + p_out = NULL;
> > + }
> > +
> > + block_Release( p_block );
> > + return p_out;
> > +}
> > +
> > +/*****************************************************************************
> > + * OpenDecoder :
> > +
> > *****************************************************************************/
> > +static int OpenDecoder( vlc_object_t *p_this )
> > +{
> > + decoder_t *p_dec = (decoder_t *)p_this;
> > + decoder_sys_t *p_sys;
> > +
> > + if( p_dec->fmt_in.i_codec != VLC_CODEC_MPGA && p_dec->fmt_in.i_codec
> > != VLC_CODEC_MP3 &&
> > + p_dec->fmt_in.i_codec != VLC_FOURCC('m','p','g','3') )
> > + return VLC_EGENERIC;
> > +
> > + p_dec->fmt_out.i_cat = AUDIO_ES;
> > + p_dec->fmt_out.i_codec = VLC_CODEC_FL32;
> > +
> > + /* Initialize libmpg123 */
> > + if( InitMPG123() != MPG123_OK )
> > + return VLC_EGENERIC;
> > +
> > + /* Allocate the memory needed to store the module's structure */
> > + p_sys = p_dec->p_sys = malloc( sizeof(decoder_sys_t) );
> > + if( p_sys == NULL )
> > + return VLC_EGENERIC;
> > +
> > + /* Create our mpg123 handle */
> > + if( ( p_sys->p_handle = mpg123_new( NULL, NULL ) ) == NULL )
> > + goto error;
> > +
> > + /* Open a new bitstream */
> > + if( mpg123_open_feed( p_sys->p_handle ) != MPG123_OK )
> > + {
> > + msg_Err( p_this, "mpg123 error: can't open feed" );
> > + mpg123_delete( p_sys->p_handle );
>
> This could also be part of the error: path
>
> > + goto error;
> > + }
> > +
> > + /* Disable resync stream after error */
> > + mpg123_param( p_sys->p_handle, MPG123_ADD_FLAGS, MPG123_NO_RESYNC, 0
> > );
> > +
> > + /* Setup output format */
> > + mpg123_format_none( p_sys->p_handle );
> > +
> > + if( MPG123_OK != mpg123_format( p_sys->p_handle,
> > + p_dec->fmt_out.audio.i_rate,
> > + MPG123_MONO | MPG123_STEREO,
> > + MPG123_ENC_FLOAT_32 ) )
> > + {
> > + msg_Err( p_this, "mpg123 error: %s",
> > + mpg123_strerror( p_sys->p_handle ) );
> > + mpg123_close( p_sys->p_handle );
> > + mpg123_delete( p_sys->p_handle );
> > + goto error;
> > + }
> > +
> > + p_dec->fmt_in.audio.i_rate = 0; /* So end_date gets initialized */
> > + p_dec->pf_decode_audio = DecodeBlock;
> > + p_dec->fmt_out.audio.i_format = p_dec->fmt_out.i_codec;
> > + p_dec->fmt_out.audio.i_bitspersample =
> > + aout_BitsPerSample( p_dec->fmt_out.i_codec );
> > +
> > + msg_Dbg( p_this, "%4.4s->%4.4s, bits per sample: %i",
> > + (char *)&p_dec->fmt_in.i_codec,
> > + (char *)&p_dec->fmt_out.i_codec,
> > + p_dec->fmt_out.audio.i_bitspersample );
> > +
> > + return VLC_SUCCESS;
> > +error:
> > + ExitMPG123();
> > + free( p_sys );
> > + return VLC_EGENERIC;
> > +}
> > +
> > +/*****************************************************************************
> > + * CloseDecoder : deallocate data structures
> > +
> > *****************************************************************************/
> > +static void CloseDecoder( vlc_object_t *p_this )
> > +{
> > + decoder_t *p_dec = (decoder_t *)p_this;
> > + decoder_sys_t *p_sys = p_dec->p_sys;
> > +
> > + mpg123_close( p_sys->p_handle );
> > + mpg123_delete( p_sys->p_handle );
> > + ExitMPG123();
> > + free( p_sys );
> > +}
> > +
> > +/*****************************************************************************
> > + * InitMPG123 : initialize the mpg123 library (reentrant)
> > +
> > *****************************************************************************/
> > +static int InitMPG123( void )
> > +{
> > + int i_ret;
> > + vlc_mutex_lock( &mpg123_mutex );
> > + if( mpg123_refcount > 0 )
> > + {
> > + mpg123_refcount++;
> > + vlc_mutex_unlock( &mpg123_mutex );
> > + return MPG123_OK;
> > + }
> > + if( ( i_ret = mpg123_init() ) == MPG123_OK )
> > + mpg123_refcount++;
> > + vlc_mutex_unlock( &mpg123_mutex );
> > + return i_ret;
>
> Could this part be implemented using atomic operations to remove the
> static mutex and a bit of code?
I didn't find a better way to make the init/exit calls reentrant. And I
fail to see how atomic operations can help me to remove the static mutex
in this context.
> > +}
> > +
> > +/*****************************************************************************
> > + * ExitMPG123 : close down the mpg123 library (reentrant)
> > +
> > *****************************************************************************/
> > +static void ExitMPG123( void )
> > +{
> > + vlc_mutex_lock( &mpg123_mutex );
> > + mpg123_refcount--;
> > + if( mpg123_refcount == 0 )
> > + mpg123_exit();
> > + vlc_mutex_unlock( &mpg123_mutex );
> > +}
> > --
> > 2.1.3
> >
> > _______________________________________________
> > vlc-devel mailing list
> > To unsubscribe or modify your subscription options:
> > https://mailman.videolan.org/listinfo/vlc-devel
Except than that, all remarks addressed in the upcoming patch.
Thanks for the review.
--
Ludovic Fauvet
www.videolan.org
More information about the vlc-devel
mailing list