]> git.sesse.net Git - vlc/commitdiff
* include/common.h and input_ext-plugins.h, src/misc/modules_plugin.h : export...
authorLaurent Aimar <fenrir@videolan.org>
Fri, 10 May 2002 02:04:17 +0000 (02:04 +0000)
committerLaurent Aimar <fenrir@videolan.org>
Fri, 10 May 2002 02:04:17 +0000 (02:04 +0000)
    * plugins/mpeg_system/mpeg_audio.c : a demux for mpeg audio stream (file, web radio ...)
    * Makefile configure.in : to compile it

Makefile
configure
configure.in
include/common.h
include/input_ext-plugins.h
plugins/avi/avi.c
plugins/ffmpeg/ffmpeg.c
plugins/mad/mad_libmad.c
plugins/mpeg_system/Makefile
plugins/mpeg_system/mpeg_audio.c [new file with mode: 0644]
src/misc/modules_plugin.h

index 43375d05533d41bfe39a202374b1c3fdfc6cab59..80e1194110ed968e38716ce8e3ace93b4fcfa608 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -128,6 +128,7 @@ PLUGINS_TARGETS := a52/a52 \
                motion/motionmmxext \
                motion/motion3dnow \
                motion/motionaltivec \
+        mpeg_system/mpeg_audio \
                mpeg_system/mpeg_es \
                mpeg_system/mpeg_ps \
                mpeg_system/mpeg_ts \
index 3514ffabc400251b717a0947c3328cd68cdead59..2463d8c5fc8ca6471aed1ea04591753b3101737f 100755 (executable)
--- a/configure
+++ b/configure
@@ -5417,7 +5417,7 @@ case x"${target_cpu}" in
 esac
 
 BUILTINS="${BUILTINS} idct idctclassic motion imdct downmix chroma_i420_rgb chroma_i420_yuy2 chroma_i422_yuy2 chroma_i420_ymga mpeg_adec ac3_adec mpeg_vdec"
-PLUGINS="${PLUGINS} dummy null rc logger mpeg_es mpeg_ps mpeg_ts file udp http ipv4 memcpy lpcm_adec ac3_spdif spudec filter_deinterlace filter_invert filter_wall filter_transform filter_distort fx_scope"
+PLUGINS="${PLUGINS} dummy null rc logger mpeg_es mpeg_ps mpeg_ts mpeg_audio file udp http ipv4 memcpy lpcm_adec ac3_spdif spudec filter_deinterlace filter_invert filter_wall filter_transform filter_distort fx_scope"
 
 MMX_MODULES="memcpymmx idctmmx motionmmx chroma_i420_rgb_mmx chroma_i420_yuy2_mmx chroma_i422_yuy2_mmx chroma_i420_ymga_mmx"
 MMXEXT_MODULES="memcpymmxext idctmmxext motionmmxext"
index d13e827a3af933917d3e49ab99ce6234f6edbf95..b32890e2221a788086bd73df878f400263807cc9 100644 (file)
@@ -406,7 +406,7 @@ dnl
 dnl  default modules
 dnl
 BUILTINS="${BUILTINS} idct idctclassic motion imdct downmix chroma_i420_rgb chroma_i420_yuy2 chroma_i422_yuy2 chroma_i420_ymga mpeg_adec ac3_adec mpeg_vdec"
-PLUGINS="${PLUGINS} dummy null rc logger mpeg_es mpeg_ps mpeg_ts file udp http ipv4 memcpy lpcm_adec ac3_spdif spudec filter_deinterlace filter_invert filter_wall filter_transform filter_distort fx_scope"
+PLUGINS="${PLUGINS} dummy null rc logger mpeg_es mpeg_ps mpeg_ts mpeg_audio file udp http ipv4 memcpy lpcm_adec ac3_spdif spudec filter_deinterlace filter_invert filter_wall filter_transform filter_distort fx_scope"
 
 dnl
 dnl  Accelerated modules
index 76480003e531554bc628c4ce37404238def48adf..e7ba691a846b3de16894e499c66d13b86c34008b 100644 (file)
@@ -3,7 +3,7 @@
  * Collection of useful common types and macros definitions
  *****************************************************************************
  * Copyright (C) 1998, 1999, 2000 VideoLAN
- * $Id: common.h,v 1.103 2002/05/03 20:49:30 sam Exp $
+ * $Id: common.h,v 1.104 2002/05/10 02:04:16 fenrir Exp $
  *
  * Authors: Samuel Hocevar <sam@via.ecp.fr>
  *          Vincent Seguin <seguin@via.ecp.fr>
@@ -636,6 +636,9 @@ typedef struct module_symbols_s
     int ( * input_ClockManageControl )   ( struct input_thread_s *,
                                            struct pgrm_descriptor_s *,
                                            mtime_t );
+    mtime_t ( *input_ClockGetTS )       ( struct input_thread_s *,
+                                             struct  pgrm_descriptor_s *, 
+                                             mtime_t );
     void ( * input_FDSeek )         ( struct input_thread_s *, off_t );
     void ( * input_FDClose )        ( struct input_thread_s * );
     ssize_t ( * input_FDRead )          ( struct input_thread_s *, byte_t *,
index cfd16cc0c92e5f9d739b0688073af5ccdcd96097..431c78f9e34a87cb56136793a1ff941bf1282a89 100644 (file)
@@ -3,7 +3,7 @@
  *                      but exported to plug-ins
  *****************************************************************************
  * Copyright (C) 1999-2002 VideoLAN
- * $Id: input_ext-plugins.h,v 1.24 2002/04/25 21:52:42 sam Exp $
+ * $Id: input_ext-plugins.h,v 1.25 2002/05/10 02:04:16 fenrir Exp $
  *
  * Authors: Christophe Massiot <massiot@via.ecp.fr>
  *
@@ -102,6 +102,7 @@ mtime_t input_ClockGetTS( struct input_thread_s *,
 #else
 #   define input_ClockManageRef p_symbols->input_ClockManageRef
 #   define input_ClockManageControl p_symbols->input_ClockManageControl
+#   define input_ClockGetTS p_symbols->input_ClockGetTS
 #endif
 
 /*****************************************************************************
index 63cc308a21383f4f30907a07be831e29bccecb6b..9af9eb92bda186f187db14e04523d4b9d56e088f 100644 (file)
@@ -2,7 +2,7 @@
  * avi.c : AVI file Stream input module for vlc
  *****************************************************************************
  * Copyright (C) 2001 VideoLAN
- * $Id: avi.c,v 1.14 2002/05/07 13:53:55 fenrir Exp $
+ * $Id: avi.c,v 1.15 2002/05/10 02:04:17 fenrir Exp $
  * Authors: Laurent Aimar <fenrir@via.ecp.fr>
  * 
  * This program is free software; you can redistribute it and/or modify
@@ -438,7 +438,7 @@ static int AVIInit( input_thread_t *p_input )
     /* we need to seek to be able to readcorrectly */
     if( !p_input->stream.b_seekable ) 
     {
-        intf_ErrMsg( "input error: need the ability to seek in stream" );
+        intf_WarnMsg( 2,"input: RIFF-AVI plug-in discarded (no seekable)" );
         return( -1 );
     }
     p_input->p_demux_data = 
@@ -461,7 +461,7 @@ static int AVIInit( input_thread_t *p_input )
     if( RIFF_TestFileHeader( p_input, &p_riff, FOURCC_AVI ) != 0 )    
     {
         __AVIFreeDemuxData( p_input );
-        intf_ErrMsg( "input: RIFF-AVI plug-in discarded (avi_file)" );
+        intf_WarnMsg( 2,"input: RIFF-AVI plug-in discarded (avi_file)" );
         return( -1 );
     }
     p_avi_demux->p_riff = p_riff;
@@ -802,7 +802,6 @@ static int AVIInit( input_thread_t *p_input )
     }
     else
     {
-        /* TODO: if there is more than 1 video stream */
         intf_Msg( "input error: no video stream found !" );
     }
     if( p_avi_demux->p_info_audio != NULL ) 
@@ -883,17 +882,14 @@ static int __AVI_NextIndexEntry( input_thread_t *p_input,
     p_info->i_idxposc--;
     
     /* create entry on the fly */
-    /* TODO: when parsing for a stream take care of the other to not do 
-       the same things two time */
-    /* search for the less advance stream and parse from it for all streams*/
+    /* search for the more advance stream and parse from it for all streams*/
     p_info_tmp = p_info;
-    /* XXX XXX XXX change to take the stream the more advanced */
     
     for( i = 0; i < p_avi_demux->i_streams; i++ )
     {
 #define p_info_i p_avi_demux->pp_info[i]
         if( p_info_i->p_index[p_info_i->i_idxnb - 1].i_offset + 
-                        p_info_i->i_idxoffset 
+                        p_info_i->i_idxoffset >
             p_info_tmp->p_index[p_info_tmp->i_idxnb - 1].i_offset +
                         p_info_tmp->i_idxoffset )
         {
@@ -1264,6 +1260,8 @@ static int AVI_ReAlign( input_thread_t *p_input )
         && ( i_pos < p_info->p_index[p_info->i_idxposc].i_offset +
                 p_info->p_index[p_info->i_idxposc].i_length ) )
     {
+        /* FIXME FIXME FIXME if master == audio and samplesize != 0 */
+        /* don't work with big chunk */
         /* don't do anything we are in the current chunk  */
         return( 0 );
     }
@@ -1387,7 +1385,6 @@ static pes_packet_t *AVI_GetFrameInPES( input_thread_t *p_input,
         /* stream is chunk based , easy */
         int i_chunk = __AVI_PTSToChunk( p_info, i_dpts);
         /* at least one frame */
-        /* i_chunk = __MIN( 50, i_chunk ); */ /* but no more than 20 */
         /* read them */
         p_pes_first = NULL;
         for( i = 0; i < i_chunk; i++ )
index cdabd83b962f278d5ab7fdd1fe4150056ee48e93..96056126cd1776009ba115f8b22fda55242040e7 100644 (file)
@@ -2,7 +2,7 @@
  * ffmpeg.c: video decoder using ffmpeg library
  *****************************************************************************
  * Copyright (C) 1999-2001 VideoLAN
- * $Id: ffmpeg.c,v 1.6 2002/05/07 13:55:36 fenrir Exp $
+ * $Id: ffmpeg.c,v 1.7 2002/05/10 02:04:17 fenrir Exp $
  *
  * Authors: Laurent Aimar <fenrir@via.ecp.fr>
  *
@@ -120,7 +120,7 @@ static int decoder_Probe( u8 *pi_type )
     switch( *pi_type )
     {
 /*        case( MPEG1_VIDEO_ES ): marche pas pr le moment 
-        case( MPEG2_VIDEO_ES ): */
+        case( MPEG2_VIDEO_ES ):  */
         case( MSMPEG4_VIDEO_ES ):
         case( MPEG4_VIDEO_ES ):
             return( 0 );
index 2b4b48301b0b88c12fe4f15346ebe792f4b8ca4e..c3de807c44a59d9f7241f35b1c595fa509c7c48f 100644 (file)
@@ -292,7 +292,7 @@ enum mad_flow libmad_output(void *data, struct mad_header const *p_libmad_header
     {
        p_mad_adec->p_aout_fifo = aout_CreateFifo(
                 AOUT_FIFO_PCM,              /* fifo type */
-                p_libmad_pcm->channels,     /* nr. of channels */
+                2, /*p_libmad_pcm->channels,*/     /* nr. of channels */
                 p_libmad_pcm->samplerate,   /* frame rate in Hz ?*/
                 p_libmad_pcm->length*2,     /* length of output buffer *2 channels*/
                 NULL  );                    /* buffer */
@@ -373,9 +373,11 @@ enum mad_flow libmad_output(void *data, struct mad_header const *p_libmad_header
     }
 
     /* DEBUG */
+    /*
     if (p_libmad_pcm->channels == 1) {
        intf_ErrMsg( "mad debug: libmad_output channels [%d]", p_libmad_pcm->channels);
     }
+    */
 
     vlc_mutex_lock (&p_mad_adec->p_aout_fifo->data_lock);
     p_mad_adec->p_aout_fifo->i_end_frame = (p_mad_adec->p_aout_fifo->i_end_frame + 1) & AOUT_FIFO_SIZE;
index 9938543842e62938e10aae015c33f963983c595e..766f52ef3b50c529ae5f4a31656c969cd1031c94 100644 (file)
@@ -2,3 +2,5 @@ mpeg_es_SOURCES = mpeg_es.c
 mpeg_ps_SOURCES = mpeg_ps.c
 mpeg_ts_SOURCES = mpeg_ts.c
 mpeg_ts_dvbpsi_SOURCES = mpeg_ts.c
+mpeg_audio_SOURCES = mpeg_audio.c
+
diff --git a/plugins/mpeg_system/mpeg_audio.c b/plugins/mpeg_system/mpeg_audio.c
new file mode 100644 (file)
index 0000000..833bfda
--- /dev/null
@@ -0,0 +1,566 @@
+/*****************************************************************************
+ * mpeg_audio.c : mpeg_audio Stream input module for vlc
+ *****************************************************************************
+ * Copyright (C) 2001 VideoLAN
+ * $Id: mpeg_audio.c,v 1.1 2002/05/10 02:04:17 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 <videolan/vlc.h>
+
+#include <sys/types.h>
+
+#include "stream_control.h"
+#include "input_ext-intf.h"
+#include "input_ext-dec.h"
+#include "input_ext-plugins.h"
+
+/*****************************************************************************
+ * Local prototypes
+ *****************************************************************************/
+static void input_getfunctions( function_list_t * p_function_list );
+static int  MPEGAudioDemux         ( struct input_thread_s * );
+static int  MPEGAudioInit          ( struct input_thread_s * );
+static void MPEGAudioEnd           ( struct input_thread_s * );
+
+/* TODO: support MPEG-2.5, not difficult */
+
+/*****************************************************************************
+ * Build configuration tree.
+ *****************************************************************************/
+MODULE_CONFIG_START
+MODULE_CONFIG_STOP
+
+MODULE_INIT_START
+    SET_DESCRIPTION( "MPEG I/II Audio stream demux" )
+    ADD_CAPABILITY( DEMUX, 110 )
+    ADD_SHORTCUT( "mpeg_audio" )
+MODULE_INIT_STOP
+
+MODULE_ACTIVATE_START
+    input_getfunctions( &p_module->p_functions->demux );
+MODULE_ACTIVATE_STOP
+
+MODULE_DEACTIVATE_START
+MODULE_DEACTIVATE_STOP
+
+/*****************************************************************************
+ * Functions exported as capabilities. They are declared as static so that
+ * we don't pollute the namespace too much.
+ *****************************************************************************/
+static void input_getfunctions( function_list_t * p_function_list )
+{
+#define input p_function_list->functions.demux
+    input.pf_init             = MPEGAudioInit;
+    input.pf_end              = MPEGAudioEnd;
+    input.pf_demux            = MPEGAudioDemux;
+    input.pf_rewind           = NULL;
+#undef input
+}
+
+/*****************************************************************************
+ * Definitions of structures  and functions used by this plugins 
+ *****************************************************************************/
+
+typedef struct mpegaudio_format_s
+{
+    u32 i_header;
+    int i_version;
+    int i_layer;
+    int i_crc;
+    int i_bitrate;
+    int i_samplingfreq;
+    int i_padding;
+    int i_extension;
+    int i_mode;
+    int i_modeext;
+    int i_copyright;
+    int i_original;
+    int i_emphasis;
+
+} mpegaudio_format_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 mpegaudio_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 */
+    u8  i_toc[100];   /* for seek */
+    int i_avgbitrate; /* calculated, XXX: bits/sec not Kb */
+} mpegaudio_xing_header_t;
+
+typedef struct demux_data_mpegaudio_s
+{
+    mtime_t i_pts;
+
+    int     i_framecount;
+   
+    es_descriptor_t         *p_es;
+    mpegaudio_format_t      mpeg;
+    mpegaudio_xing_header_t xingheader;
+
+} demux_data_mpegaudio_t;
+
+
+static int mpegaudio_bitrate[2][3][16] =
+{
+    {
+        { 0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448, 0 }, /* v1 l1 */
+        { 0, 32, 48, 56,  64,  80,  96, 112, 128, 160, 192, 224, 256, 320, 384, 0 }, /* v1 l2 */
+        { 0, 32, 40, 48,  56,  64,  80,  96, 112, 128, 160, 192, 224, 256, 320, 0 }  /* v1 l3 */
+    },
+    
+    {
+        { 0, 32, 48, 56,  64,  80,  96, 112, 128, 144, 160, 176, 192, 224, 256, 0 }, /* v2 l1 */
+        { 0,  8, 16, 24,  32,  40,  48,  56,  64,  80,  96, 112, 128, 144, 160, 0 }, /* v2 l2 */
+        { 0,  8, 16, 24,  32,  40,  48,  56,  64,  80,  96, 112, 128, 144, 160, 0 }  /* v2 l3 */
+    }
+
+};
+
+static int mpegaudio_samplingfreq[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"
+};
+
+/*****************************************************************************
+ * MPEGAudio_CheckHeader : Test the validity of the header 
+ *****************************************************************************/
+static int MPEGAudio_CheckHeader( u32 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 */
+}
+
+/*****************************************************************************
+ * MPEGAudio_ParseHeader : Parse a header ;)
+ *****************************************************************************/
+static void MPEGAudio_ParseHeader( u32 i_header, mpegaudio_format_t *p_mpeg )
+{
+    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_samplingfreq = mpegaudio_samplingfreq[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;
+}
+
+/*****************************************************************************
+ * MPEGAudio_FrameSize : give the size of a frame in the mpeg stream
+ *****************************************************************************/
+static int MPEGAudio_FrameSize( mpegaudio_format_t *p_mpeg )
+{
+    /* XXX if crc do i need to add 2 bytes or not? */
+    switch( p_mpeg->i_layer )
+    {
+        case( 0 ):
+            return( ( ( ( !p_mpeg->i_version ? 12000 : 6000 ) * 
+                         p_mpeg->i_bitrate ) / 
+                         p_mpeg->i_samplingfreq + p_mpeg->i_padding ) * 4);
+        case( 1 ):
+        case( 2 ):
+            return( ( ( !p_mpeg->i_version ? 144000 : 72000 ) * 
+                         p_mpeg->i_bitrate ) /  
+                         p_mpeg->i_samplingfreq + p_mpeg->i_padding );
+    }
+    return( 1024 ); /* must never happen, 1k to advance in stream*/
+}
+
+/*****************************************************************************
+ * MPEGAudio_DecodedFrameSize : give the length of the decoded pcm data
+ *****************************************************************************/
+static int MPEGAudio_DecodedFrameSize( mpegaudio_format_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 );
+}
+
+/*****************************************************************************
+ * MPEGAudio_FindFrame : Find a header that could be valid. 
+ *****************************************************************************
+ * The idea is to search for 2 consecutive headers that seem valid 
+ * Perhaps we can search 2 header with same version or samplefreq(...) to be
+ * more secure but this seems to be enougth
+ *****************************************************************************/
+static int MPEGAudio_FindFrame( input_thread_t *p_input, 
+                                 int *pi_pos, 
+                                 mpegaudio_format_t *p_mpeg )
+{
+    byte_t *p_buff;
+    u32 i_header;
+    int i_framesize;
+
+    int i_pos = 0;
+    int i_size = input_Peek( p_input, &p_buff, 8192 );
+
+    while( i_pos + 4 <= i_size ) /* need at least 4 bytes */
+    {
+        i_header = U32_AT( p_buff );
+        if( MPEGAudio_CheckHeader( i_header ) )
+        {
+            MPEGAudio_ParseHeader( i_header, p_mpeg );
+            i_framesize = MPEGAudio_FrameSize( p_mpeg );
+            if( ( i_pos + i_framesize + 4 > i_size )
+                ||( MPEGAudio_CheckHeader( U32_AT( p_buff + i_framesize ) ) ) )
+            {
+                *pi_pos = i_pos;
+                return( 1 );
+            }
+        }
+        p_buff++;
+        i_pos++;
+    }
+
+    *pi_pos = 0;
+    return( 0 );
+}
+
+/*****************************************************************************
+ * MPEGAudio_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 MPEGAudio_ExtractXingHeader( input_thread_t *p_input,
+                                    mpegaudio_xing_header_t *p_xh )
+{
+    int i_pos;
+    int i_size;
+    mpegaudio_format_t mpeg;
+    byte_t  *p_buff;
+    
+    p_xh->i_flags = 0;  /* nothing present */
+    if( !(MPEGAudio_FindFrame( p_input, &i_pos, &mpeg )) )
+    {
+        return; /* failed , can't */
+    }
+    p_xh->i_avgbitrate = mpeg.i_bitrate * 1000; /* default */
+
+    /* 1024 is very very enougth */
+    if( ( i_size = input_Peek( p_input, &p_buff, 1024 + i_pos ) ) < 8 )
+    {
+        return;
+    }
+    p_buff += i_pos;
+
+    /* calculate pos of xing header */
+    if( !mpeg.i_version )
+    {
+        p_buff += mpeg.i_mode != 3 ? 36 : 21;
+    }
+    else
+    {
+        p_buff += mpeg.i_mode != 3 ? 21 : 13;
+    }
+    
+    if( (*p_buff != 'X' )||(*(p_buff+1) != 'i' )
+        ||(*(p_buff+2) != 'n' )||(*(p_buff+3) != 'g' ) )
+    {
+        return;
+    }
+    p_buff += 4;
+
+    p_xh->i_flags = U32_AT( p_buff ); 
+    p_buff += 4;
+
+    if( p_xh->i_flags&FRAMES_FLAG ) 
+    {
+        p_xh->i_frames = U32_AT( p_buff );
+        p_buff += 4;
+    }
+    if( p_xh->i_flags&BYTES_FLAG ) 
+    {
+        p_xh->i_bytes = U32_AT( p_buff );
+        p_buff += 4;
+    }
+    if( p_xh->i_flags&TOC_FLAG ) 
+    {
+        FAST_MEMCPY( p_xh->i_toc, p_buff, 100 );
+        p_buff += 100;
+    }
+    if( p_xh->i_flags&VBR_SCALE_FLAG ) 
+    {
+        p_xh->i_vbr_scale = U32_AT( p_buff );
+        p_buff += 4;
+    }
+    if( ( p_xh->i_flags&FRAMES_FLAG )&&( p_xh->i_flags&BYTES_FLAG ) )
+    {
+        p_xh->i_avgbitrate = 
+              ((u64)p_xh->i_bytes * (u64)8 * (u64)mpeg.i_samplingfreq) / 
+               ((u64)p_xh->i_frames * (u64)MPEGAudio_DecodedFrameSize( &mpeg));
+    }
+}
+                                    
+
+/*****************************************************************************
+ * MPEGaudioInit : initializes MPEGaudio structures
+ *****************************************************************************/
+static int MPEGAudioInit( input_thread_t * p_input )
+{
+    demux_data_mpegaudio_t *p_mpegaudio;
+    mpegaudio_format_t mpeg;
+    es_descriptor_t * p_es;
+    int i_pos;
+
+    /* XXX: i don't know what it's supposed to do, copied from ESInit */
+    /* Initialize access plug-in structures. */
+    if( p_input->i_mtu == 0 )
+    {
+    /* Improve speed. */
+        p_input->i_bufsize = INPUT_DEFAULT_BUFSIZE;
+    }
+    
+    if( !(MPEGAudio_FindFrame( p_input, &i_pos, &mpeg )) )
+    {
+        intf_ErrMsg( "input: MPEGAudio plug-in discarded (no MPEG header)" );
+        return( -1 );
+    }
+    
+    vlc_mutex_lock( &p_input->stream.stream_lock );
+    if( input_InitStream( p_input, 0 ) == -1)
+    {
+        intf_ErrMsg( "input error: cannot init stream" );
+        return( -1 );
+    }    
+    if( input_AddProgram( p_input, 0, 0) == NULL )
+    {
+        intf_ErrMsg( "input error: cannot add program" );
+        return( -1 );
+    }
+    p_input->stream.pp_programs[0]->b_is_ok = 0;
+    p_input->stream.p_selected_program = 
+            p_input->stream.p_new_program = p_input->stream.pp_programs[0];
+    
+    /* create our ES */ 
+    p_es = input_AddES( p_input, 
+                        p_input->stream.p_selected_program, 
+                        1, /* id */
+                        0 );
+    if( !p_es )
+    {
+        vlc_mutex_unlock( &p_input->stream.stream_lock );
+        intf_ErrMsg( "input error: not enough memory." );
+        return( -1 );
+    }
+    p_es->i_stream_id = 1;
+    p_es->i_type = !mpeg.i_layer ? MPEG1_AUDIO_ES : MPEG2_AUDIO_ES;
+    p_es->i_cat = AUDIO_ES;
+    p_es->b_audio = 1;
+    input_SelectES( p_input, p_es );
+
+    p_input->stream.p_selected_program->b_is_ok = 1;
+    vlc_mutex_unlock( &p_input->stream.stream_lock );
+
+    /* create p_mpegaudio and init it */
+    p_input->p_demux_data =
+           p_mpegaudio = malloc( sizeof( demux_data_mpegaudio_t ));
+
+    if( !p_mpegaudio )
+    {
+        intf_ErrMsg( "input error: not enough memory." );
+        return( -1 );
+    }
+
+    /*input_ClockInit(  p_input->stream.p_selected_program ); 
+      done by AddProgram */
+    p_mpegaudio->p_es = p_es;
+    p_mpegaudio->mpeg = mpeg;
+    p_mpegaudio->i_framecount = 0;
+    p_mpegaudio->i_pts = 0;  
+
+    /* parse Xing Header if present */
+    MPEGAudio_ExtractXingHeader( p_input, &p_mpegaudio->xingheader );
+    
+    vlc_mutex_lock( &p_input->stream.stream_lock );
+    p_input->stream.i_mux_rate = p_mpegaudio->xingheader.i_avgbitrate / 50 / 8;
+    vlc_mutex_unlock( &p_input->stream.stream_lock );
+
+    /* FIXME FIXME FIXME FIXME FIXME FIXME FIXME */
+    /* if i don't do that, it don't work correctly but why ??? */
+    if( p_input->stream.b_seekable )
+    {
+        p_input->pf_seek( p_input, 0 );
+        input_AccessReinit( p_input );
+    }
+    /* FIXME FIXME FIXME FIXME FIXME FIXME FIXME */
+
+    /* all is ok :)) */
+    intf_Msg( "input init: Audio MPEG-%d layer %d %s %dHz %dKb/s %s",
+                mpeg.i_version + 1,
+                mpeg.i_layer +1 ,
+                mpegaudio_mode[mpeg.i_mode],
+                mpeg.i_samplingfreq,
+                p_mpegaudio->xingheader.i_avgbitrate / 1000,
+                p_mpegaudio->xingheader.i_flags ?
+                        "VBR (Xing)" : "" 
+                    );
+    return( 0 );
+}
+
+
+/*****************************************************************************
+ * MPEGAudioEnd: frees unused data
+ *****************************************************************************/
+static void MPEGAudioEnd( input_thread_t * p_input )
+{
+    
+}
+
+
+/*****************************************************************************
+ * MPEGAudioDemux: reads and demuxes data packets
+ *****************************************************************************
+ * Returns -1 in case of error, 0 in case of EOF, 1 otherwise
+ *****************************************************************************/
+static int MPEGAudioDemux( input_thread_t * p_input )
+{
+    int i_pos;
+    int i_toread;
+    pes_packet_t    *p_pes;
+    mpegaudio_format_t mpeg;
+    demux_data_mpegaudio_t *p_mpegaudio = 
+                        (demux_data_mpegaudio_t*) p_input->p_demux_data;
+
+    /*  look for a frame */
+    if( !MPEGAudio_FindFrame( p_input, &i_pos, &mpeg ) )
+    {
+        intf_WarnMsg( 1, "input error: cannot found next frame");
+        return( 0 );
+    }
+    
+    /* if stream has changed */
+    if( ( mpeg.i_version != p_mpegaudio->mpeg.i_version )
+        ||( mpeg.i_layer != p_mpegaudio->mpeg.i_layer )
+        ||( mpeg.i_samplingfreq != p_mpegaudio->mpeg.i_samplingfreq ) )
+    {
+        intf_WarnMsg( 1, "input demux: stream has changed" );
+        p_mpegaudio->i_framecount = 0;
+        p_mpegaudio->i_pts = 0;
+    }
+
+    input_ClockManageRef( p_input,
+                          p_input->stream.p_selected_program,
+                          p_mpegaudio->i_pts );
+
+    /* in fact i_pos may be garbage but ... i don't want to skip it 
+        it's borring ;) */
+
+    i_toread = MPEGAudio_FrameSize( &mpeg ) + i_pos;
+    /* create one pes */
+    if( !(p_pes = input_NewPES( p_input->p_method_data )) )
+    {
+        intf_ErrMsg( "input demux: out of memory" );
+        return( -1 );
+    }
+
+    while( i_toread > 0 )
+    {
+        data_packet_t   *p_data;
+        int i_read;
+
+        if( (i_read = input_SplitBuffer( p_input, &p_data, i_toread ) ) <= 0 )
+        {
+            break;
+        }
+        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_toread -= i_read;
+    }
+    /* XXX VERY STRANGE need to *90000 and not *1000000 WHYYYY ??? 
+        I know that for mpeg system clock unit is based on 90000 but 
+        pts is not supposed to be in microsec for vlc ? 
+        At least it's welcome to write it somewhere in input_clock.c 
+        i've wasted time because of it :( */
+    p_mpegaudio->i_pts = (mtime_t)90000 * 
+                               (mtime_t)p_mpegaudio->i_framecount * 
+                               (mtime_t)MPEGAudio_DecodedFrameSize( &mpeg ) /
+                               (mtime_t)mpeg.i_samplingfreq;
+    p_pes->i_dts = 0;
+    p_pes->i_pts = input_ClockGetTS( p_input,
+                                     p_input->stream.p_selected_program,
+                                     p_mpegaudio->i_pts );
+
+    if( !p_mpegaudio->p_es->p_decoder_fifo )
+    {
+        intf_ErrMsg( "input demux: no audio decoder" );
+        input_DeletePES( p_input->p_method_data, p_pes );
+        return( -1 ); /* perhaps not, it's my choice */
+    }
+    else
+    {
+        input_DecodePES( p_mpegaudio->p_es->p_decoder_fifo, p_pes );
+    }
+
+    p_mpegaudio->i_framecount++;
+    p_mpegaudio->mpeg = mpeg; 
+
+    return( 1 );
+}
+
+
index 71ed054833247bdb292048a596f63561ee5d993f..2e9f5ebfa1018dfbaccf8bcfaa019cfcb3f55cf3 100644 (file)
@@ -2,7 +2,7 @@
  * modules_plugin.h : Plugin management functions used by the core application.
  *****************************************************************************
  * Copyright (C) 2001 VideoLAN
- * $Id: modules_plugin.h,v 1.24 2002/05/03 20:49:30 sam Exp $
+ * $Id: modules_plugin.h,v 1.25 2002/05/10 02:04:17 fenrir Exp $
  *
  * Authors: Samuel Hocevar <sam@zoy.org>
  *
@@ -253,6 +253,7 @@ module_error( char *psz_buffer )
     (p_symbols)->input_DemuxTS = input_DemuxTS; \
     (p_symbols)->input_ClockManageRef = input_ClockManageRef; \
     (p_symbols)->input_ClockManageControl = input_ClockManageControl; \
+    (p_symbols)->input_ClockGetTS = input_ClockGetTS; \
     (p_symbols)->input_FDSeek = input_FDSeek; \
     (p_symbols)->input_FDClose = input_FDClose; \
     (p_symbols)->input_FDRead = input_FDRead; \