]> git.sesse.net Git - vlc/blob - modules/access/dvdplay/es.c
caec0ad78e8bbce6fbfc086a7382e22d3ba46c86
[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.5 2003/01/29 11:17:44 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, size )                            \
75     msg_Dbg( p_input, "new es 0x%x", i_id );                            \
76     p_es = input_AddES( p_input, NULL, id, size );                      \
77     p_es->i_stream_id = i_id & 0xff;                                    \
78     p_es->i_fourcc = (fourcc);                                          \
79     p_es->i_cat = (cat);                                                \
80     if( lang )                                                          \
81     {                                                                   \
82         strcpy( p_es->psz_desc, DecodeLanguage( lang ) );               \
83     }
84
85 /*****************************************************************************
86  * dvdplay_Video: read video ES
87  *****************************************************************************/
88 void dvdplay_Video( input_thread_t * p_input )
89 {
90     dvd_data_t *            p_dvd;
91     es_descriptor_t *       p_es;
92     video_attr_t *          p_attr;
93     int                     i_id;
94
95     p_dvd = (dvd_data_t*)(p_input->p_access_data);
96     p_attr = dvdplay_video_attr( p_dvd->vmg );
97     
98     /* ES 0 -> video MPEG2 */
99     i_id = 0xe0;
100     
101     if( p_attr->display_aspect_ratio )
102     {
103         ADDES( 0xe0, VLC_FOURCC('m','p','g','v'), VIDEO_ES, 0, sizeof(int) );
104         *(int*)(p_es->p_demux_data) = p_attr->display_aspect_ratio;
105     }
106     else
107     {
108         ADDES( 0xe0, VLC_FOURCC('m','p','g','v'), VIDEO_ES, 0, 0 );
109     }
110         
111 }
112
113 /*****************************************************************************
114  * dvdplay_Audio: read audio ES
115  *****************************************************************************/
116 void dvdplay_Audio( input_thread_t * p_input )
117 {
118     dvd_data_t *            p_dvd;
119     es_descriptor_t *       p_es;
120     audio_attr_t *          p_attr;
121     int                     i_audio_nr  = -1;
122     int                     i_audio     = -1;
123     int                     i_channels;
124     int                     i_lang;
125     int                     i_id;
126     int                     i;
127
128     p_dvd = (dvd_data_t*)(p_input->p_access_data);
129     p_dvd->i_audio_nb = 0;
130     dvdplay_audio_info( p_dvd->vmg, &i_audio_nr, &i_audio );
131     
132     /* Audio ES, in the order they appear in .ifo */
133     for( i = 1 ; i <= i_audio_nr ; i++ )
134     {
135         if( ( i_id = dvdplay_audio_id( p_dvd->vmg, i-1 ) ) > 0 )
136         {
137             p_attr     = dvdplay_audio_attr( p_dvd->vmg, i-1 );
138             i_channels = p_attr->channels;
139             i_lang     = p_attr->lang_code;
140
141             ++p_dvd->i_audio_nb;
142
143             switch( p_attr->audio_format )
144             {
145             case 0x00:              /* A52 */
146                 ADDES( i_id, VLC_FOURCC('a','5','2','b'), AUDIO_ES, i_lang, 0 );
147                 strcat( p_es->psz_desc, " (A52)" );
148
149                 break;
150             case 0x02:
151             case 0x03:              /* MPEG audio */
152                 ADDES( i_id, VLC_FOURCC('m','p','g','a'), AUDIO_ES, i_lang, 0 );
153                 strcat( p_es->psz_desc, " (mpeg)" );
154
155                 break;
156             case 0x04:              /* LPCM */
157                 ADDES( i_id, VLC_FOURCC('l','p','c','b'), AUDIO_ES, i_lang, 0 );
158                 strcat( p_es->psz_desc, " (lpcm)" );
159
160                 break;
161             case 0x05:              /* SDDS */
162                 ADDES( i_id, VLC_FOURCC('s','d','d','b'), AUDIO_ES, i_lang, 0 );
163                 strcat( p_es->psz_desc, " (sdds)" );
164
165                 break;
166             case 0x06:              /* DTS */
167                 ADDES( i_id, VLC_FOURCC('d','t','s','b'), AUDIO_ES, i_lang, 0 );
168                 strcat( p_es->psz_desc, " (dts)" );
169
170                 break;
171             default:
172                 i_id = 0;
173                 msg_Warn( p_input, "unknown audio type %.2x",
174                              p_attr->audio_format );
175             }
176         }
177     }
178 }
179
180 /*****************************************************************************
181  * dvdplay_Subp: read subpictures ES
182  *****************************************************************************/
183 void dvdplay_Subp( input_thread_t * p_input )
184 {
185     dvd_data_t *            p_dvd;
186     es_descriptor_t *       p_es;
187     subp_attr_t *           p_attr;
188     u32 *                   pi_palette;
189     int                     i_subp_nr   = -1;
190     int                     i_subp      = -1;
191     int                     i_id;
192     int                     i;
193
194     p_dvd = (dvd_data_t*)(p_input->p_access_data);
195     p_dvd->i_spu_nb = 0;
196
197     dvdplay_subp_info( p_dvd->vmg, &i_subp_nr, &i_subp );
198     pi_palette = dvdplay_subp_palette( p_dvd->vmg );
199
200     for( i = 1 ; i <= i_subp_nr; i++ )
201     {
202         if( ( i_id = dvdplay_subp_id( p_dvd->vmg, i-1 ) ) >= 0 )
203         {
204             p_attr = dvdplay_subp_attr( p_dvd->vmg, i-1 );
205             ++p_dvd->i_spu_nb;
206
207             if( pi_palette )
208             {
209                 ADDES( i_id, VLC_FOURCC('s','p','u','b'), SPU_ES,
210                        p_attr->lang_code, sizeof(int) + 16*sizeof(u32) );
211                 *(int*)p_es->p_demux_data = 0xBeeF;
212                 memcpy( (void*)p_es->p_demux_data + sizeof(int),
213                         pi_palette, 16*sizeof(u32) ); 
214             }
215             else
216             {
217                 ADDES( i_id, VLC_FOURCC('s','p','u','b'), SPU_ES,
218                        p_attr->lang_code, 0 );
219             }
220         }
221     }
222 }
223
224 /*****************************************************************************
225  * dvdplay_LaunchDecoders
226  *****************************************************************************/
227 void dvdplay_LaunchDecoders( input_thread_t * p_input )
228 {
229     dvd_data_t *            p_dvd;
230     int                     i_audio_nr  = -1;
231     int                     i_audio     = -1;
232     int                     i_subp_nr   = -1;
233     int                     i_subp      = -1;
234
235     p_dvd = (dvd_data_t*)(p_input->p_access_data);
236
237     /* For audio: check user settings first, then check dvdplay settings. */
238     i_audio = config_GetInt( p_input, "audio-channel" );
239     if( i_audio <= 0 || i_audio > p_dvd->i_audio_nb )
240     {
241         /* if i_audio = -1 dvdplay_audio_info() will select a default channel,
242          * otherwise it warns libdvdplay that we have chosen another stream. */
243         i_audio = -1;
244     }
245     dvdplay_audio_info( p_dvd->vmg, &i_audio_nr, &i_audio );
246
247     /* For spu: check user settings first, the check dvdplay settings. */
248     i_subp = config_GetInt( p_input, "spu-channel" );
249     if( i_subp <= 0 || i_subp > p_dvd->i_spu_nb )
250     {
251         i_subp = -1;
252     }
253     dvdplay_subp_info( p_dvd->vmg, &i_subp_nr, &i_subp );
254
255     input_SelectES( p_input, p_input->stream.pp_es[0] );
256
257     if( i_audio > p_dvd->i_audio_nb ) i_audio = 1;
258     if( ( i_audio > 0 ) && ( p_dvd->i_audio_nb > 0 ) )
259     {
260         if( config_GetInt( p_input, "audio-type" ) == REQUESTED_A52 )
261         {
262             int     i_a52 = i_audio;
263
264             while( ( i_a52 < p_dvd->i_audio_nb ) &&
265                    ( p_input->stream.pp_es[i_a52]->i_fourcc !=
266                         VLC_FOURCC('a','5','2','b') ) )
267             {
268                 i_a52++;
269             }
270             if( p_input->stream.pp_es[i_a52]->i_fourcc ==
271                     VLC_FOURCC('a','5','2','b') )
272             {
273                 input_SelectES( p_input,
274                                 p_input->stream.pp_es[i_a52] );
275
276                 /* warn libdvdplay that we have chosen another stream */
277                 dvdplay_audio_info( p_dvd->vmg, &i_audio_nr, &i_a52 );
278             }
279             else
280             {
281                 /* none found, select the default one */
282                 input_SelectES( p_input,
283                                 p_input->stream.pp_es[i_audio] );
284             }
285         }
286         else
287         {
288             input_SelectES( p_input,
289                             p_input->stream.pp_es[i_audio] );
290         }
291     }
292
293     if( i_subp > p_dvd->i_spu_nb ) i_subp = -1;
294     if( ( i_subp > 0 ) && ( p_dvd->i_spu_nb > 0 ) )
295     {
296         i_subp += p_dvd->i_audio_nb;
297         input_SelectES( p_input, p_input->stream.pp_es[i_subp] );
298     }
299 }
300
301 /*****************************************************************************
302  * dvdplay_ES:
303  *****************************************************************************/
304 void dvdplay_ES( input_thread_t * p_input )
305 {
306     dvdplay_DeleteES      ( p_input );
307     dvdplay_Video         ( p_input );
308     dvdplay_Audio         ( p_input );
309     dvdplay_Subp          ( p_input );
310     dvdplay_LaunchDecoders( p_input );
311 }
312
313