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.20 2002/06/01 12:31:58 sam 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 *****************************************************************************/
38 #include <vlc/input.h>
45 #include <sys/types.h>
50 #ifdef STRNCASECMP_IN_STRINGS_H
55 # include "dummy_dvdcss.h"
57 # include <dvdcss/dvdcss.h>
64 #include "dvd_summary.h"
67 /*****************************************************************************
69 *****************************************************************************/
71 /* called from outside */
72 static int DVDOpen ( input_thread_t * );
73 static void DVDClose ( input_thread_t * );
74 static int DVDSetArea ( input_thread_t *, input_area_t * );
75 static int DVDSetProgram ( input_thread_t *, pgrm_descriptor_t * );
76 static ssize_t DVDRead ( input_thread_t *, byte_t *, size_t );
77 static void DVDSeek ( input_thread_t *, off_t );
79 static char * DVDParse( input_thread_t * );
81 /*****************************************************************************
82 * Functions exported as capabilities. They are declared as static so that
83 * we don't pollute the namespace too much.
84 *****************************************************************************/
85 void _M( access_getfunctions)( function_list_t * p_function_list )
87 #define input p_function_list->functions.access
88 input.pf_open = DVDOpen;
89 input.pf_close = DVDClose;
90 input.pf_read = DVDRead;
91 input.pf_set_area = DVDSetArea;
92 input.pf_set_program = DVDSetProgram;
93 input.pf_seek = DVDSeek;
98 * Data access functions
101 #define DVDTell LB2OFF( p_dvd->i_vts_start + p_dvd->i_vts_lb ) \
102 - p_input->stream.p_selected_area->i_start
104 /*****************************************************************************
106 *****************************************************************************/
107 static int DVDOpen( input_thread_t *p_input )
110 thread_dvd_data_t * p_dvd;
111 input_area_t * p_area;
114 p_dvd = malloc( sizeof(thread_dvd_data_t) );
117 msg_Err( p_input, "out of memory" );
120 p_input->p_access_data = (void *)p_dvd;
122 /* Parse command line */
123 if( !( psz_device = DVDParse( p_input ) ) )
137 p_dvd->dvdhandle = dvdcss_open( psz_device );
139 /* free allocated string */
142 if( p_dvd->dvdhandle == NULL )
144 msg_Err( p_input, "dvdcss cannot open device" );
149 if( dvdcss_seek( p_dvd->dvdhandle, 0, DVDCSS_NOFLAGS ) < 0 )
151 msg_Err( p_input, "%s", dvdcss_error( p_dvd->dvdhandle ) );
152 dvdcss_close( p_dvd->dvdhandle );
157 /* Ifo allocation & initialisation */
158 if( IfoCreate( p_dvd ) < 0 )
160 msg_Err( p_input, "allcation error in ifo" );
161 dvdcss_close( p_dvd->dvdhandle );
166 if( IfoInit( p_dvd->p_ifo ) < 0 )
168 msg_Err( p_input, "fatal failure in ifo" );
169 IfoDestroy( p_dvd->p_ifo );
170 dvdcss_close( p_dvd->dvdhandle );
175 /* Set stream and area data */
176 vlc_mutex_lock( &p_input->stream.stream_lock );
178 p_input->stream.i_method = INPUT_METHOD_DVD;
179 p_input->stream.b_pace_control = 1;
180 p_input->stream.b_seekable = 1;
181 p_input->stream.p_selected_area->i_size = 0;
182 p_input->stream.p_selected_area->i_tell = 0;
184 /* Initialize ES structures */
185 input_InitStream( p_input, sizeof( stream_ps_data_t ) );
187 #define title_inf p_dvd->p_ifo->vmg.title_inf
188 msg_Dbg( p_input, "number of titles: %d", title_inf.i_title_nb );
190 #define area p_input->stream.pp_areas
191 /* We start from 1 here since the default area 0
192 * is reserved for video_ts.vob */
193 for( i = 1 ; i <= title_inf.i_title_nb ; i++ )
195 input_AddArea( p_input );
197 /* Titles are Program Chains */
200 /* Absolute start offset and size
201 * We can only set that with vts ifo, so we do it during the
202 * first call to DVDSetArea */
203 area[i]->i_start = 0;
206 /* Number of chapters */
207 area[i]->i_part_nb = title_inf.p_attr[i-1].i_chapter_nb;
210 /* Offset to vts_i_0.ifo */
211 area[i]->i_plugin_data = p_dvd->p_ifo->i_start +
212 title_inf.p_attr[i-1].i_start_sector;
216 p_dvd->i_title = p_dvd->i_title <= title_inf.i_title_nb ?
220 p_area = p_input->stream.pp_areas[p_dvd->i_title];
222 p_area->i_part = p_dvd->i_chapter <= p_area->i_part_nb ?
223 p_dvd->i_chapter : 1;
224 p_dvd->i_chapter = 1;
226 p_dvd->b_new_chapter = 0;
227 p_dvd->i_audio_nb = 0;
230 /* set title, chapter, audio and subpic */
231 if( DVDSetArea( p_input, p_area ) < 0 )
233 vlc_mutex_unlock( &p_input->stream.stream_lock );
234 IfoDestroy( p_dvd->p_ifo );
235 dvdcss_close( p_dvd->dvdhandle );
240 vlc_mutex_unlock( &p_input->stream.stream_lock );
242 p_input->psz_demux = "dvd";
247 /*****************************************************************************
248 * DVDClose: close dvd
249 *****************************************************************************/
250 static void DVDClose( input_thread_t *p_input )
252 thread_dvd_data_t *p_dvd = (thread_dvd_data_t*)p_input->p_access_data;
254 IfoDestroy( p_dvd->p_ifo );
255 dvdcss_close( p_dvd->dvdhandle );
259 /*****************************************************************************
260 * DVDSetProgram: used to change angle
261 *****************************************************************************/
262 static int DVDSetProgram( input_thread_t * p_input,
263 pgrm_descriptor_t * p_program )
265 if( p_input->stream.p_selected_program != p_program )
267 thread_dvd_data_t * p_dvd;
270 p_dvd = (thread_dvd_data_t*)(p_input->p_access_data);
271 i_angle = p_program->i_number;
273 /* DVD is actually mono-program: we only need the current angle
274 * number, so copy the data between programs */
276 p_input->stream.p_selected_program,
277 sizeof(pgrm_descriptor_t) );
278 p_program->i_number = i_angle;
279 p_input->stream.p_selected_program = p_program;
282 p_dvd->p_ifo->vts.title_unit.p_title[p_dvd->i_title_id-1].title
283 if( title.p_cell_play[p_dvd->i_prg_cell].i_category & 0xf000 )
285 if( ( p_program->i_number - p_dvd->i_angle ) < 0 )
287 /* we have to go backwards */
288 p_dvd->i_map_cell = 0;
290 p_dvd->i_prg_cell += ( p_program->i_number - p_dvd->i_angle );
291 p_dvd->i_map_cell = CellPrg2Map( p_dvd );
292 p_dvd->i_map_cell += p_dvd->i_angle_cell;
293 p_dvd->i_vts_lb = CellFirstSector( p_dvd );
294 p_dvd->i_last_lb = CellLastSector( p_dvd );
295 p_dvd->i_angle = p_program->i_number;
299 p_dvd->i_angle = p_program->i_number;
302 msg_Dbg( p_input, "angle %d selected", p_dvd->i_angle );
308 /*****************************************************************************
309 * DVDSetArea: initialize input data for title x, chapter y.
310 * It should be called for each user navigation request.
311 *****************************************************************************
312 * Take care that i_title starts from 0 (vmg) and i_chapter start from 1.
313 * Note that you have to take the lock before entering here.
314 *****************************************************************************/
315 #define vmg p_dvd->p_ifo->vmg
316 #define vts p_dvd->p_ifo->vts
318 static void DVDFlushStream( input_thread_t * p_input )
320 if( p_input->stream.pp_programs != NULL )
322 /* We don't use input_EndStream here since
323 * we keep area structures */
324 while( p_input->stream.i_es_number )
326 input_DelES( p_input, p_input->stream.pp_es[0] );
329 while( p_input->stream.i_pgrm_number )
331 input_DelProgram( p_input, p_input->stream.pp_programs[0] );
334 if( p_input->stream.pp_selected_es )
336 free( p_input->stream.pp_selected_es );
337 p_input->stream.pp_selected_es = NULL;
339 p_input->stream.i_selected_es_number = 0;
345 static int DVDReadAngle( input_thread_t * p_input )
347 thread_dvd_data_t * p_dvd;
351 p_dvd = (thread_dvd_data_t*)(p_input->p_access_data);
352 i_angle_nb = vmg.title_inf.p_attr[p_dvd->i_title-1].i_angle_nb;
354 input_AddProgram( p_input, 1, sizeof( stream_ps_data_t ) );
355 p_input->stream.p_selected_program = p_input->stream.pp_programs[0];
357 for( i = 1 ; i < i_angle_nb ; i++ )
359 input_AddProgram( p_input, i+1, 0 );
365 static int DVDSetArea( input_thread_t * p_input, input_area_t * p_area )
367 thread_dvd_data_t * p_dvd;
369 p_dvd = (thread_dvd_data_t*)(p_input->p_access_data);
371 /* we can't use the interface slider until initilization is complete */
372 p_input->stream.b_seekable = 0;
374 if( p_area != p_input->stream.p_selected_area )
380 /* Reset the Chapter position of the old title */
381 p_input->stream.p_selected_area->i_part = 1;
382 p_input->stream.p_selected_area = p_area;
385 * We have to load all title information
388 /* title number as it appears in the interface list */
389 p_dvd->i_title = p_area->i_id;
390 p_dvd->i_chapter_nb = p_area->i_part_nb;
392 if( IfoTitleSet( p_dvd->p_ifo, p_dvd->i_title ) < 0 )
394 msg_Err( p_input, "fatal error in vts ifo" );
399 /* title position inside the selected vts */
400 i_vts_title = vmg.title_inf.p_attr[p_dvd->i_title-1].i_title_num;
402 vts.title_inf.p_title_start[i_vts_title-1].i_title_id;
404 msg_Dbg( p_input, "title %d vts_title %d pgc %d",
405 p_dvd->i_title, i_vts_title, p_dvd->i_title_id );
407 /* title set offset XXX: convert to block values */
409 vts.i_pos + vts.manager_inf.i_title_vob_start_sector;
412 p_dvd->i_prg_cell = -1 +
413 vts.title_unit.p_title[p_dvd->i_title_id-1].title.i_cell_nb;
414 p_dvd->i_map_cell = 0;
415 p_dvd->i_map_cell = CellPrg2Map( p_dvd );
416 i_last = CellLastSector( p_dvd );
419 p_dvd->i_prg_cell = 0;
420 p_dvd->i_map_cell = 0;
421 p_dvd->i_angle_cell = 0;
422 p_dvd->i_map_cell = CellPrg2Map ( p_dvd );
423 p_dvd->i_vts_lb = CellFirstSector( p_dvd );
424 p_dvd->i_last_lb = CellLastSector ( p_dvd );
426 /* Force libdvdcss to check its title key.
427 * It is only useful for title cracking method. Methods using the
428 * decrypted disc key are fast enough to check the key at each seek */
429 i_first = dvdcss_seek( p_dvd->dvdhandle,
430 p_dvd->i_vts_start + p_dvd->i_vts_lb,
434 msg_Err( p_input, "%s", dvdcss_error( p_dvd->dvdhandle ) );
438 /* Area definition */
439 p_input->stream.p_selected_area->i_start = LB2OFF( i_first );
440 p_input->stream.p_selected_area->i_size =
441 LB2OFF( i_last + 1 - p_dvd->i_vts_lb );
443 /* Destroy obsolete ES by reinitializing programs */
444 DVDFlushStream( p_input );
446 /* Angle management: angles are handled through programs */
447 p_dvd->i_angle_nb = DVDReadAngle( p_input );
448 if( ( p_dvd->i_angle <= 0 ) || p_dvd->i_angle > p_dvd->i_angle_nb )
453 DVDSetProgram( p_input,
454 p_input->stream.pp_programs[p_dvd->i_angle-1] );
456 msg_Dbg( p_input, "title first %i, last %i, size %i",
457 i_first, i_last, i_last + 1 - p_dvd->i_vts_lb );
458 IfoPrintTitle( p_dvd );
460 /* No PSM to read in DVD mode, we already have all information */
461 p_input->stream.p_selected_program->b_is_ok = 1;
463 /* Find all ES in title with ifo data */
464 DVDReadVideo( p_input );
465 DVDReadAudio( p_input );
466 DVDReadSPU ( p_input );
468 if( p_input->p_demux_module )
470 DVDLaunchDecoders( p_input );
476 p_area = p_input->stream.p_selected_area;
479 /* Chapter selection */
480 p_dvd->i_chapter = DVDSetChapter( p_dvd, p_area->i_part );
482 p_input->stream.p_selected_area->i_tell = DVDTell;
484 /* warn interface that something has changed */
485 p_input->stream.b_seekable = 1;
486 p_input->stream.b_changed = 1;
494 p_dvd->p_ifo->vts.title_unit.p_title[p_dvd->i_title_id-1].title
496 /*****************************************************************************
497 * DVDRead: reads data packets.
498 *****************************************************************************
499 * Returns -1 in case of error, 0 in case of EOF, otherwise the number of
501 *****************************************************************************/
502 static ssize_t DVDRead( input_thread_t * p_input,
503 byte_t * p_buffer, size_t i_count )
505 thread_dvd_data_t * p_dvd;
508 int i_block_once = 0;
510 p_dvd = (thread_dvd_data_t *)(p_input->p_access_data);
513 i_blocks = OFF2LB(i_count);
517 i_block_once = LbMaxOnce( p_dvd );
518 if( i_block_once > i_blocks )
520 i_block_once = i_blocks;
522 else if( i_block_once <= 0 )
528 if( i_block_once != dvdcss_read( p_dvd->dvdhandle, p_buffer,
529 i_block_once, DVDCSS_READ_DECRYPT ) )
534 i_blocks -= i_block_once;
535 i_read += i_block_once;
536 p_buffer += LB2OFF( i_block_once );
538 /* Update global position */
539 p_dvd->i_vts_lb += i_block_once;
542 vlc_mutex_lock( &p_input->stream.stream_lock );
544 p_input->stream.p_selected_area->i_tell += LB2OFF( i_read );
545 if( p_dvd->b_new_chapter )
547 p_input->stream.p_selected_area->i_part = p_dvd->i_chapter;
548 p_dvd->b_new_chapter = 0;
551 if( ( p_input->stream.p_selected_area->i_tell
552 >= p_input->stream.p_selected_area->i_size )
553 || ( i_block_once <= 0 ) )
555 if( ( p_dvd->i_title + 1 ) >= p_input->stream.i_area_nb )
558 vlc_mutex_unlock( &p_input->stream.stream_lock );
563 msg_Dbg( p_input, "new title" );
565 DVDSetArea( p_input, p_input->stream.pp_areas[p_dvd->i_title] );
568 vlc_mutex_unlock( &p_input->stream.stream_lock );
570 return LB2OFF( i_read );
573 /*****************************************************************************
574 * DVDSeek : Goes to a given position on the stream.
575 *****************************************************************************
576 * This one is used by the input and translate chronological position from
577 * input to logical position on the device.
578 * The lock should be taken before calling this function.
579 *****************************************************************************/
580 static void DVDSeek( input_thread_t * p_input, off_t i_off )
582 thread_dvd_data_t * p_dvd;
584 p_dvd = ( thread_dvd_data_t * )(p_input->p_access_data);
586 vlc_mutex_lock( &p_input->stream.stream_lock );
587 p_dvd->i_vts_lb = OFF2LB(i_off + p_input->stream.p_selected_area->i_start)
588 - p_dvd->i_vts_start;
589 vlc_mutex_unlock( &p_input->stream.stream_lock );
591 p_dvd->i_prg_cell = Lb2CellPrg( p_dvd );
592 p_dvd->i_map_cell = Lb2CellMap( p_dvd );
594 if( CellIsInterleaved( p_dvd ) )
596 /* if we're inside a multi-angle zone, we have to choose i_sector
597 * in the current angle ; we can't do it all the time since cells
598 * can be very wide out of such zones */
599 p_dvd->i_vts_lb = CellFirstSector( p_dvd );
602 p_dvd->i_last_lb = CellLastSector( p_dvd );
603 p_dvd->i_chapter = CellPrg2Chapter( p_dvd );
605 if( dvdcss_seek( p_dvd->dvdhandle, p_dvd->i_vts_start + p_dvd->i_vts_lb,
606 DVDCSS_SEEK_MPEG ) < 0 )
608 msg_Err( p_input, "%s", dvdcss_error( p_dvd->dvdhandle ) );
609 p_input->b_error = 1;
613 vlc_mutex_lock( &p_input->stream.stream_lock );
614 p_input->stream.p_selected_area->i_part = p_dvd->i_chapter;
615 p_input->stream.p_selected_area->i_tell = DVDTell;
616 vlc_mutex_unlock( &p_input->stream.stream_lock );
618 msg_Dbg( p_input, "program cell: %d cell: %d chapter: %d tell %lld",
619 p_dvd->i_prg_cell, p_dvd->i_map_cell, p_dvd->i_chapter, DVDTell );
624 /*****************************************************************************
625 * DVDParse: parse command line
626 *****************************************************************************/
627 static char * DVDParse( input_thread_t * p_input )
629 thread_dvd_data_t * p_dvd;
630 struct stat stat_info;
635 vlc_bool_t b_options = 0;
641 p_dvd = (thread_dvd_data_t*)(p_input->p_access_data);
644 /* On Win32 we want the DVD access plugin to be explicitly requested,
645 * we end up with lots of problems otherwise */
646 if( !p_input->psz_access || !*p_input->psz_access ) return NULL;
649 psz_parser = psz_device = strdup( p_input->psz_name );
655 /* Parse input string :
656 * [device][@rawdevice][@[title][,[chapter][,angle]]] */
657 while( *psz_parser && *psz_parser != '@' )
662 if( *psz_parser == '@' )
664 /* Maybe found raw device or option list */
666 psz_raw = ++psz_parser;
673 if( *psz_parser && !strtol( psz_parser, NULL, 10 ) )
675 /* what we've found is either a raw device or a partial option
676 * list e.g. @,29 or both a device and a list ; search end of string */
677 while( *psz_parser && *psz_parser != '@' )
682 if( *psz_parser == '@' )
684 /* found end of raw device, and beginning of options */
691 psz_parser = psz_raw + 1;
692 for( i=0 ; i<3 ; i++ )
696 /* we have only a raw device */
699 if( strtol( psz_parser, NULL, 10 ) )
701 /* we have only a partial list of options, no device */
702 psz_parser = psz_raw;
713 /* found beginning of options ; no raw device specified */
721 i_title = (int)strtol( psz_parser, &psz_next, 10 );
724 psz_parser = psz_next + 1;
725 i_chapter = (int)strtol( psz_parser, &psz_next, 10 );
728 i_angle = (int)strtol( psz_next + 1, NULL, 10 );
732 p_dvd->i_title = i_title ? i_title : 1;
733 p_dvd->i_chapter = i_chapter ? i_chapter : 1;
734 p_dvd->i_angle = i_angle ? i_angle : 1;
741 /* check the raw device */
742 if( stat( psz_raw, &stat_info ) == -1 )
744 msg_Warn( p_input, "cannot stat() raw device `%s' (%s)",
745 psz_raw, strerror(errno));
747 *(psz_raw - 1) = '@';
755 if( !S_ISCHR(stat_info.st_mode) )
757 msg_Warn( p_input, "raw device %s is"
758 " not a valid char device", psz_raw );
760 *(psz_raw - 1) = '@';
766 psz_env = malloc( strlen("DVDCSS_RAW_DEVICE=")
767 + strlen( psz_raw ) + 1 );
768 sprintf( psz_env, "DVDCSS_RAW_DEVICE=%s", psz_raw );
783 if( !p_input->psz_access )
785 /* no device and no access specified: we probably don't want DVD */
788 psz_device = config_GetPsz( p_input, "dvd" );
792 /* check block device */
793 if( stat( psz_device, &stat_info ) == -1 )
795 msg_Err( p_input, "cannot stat() device `%s' (%s)",
796 psz_device, strerror(errno));
801 if( !S_ISBLK(stat_info.st_mode) && !S_ISCHR(stat_info.st_mode) )
804 "dvd module discarded (not a valid block device)" );
810 msg_Dbg( p_input, "dvd=%s raw=%s title=%d chapter=%d angle=%d",
811 psz_device, psz_raw, p_dvd->i_title,
812 p_dvd->i_chapter, p_dvd->i_angle );