From: Laurent Aimar Date: Mon, 14 Oct 2002 21:59:44 +0000 (+0000) Subject: * araw.c : pseudo pcm decoder X-Git-Tag: 0.5.0~865 X-Git-Url: https://git.sesse.net/?a=commitdiff_plain;h=9a5df48be189e468804f2d3b2da4b9248dea6a36;p=vlc * araw.c : pseudo pcm decoder * wav : demux for wav file( should work with raw pcm, mp3 or a52 stream ) but untested under big endian machine(for pcm). All are compiled by default. --- diff --git a/configure.ac.in b/configure.ac.in index 2103a71e2e..4b18581afa 100644 --- a/configure.ac.in +++ b/configure.ac.in @@ -544,6 +544,7 @@ PLUGINS="${PLUGINS} aout_file" #PLUGINS="${PLUGINS} scope" PLUGINS="${PLUGINS} i420_rgb i420_yuy2 i422_yuy2 i420_ymga" PLUGINS="${PLUGINS} id3" +PLUGINS="${PLUGINS} wav araw" dnl dnl Network modules diff --git a/modules/Makefile.am b/modules/Makefile.am index 26a8d9864e..66b82ecbae 100644 --- a/modules/Makefile.am +++ b/modules/Makefile.am @@ -35,6 +35,7 @@ EXTRA_DIST = \ demux/mp4/Modules.am \ demux/mpeg/Modules.am \ demux/util/Modules.am \ + demux/wav/Modules.am \ gui/beos/Modules.am \ gui/familiar/Modules.am \ gui/gtk/Modules.am \ diff --git a/modules/codec/Modules.am b/modules/codec/Modules.am index ff9af06cb9..011cd67635 100644 --- a/modules/codec/Modules.am +++ b/modules/codec/Modules.am @@ -1,2 +1,3 @@ SOURCES_a52 = modules/codec/a52.c SOURCES_lpcm = modules/codec/lpcm.c +SOURCES_araw = modules/codec/araw.c diff --git a/modules/codec/araw.c b/modules/codec/araw.c new file mode 100644 index 0000000000..912d1e0305 --- /dev/null +++ b/modules/codec/araw.c @@ -0,0 +1,377 @@ +/***************************************************************************** + * araw.c: Pseudo audio decoder; for raw pcm data + ***************************************************************************** + * Copyright (C) 2001, 2002 VideoLAN + * $Id: araw.c,v 1.1 2002/10/14 21:59:44 fenrir Exp $ + * + * Authors: Laurent Aimar + * + * 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 +#include +#include +#include + +#include /* malloc(), free() */ +#include /* strdup() */ + +/***************************************************************************** + * Local prototypes + *****************************************************************************/ +typedef struct waveformatex_s +{ + u16 i_formattag; + u16 i_channels; + u32 i_samplespersec; + u32 i_avgbytespersec; + u16 i_blockalign; + u16 i_bitspersample; + u16 i_size; /* the extra size in bytes */ + u8 *p_data; /* The extra data */ +} waveformatex_t; + +typedef struct adec_thread_s +{ + waveformatex_t format; + + /* The bit stream structure handles the PES stream at the bit level */ + bit_stream_t bit_stream; + + /* Input properties */ + decoder_fifo_t *p_fifo; + + /* Output properties */ + aout_instance_t * p_aout; /* opaque */ + aout_input_t * p_aout_input; /* opaque */ + audio_sample_format_t output_format; + + audio_date_t date; + mtime_t pts; + +} adec_thread_t; + +static int OpenDecoder ( vlc_object_t * ); + +static int RunDecoder ( decoder_fifo_t * ); +static int InitThread ( adec_thread_t * ); +static void DecodeThread ( adec_thread_t * ); +static void EndThread ( adec_thread_t * ); + +/***************************************************************************** + * Module descriptor + *****************************************************************************/ + +vlc_module_begin(); + set_description( _("Pseudo Raw Audio decoder") ); + set_capability( "decoder", 50 ); + set_callbacks( OpenDecoder, NULL ); +vlc_module_end(); + +/***************************************************************************** + * OpenDecoder: probe the decoder and return score + ***************************************************************************** + * Tries to launch a decoder and return score so that the interface is able + * to choose. + *****************************************************************************/ +static int OpenDecoder( vlc_object_t *p_this ) +{ + decoder_fifo_t *p_fifo = (decoder_fifo_t*) p_this; + + switch( p_fifo->i_fourcc ) + { + case VLC_FOURCC('a','r','a','w'): + case VLC_FOURCC('t','w','o','s'): /* for mov file */ + p_fifo->pf_run = RunDecoder; + return VLC_SUCCESS; + + default: + return VLC_EGENERIC; + } + +} + +/***************************************************************************** + * RunDecoder: this function is called just after the thread is created + *****************************************************************************/ +static int RunDecoder( decoder_fifo_t *p_fifo ) +{ + adec_thread_t *p_adec; + int b_error; + + if( !( p_adec = malloc( sizeof( adec_thread_t ) ) ) ) + { + msg_Err( p_fifo, "out of memory" ); + DecoderError( p_fifo ); + return( -1 ); + } + memset( p_adec, 0, sizeof( adec_thread_t ) ); + + p_adec->p_fifo = p_fifo; + + if( InitThread( p_adec ) != 0 ) + { + DecoderError( p_fifo ); + return( -1 ); + } + + while( ( !p_adec->p_fifo->b_die )&&( !p_adec->p_fifo->b_error ) ) + { + DecodeThread( p_adec ); + } + + + if( ( b_error = p_adec->p_fifo->b_error ) ) + { + DecoderError( p_adec->p_fifo ); + } + + EndThread( p_adec ); + if( b_error ) + { + return( -1 ); + } + + return( 0 ); +} + + +#define FREE( p ) if( p ) free( p ); p = NULL +#define GetWLE( p ) \ + ( *(u8*)(p) + ( *((u8*)(p)+1) << 8 ) ) + +#define GetDWLE( p ) \ + ( *(u8*)(p) + ( *((u8*)(p)+1) << 8 ) + \ + ( *((u8*)(p)+2) << 16 ) + ( *((u8*)(p)+3) << 24 ) ) + +static void GetWaveFormatEx( waveformatex_t *p_wh, + u8 *p_data ) +{ + + p_wh->i_formattag = GetWLE( p_data ); + p_wh->i_channels = GetWLE( p_data + 2 ); + p_wh->i_samplespersec = GetDWLE( p_data + 4 ); + p_wh->i_avgbytespersec= GetDWLE( p_data + 8 ); + p_wh->i_blockalign = GetWLE( p_data + 12 ); + p_wh->i_bitspersample = GetWLE( p_data + 14 ); + if( p_wh->i_formattag != 1 ) + { + p_wh->i_size = GetWLE( p_data + 16 ); + + if( p_wh->i_size ) + { + p_wh->p_data = malloc( p_wh->i_size ); + memcpy( p_wh->p_data, p_data + 18, p_wh->i_size ); + } + } +} + +/* get the first pes from fifo */ +static pes_packet_t *PESGetFirst( decoder_fifo_t *p_fifo ) +{ + pes_packet_t *p_pes; + + vlc_mutex_lock( &p_fifo->data_lock ); + + /* if fifo is empty wait */ + while( !p_fifo->p_first ) + { + if( p_fifo->b_die ) + { + vlc_mutex_unlock( &p_fifo->data_lock ); + return NULL; + } + vlc_cond_wait( &p_fifo->data_wait, &p_fifo->data_lock ); + } + p_pes = p_fifo->p_first; + + vlc_mutex_unlock( &p_fifo->data_lock ); + + return p_pes; +} +static int PESGetSize( pes_packet_t *p_pes ) +{ + data_packet_t *p_data; + int i_size = 0; + + if( !p_pes ) + { + return( 0 ); + } + + for( p_data = p_pes->p_first; p_data != NULL; p_data = p_data->p_next ) + { + i_size += p_data->p_payload_end - p_data->p_payload_start; + } + + return( i_size ); +} + +/***************************************************************************** + * InitThread: initialize data before entering main loop + *****************************************************************************/ +static int InitThread( adec_thread_t * p_adec ) +{ + + if( p_adec->p_fifo->p_demux_data ) + { + GetWaveFormatEx( &p_adec->format, + (u8*)p_adec->p_fifo->p_demux_data ); + /* fixing some values */ + if( p_adec->format.i_formattag == 1 && !p_adec->format.i_blockalign ) + { + p_adec->format.i_blockalign = p_adec->format.i_channels * + ( ( p_adec->format.i_bitspersample + 7 ) / 8 ); + } + } + else + { + msg_Err( p_adec->p_fifo, "unknown raw format" ); + return( -1 ); + } + + msg_Dbg( p_adec->p_fifo, + "raw format: samplerate:%dHz channels:%d bits/sample:%d blockalign:%d", + p_adec->format.i_samplespersec, + p_adec->format.i_channels, + p_adec->format.i_bitspersample, p_adec->format.i_blockalign ); + + /* Initialize the thread properties */ + switch( ( p_adec->format.i_bitspersample + 7 ) / 8 ) + { + case( 2 ): + p_adec->output_format.i_format = VLC_FOURCC('s','1','6','l'); + break; + case( 3 ): + p_adec->output_format.i_format = VLC_FOURCC('s','2','4','l'); + break; + case( 4 ): + p_adec->output_format.i_format = VLC_FOURCC('s','3','2','l'); + break; + + case( 1 ): + default: + msg_Err( p_adec->p_fifo, "bad parameters(bits/sample)" ); + return( -1 ); + } + p_adec->output_format.i_rate = p_adec->format.i_samplespersec; + p_adec->output_format.i_channels = p_adec->format.i_channels; + p_adec->p_aout = NULL; + p_adec->p_aout_input = NULL; + + /* **** Create a new audio output **** */ + aout_DateInit( &p_adec->date, p_adec->output_format.i_rate ); + p_adec->p_aout_input = aout_DecNew( p_adec->p_fifo, + &p_adec->p_aout, + &p_adec->output_format ); + if( !p_adec->p_aout_input ) + { + msg_Err( p_adec->p_fifo, "cannot create aout" ); + return( -1 ); + } + + /* Init the BitStream */ + InitBitstream( &p_adec->bit_stream, p_adec->p_fifo, + NULL, NULL ); + + return( 0 ); +} + +/***************************************************************************** + * DecodeThread: decodes a frame + *****************************************************************************/ +static void DecodeThread( adec_thread_t *p_adec ) +{ + aout_buffer_t *p_aout_buffer; + int i_samples; // per channels + int i_size; + pes_packet_t *p_pes; + + /* **** get samples count **** */ + p_pes = PESGetFirst( p_adec->p_fifo ); + + i_size = PESGetSize( p_pes ); + if( p_adec->format.i_blockalign > 0 ) + { + i_size -= i_size % p_adec->format.i_blockalign; + } + i_size = __MAX( i_size, p_adec->format.i_blockalign ); + + if( !i_size || !p_pes ) + { + msg_Err( p_adec->p_fifo, "infinite loop..." ); + return; + } + i_samples = i_size / + ( ( p_adec->format.i_bitspersample + 7 ) / 8 ) / + p_adec->format.i_channels; + +// msg_Warn( p_adec->p_fifo, "got %d samples (%d bytes)", i_samples, i_size ); + p_adec->pts = p_pes->i_pts; + + /* **** Now we can output these samples **** */ + + if( p_adec->pts != 0 && p_adec->pts != aout_DateGet( &p_adec->date ) ) + { + aout_DateSet( &p_adec->date, p_adec->pts ); + } + else if( !aout_DateGet( &p_adec->date ) ) + { + return; + } + + p_aout_buffer = aout_DecNewBuffer( p_adec->p_aout, + p_adec->p_aout_input, + i_samples ); + if( !p_aout_buffer ) + { + msg_Err( p_adec->p_fifo, "cannot get aout buffer" ); + p_adec->p_fifo->b_error = 1; + return; + } + + p_aout_buffer->start_date = aout_DateGet( &p_adec->date ); + p_aout_buffer->end_date = aout_DateIncrement( &p_adec->date, + i_samples ); + GetChunk( &p_adec->bit_stream, + p_aout_buffer->p_buffer, + p_aout_buffer->i_nb_bytes ); + + aout_DecPlay( p_adec->p_aout, p_adec->p_aout_input, p_aout_buffer ); +} + + +/***************************************************************************** + * EndThread : faad decoder thread destruction + *****************************************************************************/ +static void EndThread (adec_thread_t *p_adec) +{ + if( p_adec->p_aout_input ) + { + aout_DecDelete( p_adec->p_aout, p_adec->p_aout_input ); + } + + FREE( p_adec->format.p_data ); + + msg_Dbg( p_adec->p_fifo, "raw audio decoder closed" ); + + free( p_adec ); +} + + diff --git a/modules/codec/ffmpeg/ffmpeg.c b/modules/codec/ffmpeg/ffmpeg.c index 94c6d197cf..87405157ad 100644 --- a/modules/codec/ffmpeg/ffmpeg.c +++ b/modules/codec/ffmpeg/ffmpeg.c @@ -2,7 +2,7 @@ * ffmpeg.c: video decoder using ffmpeg library ***************************************************************************** * Copyright (C) 1999-2001 VideoLAN - * $Id: ffmpeg.c,v 1.6 2002/08/26 09:12:46 sam Exp $ + * $Id: ffmpeg.c,v 1.7 2002/10/14 21:59:44 fenrir Exp $ * * Authors: Laurent Aimar * @@ -666,8 +666,12 @@ static int InitThread( videodec_thread_t *p_vdec ) } /* ***** Fill p_context with init values ***** */ - p_vdec->p_context = &p_vdec->context; +#if LIBAVCODEC_BUILD >= 4624 + p_vdec->p_context = avcodec_alloc_context(); +#else + p_vdec->p_context = malloc( sizeof( AVCodecContext ) ); memset( p_vdec->p_context, 0, sizeof( AVCodecContext ) ); +#endif p_vdec->p_context->width = p_vdec->format.i_width; p_vdec->p_context->height = p_vdec->format.i_height; @@ -966,6 +970,7 @@ static void EndThread( videodec_thread_t *p_vdec ) avcodec_close( p_vdec->p_context ); msg_Dbg( p_vdec->p_fifo, "ffmpeg codec (%s) stopped", p_vdec->psz_namecodec ); + free( p_vdec->p_context ); } if( p_vdec->p_vout != NULL ) diff --git a/modules/codec/ffmpeg/ffmpeg.h b/modules/codec/ffmpeg/ffmpeg.h index beefe4c565..0ac0070c61 100644 --- a/modules/codec/ffmpeg/ffmpeg.h +++ b/modules/codec/ffmpeg/ffmpeg.h @@ -2,7 +2,7 @@ * ffmpeg_vdec.h: video decoder using ffmpeg library ***************************************************************************** * Copyright (C) 2001 VideoLAN - * $Id: ffmpeg.h,v 1.3 2002/08/10 20:05:21 fenrir Exp $ + * $Id: ffmpeg.h,v 1.4 2002/10/14 21:59:44 fenrir Exp $ * * Authors: Laurent Aimar * @@ -59,7 +59,7 @@ typedef struct videodec_thread_s bitmapinfoheader_t format; - AVCodecContext context, *p_context; + AVCodecContext *p_context; AVCodec *p_codec; vout_thread_t *p_vout; diff --git a/modules/demux/wav/.cvsignore b/modules/demux/wav/.cvsignore new file mode 100644 index 0000000000..ec96903b9d --- /dev/null +++ b/modules/demux/wav/.cvsignore @@ -0,0 +1,2 @@ +.deps +.dirstamp diff --git a/modules/demux/wav/Modules.am b/modules/demux/wav/Modules.am new file mode 100644 index 0000000000..0369488972 --- /dev/null +++ b/modules/demux/wav/Modules.am @@ -0,0 +1,5 @@ +SOURCES_wav = \ + modules/demux/wav/wav.c + +noinst_HEADERS += \ + modules/demux/wav/wav.h diff --git a/modules/demux/wav/wav.c b/modules/demux/wav/wav.c new file mode 100644 index 0000000000..356b13351f --- /dev/null +++ b/modules/demux/wav/wav.c @@ -0,0 +1,621 @@ +/***************************************************************************** + * wav.c : wav file input module for vlc + ***************************************************************************** + * Copyright (C) 2001 VideoLAN + * $Id: wav.c,v 1.1 2002/10/14 21:59:44 fenrir Exp $ + * Authors: Laurent Aimar + * + * 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 /* malloc(), free() */ +#include /* strdup() */ +#include +#include + +#include +#include + +#include "wav.h" + +/***************************************************************************** + * Local prototypes + *****************************************************************************/ +static int WAVInit ( vlc_object_t * ); +static void __WAVEnd ( vlc_object_t * ); +static int WAVDemux ( input_thread_t * ); +static int WAVCallDemux ( input_thread_t * ); + +#define WAVEnd(a) __WAVEnd(VLC_OBJECT(a)) + +/***************************************************************************** + * Module descriptor + *****************************************************************************/ +vlc_module_begin(); + set_description( "WAV demuxer" ); + set_capability( "demux", 142 ); + set_callbacks( WAVInit, __WAVEnd ); +vlc_module_end(); + +/***************************************************************************** + * Declaration of local function + *****************************************************************************/ + +#define FREE( p ) if( p ) free( p ); (p) = NULL + +#define __EVEN( x ) ( (x)%2 != 0 ) ? ((x)+1) : (x) + +/* Some functions to manipulate memory */ +static u16 GetWLE( u8 *p_buff ) +{ + return( (p_buff[0]) + ( p_buff[1] <<8 ) ); +} + +static u32 GetDWLE( u8 *p_buff ) +{ + return( p_buff[0] + ( p_buff[1] <<8 ) + + ( p_buff[2] <<16 ) + ( p_buff[3] <<24 ) ); +} + +static u32 CreateDWLE( int a, int b, int c, int d ) +{ + return( a + ( b << 8 ) + ( c << 16 ) + ( d << 24 ) ); +} + + +static off_t TellAbsolute( input_thread_t *p_input ) +{ + off_t i_pos; + + vlc_mutex_lock( &p_input->stream.stream_lock ); + + i_pos= p_input->stream.p_selected_area->i_tell - + ( p_input->p_last_data - p_input->p_current_data ); + + vlc_mutex_unlock( &p_input->stream.stream_lock ); + + return( i_pos ); +} + +static int SeekAbsolute( input_thread_t *p_input, + off_t i_pos) +{ + off_t i_filepos; + + if( i_pos >= p_input->stream.p_selected_area->i_size ) + { + return( 0 ); + } + + i_filepos = TellAbsolute( p_input ); + if( i_pos != i_filepos ) + { + p_input->pf_seek( p_input, i_pos ); + input_AccessReinit( p_input ); + } + return( 1 ); +} + +static int SkipBytes( input_thread_t *p_input, int i_skip ) +{ + return( SeekAbsolute( p_input, TellAbsolute( p_input ) + i_skip ) ); +} + +/* return 1 if success, 0 if fail */ +static int ReadData( input_thread_t *p_input, u8 *p_buff, int i_size ) +{ + data_packet_t *p_data; + + int i_read; + + + if( !i_size ) + { + return( 1 ); + } + + do + { + i_read = input_SplitBuffer(p_input, &p_data, __MIN( i_size, 1024 ) ); + if( i_read <= 0 ) + { + return( 0 ); + } + memcpy( p_buff, p_data->p_payload_start, i_read ); + input_DeletePacket( p_input->p_method_data, p_data ); + + p_buff += i_read; + i_size -= i_read; + + } while( i_size ); + + 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 ); +} + +static int FindTag( input_thread_t *p_input, u32 i_tag ) +{ + u32 i_id; + u32 i_size; + u8 *p_peek; + + for( ;; ) + { + + if( input_Peek( p_input, &p_peek, 8 ) < 8 ) + { + msg_Err( p_input, "cannot peek()" ); + return( 0 ); + } + + i_id = GetDWLE( p_peek ); + i_size = GetDWLE( p_peek + 4 ); + + msg_Dbg( p_input, "FindTag: tag:%4.4s size:%d", &i_id, i_size ); + if( i_id == i_tag ) + { + /* Yes, we have found the good tag */ + return( 1 ); + } + if( !SkipBytes( p_input, __EVEN( i_size ) + 8 ) ) + { + return( 0 ); + } + } +} + +static int LoadTag_fmt( input_thread_t *p_input, + demux_sys_t *p_demux ) +{ + u8 *p_peek; + u32 i_size; + + if( input_Peek( p_input, &p_peek , 8 ) < 8 ) + { + return( 0 ); + } + + p_demux->i_wf = i_size = GetDWLE( p_peek + 4 ); + SkipBytes( p_input, 8 ); + if( i_size < 16 ) + { + SkipBytes( p_input, i_size ); + return( 0 ); + } + p_demux->p_wf = malloc( i_size ); + ReadData( p_input, p_demux->p_wf, __EVEN( i_size ) ); + p_demux->format.i_format = GetWLE( p_demux->p_wf ); + p_demux->format.i_channels = GetWLE( p_demux->p_wf + 2 ); + p_demux->format.i_samplepersec = GetDWLE( p_demux->p_wf + 4 ); + p_demux->format.i_avgbytespersec = GetDWLE( p_demux->p_wf + 8); + p_demux->format.i_blockalign = GetWLE( p_demux->p_wf + 12 ); + p_demux->format.i_bitspersample = GetWLE( p_demux->p_wf + 14); + if( i_size > 18 ) + { + p_demux->format.i_size = GetWLE( p_demux->p_wf + 16 ); + p_demux->format.p_data = malloc( p_demux->format.i_size ); + memcpy( p_demux->format.p_data, + p_demux->p_wf + 18, + p_demux->format.i_size ); + } + else + { + p_demux->format.i_size = 0; + p_demux->format.p_data = NULL; + } + + msg_Dbg( p_input, "loaded \"fmt \" chunk" ); + return( 1 ); +} + +static int PCM_GetFrame( input_thread_t *p_input, + waveformatex_t *p_wf, + pes_packet_t **pp_pes, + mtime_t *pi_length ) +{ + int i_samples; + + int i_bytes; + int i_modulo; + + /* read samples for 50ms of */ + i_samples = __MAX( p_wf->i_samplepersec / 20, 1 ); + + + *pi_length = (mtime_t)1000000 * + (mtime_t)i_samples / + (mtime_t)p_wf->i_samplepersec; + + i_bytes = i_samples * p_wf->i_channels * ( p_wf->i_bitspersample + 7 ) / 8; + + if( p_wf->i_blockalign > 0 ) + { + if( ( i_modulo = i_bytes % p_wf->i_blockalign ) != 0 ) + { + i_bytes += p_wf->i_blockalign - i_modulo; + } + } + + return( ReadPES( p_input, pp_pes, i_bytes ) ); +} + +/***************************************************************************** + * WAVInit: check file and initializes structures + *****************************************************************************/ +static int WAVInit( vlc_object_t * p_this ) +{ + input_thread_t *p_input = (input_thread_t *)p_this; + u8 *p_peek; + u32 i_size; + + demux_sys_t *p_demux; + + + + /* Initialize access plug-in structures. */ + if( p_input->i_mtu == 0 ) + { + /* Improve speed. */ + p_input->i_bufsize = INPUT_DEFAULT_BUFSIZE ; + } + + /* a little test to see if it's a wav file */ + if( input_Peek( p_input, &p_peek, 12 ) < 12 ) + { + msg_Warn( p_input, "WAV plugin discarded (cannot peek)" ); + return( -1 ); + } + + if( ( GetDWLE( p_peek ) != CreateDWLE( 'R', 'I', 'F', 'F' ) )|| + ( GetDWLE( p_peek + 8 ) != CreateDWLE( 'W', 'A', 'V', 'E' ) ) ) + { + msg_Warn( p_input, "WAV plugin discarded (not a valid file)" ); + return( -1 ); + } + i_size = GetDWLE( p_peek + 4 ); + SkipBytes( p_input, 12 ); + + if( !FindTag( p_input, CreateDWLE( 'f', 'm', 't' ,' ' ) ) ) + { + msg_Err( p_input, "cannot find \"fmt \" tag" ); + return( -1 ); + } + + /* create our structure that will contains all data */ + if( !( p_input->p_demux_data = + p_demux = malloc( sizeof( demux_sys_t ) ) ) ) + { + msg_Err( p_input, "out of memory" ); + return( -1 ); + } + memset( p_demux, 0, sizeof( demux_sys_t ) ); + + /* Load waveformatex_t header */ + if( !LoadTag_fmt( p_input, p_demux ) ) + { + msg_Err( p_input, "cannot load \"fmt \" tag" ); + FREE( p_demux ); + return( -1 ); + } + msg_Dbg( p_input, "format:0x%4.4x channels:%d %dHz %dKo/s blockalign:%d bits/samples:%d extra size:%d", + p_demux->format.i_format, + p_demux->format.i_channels, + p_demux->format.i_samplepersec, + p_demux->format.i_avgbytespersec/1024, + p_demux->format.i_blockalign, + p_demux->format.i_bitspersample, + p_demux->format.i_size ); + + if( !FindTag( p_input, CreateDWLE( 'd', 'a', 't', 'a' ) ) ) + { + msg_Err( p_input, "cannot find \"data\" tag" ); + FREE( p_demux->p_wf ); + FREE( p_demux->format.p_data ); + FREE( p_demux ); + return( -1 ); + } + if( input_Peek( p_input, &p_peek, 8 ) < 8 ) + { + msg_Warn( p_input, "WAV plugin discarded (cannot peek)" ); + FREE( p_demux->p_wf ); + FREE( p_demux->format.p_data ); + FREE( p_demux ); + return( -1 ); + } + + p_demux->i_data_pos = TellAbsolute( p_input ) + 8; + p_demux->i_data_size = GetDWLE( p_peek + 4 ); + SkipBytes( p_input, 8 ); + + /* XXX p_demux->psz_demux shouldn't be NULL ! */ + switch( p_demux->format.i_format ) + { + case( 0x01 ): + msg_Dbg( p_input,"found raw pcm audio format" ); + p_demux->i_fourcc = VLC_FOURCC( 'a', 'r', 'a', 'w' ); + p_demux->GetFrame = PCM_GetFrame; + p_demux->psz_demux = strdup( "" ); + break; + case( 0x50 ): + case( 0x55 ): + msg_Dbg( p_input, "found mpeg audio format" ); + p_demux->i_fourcc = VLC_FOURCC( 'm', 'p', 'g', 'a' ); + p_demux->GetFrame = NULL; + p_demux->psz_demux = strdup( "mpegaudio" ); + break; + case( 0x2000 ): + msg_Dbg( p_input,"found a52 audio format" ); + p_demux->i_fourcc = VLC_FOURCC( 'a', '5', '2', ' ' ); + p_demux->GetFrame = NULL; + p_demux->psz_demux = strdup( "a52" ); + break; + default: + msg_Warn( p_input,"unrecognize audio format(0x%x)", + p_demux->format.i_format ); + p_demux->i_fourcc = + VLC_FOURCC( 'm', 's', + (p_demux->format.i_format >> 8)&0xff, + (p_demux->format.i_format )&0xff); + p_demux->GetFrame = NULL; + p_demux->psz_demux = strdup( "" ); + break; + } + + if( p_demux->GetFrame ) + { + msg_Dbg( p_input, "using internal demux" ); + + p_input->pf_demux = WAVDemux; + p_input->p_demux_data = p_demux; + + /* create one program */ + 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" ); + // FIXME + return( -1 ); + } + if( input_AddProgram( p_input, 0, 0) == NULL ) + { + vlc_mutex_unlock( &p_input->stream.stream_lock ); + msg_Err( p_input, "cannot add program" ); + // FIXME + return( -1 ); + } + p_input->stream.p_selected_program = p_input->stream.pp_programs[0]; + p_input->stream.i_mux_rate = 0 ; /* FIXME */ + + p_demux->p_es = input_AddES( p_input, + p_input->stream.p_selected_program, 1, + p_demux->i_wf ); + p_demux->p_es->i_stream_id = 1; + p_demux->p_es->i_fourcc = p_demux->i_fourcc; + p_demux->p_es->i_cat = AUDIO_ES; + if( p_demux->i_wf > 0 && p_demux->p_wf ) + { + memcpy( p_demux->p_es->p_demux_data, + p_demux->p_wf, + p_demux->i_wf ); + } + + 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 ); + } + else + { + char *psz_sav; + /* call an external demux */ + msg_Warn( p_input, "unsupported formattag, using external demux" ); + + psz_sav = p_input->psz_demux; + p_input->psz_demux = p_demux->psz_demux; + + p_demux->p_demux = module_Need( p_input, "demux", NULL ); + + p_input->psz_demux = psz_sav; + + if( !p_demux->p_demux ) + { + msg_Err( p_input, + "cannot get external demux for formattag 0x%x", + p_demux->format.i_format ); + FREE( p_demux->psz_demux ); + FREE( p_demux->p_wf ); + FREE( p_demux->format.p_data ); + FREE( p_demux ); + return( -1 ); + } + /* save value and switch back */ + p_demux->pf_demux = p_input->pf_demux; + p_demux->p_demux_data = p_input->p_demux_data; + + p_input->pf_demux = WAVCallDemux; + p_input->p_demux_data = p_demux; + + } + + + return( 0 ); +} + +/***************************************************************************** + * WAVCallDemux: call true demux + ***************************************************************************** + * Returns -1 in case of error, 0 in case of EOF, 1 otherwise + *****************************************************************************/ +static int WAVCallDemux( input_thread_t *p_input ) +{ + demux_sys_t *p_demux = p_input->p_demux_data; + int i_status; + char *psz_sav; + + /* save context */ + psz_sav = p_input->psz_demux; + + /* switch context */ + p_input->pf_demux = p_demux->pf_demux; + p_input->p_demux_data = p_demux->p_demux_data; + p_input->psz_demux = p_demux->psz_demux; + + /* call demux */ + i_status = p_input->pf_demux( p_input ); + + /* save (new?) state */ + p_demux->pf_demux = p_input->pf_demux; + p_demux->p_demux_data = p_input->p_demux_data; + + /* switch back */ + p_input->psz_demux = psz_sav; + p_input->pf_demux = WAVCallDemux; + p_input->p_demux_data = p_demux; + + return( i_status ); +} + +/***************************************************************************** + * WAVDemux: read packet and send them to decoders + ***************************************************************************** + * Returns -1 in case of error, 0 in case of EOF, 1 otherwise + *****************************************************************************/ +static int WAVDemux( input_thread_t *p_input ) +{ + demux_sys_t *p_demux = p_input->p_demux_data; + pes_packet_t *p_pes; + mtime_t i_length; + + if( p_input->stream.p_selected_program->i_synchro_state == SYNCHRO_REINIT ) + { + off_t i_offset; + + i_offset = TellAbsolute( p_input ) - p_demux->i_data_pos; + if( i_offset < 0 ) + { + SeekAbsolute( p_input, p_demux->i_data_pos ); + } + else + if( p_demux->format.i_blockalign != 0 ) + { + + i_offset = i_offset - i_offset % p_demux->format.i_blockalign; + SeekAbsolute( p_input, p_demux->i_data_pos + i_offset ); + } + } + + input_ClockManageRef( p_input, + p_input->stream.p_selected_program, + p_demux->i_pcr ); + + if( TellAbsolute( p_input ) >= p_demux->i_data_pos + p_demux->i_data_size ) + { + return( 0 ); // EOF + } + + if( !p_demux->GetFrame( p_input, &p_demux->format, &p_pes, &i_length ) ) + { + msg_Warn( p_input, "failed to get one frame" ); + return( 0 ); + } + + p_pes->i_dts = + p_pes->i_pts = input_ClockGetTS( p_input, + p_input->stream.p_selected_program, + p_demux->i_pcr ); + + 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 ); + } + else + { + input_DecodePES( p_demux->p_es->p_decoder_fifo, p_pes ); + } + + p_demux->i_pcr += i_length * 9 / 100; + return( 1 ); +} + +/***************************************************************************** + * WAVEnd: frees unused data + *****************************************************************************/ +static void __WAVEnd ( vlc_object_t * p_this ) +{ + input_thread_t * p_input = (input_thread_t *)p_this; + demux_sys_t *p_demux = p_input->p_demux_data; + + FREE( p_demux->p_wf ); + FREE( p_demux->format.p_data ); + FREE( p_demux->psz_demux ); + + if( p_demux->p_demux ) + { + module_Unneed( p_input, p_demux->p_demux ); + } + +} + diff --git a/modules/demux/wav/wav.h b/modules/demux/wav/wav.h new file mode 100644 index 0000000000..fcd5e7cacc --- /dev/null +++ b/modules/demux/wav/wav.h @@ -0,0 +1,82 @@ +/***************************************************************************** + * wav.h : wav file input module for vlc + ***************************************************************************** + * Copyright (C) 2001 VideoLAN + * $Id: wav.h,v 1.1 2002/10/14 21:59:44 fenrir Exp $ + * Authors: Laurent Aimar + * + * 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. + *****************************************************************************/ + + + +/***************************************************************************** + * Structure needed for decoder + *****************************************************************************/ +typedef struct waveformatex_s +{ + u16 i_format; + u16 i_channels; + u32 i_samplepersec; + u32 i_avgbytespersec; + u16 i_blockalign; + u16 i_bitspersample; + u16 i_size; /* This give size of data + imediatly following this header. */ + u8 *p_data; +} waveformatex_t; + + +/***************************************************************************** + * + *****************************************************************************/ +struct demux_sys_t +{ + + mtime_t i_pcr; + mtime_t i_time; + + vlc_fourcc_t i_fourcc; + es_descriptor_t *p_es; + + waveformatex_t format; + + int i_wf; /* taille de p_wf */ + u8 *p_wf; /* waveformatex_t as store in file */ + + off_t i_data_pos; + u64 i_data_size; + + /* Two case: + - we have an internal demux(pcm) + - we use an external demux(mp3, a52 ..) + */ + + /* module for external demux */ + module_t *p_demux; + int (*pf_demux)( input_thread_t * ); + void *p_demux_data; + char *psz_demux; + + /* getframe for internal demux */ + int (*GetFrame)( input_thread_t *p_input, + waveformatex_t *p_wf, + pes_packet_t **pp_pes, + mtime_t *pi_length ); + +}; + + +