]> git.sesse.net Git - vlc/blob - modules/access/cdda.c
* modules/access/cdda.c, modules/access/vcd/*: New CD digital audio module (by me...
[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.1 2003/05/17 20:30:31 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", 80 );
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     return 0;
244 }
245
246 /*****************************************************************************
247  * CDDAClose: closes cdda
248  *****************************************************************************/
249 static void CDDAClose( vlc_object_t *p_this )
250 {
251     input_thread_t *   p_input = (input_thread_t *)p_this;
252     cdda_data_t *p_cdda = (cdda_data_t *)p_input->p_access_data;
253
254     ioctl_Close( p_this, p_cdda->vcddev );
255     free( p_cdda );
256 }
257
258 /*****************************************************************************
259  * CDDARead: reads from the CDDA into PES packets.
260  *****************************************************************************
261  * Returns -1 in case of error, 0 in case of EOF, otherwise the number of
262  * bytes.
263  *****************************************************************************/
264 static int CDDARead( input_thread_t * p_input, byte_t * p_buffer,
265                      size_t i_len )
266 {
267     cdda_data_t *           p_cdda;
268     int                     i_blocks;
269     int                     i_index;
270     int                     i_read;
271
272     p_cdda = (cdda_data_t *)p_input->p_access_data;
273
274     i_read = 0;
275
276     /* Compute the number of blocks we have to read */
277
278     i_blocks = i_len / CDDA_DATA_SIZE;
279
280     for ( i_index = 0; i_index < i_blocks; i_index++ )
281     {
282         if ( ioctl_ReadSector( VLC_OBJECT(p_input), p_cdda->vcddev,
283                  p_cdda->i_sector, p_buffer + i_index * CDDA_DATA_SIZE,
284                  CDDA_DATA_START, CDDA_DATA_SIZE ) < 0 )
285         {
286             msg_Err( p_input, "could not read sector %d", p_cdda->i_sector );
287             return -1;
288         }
289
290         p_cdda->i_sector ++;
291         if ( p_cdda->i_sector == p_cdda->p_sectors[p_cdda->i_track + 1] )
292         {
293             input_area_t *p_area;
294
295             if ( p_cdda->i_track >= p_cdda->i_nb_tracks - 1 )
296                 return 0; /* EOF */
297
298             vlc_mutex_lock( &p_input->stream.stream_lock );
299             p_area = p_input->stream.pp_areas[
300                     p_input->stream.p_selected_area->i_id + 1 ];
301
302             msg_Dbg( p_input, "new title" );
303
304             p_area->i_part = 1;
305             CDDASetArea( p_input, p_area );
306             vlc_mutex_unlock( &p_input->stream.stream_lock );
307         }
308         i_read += CDDA_DATA_SIZE;
309     }
310
311     if ( i_len % CDDA_DATA_SIZE ) /* this should not happen */
312     {
313         msg_Err( p_input, "must read full sectors" );
314     }
315
316     return i_read;
317 }
318
319
320 /*****************************************************************************
321  * CDDASetProgram: Does nothing since a CDDA is mono_program
322  *****************************************************************************/
323 static int CDDASetProgram( input_thread_t * p_input,
324                            pgrm_descriptor_t * p_program)
325 {
326     return 0;
327 }
328
329
330 /*****************************************************************************
331  * CDDASetArea: initialize input data for title x.
332  * It should be called for each user navigation request.
333  ****************************************************************************/
334 static int CDDASetArea( input_thread_t * p_input, input_area_t * p_area )
335 {
336     cdda_data_t *p_cdda = (cdda_data_t*)p_input->p_access_data;
337     vlc_value_t val;
338
339     /* we can't use the interface slider until initilization is complete */
340     p_input->stream.b_seekable = 0;
341
342     if( p_area != p_input->stream.p_selected_area )
343     {
344         /* Change the default area */
345         p_input->stream.p_selected_area = p_area;
346
347         /* Change the current track */
348         p_cdda->i_track = p_area->i_id - 1;
349         p_cdda->i_sector = p_cdda->p_sectors[p_cdda->i_track];
350
351         /* Update the navigation variables without triggering a callback */
352         val.i_int = p_area->i_id;
353         var_Change( p_input, "title", VLC_VAR_SETVALUE, &val, NULL );
354     }
355
356     p_cdda->i_sector = p_cdda->p_sectors[p_cdda->i_track];
357
358     p_input->stream.p_selected_area->i_tell =
359         (off_t)p_cdda->i_sector * (off_t)CDDA_DATA_SIZE
360          - p_input->stream.p_selected_area->i_start;
361
362     /* warn interface that something has changed */
363     p_input->stream.b_seekable = 1;
364     p_input->stream.b_changed = 1;
365
366     return 0;
367 }
368
369
370 /****************************************************************************
371  * CDDASeek
372  ****************************************************************************/
373 static void CDDASeek( input_thread_t * p_input, off_t i_off )
374 {
375     cdda_data_t * p_cdda;
376
377     p_cdda = (cdda_data_t *) p_input->p_access_data;
378
379     p_cdda->i_sector = p_cdda->p_sectors[p_cdda->i_track]
380                        + i_off / (off_t)CDDA_DATA_SIZE;
381
382     vlc_mutex_lock( &p_input->stream.stream_lock );
383     p_input->stream.p_selected_area->i_tell =
384         (off_t)p_cdda->i_sector * (off_t)CDDA_DATA_SIZE
385          - p_input->stream.p_selected_area->i_start;
386     vlc_mutex_unlock( &p_input->stream.stream_lock );
387 }
388
389 /****************************************************************************
390  * Demux Part
391  ****************************************************************************/
392 static int  CDDAOpenDemux    ( vlc_object_t * p_this)
393 {
394     input_thread_t *p_input = (input_thread_t *)p_this;
395     demux_sys_t    *p_demux;
396     WAVEFORMATEX   *p_wf;
397
398     if( p_input->stream.i_method != INPUT_METHOD_CDDA )
399     {
400         return VLC_EGENERIC;
401     }
402
403     p_demux = malloc( sizeof( es_descriptor_t ) );
404     p_demux->i_pts = 0;
405     p_demux->p_es = NULL;
406
407     p_input->pf_demux  = CDDADemux;
408     p_input->pf_rewind = NULL;
409     p_input->p_demux_data = p_demux;
410
411     vlc_mutex_lock( &p_input->stream.stream_lock );
412     if( input_AddProgram( p_input, 0, 0) == NULL )
413     {
414         msg_Err( p_input, "cannot add program" );
415         free( p_input->p_demux_data );
416         return( -1 );
417     }
418     p_input->stream.pp_programs[0]->b_is_ok = 0;
419     p_input->stream.p_selected_program = p_input->stream.pp_programs[0];
420
421     /* create our ES */ 
422     p_demux->p_es = input_AddES( p_input, 
423                                  p_input->stream.p_selected_program,
424                                  1 /* id */, AUDIO_ES, NULL, 0 );
425     if( !p_demux->p_es )
426     {
427         vlc_mutex_unlock( &p_input->stream.stream_lock );
428         msg_Err( p_input, "out of memory" );
429         free( p_input->p_demux_data );
430         return( -1 );
431     }
432     p_demux->p_es->i_stream_id = 1;
433     p_demux->p_es->i_fourcc = VLC_FOURCC('a','r','a','w');
434
435     p_demux->p_es->p_waveformatex = p_wf = malloc( sizeof( WAVEFORMATEX ) );
436     p_wf->wFormatTag = WAVE_FORMAT_PCM;
437     p_wf->nChannels = 2;
438     p_wf->nSamplesPerSec = 44100;
439     p_wf->nAvgBytesPerSec = 2 * 44100 * 2;
440     p_wf->nBlockAlign = 4;
441     p_wf->wBitsPerSample = 16;
442     p_wf->cbSize = 0;
443
444     input_SelectES( p_input, p_demux->p_es );
445
446     p_input->stream.p_selected_program->b_is_ok = 1;
447     vlc_mutex_unlock( &p_input->stream.stream_lock );
448
449     return VLC_SUCCESS;
450 }
451
452 static void CDDACloseDemux( vlc_object_t * p_this)
453 {
454     input_thread_t *p_input = (input_thread_t*)p_this;
455     demux_sys_t    *p_demux = (demux_sys_t*)p_input->p_demux_data;
456
457     free( p_demux );
458     p_input->p_demux_data = NULL;
459     return;
460 }
461
462 static int  CDDADemux( input_thread_t * p_input )
463 {
464     demux_sys_t    *p_demux = (demux_sys_t*)p_input->p_demux_data;
465     ssize_t         i_read;
466     data_packet_t * p_data;
467     pes_packet_t *  p_pes;
468
469     input_ClockManageRef( p_input,
470                           p_input->stream.p_selected_program,
471                           p_demux->i_pts );
472
473     if( ( i_read = input_SplitBuffer( p_input, &p_data, CDDA_DATA_SIZE ) )
474         <= 0 )
475     {
476         return 0; // EOF
477     }
478
479     p_pes = input_NewPES( p_input->p_method_data );
480
481     if( p_pes == NULL )
482     {
483         msg_Err( p_input, "out of memory" );
484         input_DeletePacket( p_input->p_method_data, p_data );
485         return -1;
486     }
487
488     p_pes->i_rate = p_input->stream.control.i_rate;
489     p_pes->p_first = p_pes->p_last = p_data;
490     p_pes->i_nb_data = 1;
491     p_pes->i_pes_size = i_read;
492
493     p_pes->i_dts =
494         p_pes->i_pts = input_ClockGetTS( p_input,
495                                          p_input->stream.p_selected_program,
496                                          p_demux->i_pts );
497
498     if( p_demux->p_es->p_decoder_fifo )
499     {
500         input_DecodePES( p_demux->p_es->p_decoder_fifo, p_pes );
501     }
502     else
503     {
504         input_DeletePES( p_input->p_method_data, p_pes );
505     }
506
507     p_demux->i_pts += ((mtime_t)90000) * i_read
508                       / (mtime_t)44100 / 4 /* stereo 16 bits */;
509     return 1;
510 }