* mpeg_audio.c : mpeg_audio Stream input module for vlc
*****************************************************************************
* Copyright (C) 2001 VideoLAN
- * $Id: mpeg_audio.c,v 1.7 2002/05/17 23:01:02 fenrir Exp $
+ * $Id: mpeg_audio.c,v 1.14 2002/07/31 20:56:52 sam Exp $
+ *
* Authors: Laurent Aimar <fenrir@via.ecp.fr>
*
* This program is free software; you can redistribute it and/or modify
#include <stdlib.h> /* malloc(), free() */
#include <string.h>
-#include <videolan/vlc.h>
+#include <vlc/vlc.h>
+#include <vlc/input.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 * );
+static int Activate ( vlc_object_t * );
+static int Demux ( input_thread_t * );
/* 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( "mpegaudio" )
-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.
+ * Module descriptor
*****************************************************************************/
-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
-}
+vlc_module_begin();
+ set_description( _("ISO 13818-3 MPEG I/II audio stream demux" ) );
+ set_capability( "demux", 100 );
+ set_callbacks( Activate, NULL );
+ add_shortcut( "mpegaudio" );
+vlc_module_end();
/*****************************************************************************
* Definitions of structures and functions used by this plugins
"stereo", "joint stereo", "dual channel", "mono"
};
-static __inline__ u32 __GetDWBE( byte_t *p_buff )
+static inline u32 __GetDWBE( byte_t *p_buff )
{
return( ( (*(p_buff)) << 24 ) + ( (*(p_buff+1)) << 16 ) +
( (*(p_buff+2)) << 8 ) + ( (*(p_buff+3)) ) );
return( 0 );
}
+static int MPEGAudio_SkipID3Tag( input_thread_t *p_input )
+{
+ int count;
+ byte_t *p_peek;
+ byte_t version, revision;
+ int b_footer;
+ int i_size;
+
+ msg_Dbg( p_input, "Checking for ID3 tag" );
+ /* get 10 byte id3 header */
+ if( ( count = input_Peek( p_input, &p_peek, 10 ) ) < 10 )
+ {
+ msg_Err( p_input, "cannot peek()" );
+ return( -1 );
+ }
+/*
+ msg_Info( p_input, "Three first bytes are: %d %d %d",
+ p_peek[0],
+ p_peek[1],
+ p_peek[2]
+ );
+*/
+ if ( !( (p_peek[0] == 0x49) && (p_peek[1] == 0x44) && (p_peek[2] == 0x33)))
+ {
+ return( 0 );
+ }
+
+ version = p_peek[3]; /* These may become usfull later, */
+ revision = p_peek[4]; /* but we ignore them for now */
+
+ b_footer = p_peek[5] & 0x10;
+ i_size = (p_peek[6] << 21) +
+ (p_peek[7] << 14) +
+ (p_peek[8] << 7) +
+ p_peek[9]; //Is this safe?
+ if ( b_footer )
+ {
+ i_size += 10;
+ }
+ i_size += 10;
+ msg_Dbg( p_input, "ID3 tag found, skiping %d bytes", i_size );
+ if ( input_Peek( p_input, &p_peek, i_size ) < i_size )
+ {
+ msg_Err( p_input, "cannot peek()" );
+ return( -1 );
+ }
+
+ p_input->p_current_data += i_size; //seek passed end of ID3 tag
+
+ return (0);
+}
+
/*****************************************************************************
* MPEGAudio_FindFrame : Find a header that could be valid.
*****************************************************************************
}
if( p_xh->i_flags&TOC_FLAG )
{
- FAST_MEMCPY( p_xh->i_toc, p_buff, 100 );
+ p_input->p_vlc->pf_memcpy( p_xh->i_toc, p_buff, 100 );
p_buff += 100;
}
if( p_xh->i_flags&VBR_SCALE_FLAG )
/*****************************************************************************
- * MPEGaudioInit : initializes MPEGaudio structures
+ * Activate: initializes MPEGaudio structures
*****************************************************************************/
-static int MPEGAudioInit( input_thread_t * p_input )
+static int Activate( vlc_object_t * p_this )
{
- demux_data_mpegaudio_t *p_mpegaudio;
+ input_thread_t * p_input = (input_thread_t *)p_this;
+ demux_data_mpegaudio_t * p_mpegaudio;
mpegaudio_format_t mpeg;
es_descriptor_t * p_es;
int i_pos;
int b_forced;
+ input_info_category_t * p_category;
+
+ /* Set the demux function */
+ p_input->pf_demux = Demux;
/* XXX: i don't know what it's supposed to do, copied from ESInit */
/* Initialize access plug-in structures. */
b_forced = 0;
}
+ if ( MPEGAudio_SkipID3Tag( p_input ) )
+ {
+ return -1;
+ }
+
/* check if it can be a ps stream */
if( __CheckPS( p_input ) && !b_forced )
{
return( -1 );
}
+
/* must be sure that is mpeg audio stream */
if( MPEGAudio_FindFrame( p_input,
&i_pos,
MPEGAUDIO_MAXTESTPOS) )
< (b_forced ? 1 : 2) )
{
- intf_WarnMsg( 2,"input: MPEGAudio plug-in discarded" );
+ msg_Warn( p_input, "MPEGAudio module discarded (no frame found)" );
return( -1 );
}
vlc_mutex_lock( &p_input->stream.stream_lock );
if( input_InitStream( p_input, 0 ) == -1)
{
- intf_ErrMsg( "input error: cannot init stream" );
+ msg_Err( p_input, "cannot init stream" );
return( -1 );
}
if( input_AddProgram( p_input, 0, 0) == NULL )
{
- intf_ErrMsg( "input error: cannot add program" );
+ msg_Err( p_input, "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];
+ p_input->stream.p_selected_program = p_input->stream.pp_programs[0];
/* create our ES */
p_es = input_AddES( p_input,
if( !p_es )
{
vlc_mutex_unlock( &p_input->stream.stream_lock );
- intf_ErrMsg( "input error: not enough memory." );
+ msg_Err( p_input, "out of 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_fourcc = !mpeg.i_layer ? VLC_FOURCC('m','p','g','a') /* layer 1 */
+ : VLC_FOURCC('m','p','g','a'); /* layer 2 */
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;
if( !p_mpegaudio )
{
- intf_ErrMsg( "input error: not enough memory." );
+ msg_Err( p_input, "out of memory" );
return( -1 );
}
/* FIXME FIXME FIXME FIXME FIXME FIXME FIXME */
/* all is ok :)) */
- intf_Msg( "input init: Audio MPEG-%d layer %d %s %dHz %dKb/s %s",
+ msg_Dbg( p_input, "audio MPEG-%d layer %d %s %dHz %dKb/s %s",
mpeg.i_version + 1,
- mpeg.i_layer +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 )
-{
+ vlc_mutex_lock( &p_input->stream.stream_lock );
+ p_category = input_InfoCategory( p_input, "mpeg" );
+ input_AddInfo( p_category, "input type", "audio MPEG-%d",
+ mpeg.i_version +1 );
+ input_AddInfo( p_category, "layer", "%d", mpeg.i_layer + 1 );
+ input_AddInfo( p_category, "mode", mpegaudio_mode[mpeg.i_mode] );
+ input_AddInfo( p_category, "sample rate", "%dHz", mpeg.i_samplingfreq );
+ input_AddInfo( p_category, "average bitrate", "%dKb/s",
+ p_mpegaudio->xingheader.i_avgbitrate / 1000 );
+ vlc_mutex_unlock( &p_input->stream.stream_lock );
+ return( 0 );
}
-
/*****************************************************************************
- * MPEGAudioDemux: reads and demuxes data packets
+ * Demux: 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 )
+static int Demux( input_thread_t * p_input )
{
int i_pos;
int i_toread;
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, 4096 ) )
{
- intf_WarnMsg( 1, "input error: cannot find next frame");
+ msg_Warn( p_input, "cannot find next frame" );
return( 0 );
}
||( mpeg.i_layer != p_mpegaudio->mpeg.i_layer )
||( mpeg.i_samplingfreq != p_mpegaudio->mpeg.i_samplingfreq ) )
{
- intf_WarnMsg( 1, "input demux: stream has changed" );
+ msg_Dbg( p_input, "stream has changed" );
p_mpegaudio->i_framecount = 0;
p_mpegaudio->i_pts = 0;
}
/* create one pes */
if( !(p_pes = input_NewPES( p_input->p_method_data )) )
{
- intf_ErrMsg( "input demux: out of memory" );
+ msg_Err( p_input, "cannot allocate new PES" );
return( -1 );
}
if( !p_mpegaudio->p_es->p_decoder_fifo )
{
- intf_ErrMsg( "input demux: no audio decoder" );
+ msg_Err( p_input, "no audio decoder" );
input_DeletePES( p_input->p_method_data, p_pes );
return( -1 ); /* perhaps not, it's my choice */
}