* mpga: mp3 demuxer written from scratch using ninput.h
authorLaurent Aimar <fenrir@videolan.org>
Fri, 1 Aug 2003 00:37:06 +0000 (00:37 +0000)
committerLaurent Aimar <fenrir@videolan.org>
Fri, 1 Aug 2003 00:37:06 +0000 (00:37 +0000)
modules/demux/mpeg/Modules.am
modules/demux/mpeg/audio.c [deleted file]
modules/demux/mpeg/mpga.c [new file with mode: 0644]

index c88cee2..86d6cbf 100644 (file)
@@ -24,7 +24,7 @@ SOURCES_ts_dvbpsi = \
        ts.c \
        $(NULL)
 
-SOURCES_audio = \
-       audio.c \
+SOURCES_mpga = \
+       mpga.c \
        $(NULL)
 
diff --git a/modules/demux/mpeg/audio.c b/modules/demux/mpeg/audio.c
deleted file mode 100644 (file)
index cf6f508..0000000
+++ /dev/null
@@ -1,726 +0,0 @@
-/*****************************************************************************
- * audio.c : mpeg audio Stream input module for vlc
- *****************************************************************************
- * Copyright (C) 2001 VideoLAN
- * $Id: audio.c,v 1.18 2003/05/05 22:23:36 gbazin Exp $
- *
- * Authors: Laurent Aimar <fenrir@via.ecp.fr>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
- *****************************************************************************/
-
-/*****************************************************************************
- * Preamble
- *****************************************************************************/
-#include <stdlib.h>                                      /* malloc(), free() */
-#include <string.h>
-
-#include <vlc/vlc.h>
-#include <vlc/input.h>
-
-#include <sys/types.h>
-
-/*****************************************************************************
- * Local prototypes
- *****************************************************************************/
-static int  Activate ( vlc_object_t * );
-static int  Demux ( input_thread_t * );
-
-/* TODO: support MPEG-2.5, not difficult, but I need somes samples... */
-
-/*****************************************************************************
- * Module descriptor
- *****************************************************************************/
-vlc_module_begin();
-    set_description( _("MPEG I/II audio stream demuxer" ) );
-    set_capability( "demux", 50 );
-    set_callbacks( Activate, NULL );
-    add_shortcut( "mpegaudio" );
-    add_shortcut( "mp3" );
-vlc_module_end();
-
-/*****************************************************************************
- * Definitions of structures  and functions used by this plugins
- *****************************************************************************/
-
-/* XXX set this to 0 to avoid problem with PS XXX */
-/* but with some file or web radio will failed to detect */
-/* it's you to choose */
-#define MPEGAUDIO_MAXTESTPOS    0
-
-typedef struct mpeg_header_s
-{
-    uint32_t i_header;
-    int i_version;
-    int i_layer;
-    int i_crc;
-    int i_bitrate;
-    int i_samplerate;
-    int i_padding;
-    int i_extension;
-    int i_mode;
-    int i_modeext;
-    int i_copyright;
-    int i_original;
-    int i_emphasis;
-
-} mpeg_header_t;
-
-/* Xing Header if present */
-#define FRAMES_FLAG     0x0001  /* these flags is for i_flags */
-#define BYTES_FLAG      0x0002  /* because all is optionnal */
-#define TOC_FLAG        0x0004
-#define VBR_SCALE_FLAG  0x0008
-typedef struct xing_header_s
-{
-    int     i_flags;      /* from Xing header data */
-    int     i_frames;     /* total bit stream frames from Xing header data */
-    int     i_bytes;      /* total bit stream bytes from Xing header data */
-    int     i_vbr_scale;  /* encoded vbr scale from Xing header data */
-    uint8_t i_toc[100];   /* for seek */
-    int     i_avgbitrate; /* calculated, XXX: bits/sec not Kb */
-} xing_header_t;
-
-struct demux_sys_t
-{
-    mtime_t i_pts;
-
-    es_descriptor_t *p_es;
-    mpeg_header_t   mpeg;
-    xing_header_t   xingheader;
-
-    /* extracted information */
-    int i_samplerate;
-    int i_samplelength;
-    int i_framelength;
-};
-
-
-static int mpegaudio_bitrate[2][3][16] =
-{
-  {
-    /* v1 l1 */
-    { 0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448, 0},
-    /* v1 l2 */
-    { 0, 32, 48, 56,  64,  80,  96, 112, 128, 160, 192, 224, 256, 320, 384, 0},
-    /* v1 l3 */
-    { 0, 32, 40, 48,  56,  64,  80,  96, 112, 128, 160, 192, 224, 256, 320, 0}
-  },
-
-  {
-     /* v2 l1 */
-    { 0, 32, 48, 56,  64,  80,  96, 112, 128, 144, 160, 176, 192, 224, 256, 0},
-    /* v2 l2 */
-    { 0,  8, 16, 24,  32,  40,  48,  56,  64,  80,  96, 112, 128, 144, 160, 0},
-    /* v2 l3 */
-    { 0,  8, 16, 24,  32,  40,  48,  56,  64,  80,  96, 112, 128, 144, 160, 0}
-  }
-
-};
-
-static int mpegaudio_samplerate[2][4] = /* version 1 then 2 */
-{
-    { 44100, 48000, 32000, 0 },
-    { 22050, 24000, 16000, 0 }
-};
-
-static char* mpegaudio_mode[4] =
-{
-    "stereo", "joint stereo", "dual channel", "mono"
-};
-
-static inline uint32_t GetDWBE( uint8_t *p_buff )
-{
-    return( ( p_buff[0] << 24 )|( p_buff[1] << 16 )|
-            ( p_buff[2] <<  8 )|( p_buff[3] ) );
-}
-
-/*****************************************************************************
- * Function to manipulate stream easily
- *****************************************************************************
- *
- * SkipBytes : skip bytes, not yet optimised, read bytes to be skipped :P
- *
- * ReadPes : read data and make a PES
- *
- *****************************************************************************/
-static int SkipBytes( input_thread_t *p_input, int i_size )
-{
-    data_packet_t *p_data;
-    int i_read;
-
-    while( i_size > 0 )
-    {
-        i_read = input_SplitBuffer(p_input, &p_data, __MIN( i_size, 1024 ) );
-        if( i_read <= 0 )
-        {
-            return( 0 );
-        }
-        input_DeletePacket( p_input->p_method_data, p_data );
-        i_size -= i_read;
-    }
-    return( 1 );
-}
-
-static int ReadPES( input_thread_t *p_input,
-                    pes_packet_t **pp_pes,
-                    int i_size )
-{
-    pes_packet_t *p_pes;
-
-    *pp_pes = NULL;
-
-    if( !(p_pes = input_NewPES( p_input->p_method_data )) )
-    {
-        msg_Err( p_input, "cannot allocate new PES" );
-        return( 0 );
-    }
-
-    while( i_size > 0 )
-    {
-        data_packet_t   *p_data;
-        int i_read;
-
-        if( (i_read = input_SplitBuffer( p_input,
-                                         &p_data,
-                                         __MIN( i_size, 1024 ) ) ) <= 0 )
-        {
-            input_DeletePES( p_input->p_method_data, p_pes );
-            return( 0 );
-        }
-        if( !p_pes->p_first )
-        {
-            p_pes->p_first = p_data;
-            p_pes->i_nb_data = 1;
-            p_pes->i_pes_size = i_read;
-        }
-        else
-        {
-            p_pes->p_last->p_next  = p_data;
-            p_pes->i_nb_data++;
-            p_pes->i_pes_size += i_read;
-        }
-        p_pes->p_last  = p_data;
-        i_size -= i_read;
-    }
-    *pp_pes = p_pes;
-    return( 1 );
-}
-
-/*****************************************************************************
- * CheckHeader : Test the validity of the header
- *****************************************************************************/
-static int CheckHeader( uint32_t i_header )
-{
-    if( ((( i_header >> 20 )&0x0FFF) != 0x0FFF )  /* header sync */
-        || (((i_header >> 17)&0x03) == 0 )  /* valid layer ?*/
-        || (((i_header >> 12)&0x0F) == 0x0F )
-        || (((i_header >> 12)&0x0F) == 0x00 ) /* valid bitrate ? */
-        || (((i_header >> 10) & 0x03) == 0x03 ) /* valide sampling freq ? */
-        || ((i_header & 0x03) == 0x02 )) /* valid emphasis ? */
-    {
-        return( 0 ); /*invalid */
-    }
-    return( 1 ); /* valid */
-}
-
-/*****************************************************************************
- * DecodedFrameSize : give the length of the decoded pcm data
- *****************************************************************************/
-static int DecodedFrameSize( mpeg_header_t *p_mpeg )
-{
-    switch( p_mpeg->i_layer )
-    {
-        case( 0 ): /* layer 1 */
-            return( 384);
-        case( 1 ): /* layer 2 */
-            return( 1152 );
-        case( 2 ): /* layer 3 */
-            return( !p_mpeg->i_version ? 1152 : 576 );
-            /* XXX: perhaps we have to /2 for all layer but i'm not sure */
-    }
-    return( 0 );
-}
-
-/****************************************************************************
- * GetHeader : find an mpeg header and load it
- ****************************************************************************/
-static int GetHeader( input_thread_t  *p_input,
-                      mpeg_header_t   *p_mpeg,
-                      int             i_max_pos,
-                      int             *pi_skip )
-{
-    uint32_t i_header;
-    uint8_t  *p_peek;
-    int i_size;
-
-    *pi_skip = 0;
-    i_size = input_Peek( p_input, &p_peek, i_max_pos + 4 );
-
-    for( ; ; )
-    {
-        if( i_size < 4 )
-        {
-            return( 0 );
-        }
-        if( !CheckHeader( GetDWBE( p_peek ) ) )
-        {
-            p_peek++;
-            i_size--;
-            *pi_skip += 1;
-            continue;
-        }
-        /* we found an header, load it */
-        break;
-    }
-    i_header = GetDWBE( p_peek );
-    p_mpeg->i_header = i_header;
-    p_mpeg->i_version =  1 - ( ( i_header >> 19 ) & 0x01 );
-    p_mpeg->i_layer =  3 - ( ( i_header >> 17 ) & 0x03 );
-    p_mpeg->i_crc = 1 - (( i_header >> 16 ) & 0x01);
-    p_mpeg->i_bitrate =
-        mpegaudio_bitrate[p_mpeg->i_version][p_mpeg->i_layer][(i_header>>12)&0x0F];
-    p_mpeg->i_samplerate = mpegaudio_samplerate[p_mpeg->i_version][(i_header>>10)&0x03];
-    p_mpeg->i_padding = (( i_header >> 9 ) & 0x01);
-    p_mpeg->i_extension = ( i_header >> 7 ) & 0x01;
-    p_mpeg->i_mode = ( i_header >> 6 ) & 0x03;
-    p_mpeg->i_modeext = ( i_header >> 4 ) & 0x03;
-    p_mpeg->i_copyright = ( i_header >> 3 ) & 0x01;
-    p_mpeg->i_original = ( i_header >> 2 ) & 0x01;
-    p_mpeg->i_emphasis = ( i_header ) & 0x03;
-
-    return( 1 );
-}
-
-/*****************************************************************************
- * ExtractXingHeader : extract a Xing header if exist
- *****************************************************************************
- * It also calcul avgbitrate, using Xing header if present or assume that
- * the bitrate of the first frame is the same for the all file
- *****************************************************************************/
-static void ExtractXingHeader( input_thread_t *p_input,
-                               xing_header_t *p_xh )
-{
-    int i_skip;
-    int i_size;
-    uint8_t  *p_peek;
-    mpeg_header_t mpeg;
-
-    p_xh->i_flags = 0;  /* nothing present */
-    if( !( GetHeader( p_input,
-                      &mpeg,
-                      8192,
-                      &i_skip ) ) )
-    {
-        msg_Err( p_input, "ExtractXingHeader failed, shouldn't ..." );
-        return;
-    }
-
-    p_xh->i_avgbitrate = mpeg.i_bitrate * 1000; /* default */
-
-    /* 1024 is enougth */
-    if( ( i_size = input_Peek( p_input, &p_peek, 1024 + i_skip ) ) < 8 )
-    {
-        return;
-    }
-    p_peek += i_skip;
-    i_size -= i_skip;
-
-    /* calculate pos of xing header */
-    if( !mpeg.i_version )
-    {
-        p_peek += mpeg.i_mode != 3 ? 36 : 21;
-        i_size -= mpeg.i_mode != 3 ? 36 : 21;
-    }
-    else
-    {
-        p_peek += mpeg.i_mode != 3 ? 21 : 13;
-        i_size -= mpeg.i_mode != 3 ? 21 : 13;
-    }
-    if( i_size < 8 )
-    {
-        return;
-    }
-    if( ( p_peek[0] != 'X' )||( p_peek[1] != 'i' )||
-        ( p_peek[2] != 'n' )||( p_peek[3] != 'g' ) )
-    {
-        return;
-    }
-    else
-    {
-        msg_Dbg( p_input, "Xing header is present" );
-        p_peek += 4;
-        i_size -= 4;
-    }
-    if( i_size < 4 )
-    {
-        return;
-    }
-    else
-    {
-        p_xh->i_flags = GetDWBE( p_peek );
-        p_peek += 4;
-        i_size -= 4;
-    }
-
-    if( ( p_xh->i_flags&FRAMES_FLAG )&&( i_size >= 4 ) )
-    {
-        p_xh->i_frames = GetDWBE( p_peek );
-        if( p_xh->i_frames == 0 ) p_xh->i_flags &= ~FRAMES_FLAG;
-        p_peek += 4;
-        i_size -= 4;
-    }
-    if( ( p_xh->i_flags&BYTES_FLAG ) &&( i_size >= 4 ) )
-
-    {
-        p_xh->i_bytes = GetDWBE( p_peek );
-        if( p_xh->i_bytes == 0 ) p_xh->i_flags &= ~BYTES_FLAG;
-        p_peek += 4;
-        i_size -= 4;
-    }
-    if( ( p_xh->i_flags&TOC_FLAG ) &&( i_size >= 100 ) )
-
-    {
-        memcpy( p_xh->i_toc, p_peek, 100 );
-        p_peek += 100;
-        i_size -= 100;
-    }
-    if( ( p_xh->i_flags&VBR_SCALE_FLAG ) &&( i_size >= 4 ) )
-
-    {
-        p_xh->i_vbr_scale = GetDWBE( p_peek );
-        p_peek += 4;
-        i_size -= 4;
-    }
-
-    if( ( p_xh->i_flags&FRAMES_FLAG )&&( p_xh->i_flags&BYTES_FLAG ) )
-    {
-        p_xh->i_avgbitrate =
-              ( (uint64_t)p_xh->i_bytes *
-                (uint64_t)8 *
-                (uint64_t)mpeg.i_samplerate) /
-               ((uint64_t)p_xh->i_frames * (uint64_t)DecodedFrameSize( &mpeg ) );
-    }
-}
-
-/****************************************************************************
- * ExtractConfiguration : extract usefull informations from mpeg_header_t
- ****************************************************************************/
-static void ExtractConfiguration( demux_sys_t *p_demux )
-{
-    p_demux->i_samplerate   = p_demux->mpeg.i_samplerate;
-
-    p_demux->i_samplelength = DecodedFrameSize( &p_demux->mpeg );
-
-    /* XXX if crc do i need to add 2 bytes or not? */
-    switch( p_demux->mpeg.i_layer )
-    {
-        case( 0 ):
-            p_demux->i_framelength =
-                ( ( 12000 * p_demux->mpeg.i_bitrate ) /
-                       p_demux->mpeg.i_samplerate + p_demux->mpeg.i_padding ) * 4;
-            break;
-        case( 1 ):
-            p_demux->i_framelength =
-                  ( 144000 * p_demux->mpeg.i_bitrate ) /
-                       p_demux->mpeg.i_samplerate + p_demux->mpeg.i_padding;
-            break;
-        case( 2 ):
-            p_demux->i_framelength =
-                  (p_demux->mpeg.i_version ? 72000 : 144000) *
-                  p_demux->mpeg.i_bitrate /
-                       p_demux->mpeg.i_samplerate + p_demux->mpeg.i_padding;
-            break;
-
-    }
-}
-
-/****************************************************************************
- * CheckPS : check if this stream could be some ps,
- *           yes it's ugly ...  but another idea ?
- *
- ****************************************************************************/
-static int CheckPS( input_thread_t *p_input )
-{
-    uint8_t  *p_peek;
-    int i_startcode = 0;
-    int i_size = input_Peek( p_input, &p_peek, 8196 );
-
-    while( i_size > 4 )
-    {
-        if( ( p_peek[0] == 0 ) && ( p_peek[1] == 0 ) &&
-            ( p_peek[2] == 1 ) && ( p_peek[3] >= 0xb9 ) &&
-            ++i_startcode >= 3 )
-        {
-            return 1;
-        }
-        p_peek++;
-        i_size--;
-    }
-
-    return 0;
-}
-
-/*****************************************************************************
- * Activate: initializes MPEGaudio structures
- *****************************************************************************/
-static int Activate( vlc_object_t * p_this )
-{
-    input_thread_t * p_input = (input_thread_t *)p_this;
-    demux_sys_t * p_demux;
-    input_info_category_t * p_category;
-    module_t * p_id3;
-
-    int i_found;
-    int b_forced;
-    int i_skip;
-
-    int i_max_pos;
-
-    /* Set the demux function */
-    p_input->pf_demux = Demux;
-
-    /* Initialize access plug-in structures. */
-    if( p_input->i_mtu == 0 )
-    {
-        /* Improve speed. */
-        p_input->i_bufsize = INPUT_DEFAULT_BUFSIZE;
-    }
-
-    b_forced = VLC_FALSE;
-    i_max_pos = MPEGAUDIO_MAXTESTPOS;
-
-    if( ( *p_input->psz_demux )
-        &&( ( !strncmp( p_input->psz_demux, "mpegaudio", 10 ) )||
-            ( !strncmp( p_input->psz_demux, "mp3", 3 ) ) ) )
-    {
-        b_forced = VLC_TRUE;
-        i_max_pos = 4000;
-    }
-    else if( p_input->psz_name )
-    {
-        char *name = p_input->psz_name;
-        int  i_len = strlen( name );
-
-        if( i_len > 4 && !strcasecmp( &name[i_len - 4], ".mp3" ) )
-        {
-            i_max_pos = 2000;
-        }
-    }
-
-    p_id3 = module_Need( p_input, "id3", NULL );
-    if ( p_id3 ) {
-        module_Unneed( p_input, p_id3 );
-    }
-
-    /* create p_demux and init it */
-    if( !( p_demux = p_input->p_demux_data = malloc( sizeof(demux_sys_t) ) ) )
-    {
-        msg_Err( p_input, "out of memory" );
-        return( -1 );
-    }
-    memset( p_demux, 0, sizeof(demux_sys_t) );
-
-    /* check if it could be a ps stream */
-    if( !b_forced && CheckPS(  p_input ))
-    {
-        free( p_input->p_demux_data );
-        return( -1 );
-    }
-
-
-    /* must be sure that is mpeg audio stream unless forced */
-    if( !( i_found = GetHeader( p_input,
-                                &p_demux->mpeg,
-                                i_max_pos,
-                                &i_skip ) ) )
-    {
-        if( b_forced )
-        {
-            msg_Warn( p_input,
-                      "this does not look like an MPEG audio stream, "
-                      "but continuing anyway" );
-        }
-        else
-        {
-            msg_Warn( p_input, "MPEGAudio module discarded (no frame found)" );
-            free( p_input->p_demux_data );
-            return( -1 );
-        }
-    }
-    else
-    {
-        ExtractConfiguration( p_demux );
-    }
-
-
-    vlc_mutex_lock( &p_input->stream.stream_lock );
-    if( input_InitStream( p_input, 0 ) == -1)
-    {
-        msg_Err( p_input, "cannot init stream" );
-        free( p_input->p_demux_data );
-        return( -1 );
-    }
-    if( input_AddProgram( p_input, 0, 0) == NULL )
-    {
-        msg_Err( p_input, "cannot add program" );
-        free( p_input->p_demux_data );
-        return( -1 );
-    }
-    p_input->stream.pp_programs[0]->b_is_ok = 0;
-    p_input->stream.p_selected_program = p_input->stream.pp_programs[0];
-
-    /* create our ES */
-    p_demux->p_es = input_AddES( p_input, p_input->stream.p_selected_program,
-                                 1 /* id */, AUDIO_ES, NULL, 0 );
-    if( !p_demux->p_es )
-    {
-        vlc_mutex_unlock( &p_input->stream.stream_lock );
-        msg_Err( p_input, "out of memory" );
-        free( p_input->p_demux_data );
-        return( -1 );
-    }
-    p_demux->p_es->i_stream_id = 1;
-    p_demux->p_es->i_fourcc = VLC_FOURCC('m','p','g','a');
-
-    input_SelectES( p_input, p_demux->p_es );
-
-    p_input->stream.p_selected_program->b_is_ok = 1;
-    vlc_mutex_unlock( &p_input->stream.stream_lock );
-
-
-    if( i_found )
-    {
-        /* parse Xing Header if present */
-        ExtractXingHeader( p_input, &p_demux->xingheader );
-
-        vlc_mutex_lock( &p_input->stream.stream_lock );
-        p_input->stream.i_mux_rate = p_demux->xingheader.i_avgbitrate / 50 / 8;
-        vlc_mutex_unlock( &p_input->stream.stream_lock );
-
-
-        /* all is ok :)) */
-        msg_Dbg( p_input, "audio MPEG-%d layer %d %s %dHz %dKb/s %s",
-                p_demux->mpeg.i_version + 1,
-                p_demux->mpeg.i_layer + 1,
-                mpegaudio_mode[p_demux->mpeg.i_mode],
-                p_demux->mpeg.i_samplerate,
-                p_demux->xingheader.i_avgbitrate / 1000,
-                p_demux->xingheader.i_flags ?
-                        "VBR (Xing)" : ""
-                    );
-
-        vlc_mutex_lock( &p_input->stream.stream_lock );
-        p_category = input_InfoCategory( p_input, _("mpeg") );
-        input_AddInfo( p_category, _("Input Type"), "Audio MPEG-%d",
-                       p_demux->mpeg.i_version +1 );
-        input_AddInfo( p_category, _("Layer"), "%d", p_demux->mpeg.i_layer + 1 );
-        input_AddInfo( p_category, _("Mode"),
-                       mpegaudio_mode[p_demux->mpeg.i_mode] );
-        input_AddInfo( p_category, _("Sample Rate"), "%dHz",
-                       p_demux->mpeg.i_samplerate );
-        input_AddInfo( p_category, _("Average Bitrate"), "%dKb/s",
-                       p_demux->xingheader.i_avgbitrate / 1000 );
-        vlc_mutex_unlock( &p_input->stream.stream_lock );
-    }
-    else
-    {
-        msg_Dbg( p_input,
-                 "assuming audio MPEG, but not frame header yet found" );
-        vlc_mutex_lock( &p_input->stream.stream_lock );
-        p_category = input_InfoCategory( p_input, _("mpeg") );
-        input_AddInfo( p_category, _("Input Type"), "Audio MPEG-?" );
-        vlc_mutex_unlock( &p_input->stream.stream_lock );
-
-    }
-
-    return( 0 );
-}
-
-/*****************************************************************************
- * Demux: reads and demuxes data packets
- *****************************************************************************
- * Returns -1 in case of error, 0 in case of EOF, 1 otherwise
- *****************************************************************************/
-static int Demux( input_thread_t * p_input )
-{
-    demux_sys_t  *p_demux = p_input->p_demux_data;
-    pes_packet_t *p_pes;
-    int          i_skip;
-
-    if( !GetHeader( p_input,
-                    &p_demux->mpeg,
-                    8192,
-                    &i_skip ) )
-    {
-        if( i_skip > 0)
-        {
-            msg_Dbg( p_input,
-                     "skipping %d bytes (garbage ?)",
-                     i_skip );
-            SkipBytes( p_input, i_skip );
-            return( 1 );
-        }
-        else
-        {
-            msg_Dbg( p_input,
-                     "cannot find next frame (EOF ?)" );
-            return( 0 );
-        }
-    }
-
-    ExtractConfiguration( p_demux );
-
-    input_ClockManageRef( p_input,
-                          p_input->stream.p_selected_program,
-                          p_demux->i_pts );
-
-    /*
-     * For layer 1 and 2 i_skip is garbage but for layer 3 it is not.
-     * Since mad accept without to much trouble garbage I don't skip
-     * it ( in case I misdetect garbage ... )
-     *
-     */
-    if( !ReadPES( p_input, &p_pes, p_demux->i_framelength + i_skip) )
-    {
-        msg_Warn( p_input,
-                "cannot read data" );
-        return( -1 );
-    }
-
-    p_pes->i_rate = p_input->stream.control.i_rate;
-    p_pes->i_dts =
-        p_pes->i_pts = input_ClockGetTS( p_input,
-                                         p_input->stream.p_selected_program,
-                                         p_demux->i_pts );
-
-    if( !p_demux->p_es->p_decoder_fifo )
-    {
-        msg_Err( p_input, "no audio decoder" );
-        input_DeletePES( p_input->p_method_data, p_pes );
-        return( -1 ); /* perhaps not, it's my choice */
-    }
-    else
-    {
-        input_DecodePES( p_demux->p_es->p_decoder_fifo, p_pes );
-    }
-    p_demux->i_pts += (mtime_t)90000 *
-                      (mtime_t)p_demux->i_samplelength /
-                      (mtime_t)p_demux->i_samplerate;
-    return( 1 );
-
-}
-
-
diff --git a/modules/demux/mpeg/mpga.c b/modules/demux/mpeg/mpga.c
new file mode 100644 (file)
index 0000000..6e47fa0
--- /dev/null
@@ -0,0 +1,479 @@
+/*****************************************************************************
+ * mpga.c : MPEG-I/II Audio input module for vlc
+ *****************************************************************************
+ * Copyright (C) 2001 VideoLAN
+ * $Id: mpga.c,v 1.1 2003/08/01 00:37:06 fenrir Exp $
+ *
+ * Authors: Laurent Aimar <fenrir@via.ecp.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
+ *****************************************************************************/
+
+/*****************************************************************************
+ * Preamble
+ *****************************************************************************/
+#include <stdlib.h>                                      /* malloc(), free() */
+
+#include <vlc/vlc.h>
+#include <vlc/input.h>
+
+#include <ninput.h>
+
+/*****************************************************************************
+ * Module descriptor
+ *****************************************************************************/
+static int  Open    ( vlc_object_t * );
+static void Close  ( vlc_object_t * );
+
+vlc_module_begin();
+    set_description( _("MPEG-I/II Audio demuxer" ) );
+    set_capability( "demux", 100 );
+    set_callbacks( Open, Close );
+    add_shortcut( "mpga" );
+    add_shortcut( "mp3" );
+vlc_module_end();
+
+/* TODO:
+ * - mpeg 2.5
+ * - free bitrate
+ */
+
+/*****************************************************************************
+ * Local prototypes
+ *****************************************************************************/
+static int  Demux       ( input_thread_t * );
+
+struct demux_sys_t
+{
+    stream_t        *s;
+    mtime_t         i_time;
+
+    int             i_bitrate_avg;  /* extracted from Xing header */
+    es_descriptor_t *p_es;
+};
+
+
+static inline uint32_t GetDWBE( uint8_t *p )
+{
+    return( ( p[0] << 24 )|( p[1] << 16 )|( p[2] <<  8 )|( p[3] ) );
+}
+
+static int HeaderCheck( uint32_t h )
+{
+    if( ((( h >> 20 )&0x0FFF) != 0x0FFF )  /* header sync */
+        || (((h >> 17)&0x03) == 0 )  /* valid layer ?*/
+        || (((h >> 12)&0x0F) == 0x0F )
+        || (((h >> 12)&0x0F) == 0x00 ) /* valid bitrate ? */
+        || (((h >> 10) & 0x03) == 0x03 ) /* valide sampling freq ? */
+        || ((h & 0x03) == 0x02 )) /* valid emphasis ? */
+    {
+        return( VLC_FALSE );
+    }
+    return( VLC_TRUE );
+}
+
+static int mpga_sample_rate[2][4] =
+{
+    { 44100, 48000, 32000, 0 },
+    { 22050, 24000, 16000, 0 }
+};
+
+static int mpga_bitrate[2][3][16] =
+{
+  {
+    { 0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448, 0},
+    { 0, 32, 48, 56,  64,  80,  96, 112, 128, 160, 192, 224, 256, 320, 384, 0},
+    { 0, 32, 40, 48,  56,  64,  80,  96, 112, 128, 160, 192, 224, 256, 320, 0}
+  },
+  {
+    { 0, 32, 48, 56,  64,  80,  96, 112, 128, 144, 160, 176, 192, 224, 256, 0},
+    { 0,  8, 16, 24,  32,  40,  48,  56,  64,  80,  96, 112, 128, 144, 160, 0},
+    { 0,  8, 16, 24,  32,  40,  48,  56,  64,  80,  96, 112, 128, 144, 160, 0}
+  }
+};
+
+
+#define MPGA_VERSION( h )   ( 1 - (((h)>>19)&0x01) )
+#define MPGA_LAYER( h )     ( 3 - (((h)>>17)&0x03) )
+#define MPGA_SAMPLE_RATE(h) mpga_sample_rate[MPGA_VERSION(h)][((h)>>10)&0x03]
+#define MPGA_CHANNELS(h)    ( (((h)>>6)&0x03) == 3 ? 1 : 2)
+#define MPGA_BITRATE(h)     mpga_bitrate[MPGA_VERSION(h)][MPGA_LAYER(h)][((h)>>12)&0x0f]
+#define MPGA_PADDING(h)     ( ((h)>>9)&0x01 )
+#define MPGA_MODE(h)        (((h)>> 6)&0x03)
+
+static int mpga_frame_size( uint32_t h )
+{
+    switch( MPGA_LAYER(h) )
+    {
+        case 0:
+            return ( ( 12000 * MPGA_BITRATE(h) ) / MPGA_SAMPLE_RATE(h) + MPGA_PADDING(h) ) * 4;
+        case 1:
+            return ( 144000 * MPGA_BITRATE(h) ) / MPGA_SAMPLE_RATE(h) + MPGA_PADDING(h);
+        case 2:
+            return ( ( MPGA_VERSION(h) ? 72000 : 144000 ) * MPGA_BITRATE(h) ) / MPGA_SAMPLE_RATE(h) + MPGA_PADDING(h);
+        default:
+            return 0;
+    }
+}
+
+static int mpga_frame_samples( uint32_t h )
+{
+    switch( MPGA_LAYER(h) )
+    {
+        case 0:
+            return 384;
+        case 1:
+            return 1152;
+        case 2:
+            return MPGA_VERSION(h) ? 576 : 1152;
+        default:
+            return 0;
+    }
+}
+
+#if 0
+static int CheckPS( input_thread_t *p_input )
+{
+    uint8_t  *p_peek;
+    int i_startcode = 0;
+    int i_size = input_Peek( p_input, &p_peek, 8196 );
+
+    while( i_size > 4 )
+    {
+        if( ( p_peek[0] == 0 ) && ( p_peek[1] == 0 ) &&
+            ( p_peek[2] == 1 ) && ( p_peek[3] >= 0xb9 ) &&
+            ++i_startcode >= 3 )
+        {
+            return 1;
+        }
+        p_peek++;
+        i_size--;
+    }
+
+    return 0;
+}
+#endif
+
+/*****************************************************************************
+ * Open: initializes demux structures
+ *****************************************************************************/
+static int Open( vlc_object_t * p_this )
+{
+    input_thread_t *p_input = (input_thread_t *)p_this;
+    demux_sys_t    *p_sys;
+    vlc_bool_t     b_forced = VLC_FALSE;
+    vlc_bool_t     b_extention = VLC_FALSE;
+
+    uint32_t       header;
+
+    uint8_t        *p_peek;
+
+    module_t       *p_id3;
+
+
+    if( p_input->psz_demux &&
+        ( !strncmp( p_input->psz_demux, "mpga", 4 ) ||
+          !strncmp( p_input->psz_demux, "mp3", 3 ) ) )
+    {
+        b_forced = VLC_TRUE;
+    }
+    if( p_input->psz_name )
+    {
+        int  i_len = strlen( p_input->psz_name );
+
+        if( i_len > 4 && !strcasecmp( &p_input->psz_name[i_len - 4], ".mp3" ) )
+        {
+            b_extention = VLC_TRUE;
+        }
+    }
+
+    /* skip possible id3 header */
+    p_id3 = module_Need( p_input, "id3", NULL );
+    if ( p_id3 )
+    {
+        module_Unneed( p_input, p_id3 );
+    }
+
+    if( input_Peek( p_input, &p_peek, 4 ) < 4 )
+    {
+        msg_Err( p_input, "cannot peek" );
+        return VLC_EGENERIC;
+    }
+
+    if( !HeaderCheck( header = GetDWBE( p_peek ) ) )
+    {
+        vlc_bool_t b_ok = VLC_FALSE;
+        int i_peek;
+
+        if( !b_forced && !b_extention )
+        {
+            msg_Warn( p_input, "mpga module discarded" );
+            return VLC_EGENERIC;
+        }
+
+        i_peek = input_Peek( p_input, &p_peek, 8096 );
+
+        while( i_peek > 4 )
+        {
+            if( HeaderCheck( header = GetDWBE( p_peek ) ) )
+            {
+                b_ok = VLC_TRUE;
+                break;
+            }
+            p_peek += 4;
+            i_peek -= 4;
+        }
+        if( !b_ok && !b_forced )
+        {
+            msg_Warn( p_input, "mpga module discarded" );
+            return VLC_EGENERIC;
+        }
+    }
+
+    p_input->pf_demux = Demux;
+
+    p_input->p_demux_data = p_sys = malloc( sizeof( demux_sys_t ) );
+    p_sys->i_time = 0;
+    p_sys->i_bitrate_avg = 0;
+
+    if( ( p_sys->s = stream_OpenInput( p_input ) ) == NULL )
+    {
+        msg_Err( p_input, "cannot create stream" );
+        goto error;
+    }
+
+    if( HeaderCheck( header ) )
+    {
+        int     i_xing;
+        uint8_t *p_xing;
+
+        input_info_category_t * p_cat;
+        static char* mpga_mode[4] =
+        {
+            "stereo", "joint stereo", "dual channel", "mono"
+        };
+
+        p_sys->i_bitrate_avg = MPGA_BITRATE( header ) * 1000;
+        if( ( i_xing = stream_Peek( p_sys->s, &p_xing, 1024 ) ) >= 21 )
+        {
+            int i_skip;
+
+            if( MPGA_VERSION( header) == 0 )
+            {
+                i_skip = MPGA_MODE( header ) != 3 ? 36 : 21;
+            }
+            else
+            {
+                i_skip = MPGA_MODE( header ) != 3 ? 21 : 13;
+            }
+            if( i_skip + 8 < i_xing &&
+                !strncmp( &p_xing[i_skip], "Xing", 4 ) )
+            {
+                unsigned int i_flags = GetDWBE( &p_xing[i_skip+4] );
+                unsigned int i_bytes = 0, i_frames = 0;
+
+                p_xing += i_skip + 8;
+                i_xing -= i_skip + 8;
+
+                i_skip = 0;
+                if( i_flags&0x01 && i_skip + 4 <= i_xing )   /* XING_FRAMES */
+                {
+                    i_frames = GetDWBE( &p_xing[i_skip] );
+                    i_skip += 4;
+                }
+                if( i_flags&0x02 && i_skip + 4 <= i_xing )   /* XING_BYTES */
+                {
+                    i_bytes = GetDWBE( &p_xing[i_skip] );
+                    i_skip += 4;
+                }
+                if( i_flags&0x04 )   /* XING_TOC */
+                {
+                    i_skip += 100;
+                }
+                if( i_flags&0x08 && i_skip + 4 <= i_xing )   /* XING_VBR */
+                {
+                    p_sys->i_bitrate_avg = GetDWBE( &p_xing[i_skip] );
+                    msg_Dbg( p_input, "xing vbr value present (%d)", p_sys->i_bitrate_avg );
+                }
+                else if( i_frames > 0 && i_bytes > 0 )
+                {
+                    p_sys->i_bitrate_avg = (int64_t)i_bytes *
+                                           (int64_t)8 *
+                                           (int64_t)MPGA_SAMPLE_RATE( header ) /
+                                           (int64_t)i_frames /
+                                           (int64_t)mpga_frame_samples( header );
+                    msg_Dbg( p_input, "xing frames&bytes value present (%db/s)", p_sys->i_bitrate_avg );
+                }
+            }
+        }
+
+        msg_Dbg( p_input, "version=%d layer=%d channels=%d samplerate=%d",
+                 MPGA_VERSION( header) + 1,
+                 MPGA_LAYER( header ) + 1,
+                 MPGA_CHANNELS( header ),
+                 MPGA_SAMPLE_RATE( header ) );
+
+        vlc_mutex_lock( &p_input->stream.stream_lock );
+
+        p_cat = input_InfoCategory( p_input, _("MPEG") );
+        input_AddInfo( p_cat, _("Input Type"), "Audio MPEG-%d",
+                       MPGA_VERSION( header) + 1 );
+        input_AddInfo( p_cat, _("Layer"), "%d",
+                       MPGA_LAYER( header ) + 1 );
+        input_AddInfo( p_cat, _("Mode"),
+                       mpga_mode[MPGA_MODE( header )] );
+        input_AddInfo( p_cat, _("Sample Rate"), "%dHz",
+                       MPGA_SAMPLE_RATE( header ) );
+        input_AddInfo( p_cat, _("Average Bitrate"), "%dKb/s",
+                       p_sys->i_bitrate_avg / 1000 );
+        vlc_mutex_unlock( &p_input->stream.stream_lock );
+    }
+
+    vlc_mutex_lock( &p_input->stream.stream_lock );
+    if( input_InitStream( p_input, 0 ) == -1)
+    {
+        vlc_mutex_unlock( &p_input->stream.stream_lock );
+        msg_Err( p_input, "cannot init stream" );
+        goto error;
+    }
+    if( input_AddProgram( p_input, 0, 0) == NULL )
+    {
+        vlc_mutex_unlock( &p_input->stream.stream_lock );
+        msg_Err( p_input, "cannot add program" );
+        goto error;
+    }
+    p_input->stream.pp_programs[0]->b_is_ok = 0;
+    p_input->stream.p_selected_program = p_input->stream.pp_programs[0];
+
+    p_input->stream.i_mux_rate = p_sys->i_bitrate_avg / 8 / 50;
+
+    p_sys->p_es = input_AddES( p_input,
+                               p_input->stream.p_selected_program,
+                               1 , AUDIO_ES, NULL, 0 );
+
+    p_sys->p_es->i_stream_id = 1;
+    p_sys->p_es->i_fourcc = VLC_FOURCC( 'm', 'p', 'g', 'a' );
+    input_SelectES( p_input, p_sys->p_es );
+
+    p_input->stream.p_selected_program->b_is_ok = 1;
+    vlc_mutex_unlock( &p_input->stream.stream_lock );
+
+    return VLC_SUCCESS;
+
+error:
+    if( p_sys->s )
+    {
+        stream_Release( p_sys->s );
+    }
+    free( p_sys );
+    return VLC_EGENERIC;
+}
+
+
+/*****************************************************************************
+ * Demux: reads and demuxes data packets
+ *****************************************************************************
+ * Returns -1 in case of error, 0 in case of EOF, 1 otherwise
+ *****************************************************************************/
+static int Demux( input_thread_t * p_input )
+{
+    demux_sys_t  *p_sys = p_input->p_demux_data;
+    pes_packet_t *p_pes;
+
+    uint32_t     header;
+    uint8_t      *p_peek;
+
+    if( stream_Peek( p_sys->s, &p_peek, 4 ) < 4 )
+    {
+        msg_Warn( p_input, "cannot peek" );
+        return 0;
+    }
+
+    if( !HeaderCheck( header = GetDWBE( p_peek ) ) )
+    {
+        /* we need to resynch */
+        vlc_bool_t  b_ok = VLC_FALSE;
+        int         i_skip = 0;
+        int         i_peek;
+
+        i_peek = stream_Peek( p_sys->s, &p_peek, 8096 );
+        if( i_peek < 4 )
+        {
+            msg_Warn( p_input, "cannot peek" );
+            return 0;
+        }
+
+        while( i_peek >= 4 )
+        {
+            if( HeaderCheck( header = GetDWBE( p_peek ) ) )
+            {
+                b_ok = VLC_TRUE;
+                break;
+            }
+
+            p_peek++;
+            i_peek--;
+            i_skip++;
+        }
+
+        msg_Warn( p_input, "garbage=%d bytes", i_skip );
+        stream_Read( p_sys->s, NULL, i_skip );
+        return 1;
+    }
+
+    input_ClockManageRef( p_input,
+                          p_input->stream.p_selected_program,
+                          p_sys->i_time * 9 / 100 );
+
+    if( ( p_pes = stream_PesPacket( p_sys->s, mpga_frame_size( header ) ) ) == NULL )
+    {
+        msg_Warn( p_input, "cannot read data" );
+        return 0;
+    }
+
+    p_pes->i_dts =
+    p_pes->i_pts = input_ClockGetTS( p_input,
+                                     p_input->stream.p_selected_program,
+                                     p_sys->i_time * 9 / 100 );
+
+    if( !p_sys->p_es->p_decoder_fifo )
+    {
+        msg_Err( p_input, "no audio decoder" );
+        input_DeletePES( p_input->p_method_data, p_pes );
+        return( -1 );
+    }
+
+    input_DecodePES( p_sys->p_es->p_decoder_fifo, p_pes );
+    p_sys->i_time += (mtime_t)1000000 *
+                     (mtime_t)mpga_frame_samples( header ) /
+                     (mtime_t)MPGA_SAMPLE_RATE( header );
+    return( 1 );
+}
+
+/*****************************************************************************
+ * Close: frees unused data
+ *****************************************************************************/
+static void Close( vlc_object_t * p_this )
+{
+    input_thread_t *p_input = (input_thread_t*)p_this;
+    demux_sys_t    *p_sys = p_input->p_demux_data;
+
+    if( p_sys->s )
+    {
+        stream_Release( p_sys->s );
+    }
+    free( p_sys );
+}
+