]> git.sesse.net Git - vlc/blob - modules/access/cdda.c
* Bumped version to 0.6.0-test1
[vlc] / modules / access / cdda.c
1 /*****************************************************************************
2  * cdda.c : CD digital audio input module for vlc
3  *****************************************************************************
4  * Copyright (C) 2000 VideoLAN
5  * $Id: cdda.c,v 1.3 2003/05/19 20:47:16 gbazin Exp $
6  *
7  * Authors: Laurent Aimar <fenrir@via.ecp.fr>
8  *          Gildas Bazin <gbazin@netcourrier.com>
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
23  *****************************************************************************/
24
25 /*****************************************************************************
26  * Preamble
27  *****************************************************************************/
28 #include <stdio.h>
29 #include <stdlib.h>
30
31 #include <vlc/vlc.h>
32 #include <vlc/input.h>
33 #include <sys/types.h>
34
35 #include "codecs.h"
36
37 #ifdef HAVE_UNISTD_H
38 #   include <unistd.h>
39 #endif
40
41 #include <string.h>
42
43 #include "vcd/cdrom.h"
44
45 /* how many blocks VCDRead will read in each loop */
46 #define CDDA_BLOCKS_ONCE 20
47 #define CDDA_DATA_ONCE   (CDDA_BLOCKS_ONCE * CDDA_DATA_SIZE)
48
49 /*****************************************************************************
50  * cdda_data_t: CD audio information
51  *****************************************************************************/
52 typedef struct cdda_data_s
53 {
54     vcddev_t    *vcddev;                            /* vcd device descriptor */
55     int         i_nb_tracks;                        /* Nb of tracks (titles) */
56     int         i_track;                                    /* Current track */
57     int         i_sector;                                  /* Current Sector */
58     int *       p_sectors;                                  /* Track sectors */
59     vlc_bool_t  b_end_of_track;           /* If the end of track was reached */
60
61 } cdda_data_t;
62
63 struct demux_sys_t
64 {
65     es_descriptor_t *p_es;
66     mtime_t         i_pts;
67 };
68
69 /*****************************************************************************
70  * Local prototypes
71  *****************************************************************************/
72 static int  CDDAOpen         ( vlc_object_t * );
73 static void CDDAClose        ( vlc_object_t * );
74 static int  CDDARead         ( input_thread_t *, byte_t *, size_t );
75 static void CDDASeek         ( input_thread_t *, off_t );
76 static int  CDDASetArea      ( input_thread_t *, input_area_t * );
77 static int  CDDASetProgram   ( input_thread_t *, pgrm_descriptor_t * );
78
79 static int  CDDAOpenDemux    ( vlc_object_t * );
80 static void CDDACloseDemux   ( vlc_object_t * );
81 static int  CDDADemux        ( input_thread_t * p_input );
82
83 /*****************************************************************************
84  * Module descriptior
85  *****************************************************************************/
86 #define CACHING_TEXT N_("Caching value in ms")
87 #define CACHING_LONGTEXT N_( \
88     "Allows you to modify the default caching value for cdda streams. This " \
89     "value should be set in miliseconds units." )
90
91 vlc_module_begin();
92     set_description( _("CD Audio input") );
93     add_integer( "cdda-caching", DEFAULT_PTS_DELAY / 1000, NULL, CACHING_TEXT, CACHING_LONGTEXT, VLC_TRUE );
94     set_capability( "access", 70 );
95     set_callbacks( CDDAOpen, CDDAClose );
96     add_shortcut( "cdda" );
97
98     add_submodule();
99         set_description( _("CD Audio demux") );
100         set_capability( "demux", 0 );
101         set_callbacks( CDDAOpenDemux, CDDACloseDemux );
102         add_shortcut( "cdda" );
103 vlc_module_end();
104
105 /*****************************************************************************
106  * CDDAOpen: open cdda
107  *****************************************************************************/
108 static int CDDAOpen( vlc_object_t *p_this )
109 {
110     input_thread_t *        p_input = (input_thread_t *)p_this;
111     char *                  psz_orig;
112     char *                  psz_parser;
113     char *                  psz_source;
114     cdda_data_t *           p_cdda;
115     int                     i;
116     input_area_t *          p_area;
117     int                     i_title = 1;
118     vcddev_t                *vcddev;
119
120 #ifdef WIN32
121     /* On Win32 we want the CDDA access plugin to be explicitly requested,
122      * we end up with lots of problems otherwise */
123     if( !p_input->psz_access || !*p_input->psz_access ) return( -1 );
124 #endif
125
126     /* parse the options passed in command line : */
127     psz_orig = psz_parser = psz_source = strdup( p_input->psz_name );
128
129     if( !psz_orig )
130     {
131         return( -1 );
132     }
133
134     while( *psz_parser && *psz_parser != '@' )
135     {
136         psz_parser++;
137     }
138
139     if( *psz_parser == '@' )
140     {
141         /* Found options */
142         *psz_parser = '\0';
143         ++psz_parser;
144
145         i_title = (int)strtol( psz_parser, NULL, 10 );
146         i_title = i_title ? i_title : 1;
147     }
148
149     if( !*psz_source )
150     {
151         if( !p_input->psz_access )
152         {
153             free( psz_orig );
154             return -1;
155         }
156         psz_source = config_GetPsz( p_input, "vcd" );
157         if( !psz_source ) return -1;
158     }
159
160     /* Open CDDA */
161     if( !(vcddev = ioctl_Open( p_this, psz_source )) )
162     {
163         msg_Warn( p_input, "could not open %s", psz_source );
164         free( psz_source );
165         return -1;
166     }
167     free( psz_source );
168
169     p_cdda = malloc( sizeof(cdda_data_t) );
170     if( p_cdda == NULL )
171     {
172         msg_Err( p_input, "out of memory" );
173         free( psz_source );
174         return -1;
175     }
176
177     p_cdda->vcddev = vcddev;
178     p_input->p_access_data = (void *)p_cdda;
179
180     p_input->i_mtu = CDDA_DATA_ONCE;
181
182     /* We read the Table Of Content information */
183     p_cdda->i_nb_tracks = ioctl_GetTracksMap( VLC_OBJECT(p_input),
184                               p_cdda->vcddev, &p_cdda->p_sectors );
185     if( p_cdda->i_nb_tracks < 0 )
186         msg_Err( p_input, "unable to count tracks" );
187     else if( p_cdda->i_nb_tracks <= 0 )
188         msg_Err( p_input, "no audio tracks found" );
189
190     if( p_cdda->i_nb_tracks <= 1)
191     {
192         ioctl_Close( p_this, p_cdda->vcddev );
193         free( p_cdda );
194         return -1;
195     }
196
197     if( i_title >= p_cdda->i_nb_tracks || i_title < 1 )
198         i_title = 1;
199
200     /* Set stream and area data */
201     vlc_mutex_lock( &p_input->stream.stream_lock );
202
203     /* Initialize ES structures */
204     input_InitStream( p_input, 0 );
205
206     /* cdda input method */
207     p_input->stream.i_method = INPUT_METHOD_CDDA;
208
209     p_input->stream.b_pace_control = 1;
210     p_input->stream.b_seekable = 1;
211     p_input->stream.i_mux_rate = 44100 * 4 / 50;
212
213 #define area p_input->stream.pp_areas
214     for( i = 1 ; i <= p_cdda->i_nb_tracks ; i++ )
215     {
216         input_AddArea( p_input, i, 1 );
217
218         /* Absolute start offset and size */
219         area[i]->i_start =
220             (off_t)p_cdda->p_sectors[i-1] * (off_t)CDDA_DATA_SIZE;
221         area[i]->i_size =
222             (off_t)(p_cdda->p_sectors[i] - p_cdda->p_sectors[i-1])
223             * (off_t)CDDA_DATA_SIZE;
224     }
225 #undef area
226
227     p_area = p_input->stream.pp_areas[i_title];
228
229     CDDASetArea( p_input, p_area );
230
231     vlc_mutex_unlock( &p_input->stream.stream_lock );
232
233     if( !p_input->psz_demux || !*p_input->psz_demux )
234     {
235         p_input->psz_demux = "cdda";
236     }
237
238     p_input->pf_read = CDDARead;
239     p_input->pf_seek = CDDASeek;
240     p_input->pf_set_area = CDDASetArea;
241     p_input->pf_set_program = CDDASetProgram;
242
243     /* Update default_pts to a suitable value for cdda access */
244     p_input->i_pts_delay = config_GetInt( p_input, "cdda-caching" ) * 1000;
245
246     return 0;
247 }
248
249 /*****************************************************************************
250  * CDDAClose: closes cdda
251  *****************************************************************************/
252 static void CDDAClose( vlc_object_t *p_this )
253 {
254     input_thread_t *   p_input = (input_thread_t *)p_this;
255     cdda_data_t *p_cdda = (cdda_data_t *)p_input->p_access_data;
256
257     ioctl_Close( p_this, p_cdda->vcddev );
258     free( p_cdda );
259 }
260
261 /*****************************************************************************
262  * CDDARead: reads from the CDDA into PES packets.
263  *****************************************************************************
264  * Returns -1 in case of error, 0 in case of EOF, otherwise the number of
265  * bytes.
266  *****************************************************************************/
267 static int CDDARead( input_thread_t * p_input, byte_t * p_buffer,
268                      size_t i_len )
269 {
270     cdda_data_t *           p_cdda;
271     int                     i_blocks;
272     int                     i_index;
273     int                     i_read;
274
275     p_cdda = (cdda_data_t *)p_input->p_access_data;
276
277     i_read = 0;
278
279     /* Compute the number of blocks we have to read */
280
281     i_blocks = i_len / CDDA_DATA_SIZE;
282
283     if ( ioctl_ReadSectors( VLC_OBJECT(p_input), p_cdda->vcddev,
284              p_cdda->i_sector, p_buffer, i_blocks, CDDA_TYPE ) < 0 )
285     {
286         msg_Err( p_input, "could not read sector %d", p_cdda->i_sector );
287         return -1;
288     }
289
290     for ( i_index = 0; i_index < i_blocks; i_index++ )
291     {
292         p_cdda->i_sector ++;
293         if ( p_cdda->i_sector == p_cdda->p_sectors[p_cdda->i_track + 1] )
294         {
295             input_area_t *p_area;
296
297             if ( p_cdda->i_track >= p_cdda->i_nb_tracks - 1 )
298                 return 0; /* EOF */
299
300             vlc_mutex_lock( &p_input->stream.stream_lock );
301             p_area = p_input->stream.pp_areas[
302                     p_input->stream.p_selected_area->i_id + 1 ];
303
304             msg_Dbg( p_input, "new title" );
305
306             p_area->i_part = 1;
307             CDDASetArea( p_input, p_area );
308             vlc_mutex_unlock( &p_input->stream.stream_lock );
309         }
310         i_read += CDDA_DATA_SIZE;
311     }
312
313     if ( i_len % CDDA_DATA_SIZE ) /* this should not happen */
314     {
315         msg_Err( p_input, "must read full sectors" );
316     }
317
318     return i_read;
319 }
320
321
322 /*****************************************************************************
323  * CDDASetProgram: Does nothing since a CDDA is mono_program
324  *****************************************************************************/
325 static int CDDASetProgram( input_thread_t * p_input,
326                            pgrm_descriptor_t * p_program)
327 {
328     return 0;
329 }
330
331
332 /*****************************************************************************
333  * CDDASetArea: initialize input data for title x.
334  * It should be called for each user navigation request.
335  ****************************************************************************/
336 static int CDDASetArea( input_thread_t * p_input, input_area_t * p_area )
337 {
338     cdda_data_t *p_cdda = (cdda_data_t*)p_input->p_access_data;
339     vlc_value_t val;
340
341     /* we can't use the interface slider until initilization is complete */
342     p_input->stream.b_seekable = 0;
343
344     if( p_area != p_input->stream.p_selected_area )
345     {
346         /* Change the default area */
347         p_input->stream.p_selected_area = p_area;
348
349         /* Change the current track */
350         p_cdda->i_track = p_area->i_id - 1;
351         p_cdda->i_sector = p_cdda->p_sectors[p_cdda->i_track];
352
353         /* Update the navigation variables without triggering a callback */
354         val.i_int = p_area->i_id;
355         var_Change( p_input, "title", VLC_VAR_SETVALUE, &val, NULL );
356     }
357
358     p_cdda->i_sector = p_cdda->p_sectors[p_cdda->i_track];
359
360     p_input->stream.p_selected_area->i_tell =
361         (off_t)p_cdda->i_sector * (off_t)CDDA_DATA_SIZE
362          - p_input->stream.p_selected_area->i_start;
363
364     /* warn interface that something has changed */
365     p_input->stream.b_seekable = 1;
366     p_input->stream.b_changed = 1;
367
368     return 0;
369 }
370
371
372 /****************************************************************************
373  * CDDASeek
374  ****************************************************************************/
375 static void CDDASeek( input_thread_t * p_input, off_t i_off )
376 {
377     cdda_data_t * p_cdda;
378
379     p_cdda = (cdda_data_t *) p_input->p_access_data;
380
381     p_cdda->i_sector = p_cdda->p_sectors[p_cdda->i_track]
382                        + i_off / (off_t)CDDA_DATA_SIZE;
383
384     vlc_mutex_lock( &p_input->stream.stream_lock );
385     p_input->stream.p_selected_area->i_tell =
386         (off_t)p_cdda->i_sector * (off_t)CDDA_DATA_SIZE
387          - p_input->stream.p_selected_area->i_start;
388     vlc_mutex_unlock( &p_input->stream.stream_lock );
389 }
390
391 /****************************************************************************
392  * Demux Part
393  ****************************************************************************/
394 static int  CDDAOpenDemux    ( vlc_object_t * p_this)
395 {
396     input_thread_t *p_input = (input_thread_t *)p_this;
397     demux_sys_t    *p_demux;
398     WAVEFORMATEX   *p_wf;
399
400     if( p_input->stream.i_method != INPUT_METHOD_CDDA )
401     {
402         return VLC_EGENERIC;
403     }
404
405     p_demux = malloc( sizeof( es_descriptor_t ) );
406     p_demux->i_pts = 0;
407     p_demux->p_es = NULL;
408
409     p_input->pf_demux  = CDDADemux;
410     p_input->pf_rewind = NULL;
411     p_input->p_demux_data = p_demux;
412
413     vlc_mutex_lock( &p_input->stream.stream_lock );
414     if( input_AddProgram( p_input, 0, 0) == NULL )
415     {
416         msg_Err( p_input, "cannot add program" );
417         free( p_input->p_demux_data );
418         return( -1 );
419     }
420     p_input->stream.pp_programs[0]->b_is_ok = 0;
421     p_input->stream.p_selected_program = p_input->stream.pp_programs[0];
422
423     /* create our ES */ 
424     p_demux->p_es = input_AddES( p_input, 
425                                  p_input->stream.p_selected_program,
426                                  1 /* id */, AUDIO_ES, NULL, 0 );
427     if( !p_demux->p_es )
428     {
429         vlc_mutex_unlock( &p_input->stream.stream_lock );
430         msg_Err( p_input, "out of memory" );
431         free( p_input->p_demux_data );
432         return( -1 );
433     }
434     p_demux->p_es->i_stream_id = 1;
435     p_demux->p_es->i_fourcc = VLC_FOURCC('a','r','a','w');
436
437     p_demux->p_es->p_waveformatex = p_wf = malloc( sizeof( WAVEFORMATEX ) );
438     p_wf->wFormatTag = WAVE_FORMAT_PCM;
439     p_wf->nChannels = 2;
440     p_wf->nSamplesPerSec = 44100;
441     p_wf->nAvgBytesPerSec = 2 * 44100 * 2;
442     p_wf->nBlockAlign = 4;
443     p_wf->wBitsPerSample = 16;
444     p_wf->cbSize = 0;
445
446     input_SelectES( p_input, p_demux->p_es );
447
448     p_input->stream.p_selected_program->b_is_ok = 1;
449     vlc_mutex_unlock( &p_input->stream.stream_lock );
450
451     return VLC_SUCCESS;
452 }
453
454 static void CDDACloseDemux( vlc_object_t * p_this)
455 {
456     input_thread_t *p_input = (input_thread_t*)p_this;
457     demux_sys_t    *p_demux = (demux_sys_t*)p_input->p_demux_data;
458
459     free( p_demux );
460     p_input->p_demux_data = NULL;
461     return;
462 }
463
464 static int  CDDADemux( input_thread_t * p_input )
465 {
466     demux_sys_t    *p_demux = (demux_sys_t*)p_input->p_demux_data;
467     ssize_t         i_read;
468     data_packet_t * p_data;
469     pes_packet_t *  p_pes;
470
471     input_ClockManageRef( p_input,
472                           p_input->stream.p_selected_program,
473                           p_demux->i_pts );
474
475     if( ( i_read = input_SplitBuffer( p_input, &p_data, CDDA_DATA_SIZE ) )
476         <= 0 )
477     {
478         return 0; // EOF
479     }
480
481     p_pes = input_NewPES( p_input->p_method_data );
482
483     if( p_pes == NULL )
484     {
485         msg_Err( p_input, "out of memory" );
486         input_DeletePacket( p_input->p_method_data, p_data );
487         return -1;
488     }
489
490     p_pes->i_rate = p_input->stream.control.i_rate;
491     p_pes->p_first = p_pes->p_last = p_data;
492     p_pes->i_nb_data = 1;
493     p_pes->i_pes_size = i_read;
494
495     p_pes->i_dts =
496         p_pes->i_pts = input_ClockGetTS( p_input,
497                                          p_input->stream.p_selected_program,
498                                          p_demux->i_pts );
499
500     if( p_demux->p_es->p_decoder_fifo )
501     {
502         input_DecodePES( p_demux->p_es->p_decoder_fifo, p_pes );
503     }
504     else
505     {
506         input_DeletePES( p_input->p_method_data, p_pes );
507     }
508
509     p_demux->i_pts += ((mtime_t)90000) * i_read
510                       / (mtime_t)44100 / 4 /* stereo 16 bits */;
511     return 1;
512 }