[vlc-devel] [PATCH] Add MPEG audio layer I, II, III decoder based on mpg123

Thomas Guillem thomas at gllm.fr
Tue Dec 2 16:27:42 CET 2014



On Tue, Dec 2, 2014, at 12:14, Ludovic Fauvet wrote:
> ---
>  NEWS                      |   1 +
>  configure.ac              |   5 +
>  modules/MODULES_LIST      |   1 +
>  modules/codec/Makefile.am |   7 +
>  modules/codec/mpg123.c    | 318
>  ++++++++++++++++++++++++++++++++++++++++++++++
>  5 files changed, 332 insertions(+)
>  create mode 100644 modules/codec/mpg123.c
> 
> diff --git a/NEWS b/NEWS
> index e144db8..f133d8c 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 based on
> libmpg123
>  
>  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 188fd19..5edc868 100644
> --- a/configure.ac
> +++ b/configure.ac
> @@ -2234,6 +2234,11 @@ AC_SUBST(MAD_CFLAGS)
>  AC_SUBST(MAD_LIBS)
>  AM_CONDITIONAL([HAVE_MAD], [test "${have_mad}" = "yes"])
>  
> +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 bcf837d..4916d16 100644
> --- a/modules/MODULES_LIST
> +++ b/modules/MODULES_LIST
> @@ -226,6 +226,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
>   * mpgv: MPEG-I/II Video demuxer
>   * mtp: MTP interface module
>   * mux_asf: ASF muxer
> diff --git a/modules/codec/Makefile.am b/modules/codec/Makefile.am
> index 8d07a34..e26114b 100644
> --- a/modules/codec/Makefile.am
> +++ b/modules/codec/Makefile.am
> @@ -60,6 +60,13 @@ if HAVE_MAD
>  libmpeg_audio_plugin_la_CPPFLAGS += -DHAVE_MPGA_FILTER
>  endif
>  
> +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)
> +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..6802576
> --- /dev/null
> +++ b/modules/codec/mpg123.c
> @@ -0,0 +1,318 @@
> +/*****************************************************************************
> + * 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
> +*****************************************************************************/
> +
> +#ifdef HAVE_CONFIG_H
> +# include "config.h"
> +#endif
> +
> +#include <mpg123.h>
> +
> +#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;
> +
> +    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", 99 )
> +    set_shortname( "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;

Beware, pp_block can be NULL.

> +    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_block->i_nb_samples = mpg123_spf( 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_original_channels = AOUT_CHAN_LEFT |
> AOUT_CHAN_RIGHT;
> +            break;
> +        case MPG123_M_DUAL:
> +            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_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_block->i_nb_samples );
> +    if( unlikely( !p_out ) )
> +        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;
> +
> +    /* Make mpg123 write directly into the VLC output 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 */
> +    i_err = mpg123_decode_frame( p_sys->p_handle, NULL, NULL, NULL );
> +    if( i_err != MPG123_OK )
> +    {
> +        if( i_err != MPG123_NEW_FORMAT )
> +            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 )
> +        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" );
> +        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_in.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 );
> +        goto error;
> +    }
> +
> +    p_dec->fmt_out.audio.i_rate = 0; /* So end_date gets initialized */
> +    p_dec->fmt_out.audio.i_format = p_dec->fmt_out.i_codec;
> +    p_dec->pf_decode_audio = DecodeBlock;
> +
> +    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,
> +             aout_BitsPerSample( p_dec->fmt_out.i_codec ) );
> +
> +    return VLC_SUCCESS;
> +error:
> +    mpg123_delete( p_sys->p_handle );
> +    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;
> +}
> +
> +/*****************************************************************************
> + * 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



More information about the vlc-devel mailing list