]> git.sesse.net Git - vlc/blob - modules/access/dvd/es.c
3d544442c335cf70b62a77d1fd5682647910045c
[vlc] / modules / access / dvd / es.c
1 /* es.c: functions to find and select ES
2  *****************************************************************************
3  * Copyright (C) 1998-2001 VideoLAN
4  * $Id: es.c,v 1.6 2003/10/25 00:49:13 sam Exp $
5  *
6  * Author: Stéphane Borel <stef@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 <stdio.h>
27 #include <stdlib.h>
28 #include <string.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 #ifdef GOD_DAMN_DMCA
48 #   include "dvdcss.h"
49 #else
50 #   include <dvdcss/dvdcss.h>
51 #endif
52
53 #include "dvd.h"
54 #include "ifo.h"
55 #include "summary.h"
56 #include "iso_lang.h"
57
58 /*****************************************************************************
59  * Local prototypes
60  *****************************************************************************/
61
62 void DVDLaunchDecoders( input_thread_t * p_input );
63
64 #define vmg p_dvd->p_ifo->vmg
65 #define vts p_dvd->p_ifo->vts
66
67 #define ADDES( stream_id, private_id, fourcc, cat, lang, descr, size )  \
68     i_id = ( (private_id) << 8 ) | (stream_id);                         \
69     {                                                                   \
70         char *psz_descr;                                                \
71         psz_descr = malloc( strlen(DecodeLanguage( lang )) +            \
72                             strlen(descr) + 1 );                        \
73         if( psz_descr ) {strcpy( psz_descr, DecodeLanguage( lang ) );   \
74             strcat( psz_descr, descr );}                                \
75         p_es = input_AddES( p_input, NULL, i_id, cat,                   \
76                             psz_descr, size );                          \
77         if( psz_descr ) free( psz_descr );                              \
78     }                                                                   \
79     p_es->i_stream_id = (stream_id);                                    \
80     p_es->i_fourcc = (fourcc);
81
82
83 /*****************************************************************************
84  * DVDReadVideo: read video ES
85  *****************************************************************************/
86 void DVDReadVideo( input_thread_t * p_input )
87 {
88     thread_dvd_data_t * p_dvd;
89     es_descriptor_t *   p_es;
90     int                 i_id;
91     int                 i_ratio;
92
93     p_dvd = (thread_dvd_data_t*)(p_input->p_access_data);
94
95     /* ES 0 -> video MPEG2 */
96     IfoPrintVideo( p_dvd );
97     i_ratio = vts.manager_inf.video_attr.i_ratio;
98
99     if( i_ratio )
100     {
101         ADDES( 0xe0, 0, VLC_FOURCC('m','p','g','v'), VIDEO_ES, 0,
102                "", sizeof(int) );
103         *(int*)(p_es->p_demux_data) = i_ratio;
104     }
105     else
106     {
107         ADDES( 0xe0, 0, VLC_FOURCC('m','p','g','v'), VIDEO_ES, 0, "", 0 );
108     }
109
110 }
111
112 /*****************************************************************************
113  * DVDReadAudio: read audio ES
114  *****************************************************************************/
115 #define audio_status \
116     vts.title_unit.p_title[p_dvd->i_title_id-1].title.pi_audio_status[i-1]
117
118 void DVDReadAudio( input_thread_t * p_input )
119 {
120     thread_dvd_data_t * p_dvd;
121     es_descriptor_t *   p_es;
122     int                 i_lang;
123     int                 i_id;
124     int                 i;
125
126     p_dvd = (thread_dvd_data_t*)(p_input->p_access_data);
127     p_dvd->i_audio_nb = 0;
128
129     /* Audio ES, in the order they appear in .ifo */
130     for( i = 1 ; i <= vts.manager_inf.i_audio_nb ; i++ )
131     {
132         IfoPrintAudio( p_dvd, i );
133
134         /* audio channel is active if first byte is 0x80 */
135         if( audio_status.i_available )
136         {
137             p_dvd->i_audio_nb++;
138             i_lang = vts.manager_inf.p_audio_attr[i-1].i_lang_code;
139             i_id = audio_status.i_position;
140
141             switch( vts.manager_inf.p_audio_attr[i-1].i_coding_mode )
142             {
143             case 0x00:              /* A52 */
144                 ADDES( 0xbd, 0x80 + audio_status.i_position,
145                        VLC_FOURCC('a','5','2','b'), AUDIO_ES, i_lang,
146                        " (A52)", 0 );
147
148                 break;
149             case 0x02:
150             case 0x03:              /* MPEG audio */
151                 ADDES( 0xc0 + audio_status.i_position, 0,
152                        VLC_FOURCC('m','p','g','a'), AUDIO_ES, i_lang,
153                        " (mpeg)", 0 );
154
155                 break;
156             case 0x04:              /* LPCM */
157                 ADDES( 0xbd, 0xa0 + audio_status.i_position,
158                        VLC_FOURCC('l','p','c','b'), AUDIO_ES, i_lang,
159                        " (lpcm)", 0 );
160
161                 break;
162             case 0x06:              /* DTS */
163                 ADDES( 0xbd, 0x88 + audio_status.i_position,
164                        VLC_FOURCC('d','t','s','b'), AUDIO_ES, i_lang,
165                        " (dts)", 0 );
166
167                 break;
168             default:
169                 i_id = 0;
170                 msg_Err( p_input, "unknown audio type %.2x",
171                          vts.manager_inf.p_audio_attr[i-1].i_coding_mode );
172             }
173         }
174     }
175 }
176 #undef audio_status
177
178 /*****************************************************************************
179  * DVDReadSPU: read subpictures ES
180  *****************************************************************************/
181 #define spu_status \
182     vts.title_unit.p_title[p_dvd->i_title_id-1].title.pi_spu_status[i-1]
183 #define palette \
184     vts.title_unit.p_title[p_dvd->i_title_id-1].title.pi_yuv_color
185
186 void DVDReadSPU( input_thread_t * p_input )
187 {
188     thread_dvd_data_t * p_dvd;
189     es_descriptor_t *   p_es;
190     int                 i_id;
191     int                 i;
192
193     p_dvd = (thread_dvd_data_t*)(p_input->p_access_data);
194     p_dvd->i_spu_nb = 0;
195
196     for( i = 1 ; i <= vts.manager_inf.i_spu_nb; i++ )
197     {
198         IfoPrintSpu( p_dvd, i );
199
200         if( spu_status.i_available )
201         {
202             p_dvd->i_spu_nb++;
203
204             /*  there are several streams for one spu */
205             if(  vts.manager_inf.video_attr.i_ratio )
206             {
207                 /* 16:9 */
208                 switch( vts.manager_inf.video_attr.i_perm_displ )
209                 {
210                 case 1:
211                     i_id = spu_status.i_position_pan;
212                     break;
213                 case 2:
214                     i_id = spu_status.i_position_letter;
215                     break;
216                 default:
217                     i_id = spu_status.i_position_wide;
218                     break;
219                 }
220             }
221             else
222             {
223                 /* 4:3 */
224                 i_id = spu_status.i_position_43;
225             }
226
227             if( vmg.title.pi_yuv_color )
228             {
229                 ADDES( 0xbd, 0x20 + i_id, VLC_FOURCC('s','p','u','b'), SPU_ES,
230                        vts.manager_inf.p_spu_attr[i-1].i_lang_code, "",
231                        sizeof(int) + 16*sizeof(uint32_t) );
232                 *(int*)p_es->p_demux_data = 0xBeeF;
233                 memcpy( (char*)p_es->p_demux_data + sizeof(int),
234                         palette, 16*sizeof(uint32_t) );
235             }
236             else
237             {
238                 ADDES( 0xbd, 0x20 + i_id, VLC_FOURCC('s','p','u','b'), SPU_ES,
239                    vts.manager_inf.p_spu_attr[i-1].i_lang_code, "", 0 );
240             }
241         }
242     }
243 }
244 #undef palette
245 #undef spu_status
246
247 #undef vts
248 #undef vmg
249
250 /*****************************************************************************
251  * DVDLaunchDecoders: select ES for video, audio and spu
252  *****************************************************************************/
253 void DVDLaunchDecoders( input_thread_t * p_input )
254 {
255     thread_dvd_data_t *  p_dvd;
256     unsigned int         i_audio;
257     unsigned int         i_spu;
258
259     p_dvd = (thread_dvd_data_t*)(p_input->p_access_data);
260
261     /* Select Video stream (always 0) */
262     input_SelectES( p_input, p_input->stream.pp_es[0] );
263
264     /* Select audio stream */
265     if( p_dvd->i_audio_nb > 0 )
266     {
267         /* For audio: first one if none or a not existing one specified */
268         i_audio = config_GetInt( p_input, "audio-channel" );
269         if( i_audio <= 0 || i_audio > p_dvd->i_audio_nb )
270         {
271             config_PutInt( p_input, "audio-channel", 1 );
272             i_audio = 1;
273         }
274
275         if( ( config_GetInt( p_input, "audio-type" )
276                == REQUESTED_A52 ) )
277         {
278             int     i_a52 = i_audio;
279             while( ( p_input->stream.pp_es[i_a52]->i_fourcc !=
280                      VLC_FOURCC('a','5','2','b') ) && ( i_a52 <=
281                      p_dvd->p_ifo->vts.manager_inf.i_audio_nb ) )
282             {
283                 i_a52++;
284             }
285             if( p_input->stream.pp_es[i_a52]->i_fourcc
286                  == VLC_FOURCC('a','5','2','b') )
287             {
288                 input_SelectES( p_input,
289                                 p_input->stream.pp_es[i_a52] );
290             }
291         }
292         else
293         {
294             input_SelectES( p_input,
295                             p_input->stream.pp_es[i_audio] );
296         }
297     }
298
299     /* Select subtitle */
300     if( p_dvd->i_spu_nb )
301     {
302         /* for spu, default is none */
303         i_spu = config_GetInt( p_input, "spu-channel" );
304         if( i_spu < 0 || i_spu > p_dvd->i_spu_nb )
305         {
306             config_PutInt( p_input, "spu-channel", 0 );
307             i_spu = 0;
308         }
309         if( i_spu > 0 )
310         {
311             unsigned int i = 0, j = 0;
312             for( i = 0; i < p_input->stream.i_es_number; i++ )
313             {
314                 if ( p_input->stream.pp_es[i]->i_fourcc
315                       == VLC_FOURCC('s','p','u','b') )
316                 {
317                     j++;
318                     if ( i_spu == j ) break;
319                 }
320             }
321             if( i_spu == j )
322             {
323                 input_SelectES( p_input, p_input->stream.pp_es[i] );
324             }
325         }
326     }
327 }