1 /* dvd_access.c: DVD access plugin.
2 *****************************************************************************
3 * This plugins should handle all the known specificities of the DVD format,
4 * especially the 2048 bytes logical block size.
6 * -libdvdcss for access and unscrambling
7 * -dvd_ifo for ifo parsing and analyse
8 * -dvd_udf to find files
9 *****************************************************************************
10 * Copyright (C) 1998-2001 VideoLAN
11 * $Id: dvd_access.c,v 1.3 2002/03/08 22:58:12 stef Exp $
13 * Author: Stéphane Borel <stef@via.ecp.fr>
15 * This program is free software; you can redistribute it and/or modify
16 * it under the terms of the GNU General Public License as published by
17 * the Free Software Foundation; either version 2 of the License, or
18 * (at your option) any later version.
20 * This program is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
25 * You should have received a copy of the GNU General Public License
26 * along with this program; if not, write to the Free Software
27 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
28 *****************************************************************************/
30 /*****************************************************************************
32 *****************************************************************************/
37 #include <videolan/vlc.h>
44 #include <sys/types.h>
49 #ifdef STRNCASECMP_IN_STRINGS_H
54 # include "dummy_dvdcss.h"
56 # include <videolan/dvdcss.h>
59 #include "stream_control.h"
60 #include "input_ext-intf.h"
61 #include "input_ext-dec.h"
62 #include "input_ext-plugins.h"
68 #include "dvd_summary.h"
73 /*****************************************************************************
75 *****************************************************************************/
77 /* called from outside */
78 static int DVDOpen ( struct input_thread_s * );
79 static void DVDClose ( struct input_thread_s * );
80 static int DVDSetArea ( struct input_thread_s *, struct input_area_s * );
81 static int DVDSetProgram ( struct input_thread_s *, pgrm_descriptor_t * );
82 static int DVDRead ( struct input_thread_s *, byte_t *, size_t );
83 static void DVDSeek ( struct input_thread_s *, off_t );
85 static char * DVDParse( input_thread_t * );
87 /*****************************************************************************
88 * Functions exported as capabilities. They are declared as static so that
89 * we don't pollute the namespace too much.
90 *****************************************************************************/
91 void _M( access_getfunctions)( function_list_t * p_function_list )
93 #define input p_function_list->functions.access
94 input.pf_open = DVDOpen;
95 input.pf_close = DVDClose;
96 input.pf_read = DVDRead;
97 input.pf_set_area = DVDSetArea;
98 input.pf_set_program = DVDSetProgram;
99 input.pf_seek = DVDSeek;
104 * Data access functions
107 #define DVDLB p_dvd->i_vts_start + p_dvd->i_vts_lb
108 #define DVDTell LB2OFF( p_dvd->i_vts_start + p_dvd->i_vts_lb ) \
109 - p_input->stream.p_selected_area->i_start
111 /*****************************************************************************
113 *****************************************************************************/
114 static int DVDOpen( struct input_thread_s *p_input )
117 dvdcss_handle dvdhandle;
118 thread_dvd_data_t * p_dvd;
119 input_area_t * p_area;
122 p_dvd = malloc( sizeof(thread_dvd_data_t) );
125 intf_ErrMsg( "dvd error: out of memory" );
128 p_input->p_access_data = (void *)p_dvd;
130 /* Parse command line */
131 if( !( psz_device = DVDParse( p_input ) ) )
145 dvdhandle = dvdcss_open( psz_device );
147 /* free allocated string */
151 if( dvdhandle == NULL )
153 intf_ErrMsg( "dvd error: dvdcss can't open device" );
157 p_dvd->dvdhandle = (dvdcss_handle) dvdhandle;
159 if( dvdcss_seek( p_dvd->dvdhandle, 0, DVDCSS_NOFLAGS ) < 0 )
161 intf_ErrMsg( "dvd error: %s", dvdcss_error( p_dvd->dvdhandle ) );
165 /* Ifo allocation & initialisation */
166 if( IfoCreate( p_dvd ) < 0 )
168 intf_ErrMsg( "dvd error: allcation error in ifo" );
173 if( IfoInit( p_dvd->p_ifo ) < 0 )
175 intf_ErrMsg( "dvd error: fatal failure in ifo" );
176 IfoDestroy( p_dvd->p_ifo );
181 /* Set stream and area data */
182 vlc_mutex_lock( &p_input->stream.stream_lock );
184 p_input->stream.i_method = INPUT_METHOD_DVD;
185 p_input->stream.b_pace_control = 1;
186 p_input->stream.b_seekable = 1;
187 p_input->stream.p_selected_area->i_size = 0;
188 p_input->stream.p_selected_area->i_tell = 0;
190 /* Initialize ES structures */
191 input_InitStream( p_input, sizeof( stream_ps_data_t ) );
193 #define title_inf p_dvd->p_ifo->vmg.title_inf
194 intf_WarnMsg( 3, "dvd info: number of titles: %d", title_inf.i_title_nb );
196 #define area p_input->stream.pp_areas
197 /* We start from 1 here since the default area 0
198 * is reserved for video_ts.vob */
199 for( i = 1 ; i <= title_inf.i_title_nb ; i++ )
201 input_AddArea( p_input );
203 /* Titles are Program Chains */
206 /* Absolute start offset and size
207 * We can only set that with vts ifo, so we do it during the
208 * first call to DVDSetArea */
209 area[i]->i_start = 0;
212 /* Number of chapters */
213 area[i]->i_part_nb = title_inf.p_attr[i-1].i_chapter_nb;
216 /* Offset to vts_i_0.ifo */
217 area[i]->i_plugin_data = p_dvd->p_ifo->i_start +
218 title_inf.p_attr[i-1].i_start_sector;
222 p_dvd->i_title = p_dvd->i_title <= title_inf.i_title_nb ?
226 p_area = p_input->stream.pp_areas[p_dvd->i_title];
228 p_dvd->i_chapter = p_dvd->i_chapter <= p_area->i_part_nb ?
229 p_dvd->i_chapter : 1;
230 p_area->i_part = p_dvd->i_chapter;
232 p_dvd->b_new_chapter = 0;
233 p_dvd->i_audio_nb = 0;
236 /* set title, chapter, audio and subpic */
237 if( DVDSetArea( p_input, p_area ) < 0 )
239 vlc_mutex_unlock( &p_input->stream.stream_lock );
243 vlc_mutex_unlock( &p_input->stream.stream_lock );
245 p_input->psz_demux = "dvd";
250 /*****************************************************************************
251 * DVDClose: close dvd
252 *****************************************************************************/
253 static void DVDClose( struct input_thread_s *p_input )
255 thread_dvd_data_t * p_dvd;
257 p_dvd = (thread_dvd_data_t*)p_input->p_access_data;
259 IfoDestroy( p_dvd->p_ifo );
261 p_input->p_access_data = (void *)(p_dvd->dvdhandle);
264 /* Clean up libdvdcss */
265 dvdcss_close( (dvdcss_handle) p_input->p_access_data );
268 /*****************************************************************************
269 * DVDSetProgram: used to change angle
270 *****************************************************************************/
271 static int DVDSetProgram( input_thread_t * p_input,
272 pgrm_descriptor_t * p_program )
274 if( p_input->stream.p_selected_program != p_program )
276 thread_dvd_data_t * p_dvd;
279 p_dvd = (thread_dvd_data_t*)(p_input->p_access_data);
280 i_angle = p_program->i_number;
282 /* DVD is actually mono-program: we only need the current angle
283 * number, so copy the data between programs */
285 p_input->stream.p_selected_program,
286 sizeof(pgrm_descriptor_t) );
287 p_program->i_number = i_angle;
288 p_input->stream.p_selected_program = p_program;
291 p_dvd->p_ifo->vts.title_unit.p_title[p_dvd->i_title_id-1].title
292 if( title.p_cell_play[p_dvd->i_prg_cell].i_category & 0xf000 )
294 if( ( p_program->i_number - p_dvd->i_angle ) < 0 )
296 /* we have to go backwards */
297 p_dvd->i_map_cell = 0;
299 p_dvd->i_prg_cell += ( p_program->i_number - p_dvd->i_angle );
300 p_dvd->i_map_cell = CellPrg2Map( p_dvd );
301 p_dvd->i_map_cell += p_dvd->i_angle_cell;
302 p_dvd->i_vts_lb = CellStartSector( p_dvd );
303 p_dvd->i_end_lb = CellEndSector( p_dvd );
304 p_dvd->i_angle = p_program->i_number;
308 p_dvd->i_angle = p_program->i_number;
311 intf_WarnMsg( 3, "dvd info: angle %d selected", p_dvd->i_angle );
317 /*****************************************************************************
318 * DVDSetArea: initialize input data for title x, chapter y.
319 * It should be called for each user navigation request.
320 *****************************************************************************
321 * Take care that i_title starts from 0 (vmg) and i_chapter start from 1.
322 * Note that you have to take the lock before entering here.
323 *****************************************************************************/
324 #define vmg p_dvd->p_ifo->vmg
325 #define vts p_dvd->p_ifo->vts
327 static void DVDFlushStream( input_thread_t * p_input )
329 if( p_input->stream.pp_programs != NULL )
331 /* We don't use input_EndStream here since
332 * we keep area structures */
333 while( p_input->stream.i_es_number )
335 input_DelES( p_input, p_input->stream.pp_es[0] );
338 while( p_input->stream.i_pgrm_number )
340 input_DelProgram( p_input, p_input->stream.pp_programs[0] );
343 if( p_input->stream.pp_selected_es )
345 free( p_input->stream.pp_selected_es );
346 p_input->stream.pp_selected_es = NULL;
348 p_input->stream.i_selected_es_number = 0;
354 static int DVDReadAngle( input_thread_t * p_input )
356 thread_dvd_data_t * p_dvd;
360 p_dvd = (thread_dvd_data_t*)(p_input->p_access_data);
361 i_angle_nb = vmg.title_inf.p_attr[p_dvd->i_title-1].i_angle_nb;
363 input_AddProgram( p_input, 1, sizeof( stream_ps_data_t ) );
364 p_input->stream.p_selected_program = p_input->stream.pp_programs[0];
366 for( i = 1 ; i < i_angle_nb ; i++ )
368 input_AddProgram( p_input, i+1, 0 );
374 static int DVDSetArea( input_thread_t * p_input, input_area_t * p_area )
376 thread_dvd_data_t * p_dvd;
378 p_dvd = (thread_dvd_data_t*)(p_input->p_access_data);
380 /* we can't use the interface slider until initilization is complete */
381 p_input->stream.b_seekable = 0;
383 if( p_area != p_input->stream.p_selected_area )
389 /* Reset the Chapter position of the old title */
390 p_input->stream.p_selected_area->i_part = 1;
391 p_input->stream.p_selected_area = p_area;
394 * We have to load all title information
397 /* title number as it appears in the interface list */
398 p_dvd->i_title = p_area->i_id;
399 p_dvd->i_chapter_nb = p_area->i_part_nb;
401 if( IfoTitleSet( p_dvd->p_ifo, p_dvd->i_title ) < 0 )
403 intf_ErrMsg( "dvd error: fatal error in vts ifo" );
408 /* title position inside the selected vts */
409 i_vts_title = vmg.title_inf.p_attr[p_dvd->i_title-1].i_title_num;
411 vts.title_inf.p_title_start[i_vts_title-1].i_title_id;
413 intf_WarnMsg( 3, "dvd: title %d vts_title %d pgc %d",
414 p_dvd->i_title, i_vts_title, p_dvd->i_title_id );
416 /* title set offset XXX: convert to block values */
418 vts.i_pos + vts.manager_inf.i_title_vob_start_sector;
421 intf_WarnMsg( 4, "prg_cell nb %d", vts.title_unit.p_title[p_dvd->i_title_id-1].title.i_cell_nb );
422 p_dvd->i_prg_cell = -1 +
423 vts.title_unit.p_title[p_dvd->i_title_id-1].title.i_cell_nb;
424 p_dvd->i_map_cell = 0;
425 p_dvd->i_map_cell = CellPrg2Map( p_dvd );
426 i_size = CellEndSector( p_dvd );
429 p_dvd->i_prg_cell = 0;
430 p_dvd->i_map_cell = 0;
431 p_dvd->i_map_cell = CellPrg2Map ( p_dvd );
432 p_dvd->i_vts_lb = CellStartSector( p_dvd );
433 p_dvd->i_end_lb = CellEndSector ( p_dvd );
435 /* Force libdvdcss to check its title key.
436 * It is only useful for title cracking method. Methods using the
437 * decrypted disc key are fast enough to check the key at each seek */
438 if( ( i_start = dvdcss_seek( p_dvd->dvdhandle, DVDLB,
439 DVDCSS_SEEK_KEY ) ) < 0 )
441 intf_ErrMsg( "dvd error: %s", dvdcss_error( p_dvd->dvdhandle ) );
445 i_size -= p_dvd->i_vts_lb + 1;
447 /* Area definition */
448 p_input->stream.p_selected_area->i_start = LB2OFF( i_start );
449 p_input->stream.p_selected_area->i_size = LB2OFF( i_size );
451 /* Destroy obsolete ES by reinitializing programs */
452 DVDFlushStream( p_input );
454 /* Angle management: angles are handled through programs */
455 p_dvd->i_angle_nb = DVDReadAngle( p_input );
456 if( ( p_dvd->i_angle <= 0 ) || p_dvd->i_angle > p_dvd->i_angle_nb )
461 DVDSetProgram( p_input,
462 p_input->stream.pp_programs[p_dvd->i_angle-1] );
464 intf_WarnMsg( 3, "dvd info: title start: %d size: %d",
466 IfoPrintTitle( p_dvd );
468 /* No PSM to read in DVD mode, we already have all information */
469 p_input->stream.p_selected_program->b_is_ok = 1;
471 /* Find all ES in title with ifo data */
472 DVDReadVideo( p_input );
473 DVDReadAudio( p_input );
474 DVDReadSPU ( p_input );
476 if( p_input->p_demux_module )
478 DVDLaunchDecoders( p_input );
484 p_area = p_input->stream.p_selected_area;
487 /* Chapter selection */
488 p_dvd->i_chapter = DVDSetChapter( p_dvd, p_area->i_part );
490 p_input->stream.p_selected_area->i_tell = DVDTell;
492 /* warn interface that something has changed */
493 p_input->stream.b_seekable = 1;
494 p_input->stream.b_changed = 1;
502 p_dvd->p_ifo->vts.title_unit.p_title[p_dvd->i_title_id-1].title
504 /*****************************************************************************
505 * DVDRead: reads data packets.
506 *****************************************************************************
507 * Returns -1 in case of error, 0 in case of EOF, otherwise the number of
509 *****************************************************************************/
510 static int DVDRead( input_thread_t * p_input,
511 byte_t * p_buffer, size_t i_count )
513 thread_dvd_data_t * p_dvd;
516 int i_block_once = 0;
518 p_dvd = (thread_dvd_data_t *)(p_input->p_access_data);
521 i_blocks = OFF2LB(i_count);
525 if( ( i_block_once = __MIN( LbMaxOnce( p_dvd ), i_blocks ) ) <= 0 )
531 if( i_block_once != dvdcss_read( p_dvd->dvdhandle, p_buffer,
532 i_block_once, DVDCSS_READ_DECRYPT ) )
537 i_blocks -= i_block_once;
538 i_read += i_block_once;
539 p_buffer += LB2OFF( i_block_once );
541 /* Update global position */
542 p_dvd->i_vts_lb += i_block_once;
545 vlc_mutex_lock( &p_input->stream.stream_lock );
547 p_input->stream.p_selected_area->i_tell += LB2OFF( i_read );
548 if( p_dvd->b_new_chapter )
550 p_input->stream.p_selected_area->i_part = p_dvd->i_chapter;
551 p_dvd->b_new_chapter = 0;
554 if( ( p_input->stream.p_selected_area->i_tell
555 >= p_input->stream.p_selected_area->i_size )
556 || ( i_block_once < 0 ) )
558 if( ( p_dvd->i_title + 1 ) >= p_input->stream.i_area_nb )
561 vlc_mutex_unlock( &p_input->stream.stream_lock );
566 intf_WarnMsg( 4, "dvd info: new title" );
568 DVDSetArea( p_input, p_input->stream.pp_areas[p_dvd->i_title] );
571 vlc_mutex_unlock( &p_input->stream.stream_lock );
573 return LB2OFF( i_read );
576 /*****************************************************************************
577 * DVDSeek : Goes to a given position on the stream.
578 *****************************************************************************
579 * This one is used by the input and translate chronological position from
580 * input to logical position on the device.
581 * The lock should be taken before calling this function.
582 *****************************************************************************/
583 static void DVDSeek( input_thread_t * p_input, off_t i_off )
585 thread_dvd_data_t * p_dvd;
587 p_dvd = ( thread_dvd_data_t * )(p_input->p_access_data);
589 vlc_mutex_lock( &p_input->stream.stream_lock );
590 p_dvd->i_vts_lb = OFF2LB(i_off + p_input->stream.p_selected_area->i_start)
591 - p_dvd->i_vts_start;
592 vlc_mutex_unlock( &p_input->stream.stream_lock );
594 p_dvd->i_prg_cell = Lb2CellPrg( p_dvd );
595 p_dvd->i_map_cell = Lb2CellMap( p_dvd );
597 if( CellIsInterleaved( p_dvd ) )
599 /* if we're inside a multi-angle zone, we have to choose i_sector
600 * in the current angle ; we can't do it all the time since cells
601 * can be very wide out of such zones */
602 p_dvd->i_vts_lb = CellStartSector( p_dvd );
605 p_dvd->i_end_lb = CellEndSector ( p_dvd );
606 p_dvd->i_chapter = CellPrg2Chapter( p_dvd );
608 if( dvdcss_seek( p_dvd->dvdhandle, DVDLB,
609 DVDCSS_SEEK_MPEG ) < 0 )
611 intf_ErrMsg( "dvd error: %s", dvdcss_error( p_dvd->dvdhandle ) );
612 p_input->b_error = 1;
616 vlc_mutex_lock( &p_input->stream.stream_lock );
617 p_input->stream.p_selected_area->i_part = p_dvd->i_chapter;
618 p_input->stream.p_selected_area->i_tell = DVDTell;
619 vlc_mutex_unlock( &p_input->stream.stream_lock );
621 intf_WarnMsg( 4, "Program Cell: %d Cell: %d Chapter: %d tell %lld",
622 p_dvd->i_prg_cell, p_dvd->i_map_cell, p_dvd->i_chapter, DVDTell );
627 /*****************************************************************************
628 * DVDParse: parse command line
629 *****************************************************************************/
630 static char * DVDParse( input_thread_t * p_input )
632 thread_dvd_data_t * p_dvd;
633 struct stat stat_info;
638 boolean_t b_options = 0;
644 p_dvd = (thread_dvd_data_t*)(p_input->p_access_data);
646 psz_parser = psz_device = strdup( p_input->psz_name );
652 /* Parse input string :
653 * [device][@rawdevice][@[title][,[chapter][,angle]]] */
654 while( *psz_parser && *psz_parser != '@' )
659 if( *psz_parser == '@' )
661 /* Maybe found raw device or option list */
663 psz_raw = ++psz_parser;
670 if( *psz_parser && !strtol( psz_parser, NULL, 10 ) )
672 /* what we've found is either a raw device or a partial option
673 * list e.g. @,29 or both a device and a list ; search end of string */
674 while( *psz_parser && *psz_parser != '@' )
679 if( *psz_parser == '@' )
681 /* found end of raw device, and beginning of options */
688 psz_parser = psz_raw + 1;
689 for( i=0 ; i<3 ; i++ )
693 /* we have only a raw device */
696 if( strtol( psz_parser, NULL, 10 ) )
698 /* we have only a partial list of options, no device */
699 psz_parser = psz_raw;
710 /* found beginning of options ; no raw device specified */
718 i_title = (int)strtol( psz_parser, &psz_next, 10 );
721 psz_parser = psz_next + 1;
722 i_chapter = (int)strtol( psz_parser, &psz_next, 10 );
725 i_angle = (int)strtol( psz_next + 1, NULL, 10 );
729 p_dvd->i_title = i_title ? i_title : 1;
730 p_dvd->i_chapter = i_chapter ? i_chapter : 1;
731 p_dvd->i_angle = i_angle ? i_angle : 1;
738 /* check the raw device */
739 if( stat( psz_raw, &stat_info ) == -1 )
741 intf_WarnMsg( 3, "dvd warning: cannot stat() raw"
743 psz_raw, strerror(errno));
745 *(psz_raw - 1) = '@';
753 if( !S_ISCHR(stat_info.st_mode) )
755 intf_WarnMsg( 3, "dvd warning: raw device %s is"
756 " not a valid char device", psz_raw );
758 *(psz_raw - 1) = '@';
764 psz_env = malloc( strlen("DVDCSS_RAW_DEVICE=")
765 + strlen( psz_raw ) + 1 );
766 sprintf( psz_env, "DVDCSS_RAW_DEVICE=%s", psz_raw );
781 if( !p_input->psz_access )
783 /* no device and no access specified: we probably don't want DVD */
786 psz_device = config_GetPszVariable( INPUT_DVD_DEVICE_VAR );
789 /* check block device */
790 if( stat( psz_device, &stat_info ) == -1 )
792 intf_ErrMsg( "input error: cannot stat() device `%s' (%s)",
793 psz_device, strerror(errno));
798 if( !S_ISBLK(stat_info.st_mode) && !S_ISCHR(stat_info.st_mode) )
800 intf_WarnMsg( 3, "input: DVD plugin discarded"
801 " (not a valid block device)" );
806 intf_WarnMsg( 2, "input: dvd=%s raw=%s title=%d chapter=%d angle=%d",
807 psz_device, psz_raw, p_dvd->i_title,
808 p_dvd->i_chapter, p_dvd->i_angle );