]> git.sesse.net Git - vlc/blob - src/input/input_dvd.c
-CSS support kludged for current DVD input.
[vlc] / src / input / input_dvd.c
1 /*****************************************************************************
2  * input_dvd.c: DVD reading
3  *****************************************************************************
4  * Copyright (C) 1998-2001 VideoLAN
5  * $Id: input_dvd.c,v 1.7 2001/01/29 06:10:10 stef 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 "defs.h"
28
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <unistd.h>
32 #include <netinet/in.h>
33
34 #include <fcntl.h>
35 #include <sys/types.h>
36
37 #include <string.h>
38 #include <errno.h>
39 #include <malloc.h>
40
41 #include <sys/ioctl.h>
42 #ifdef HAVE_SYS_DVDIO_H
43 # include <sys/dvdio.h>
44 #endif
45 #ifdef LINUX_DVD
46 # include <linux/cdrom.h>
47 #endif
48
49 #include "config.h"
50 #include "common.h"
51 #include "threads.h"
52 #include "mtime.h"
53
54 #include "intf_msg.h"
55
56 #include "main.h"
57
58 #include "stream_control.h"
59 #include "input_ext-intf.h"
60 #include "input_ext-dec.h"
61
62 #include "input.h"
63
64 #include "dvd_ifo.h"
65 #include "dvd_css.h"
66 #include "input_dvd.h"
67 #include "mpeg_system.h"
68
69 #include "debug.h"
70
71
72 /*****************************************************************************
73  * Local prototypes
74  *****************************************************************************/
75 static int  DVDProbe    ( struct input_thread_s * );
76 static int  DVDRead     ( struct input_thread_s *,
77                           data_packet_t * p_packets[INPUT_READ_ONCE] );
78 static void DVDInit     ( struct input_thread_s * );
79 static void DVDEnd      ( struct input_thread_s * );
80 /* FIXME : DVDSeek should be on 64 bits ? Is it possible in input ? */
81 static int  DVDSeek     ( struct input_thread_s *, off_t );
82 static int  DVDRewind   ( struct input_thread_s * );
83 static struct data_packet_s * NewPacket ( void *, size_t );
84 static void DeletePacket( void *, struct data_packet_s * );
85 static void DeletePES   ( void *, struct pes_packet_s * );
86
87 /*
88  * Data reading functions
89  */
90
91 /*****************************************************************************
92  * DVDProbe: check the stream
93  *****************************************************************************/
94 static int DVDProbe( input_thread_t * p_input )
95 {
96 #if defined( HAVE_SYS_DVDIO_H ) || defined( LINUX_DVD )
97     dvd_struct dvd;
98
99     dvd.type = DVD_STRUCT_COPYRIGHT;
100     dvd.copyright.layer_num = 0;
101
102     if( ioctl( p_input->i_handle, DVD_READ_STRUCT, &dvd ) < 0 )
103     {
104         intf_ErrMsg( "DVD ioctl error" );
105         return -1;
106     }
107
108     return dvd.copyright.cpst;
109 #else
110     return 0;
111 #endif
112 }
113
114 /*****************************************************************************
115  * DVDInit: initializes DVD structures
116  *****************************************************************************/
117 static void DVDInit( input_thread_t * p_input )
118 {
119     thread_dvd_data_t *  p_method;
120     off64_t              i_start;
121
122     if( (p_method = malloc( sizeof(thread_dvd_data_t) )) == NULL )
123     {
124         intf_ErrMsg( "Out of memory" );
125         p_input->b_error = 1;
126         return;
127     }
128
129     p_input->p_plugin_data = (void *)p_method;
130     p_input->p_method_data = NULL;
131
132     p_method->i_fd = p_input->i_handle;
133
134
135     lseek64( p_input->i_handle, 0, SEEK_SET );
136
137     /* Ifo initialisation */
138     intf_Msg( 3, "Ifo: Initialization" );
139     p_method->ifo = IfoInit( p_input->i_handle );
140     IfoRead( &(p_method->ifo) );
141
142 #if defined( HAVE_SYS_DVDIO_H ) || defined( LINUX_DVD )
143     /* CSS authentication and keys */
144     if( ( p_method->b_encrypted = DVDProbe( p_input ) ) )
145     {
146         int   i;
147
148         intf_Msg( 3, "CSS: Initialization" );
149         p_method->css = CSSInit( p_input->i_handle );
150         p_method->css.i_title_nb = p_method->ifo.vmg.mat.i_tts_nb;
151         if( (p_method->css.p_title_key =
152              malloc( p_method->css.i_title_nb *
153                      sizeof(p_method->css.p_title_key) ) ) == NULL )
154         {
155             intf_ErrMsg( "Out of memory" );
156             p_input->b_error = 1;
157             return;
158         }
159         for( i=0 ; i<p_method->css.i_title_nb ; i++ )
160         {
161             p_method->css.p_title_key[i].i =
162                     p_method->ifo.p_vts[i].i_pos +
163                     p_method->ifo.p_vts[i].mat.i_tt_vobs_ssector *DVD_LB_SIZE;
164         }
165         CSSGetKeys( &(p_method->css) );
166     }
167 #endif
168
169     i_start = p_method->ifo.p_vts[0].i_pos +
170               p_method->ifo.p_vts[0].mat.i_tt_vobs_ssector *DVD_LB_SIZE;
171
172     i_start = lseek64( p_input->i_handle, i_start, SEEK_SET );
173     intf_Msg( "VOB start at : %lld", (long long)i_start );
174
175 #if 1
176     input_InitStream( p_input, sizeof( stream_ps_data_t ) );
177     input_AddProgram( p_input, 0, sizeof( stream_ps_data_t ) );
178
179     if( p_input->stream.b_seekable )
180     {
181         stream_ps_data_t * p_demux_data =
182              (stream_ps_data_t *)p_input->stream.pp_programs[0]->p_demux_data;
183
184         /* Pre-parse the stream to gather stream_descriptor_t. */
185         p_input->stream.pp_programs[0]->b_is_ok = 0;
186         p_demux_data->i_PSM_version = EMPTY_PSM_VERSION;
187
188         while( !p_input->b_die && !p_input->b_error
189                 && !p_demux_data->b_has_PSM )
190         {
191             int                 i_result, i;
192             data_packet_t *     pp_packets[INPUT_READ_ONCE];
193
194             i_result = DVDRead( p_input, pp_packets );
195             if( i_result == 1 )
196             {
197                 /* EOF */
198                 vlc_mutex_lock( &p_input->stream.stream_lock );
199                 p_input->stream.pp_programs[0]->b_is_ok = 1;
200                 vlc_mutex_unlock( &p_input->stream.stream_lock );
201                 break;
202             }
203             if( i_result == -1 )
204             {
205                 p_input->b_error = 1;
206                 break;
207             }
208
209             for( i = 0; i < INPUT_READ_ONCE && pp_packets[i] != NULL; i++ )
210             {
211                 /* FIXME: use i_p_config_t */
212                 input_ParsePS( p_input, pp_packets[i] );
213                 DeletePacket( p_input->p_method_data, pp_packets[i] );
214             }
215
216             /* File too big. */
217             if( p_input->stream.i_tell > INPUT_PREPARSE_LENGTH )
218             {
219                 break;
220             }
221         }
222         lseek64( p_input->i_handle, i_start, SEEK_SET );
223         vlc_mutex_lock( &p_input->stream.stream_lock );
224         p_input->stream.i_tell = 0;
225         if( p_demux_data->b_has_PSM )
226         {
227             /* (The PSM decoder will care about spawning the decoders) */
228             p_input->stream.pp_programs[0]->b_is_ok = 1;
229         }
230 #ifdef AUTO_SPAWN
231         else
232         {
233             /* (We have to do it ourselves) */
234             int                 i_es;
235
236             /* FIXME: we should do multiple passes in case an audio type
237              * is not present */
238             for( i_es = 0;
239                  i_es < p_input->stream.pp_programs[0]->i_es_number;
240                  i_es++ )
241             {
242 #define p_es p_input->stream.pp_programs[0]->pp_es[i_es]
243                 switch( p_es->i_type )
244                 {
245                     case MPEG1_VIDEO_ES:
246                     case MPEG2_VIDEO_ES:
247                         input_SelectES( p_input, p_es );
248                         break;
249
250                     case MPEG1_AUDIO_ES:
251                     case MPEG2_AUDIO_ES:
252                         if( main_GetIntVariable( INPUT_DVD_AUDIO_VAR, 0 )
253                                 == REQUESTED_MPEG 
254                             && main_GetIntVariable( INPUT_DVD_CHANNEL_VAR, 0 )
255                                 == (p_es->i_id & 0x1F) )
256                         {
257                             input_SelectES( p_input, p_es );
258                         }
259                         break;
260
261                     case AC3_AUDIO_ES:
262                         if( main_GetIntVariable( INPUT_DVD_AUDIO_VAR, 0 )
263                                 == REQUESTED_AC3
264                             && main_GetIntVariable( INPUT_DVD_CHANNEL_VAR, 0 )
265                                 == ((p_es->i_id & 0xF00) >> 8) )
266                         {
267                             input_SelectES( p_input, p_es );
268                         }
269                         break;
270
271                     case DVD_SPU_ES:
272                         if( main_GetIntVariable( INPUT_DVD_SUBTITLE_VAR, -1 )
273                                 == ((p_es->i_id & 0x1F00) >> 8) )
274                         {
275                             input_SelectES( p_input, p_es );
276                         }
277                         break;
278
279                     case LPCM_AUDIO_ES:
280                         /* FIXME ! */
281                         break;
282                 }
283             }
284                     
285         }
286 #endif
287 #ifdef STATS
288         input_DumpStream( p_input );
289 #endif
290         vlc_mutex_unlock( &p_input->stream.stream_lock );
291     }
292     else
293     {
294 #endif
295         /* The programs will be added when we read them. */
296         vlc_mutex_lock( &p_input->stream.stream_lock );
297         p_input->stream.pp_programs[0]->b_is_ok = 0;
298         vlc_mutex_unlock( &p_input->stream.stream_lock );
299     }
300 }
301
302 /*****************************************************************************
303  * DVDEnd: frees unused data
304  *****************************************************************************/
305 static void DVDEnd( input_thread_t * p_input )
306 {
307     free( p_input->stream.p_demux_data );
308     free( p_input->p_plugin_data );
309 }
310
311 /*****************************************************************************
312  * SafeRead: reads a chunk of stream and correctly detects errors
313  *****************************************************************************/
314 static __inline__ int SafeRead( input_thread_t * p_input, byte_t * p_buffer,
315                                 size_t i_len )
316 {
317     // FIXME : aie aie ugly kludge for testing purposes :)
318     static byte_t       p_tmp[2048];
319
320
321     thread_dvd_data_t * p_method;
322     int                 i_nb;
323     off64_t             i_pos;
324
325     p_method = (thread_dvd_data_t *)p_input->p_plugin_data;
326     i_pos = lseek64( p_input->i_handle, 0, SEEK_CUR );
327     if( !p_method->b_encrypted )
328     {
329         i_nb = read( p_input->i_handle, p_buffer, i_len );
330     }
331     else
332     {
333         lseek64( p_input->i_handle, i_pos & ~0x7FF, SEEK_SET );
334         i_nb = read( p_input->i_handle, p_tmp, 0x800 );
335         CSSDescrambleSector( p_method->css.p_title_key[0].key, p_tmp );
336         memcpy( p_buffer, p_tmp + (i_pos & 0x7FF ), i_len );
337     }
338     switch( i_nb )
339     {
340         case 0:
341             /* End of File */
342             return( 1 );
343         case -1:
344             intf_ErrMsg( "DVD: Read failed (%s)", strerror(errno) );
345             return( -1 );
346         default:
347             break;
348     }
349     vlc_mutex_lock( &p_input->stream.stream_lock );
350     p_input->stream.i_tell = 
351                 lseek64( p_input->i_handle, i_pos+i_len, SEEK_SET );
352     vlc_mutex_unlock( &p_input->stream.stream_lock );
353     return( 0 );
354 }
355
356 /*****************************************************************************
357  * DVDRead: reads data packets
358  *****************************************************************************
359  * Returns -1 in case of error, 0 if everything went well, and 1 in case of
360  * EOF.
361  *****************************************************************************/
362 static int DVDRead( input_thread_t * p_input,
363                    data_packet_t * pp_packets[INPUT_READ_ONCE] )
364 {
365     byte_t              p_header[6];
366     data_packet_t *     p_data;
367     size_t              i_packet_size;
368     int                 i_packet, i_error;
369     thread_dvd_data_t * p_method;
370
371     p_method = (thread_dvd_data_t *)p_input->p_plugin_data;
372
373     memset( pp_packets, 0, INPUT_READ_ONCE * sizeof(data_packet_t *) );
374     for( i_packet = 0; i_packet < INPUT_READ_ONCE; i_packet++ )
375     {
376         /* Read what we believe to be a packet header. */
377         if( (i_error = SafeRead( p_input, p_header, 6 )) )
378         {
379             return( i_error );
380         }
381
382         if( (U32_AT(p_header) & 0xFFFFFF00) != 0x100L )
383         {
384             /* This is not the startcode of a packet. Read the stream
385              * until we find one. */
386             u32         i_startcode = U32_AT(p_header);
387             int         i_nb;
388             byte_t      i_dummy;
389
390             if( i_startcode )
391             {
392                 /* It is common for MPEG-1 streams to pad with zeros
393                  * (although it is forbidden by the recommendation), so
394                  * don't bother everybody in this case. */
395                 intf_WarnMsg( 1, "Garbage at input (%x)", i_startcode );
396             }
397
398             while( (i_startcode & 0xFFFFFF00) != 0x100L )
399             {
400                 i_startcode <<= 8;
401 fprintf( stderr, "sprotch\n" );
402                 if( (i_nb = SafeRead( p_input, &i_dummy, 1 )) != 0 )
403                 {
404                     i_startcode |= i_dummy;
405                 }
406                 else
407                 {
408                     return( 1 );
409                 }
410             }
411
412             /* Packet found. */
413             *(u32 *)p_header = U32_AT(&i_startcode);
414             if( (i_error = SafeRead( p_input, p_header + 4, 2 )) )
415             {
416                 return( i_error );
417             }
418         }
419
420         if( U32_AT(p_header) != 0x1BA )
421         {
422             /* That's the case for all packets, except pack header. */
423             i_packet_size = U16_AT(&p_header[4]);
424         }
425         else
426         {
427             /* Pack header. */
428             if( (p_header[4] & 0xC0) == 0x40 )
429             {
430                 /* MPEG-2 */
431                 i_packet_size = 8;
432             }
433             else if( (p_header[4] & 0xF0) == 0x20 )
434             {
435                 /* MPEG-1 */
436                 i_packet_size = 6;
437             }
438             else
439             {
440                 intf_ErrMsg( "Unable to determine stream type" );
441                 return( -1 );
442             }
443         }
444
445         /* Fetch a packet of the appropriate size. */
446         if( (p_data = NewPacket( p_input, i_packet_size + 6 )) == NULL )
447         {
448             intf_ErrMsg( "Out of memory" );
449             return( -1 );
450         }
451
452         /* Copy the header we already read. */
453         memcpy( p_data->p_buffer, p_header, 6 );
454
455         /* Read the remaining of the packet. */
456         if( i_packet_size && (i_error =
457                 SafeRead( p_input, p_data->p_buffer + 6, i_packet_size )) )
458         {
459             return( i_error );
460         }
461
462         /* In MPEG-2 pack headers we still have to read stuffing bytes. */
463         if( U32_AT(p_header) == 0x1BA )
464         {
465             if( i_packet_size == 8 && (p_data->p_buffer[13] & 0x7) != 0 )
466             {
467                 /* MPEG-2 stuffing bytes */
468                 byte_t      p_garbage[8];
469                 if( (i_error = SafeRead( p_input, p_garbage,
470                                          p_data->p_buffer[13] & 0x7)) )
471                 {
472                     return( i_error );
473                 }
474             }
475         }
476
477         /* Give the packet to the other input stages. */
478         pp_packets[i_packet] = p_data;
479     }
480
481     return( 0 );
482 }
483
484
485 /*****************************************************************************
486  * DVDRewind : reads a stream backward
487  *****************************************************************************/
488 static int DVDRewind( input_thread_t * p_input )
489 {
490     return( -1 );
491 }
492
493 /*****************************************************************************
494  * DVDSeek : Goes to a given position on the stream ; this one is used by the 
495  * input and translate chronological position from input to logical postion
496  * on the device
497  *****************************************************************************/
498 static int DVDSeek( input_thread_t * p_input, off_t i_off )
499 {
500     return( -1 );
501 }
502
503 /*
504  * Packet management utilities
505  */
506
507 /*****************************************************************************
508  * NewPacket: allocates a data packet
509  *****************************************************************************/
510 static struct data_packet_s * NewPacket( void * p_garbage,
511                                          size_t i_size )
512 {
513     data_packet_t * p_data;
514
515     /* Safety check */
516     if( i_size > INPUT_MAX_PACKET_SIZE )
517     {
518         intf_ErrMsg( "Packet too big (%d)", i_size );
519         return NULL;
520     }
521
522     if( (p_data = (data_packet_t *)malloc( sizeof(data_packet_t) )) == NULL )
523     {
524         intf_DbgMsg( "Out of memory" );
525         return NULL;
526     }
527
528     if( (p_data->p_buffer = (byte_t *)malloc( i_size )) == NULL )
529     {
530         intf_DbgMsg( "Out of memory" );
531         free( p_data );
532         return NULL;
533     }
534
535     /* Initialize data */
536     p_data->p_next = NULL;
537     p_data->b_discard_payload = 0;
538
539     p_data->p_payload_start = p_data->p_buffer;
540     p_data->p_payload_end = p_data->p_buffer + i_size;
541
542     return( p_data );
543 }
544
545 /*****************************************************************************
546  * NewPES: allocates a pes packet
547  *****************************************************************************/
548 static pes_packet_t * NewPES( void * p_garbage )
549 {
550     pes_packet_t * p_pes;
551
552     if( (p_pes = (pes_packet_t *)malloc( sizeof(pes_packet_t) )) == NULL )
553     {
554         intf_DbgMsg( "Out of memory" );
555         return NULL;
556     }
557
558     p_pes->b_messed_up = p_pes->b_data_alignment = p_pes->b_discontinuity =
559         p_pes->i_pts = p_pes->i_dts = 0;
560     p_pes->i_pes_size = 0;
561     p_pes->p_first = NULL;
562
563     return( p_pes );
564 }
565
566 /*****************************************************************************
567  * DeletePacket: deletes a data packet
568  *****************************************************************************/
569 static void DeletePacket( void * p_garbage,
570                           data_packet_t * p_data )
571 {
572     ASSERT(p_data);
573     ASSERT(p_data->p_buffer);
574     free( p_data->p_buffer );
575     free( p_data );
576 }
577
578 /*****************************************************************************
579  * DeletePES: deletes a PES packet and associated data packets
580  *****************************************************************************/
581 static void DeletePES( void * p_garbage, pes_packet_t * p_pes )
582 {
583     data_packet_t *     p_data;
584     data_packet_t *     p_next;
585
586     p_data = p_pes->p_first;
587
588     while( p_data != NULL )
589     {
590         p_next = p_data->p_next;
591         free( p_data->p_buffer );
592         free( p_data );
593         p_data = p_next;
594     }
595
596     free( p_pes );
597 }
598
599 /*****************************************************************************
600  * DVDKludge: fakes a DVD plugin (FIXME)
601  *****************************************************************************/
602 input_capabilities_t * DVDKludge( void )
603 {
604     input_capabilities_t *  p_plugin;
605
606     p_plugin = (input_capabilities_t *)malloc( sizeof(input_capabilities_t) );
607     p_plugin->pf_probe = DVDProbe;
608     p_plugin->pf_init = DVDInit;
609     p_plugin->pf_end = DVDEnd;
610     p_plugin->pf_read = DVDRead;
611     p_plugin->pf_demux = input_DemuxPS; /* FIXME: use i_p_config_t ! */
612     p_plugin->pf_new_packet = NewPacket;
613     p_plugin->pf_new_pes = NewPES;
614     p_plugin->pf_delete_packet = DeletePacket;
615     p_plugin->pf_delete_pes = DeletePES;
616     p_plugin->pf_rewind = DVDRewind;
617     p_plugin->pf_seek = DVDSeek;
618
619     return( p_plugin );
620 }