]> git.sesse.net Git - vlc/blob - modules/demux/wav/wav.c
e4c8cc677302cd2ba3344f0e6253aff7df417350
[vlc] / modules / demux / wav / wav.c
1 /*****************************************************************************
2  * wav.c : wav file input module for vlc
3  *****************************************************************************
4  * Copyright (C) 2001 VideoLAN
5  * $Id: wav.c,v 1.7 2002/12/10 23:34:19 gbazin Exp $
6  * Authors: Laurent Aimar <fenrir@via.ecp.fr>
7  * 
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  * 
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
21  *****************************************************************************/
22
23 /*****************************************************************************
24  * Preamble
25  *****************************************************************************/
26 #include <stdlib.h>                                      /* malloc(), free() */
27 #include <string.h>                                              /* strdup() */
28
29 #include <vlc/vlc.h>
30 #include <vlc/input.h>
31
32 #include <codecs.h>
33 #include "wav.h"
34
35 /*****************************************************************************
36  * Local prototypes
37  *****************************************************************************/
38 static int    WAVInit       ( vlc_object_t * );
39 static void __WAVEnd        ( vlc_object_t * );
40 static int    WAVDemux      ( input_thread_t * );
41 static int    WAVCallDemux  ( input_thread_t * );
42
43 #define WAVEnd(a) __WAVEnd(VLC_OBJECT(a))
44
45 /*****************************************************************************
46  * Module descriptor
47  *****************************************************************************/
48 vlc_module_begin();
49     set_description( "WAV demuxer" );
50     set_capability( "demux", 142 );
51     set_callbacks( WAVInit, __WAVEnd );
52 vlc_module_end();
53
54 /*****************************************************************************
55  * Declaration of local function 
56  *****************************************************************************/
57
58 #define FREE( p ) if( p ) free( p ); (p) = NULL
59
60 #define __EVEN( x ) ( (x)%2 != 0 ) ? ((x)+1) : (x)
61
62 /* Some functions to manipulate memory */
63 static u16 GetWLE( u8 *p_buff )
64 {
65     return( (p_buff[0]) + ( p_buff[1] <<8 ) );
66 }
67
68 static u32 GetDWLE( u8 *p_buff )
69 {
70     return( p_buff[0] + ( p_buff[1] <<8 ) +
71             ( p_buff[2] <<16 ) + ( p_buff[3] <<24 ) );
72 }
73
74 static u32 CreateDWLE( int a, int b, int c, int d )
75 {
76     return( a + ( b << 8 ) + ( c << 16 ) + ( d << 24 ) );
77 }
78
79
80 static off_t TellAbsolute( input_thread_t *p_input )
81 {
82     off_t i_pos;
83     
84     vlc_mutex_lock( &p_input->stream.stream_lock );
85     
86     i_pos= p_input->stream.p_selected_area->i_tell;
87 //          - ( p_input->p_last_data - p_input->p_current_data  );
88
89     vlc_mutex_unlock( &p_input->stream.stream_lock );
90
91     return( i_pos );
92 }
93  
94 static int SeekAbsolute( input_thread_t *p_input,
95                          off_t i_pos)
96 {
97     off_t i_filepos;
98
99     if( i_pos >= p_input->stream.p_selected_area->i_size )
100     {
101     //    return( 0 );
102     }
103             
104     i_filepos = TellAbsolute( p_input );
105     if( i_pos != i_filepos )
106     {
107         p_input->pf_seek( p_input, i_pos );
108         input_AccessReinit( p_input );
109     }
110     return( 1 );
111 }
112
113 static int SkipBytes( input_thread_t *p_input, int i_skip )
114 {
115     return( SeekAbsolute( p_input, TellAbsolute( p_input ) + i_skip ) );
116 }
117
118 /* return 1 if success, 0 if fail */
119 static int ReadData( input_thread_t *p_input, u8 *p_buff, int i_size )
120 {
121     data_packet_t *p_data;
122
123     int i_read;
124
125                 
126     if( !i_size )
127     {
128         return( 1 );
129     }
130
131     do
132     {
133         i_read = input_SplitBuffer(p_input, &p_data, __MIN( i_size, 1024 ) );
134         if( i_read <= 0 )
135         {
136             return( 0 );
137         }
138         memcpy( p_buff, p_data->p_payload_start, i_read );
139         input_DeletePacket( p_input->p_method_data, p_data );
140         
141         p_buff += i_read;
142         i_size -= i_read;
143                 
144     } while( i_size );
145     
146     return( 1 );
147 }
148
149
150 static int ReadPES( input_thread_t *p_input, 
151                     pes_packet_t **pp_pes, 
152                     int i_size )
153 {
154     pes_packet_t *p_pes;
155
156     *pp_pes = NULL;
157         
158     if( !(p_pes = input_NewPES( p_input->p_method_data )) )
159     {
160         msg_Err( p_input, "cannot allocate new PES" );
161         return( 0 );
162     }
163
164     while( i_size > 0 )
165     {
166         data_packet_t   *p_data;
167         int i_read;
168
169         if( (i_read = input_SplitBuffer( p_input, 
170                                          &p_data, 
171                                          __MIN( i_size, 1024 ) ) ) <= 0 )
172         {
173             input_DeletePES( p_input->p_method_data, p_pes );
174             return( 0 );
175         }
176         if( !p_pes->p_first )
177         {
178             p_pes->p_first = p_data;
179             p_pes->i_nb_data = 1;
180             p_pes->i_pes_size = i_read;
181         }
182         else
183         {
184             p_pes->p_last->p_next  = p_data;
185             p_pes->i_nb_data++;
186             p_pes->i_pes_size += i_read;
187         }
188         p_pes->p_last  = p_data;
189         i_size -= i_read;
190     }
191     *pp_pes = p_pes;
192     return( 1 );
193 }
194
195 static int FindTag( input_thread_t *p_input, u32 i_tag )
196 {
197     u32   i_id;
198     u32   i_size;
199     u8    *p_peek;
200
201     for( ;; )
202     {
203
204         if( input_Peek( p_input, &p_peek, 8 ) < 8 )
205         {
206             msg_Err( p_input, "cannot peek()" );
207             return( 0 );
208         }
209
210         i_id   = GetDWLE( p_peek );
211         i_size = GetDWLE( p_peek + 4 );
212
213         msg_Dbg( p_input, "FindTag: tag:%4.4s size:%d", &i_id, i_size );
214         if( i_id == i_tag )
215         {
216             /* Yes, we have found the good tag */
217             return( 1 );
218         }
219         if( !SkipBytes( p_input, __EVEN( i_size ) + 8 ) )
220         {
221             return( 0 );
222         }
223     }
224 }
225
226 static int LoadTag_fmt( input_thread_t *p_input, 
227                         demux_sys_t *p_demux )
228 {
229     u8  *p_peek;
230     u32 i_size;
231     WAVEFORMATEX *p_wf;
232             
233
234     if( input_Peek( p_input, &p_peek , 8 ) < 8 )
235     {
236         return( 0 );
237     }
238
239     p_demux->i_wf = i_size = GetDWLE( p_peek + 4 );
240     SkipBytes( p_input, 8 );
241     if( i_size < 16 )
242     {
243         SkipBytes( p_input, i_size );
244         return( 0 );
245     }
246     p_wf = p_demux->p_wf = malloc( __MAX( i_size, sizeof( WAVEFORMATEX) ) );
247     ReadData( p_input, (uint8_t*)p_wf, __EVEN( i_size ) );
248
249     p_wf->wFormatTag      = GetWLE( (uint8_t*)&p_demux->p_wf->wFormatTag );
250     p_wf->nChannels       = GetWLE( (uint8_t*)&p_demux->p_wf->nChannels );
251     p_wf->nSamplesPerSec  = GetWLE( (uint8_t*)&p_demux->p_wf->nSamplesPerSec );
252     p_wf->nAvgBytesPerSec = GetWLE( (uint8_t*)&p_demux->p_wf->nAvgBytesPerSec );
253     p_wf->nBlockAlign     = GetWLE( (uint8_t*)&p_demux->p_wf->nBlockAlign );
254     p_wf->wBitsPerSample  = GetWLE( (uint8_t*)&p_demux->p_wf->wBitsPerSample );
255     if( i_size >= sizeof( WAVEFORMATEX) )
256     {
257         p_wf->cbSize          = GetWLE( (uint8_t*)&p_demux->p_wf->cbSize );
258     }
259     else
260     {
261         p_wf->cbSize = 0;
262     }
263
264     msg_Dbg( p_input, "loaded \"fmt \" chunk" );
265     return( 1 );
266 }
267
268 static int PCM_GetFrame( input_thread_t *p_input,
269                          WAVEFORMATEX   *p_wf,
270                          pes_packet_t   **pp_pes,
271                          mtime_t        *pi_length )
272 {
273     int i_samples;
274
275     int i_bytes;
276     int i_modulo;
277
278     /* read samples for 50ms of */
279     i_samples = __MAX( p_wf->nSamplesPerSec / 20, 1 );
280         
281     
282     *pi_length = (mtime_t)1000000 * 
283                  (mtime_t)i_samples / 
284                  (mtime_t)p_wf->nSamplesPerSec;
285
286     i_bytes = i_samples * p_wf->nChannels * ( (p_wf->wBitsPerSample + 7) / 8 );
287     
288     if( p_wf->nBlockAlign > 0 )
289     {
290         if( ( i_modulo = i_bytes % p_wf->nBlockAlign ) != 0 )
291         {
292             i_bytes += p_wf->nBlockAlign - i_modulo;
293         }
294     }
295
296     return( ReadPES( p_input, pp_pes, i_bytes ) );
297 }
298
299 static int MS_ADPCM_GetFrame( input_thread_t *p_input,
300                               WAVEFORMATEX   *p_wf,
301                               pes_packet_t   **pp_pes,
302                               mtime_t        *pi_length )
303 {
304     int i_samples;
305
306     i_samples = 2 + 2 * ( p_wf->nBlockAlign - 
307                                 7 * p_wf->nChannels ) / p_wf->nChannels;
308     
309     *pi_length = (mtime_t)1000000 *
310                  (mtime_t)i_samples /
311                  (mtime_t)p_wf->nSamplesPerSec;
312
313     return( ReadPES( p_input, pp_pes, p_wf->nBlockAlign ) );
314 }
315
316 static int IMA_ADPCM_GetFrame( input_thread_t *p_input,
317                                WAVEFORMATEX   *p_wf,
318                                pes_packet_t   **pp_pes,
319                                mtime_t        *pi_length )
320 {
321     int i_samples;
322
323     i_samples = 2 * ( p_wf->nBlockAlign - 
324                         4 * p_wf->nChannels ) / p_wf->nChannels;
325     
326     *pi_length = (mtime_t)1000000 *
327                  (mtime_t)i_samples /
328                  (mtime_t)p_wf->nSamplesPerSec;
329
330     return( ReadPES( p_input, pp_pes, p_wf->nBlockAlign ) );
331 }
332
333 /*****************************************************************************
334  * WAVInit: check file and initializes structures
335  *****************************************************************************/
336 static int WAVInit( vlc_object_t * p_this )
337 {   
338     input_thread_t *p_input = (input_thread_t *)p_this;
339     u8  *p_peek;
340     u32 i_size;
341     
342     demux_sys_t *p_demux;
343     
344
345
346     /* Initialize access plug-in structures. */
347     if( p_input->i_mtu == 0 )
348     {
349         /* Improve speed. */
350         p_input->i_bufsize = INPUT_DEFAULT_BUFSIZE ;
351     }
352
353     /* a little test to see if it's a wav file */
354     if( input_Peek( p_input, &p_peek, 12 ) < 12 )
355     {
356         msg_Warn( p_input, "WAV plugin discarded (cannot peek)" );
357         return( -1 );
358     }
359
360     if( ( GetDWLE( p_peek ) != CreateDWLE( 'R', 'I', 'F', 'F' ) )||
361         ( GetDWLE( p_peek + 8 ) != CreateDWLE( 'W', 'A', 'V', 'E' ) ) )
362     {
363         msg_Warn( p_input, "WAV plugin discarded (not a valid file)" );
364         return( -1 );
365     }
366     i_size = GetDWLE( p_peek + 4 );
367     SkipBytes( p_input, 12 );
368
369     if( !FindTag( p_input, CreateDWLE( 'f', 'm', 't' ,' ' ) ) )
370     {
371         msg_Err( p_input, "cannot find \"fmt \" tag" );
372         return( -1 );
373     }
374
375     /* create our structure that will contains all data */
376     if( !( p_input->p_demux_data = 
377                 p_demux = malloc( sizeof( demux_sys_t ) ) ) )
378     {
379         msg_Err( p_input, "out of memory" );
380         return( -1 );
381     }
382     memset( p_demux, 0, sizeof( demux_sys_t ) );
383        
384     /* Load WAVEFORMATEX header */
385     if( !LoadTag_fmt( p_input, p_demux ) )
386     {
387         msg_Err( p_input, "cannot load \"fmt \" tag" );
388         FREE( p_demux );
389         return( -1 );
390     }
391     msg_Dbg( p_input, "format:0x%4.4x channels:%d %dHz %dKo/s blockalign:%d bits/samples:%d extra size:%d",
392             p_demux->p_wf->wFormatTag,
393             p_demux->p_wf->nChannels,
394             p_demux->p_wf->nSamplesPerSec,
395             p_demux->p_wf->nAvgBytesPerSec / 1024,
396             p_demux->p_wf->nBlockAlign,
397             p_demux->p_wf->wBitsPerSample,
398             p_demux->p_wf->cbSize );
399            
400     if( !FindTag( p_input, CreateDWLE( 'd', 'a', 't', 'a' ) ) )
401     {
402         msg_Err( p_input, "cannot find \"data\" tag" );
403         FREE( p_demux->p_wf );
404         FREE( p_demux );
405         return( -1 );
406     }
407     if( input_Peek( p_input, &p_peek, 8 ) < 8 )
408     {
409         msg_Warn( p_input, "WAV plugin discarded (cannot peek)" );
410         FREE( p_demux->p_wf );
411         FREE( p_demux );
412         return( -1 );
413     }
414
415     p_demux->i_data_pos = TellAbsolute( p_input ) + 8;
416     p_demux->i_data_size = GetDWLE( p_peek + 4 );
417     SkipBytes( p_input, 8 );
418
419     /* XXX p_demux->psz_demux shouldn't be NULL ! */
420     switch( p_demux->p_wf->wFormatTag )
421     {
422         case( WAVE_FORMAT_PCM ):
423             msg_Dbg( p_input,"found raw pcm audio format" );
424             p_demux->i_fourcc = VLC_FOURCC( 'a', 'r', 'a', 'w' );
425             p_demux->GetFrame = PCM_GetFrame;
426             p_demux->psz_demux = strdup( "" );
427             break;
428         case( WAVE_FORMAT_MPEG ):
429         case( WAVE_FORMAT_MPEGLAYER3 ):
430             msg_Dbg( p_input, "found mpeg audio format" );
431             p_demux->i_fourcc = VLC_FOURCC( 'm', 'p', 'g', 'a' );
432             p_demux->GetFrame = NULL;
433             p_demux->psz_demux = strdup( "mpegaudio" );
434             break;
435         case( WAVE_FORMAT_A52 ):
436             msg_Dbg( p_input,"found a52 audio format" );
437             p_demux->i_fourcc = VLC_FOURCC( 'a', '5', '2', ' ' );
438             p_demux->GetFrame = NULL;
439             p_demux->psz_demux = strdup( "a52" );
440             break;
441         case( WAVE_FORMAT_ADPCM ):
442             msg_Dbg( p_input, "found ms adpcm audio format" );
443             p_demux->i_fourcc = VLC_FOURCC( 'm', 's', 0x00, 0x02 );
444             p_demux->GetFrame = MS_ADPCM_GetFrame;
445             p_demux->psz_demux = strdup( "" );
446             break;
447         case( WAVE_FORMAT_IMA_ADPCM ):
448             msg_Dbg( p_input, "found ima adpcm audio format" );
449             p_demux->i_fourcc = VLC_FOURCC( 'm', 's', 0x00, 0x11 );
450             p_demux->GetFrame = IMA_ADPCM_GetFrame;
451             p_demux->psz_demux = strdup( "" );
452             break;
453         default:
454             msg_Warn( p_input,"unrecognize audio format(0x%x)", 
455                       p_demux->p_wf->wFormatTag );
456             p_demux->i_fourcc = 
457                 VLC_FOURCC( 'm', 's', 
458                             (p_demux->p_wf->wFormatTag >> 8)&0xff,
459                             (p_demux->p_wf->wFormatTag )&0xff);
460             p_demux->GetFrame = NULL;
461             p_demux->psz_demux = strdup( "" );
462             break;
463     }
464     
465     if( p_demux->GetFrame )
466     {
467         msg_Dbg( p_input, "using internal demux" );
468
469         p_input->pf_demux = WAVDemux;
470         p_input->p_demux_data = p_demux;
471         
472         /*  create one program */
473         vlc_mutex_lock( &p_input->stream.stream_lock );
474         if( input_InitStream( p_input, 0 ) == -1)
475         {
476             vlc_mutex_unlock( &p_input->stream.stream_lock );
477             msg_Err( p_input, "cannot init stream" );
478             // FIXME 
479             return( -1 );
480         }
481         if( input_AddProgram( p_input, 0, 0) == NULL )
482         {
483             vlc_mutex_unlock( &p_input->stream.stream_lock );
484             msg_Err( p_input, "cannot add program" );
485             // FIXME 
486             return( -1 );
487         }
488         p_input->stream.p_selected_program = p_input->stream.pp_programs[0];
489         p_input->stream.i_mux_rate = 0 ; /* FIXME */
490
491         p_demux->p_es = input_AddES( p_input,
492                                      p_input->stream.p_selected_program, 1,
493                                      p_demux->i_wf );
494         p_demux->p_es->i_stream_id = 1;
495         p_demux->p_es->i_fourcc = p_demux->i_fourcc;
496         p_demux->p_es->i_cat = AUDIO_ES;
497         memcpy( p_demux->p_es->p_demux_data,
498                 p_demux->p_wf,
499                 p_demux->i_wf );
500         
501         input_SelectES( p_input, p_demux->p_es );
502         
503         p_input->stream.p_selected_program->b_is_ok = 1;
504         vlc_mutex_unlock( &p_input->stream.stream_lock );
505     }
506     else
507     {
508         char *psz_sav;
509         /* call an external demux */
510         msg_Warn( p_input, "unsupported formattag, using external demux" );
511         
512         psz_sav = p_input->psz_demux;
513         p_input->psz_demux = p_demux->psz_demux;
514
515         p_demux->p_demux = module_Need( p_input, "demux", NULL );
516         
517         p_input->psz_demux = psz_sav;
518         
519         if( !p_demux->p_demux )
520         {
521             msg_Err( p_input, 
522                      "cannot get external demux for formattag 0x%x",
523                      p_demux->p_wf->wFormatTag );
524             FREE( p_demux->psz_demux );
525             FREE( p_demux->p_wf );
526             FREE( p_demux );
527             return( -1 );
528         }
529         /* save value and switch back */
530         p_demux->pf_demux = p_input->pf_demux;
531         p_demux->p_demux_data = p_input->p_demux_data;
532
533         p_input->pf_demux = WAVCallDemux;
534         p_input->p_demux_data = p_demux;
535
536     }
537
538     return( 0 );    
539 }
540
541 /*****************************************************************************
542  * WAVCallDemux: call true demux
543  *****************************************************************************
544  * Returns -1 in case of error, 0 in case of EOF, 1 otherwise
545  *****************************************************************************/
546 static int WAVCallDemux( input_thread_t *p_input )
547 {
548     demux_sys_t  *p_demux = p_input->p_demux_data;
549     int i_status;
550     char *psz_sav;
551     
552     /* save context */
553     psz_sav = p_input->psz_demux;
554
555     /* switch context */
556     p_input->pf_demux = p_demux->pf_demux;
557     p_input->p_demux_data = p_demux->p_demux_data;
558     p_input->psz_demux = p_demux->psz_demux;
559
560     /* call demux */
561     i_status = p_input->pf_demux( p_input );
562
563     /* save (new?) state */
564     p_demux->pf_demux = p_input->pf_demux;
565     p_demux->p_demux_data = p_input->p_demux_data;
566     
567     /* switch back */
568     p_input->psz_demux = psz_sav;
569     p_input->pf_demux = WAVCallDemux;
570     p_input->p_demux_data = p_demux;
571
572     return( i_status );
573 }
574
575 /*****************************************************************************
576  * WAVDemux: read packet and send them to decoders
577  *****************************************************************************
578  * Returns -1 in case of error, 0 in case of EOF, 1 otherwise
579  *****************************************************************************/
580 static int WAVDemux( input_thread_t *p_input )
581 {
582     demux_sys_t  *p_demux = p_input->p_demux_data;
583     pes_packet_t *p_pes;
584     mtime_t      i_length;
585
586     if( p_input->stream.p_selected_program->i_synchro_state == SYNCHRO_REINIT )
587     {
588         off_t   i_offset;
589
590         i_offset = TellAbsolute( p_input ) - p_demux->i_data_pos;
591         if( i_offset < 0 )
592         {
593             i_offset = 0;
594         }
595         if( p_demux->p_wf->nBlockAlign != 0 )
596         {
597             i_offset += p_demux->p_wf->nBlockAlign - 
598                                 i_offset % p_demux->p_wf->nBlockAlign;
599         }
600         SeekAbsolute( p_input, p_demux->i_data_pos + i_offset );
601     }
602     
603     input_ClockManageRef( p_input,
604                           p_input->stream.p_selected_program,
605                           p_demux->i_pcr );
606
607     if( TellAbsolute( p_input )
608          >= (off_t)(p_demux->i_data_pos + p_demux->i_data_size) )
609     {
610         return( 0 ); // EOF
611     }
612
613     if( !p_demux->GetFrame( p_input, p_demux->p_wf, &p_pes, &i_length ) )
614     {
615         msg_Warn( p_input, "failed to get one frame" );
616         return( 0 );
617     }
618
619     p_pes->i_dts = 
620         p_pes->i_pts = input_ClockGetTS( p_input, 
621                                          p_input->stream.p_selected_program,
622                                          p_demux->i_pcr );
623    
624     if( !p_demux->p_es->p_decoder_fifo )
625     {
626         msg_Err( p_input, "no audio decoder" );
627         input_DeletePES( p_input->p_method_data, p_pes );
628         return( -1 );
629     }
630     else
631     {
632         input_DecodePES( p_demux->p_es->p_decoder_fifo, p_pes );
633     }
634     
635     p_demux->i_pcr += i_length * 9 / 100;
636     return( 1 );
637 }
638
639 /*****************************************************************************
640  * WAVEnd: frees unused data
641  *****************************************************************************/
642 static void __WAVEnd ( vlc_object_t * p_this )
643 {   
644     input_thread_t *  p_input = (input_thread_t *)p_this;
645     demux_sys_t *p_demux = p_input->p_demux_data;
646     
647     FREE( p_demux->p_wf );
648     FREE( p_demux->psz_demux );
649     
650     if( p_demux->p_demux )
651     {
652         module_Unneed( p_input, p_demux->p_demux );
653     }
654
655 }
656