]> git.sesse.net Git - vlc/blob - modules/access/dvdplay/es.c
* ALL: changed the prototype of input_AddES() to include enough information so we...
[vlc] / modules / access / dvdplay / es.c
1 /*****************************************************************************
2  * es.c: functions to handle elementary streams.
3  *****************************************************************************
4  * Copyright (C) 2001 VideoLAN
5  * $Id: es.c,v 1.6 2003/05/05 22:23:32 gbazin Exp $
6  *
7  * Author: Stéphane Borel <stef@via.ecp.fr>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  * 
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
22  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27 #include <stdio.h>
28 #include <stdlib.h>
29
30 #include <vlc/vlc.h>
31 #include <vlc/input.h>
32
33 #ifdef HAVE_UNISTD_H
34 #   include <unistd.h>
35 #endif
36
37 #include <fcntl.h>
38 #include <sys/types.h>
39 #include <sys/stat.h>
40 #include <string.h>
41 #include <errno.h>
42
43 #ifdef STRNCASECMP_IN_STRINGS_H
44 #   include <strings.h>
45 #endif
46
47 #include "dvd.h"
48 #include "iso_lang.h"
49
50 void dvdplay_LaunchDecoders( input_thread_t * p_input );
51
52 /*****************************************************************************
53  * dvdplay_DeleteES:
54  *****************************************************************************/
55 void dvdplay_DeleteES( input_thread_t* p_input )
56 {
57     free( p_input->stream.pp_selected_es );
58
59     p_input->stream.pp_selected_es = NULL;
60     p_input->stream.i_selected_es_number = 0;
61     
62     while( p_input->stream.i_es_number )
63     {
64         input_DelES( p_input, p_input->stream.pp_es[0] );
65     }
66
67     free( p_input->stream.pp_es );
68
69     p_input->stream.pp_es = NULL;
70     p_input->stream.i_es_number = 0;
71
72 }
73
74 #define ADDES( id, fourcc, cat, lang, descr, size )                     \
75     msg_Dbg( p_input, "new es 0x%x", i_id );                            \
76     {                                                                   \
77         char *psz_descr;                                                \
78         psz_descr = malloc( strlen(DecodeLanguage( lang )) +            \
79                             strlen(descr) + 1 );                        \
80         if( psz_descr ) {strcpy( psz_descr, DecodeLanguage( lang ) );   \
81             strcat( psz_descr, descr );}                                \
82         p_es = input_AddES( p_input, NULL, id, cat,                     \
83                             psz_descr, size );                          \
84         if( psz_descr ) free( psz_descr );                              \
85     }                                                                   \
86     p_es->i_stream_id = i_id & 0xff;                                    \
87     p_es->i_fourcc = (fourcc);
88
89 /*****************************************************************************
90  * dvdplay_Video: read video ES
91  *****************************************************************************/
92 void dvdplay_Video( input_thread_t * p_input )
93 {
94     dvd_data_t *            p_dvd;
95     es_descriptor_t *       p_es;
96     video_attr_t *          p_attr;
97     int                     i_id;
98
99     p_dvd = (dvd_data_t*)(p_input->p_access_data);
100     p_attr = dvdplay_video_attr( p_dvd->vmg );
101     
102     /* ES 0 -> video MPEG2 */
103     i_id = 0xe0;
104     
105     if( p_attr->display_aspect_ratio )
106     {
107         ADDES( 0xe0, VLC_FOURCC('m','p','g','v'), VIDEO_ES, 0,
108                "", sizeof(int) );
109         *(int*)(p_es->p_demux_data) = p_attr->display_aspect_ratio;
110     }
111     else
112     {
113         ADDES( 0xe0, VLC_FOURCC('m','p','g','v'), VIDEO_ES, 0, "", 0 );
114     }
115         
116 }
117
118 /*****************************************************************************
119  * dvdplay_Audio: read audio ES
120  *****************************************************************************/
121 void dvdplay_Audio( input_thread_t * p_input )
122 {
123     dvd_data_t *            p_dvd;
124     es_descriptor_t *       p_es;
125     audio_attr_t *          p_attr;
126     int                     i_audio_nr  = -1;
127     int                     i_audio     = -1;
128     int                     i_channels;
129     int                     i_lang;
130     int                     i_id;
131     int                     i;
132
133     p_dvd = (dvd_data_t*)(p_input->p_access_data);
134     p_dvd->i_audio_nb = 0;
135     dvdplay_audio_info( p_dvd->vmg, &i_audio_nr, &i_audio );
136     
137     /* Audio ES, in the order they appear in .ifo */
138     for( i = 1 ; i <= i_audio_nr ; i++ )
139     {
140         if( ( i_id = dvdplay_audio_id( p_dvd->vmg, i-1 ) ) > 0 )
141         {
142             p_attr     = dvdplay_audio_attr( p_dvd->vmg, i-1 );
143             i_channels = p_attr->channels;
144             i_lang     = p_attr->lang_code;
145
146             ++p_dvd->i_audio_nb;
147
148             switch( p_attr->audio_format )
149             {
150             case 0x00:              /* A52 */
151                 ADDES( i_id, VLC_FOURCC('a','5','2','b'), AUDIO_ES, i_lang,
152                        " (A52)", 0 );
153
154                 break;
155             case 0x02:
156             case 0x03:              /* MPEG audio */
157                 ADDES( i_id, VLC_FOURCC('m','p','g','a'), AUDIO_ES, i_lang,
158                        " (mpeg)", 0 );
159
160                 break;
161             case 0x04:              /* LPCM */
162                 ADDES( i_id, VLC_FOURCC('l','p','c','b'), AUDIO_ES, i_lang,
163                        " (lpcm)", 0 );
164
165                 break;
166             case 0x05:              /* SDDS */
167                 ADDES( i_id, VLC_FOURCC('s','d','d','b'), AUDIO_ES, i_lang,
168                        " (sdds)", 0 );
169
170                 break;
171             case 0x06:              /* DTS */
172                 ADDES( i_id, VLC_FOURCC('d','t','s','b'), AUDIO_ES, i_lang,
173                        " (dts)", 0 );
174
175                 break;
176             default:
177                 i_id = 0;
178                 msg_Warn( p_input, "unknown audio type %.2x",
179                              p_attr->audio_format );
180             }
181         }
182     }
183 }
184
185 /*****************************************************************************
186  * dvdplay_Subp: read subpictures ES
187  *****************************************************************************/
188 void dvdplay_Subp( input_thread_t * p_input )
189 {
190     dvd_data_t *            p_dvd;
191     es_descriptor_t *       p_es;
192     subp_attr_t *           p_attr;
193     u32 *                   pi_palette;
194     int                     i_subp_nr   = -1;
195     int                     i_subp      = -1;
196     int                     i_id;
197     int                     i;
198
199     p_dvd = (dvd_data_t*)(p_input->p_access_data);
200     p_dvd->i_spu_nb = 0;
201
202     dvdplay_subp_info( p_dvd->vmg, &i_subp_nr, &i_subp );
203     pi_palette = dvdplay_subp_palette( p_dvd->vmg );
204
205     for( i = 1 ; i <= i_subp_nr; i++ )
206     {
207         if( ( i_id = dvdplay_subp_id( p_dvd->vmg, i-1 ) ) >= 0 )
208         {
209             p_attr = dvdplay_subp_attr( p_dvd->vmg, i-1 );
210             ++p_dvd->i_spu_nb;
211
212             if( pi_palette )
213             {
214                 ADDES( i_id, VLC_FOURCC('s','p','u','b'), SPU_ES,
215                        p_attr->lang_code, "", sizeof(int) + 16*sizeof(u32) );
216                 *(int*)p_es->p_demux_data = 0xBeeF;
217                 memcpy( (void*)p_es->p_demux_data + sizeof(int),
218                         pi_palette, 16*sizeof(u32) ); 
219             }
220             else
221             {
222                 ADDES( i_id, VLC_FOURCC('s','p','u','b'), SPU_ES,
223                        p_attr->lang_code, "", 0 );
224             }
225         }
226     }
227 }
228
229 /*****************************************************************************
230  * dvdplay_LaunchDecoders
231  *****************************************************************************/
232 void dvdplay_LaunchDecoders( input_thread_t * p_input )
233 {
234     dvd_data_t *            p_dvd;
235     int                     i_audio_nr  = -1;
236     int                     i_audio     = -1;
237     int                     i_subp_nr   = -1;
238     int                     i_subp      = -1;
239
240     p_dvd = (dvd_data_t*)(p_input->p_access_data);
241
242     /* For audio: check user settings first, then check dvdplay settings. */
243     i_audio = config_GetInt( p_input, "audio-channel" );
244     if( i_audio <= 0 || i_audio > p_dvd->i_audio_nb )
245     {
246         /* if i_audio = -1 dvdplay_audio_info() will select a default channel,
247          * otherwise it warns libdvdplay that we have chosen another stream. */
248         i_audio = -1;
249     }
250     dvdplay_audio_info( p_dvd->vmg, &i_audio_nr, &i_audio );
251
252     /* For spu: check user settings first, the check dvdplay settings. */
253     i_subp = config_GetInt( p_input, "spu-channel" );
254     if( i_subp <= 0 || i_subp > p_dvd->i_spu_nb )
255     {
256         i_subp = -1;
257     }
258     dvdplay_subp_info( p_dvd->vmg, &i_subp_nr, &i_subp );
259
260     input_SelectES( p_input, p_input->stream.pp_es[0] );
261
262     if( i_audio > p_dvd->i_audio_nb ) i_audio = 1;
263     if( ( i_audio > 0 ) && ( p_dvd->i_audio_nb > 0 ) )
264     {
265         if( config_GetInt( p_input, "audio-type" ) == REQUESTED_A52 )
266         {
267             int     i_a52 = i_audio;
268
269             while( ( i_a52 < p_dvd->i_audio_nb ) &&
270                    ( p_input->stream.pp_es[i_a52]->i_fourcc !=
271                         VLC_FOURCC('a','5','2','b') ) )
272             {
273                 i_a52++;
274             }
275             if( p_input->stream.pp_es[i_a52]->i_fourcc ==
276                     VLC_FOURCC('a','5','2','b') )
277             {
278                 input_SelectES( p_input,
279                                 p_input->stream.pp_es[i_a52] );
280
281                 /* warn libdvdplay that we have chosen another stream */
282                 dvdplay_audio_info( p_dvd->vmg, &i_audio_nr, &i_a52 );
283             }
284             else
285             {
286                 /* none found, select the default one */
287                 input_SelectES( p_input,
288                                 p_input->stream.pp_es[i_audio] );
289             }
290         }
291         else
292         {
293             input_SelectES( p_input,
294                             p_input->stream.pp_es[i_audio] );
295         }
296     }
297
298     if( i_subp > p_dvd->i_spu_nb ) i_subp = -1;
299     if( ( i_subp > 0 ) && ( p_dvd->i_spu_nb > 0 ) )
300     {
301         i_subp += p_dvd->i_audio_nb;
302         input_SelectES( p_input, p_input->stream.pp_es[i_subp] );
303     }
304 }
305
306 /*****************************************************************************
307  * dvdplay_ES:
308  *****************************************************************************/
309 void dvdplay_ES( input_thread_t * p_input )
310 {
311     dvdplay_DeleteES      ( p_input );
312     dvdplay_Video         ( p_input );
313     dvdplay_Audio         ( p_input );
314     dvdplay_Subp          ( p_input );
315     dvdplay_LaunchDecoders( p_input );
316 }
317
318