1 /* 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 * -ifo.* for ifo parsing and analyse
9 *****************************************************************************
10 * Copyright (C) 1998-2001 VideoLAN
11 * $Id: access.c,v 1.11 2003/03/11 23:56:53 gbazin 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>
40 #include "../../demux/mpeg/system.h"
47 #include <sys/types.h>
52 #ifdef STRNCASECMP_IN_STRINGS_H
59 # include <dvdcss/dvdcss.h>
69 /*****************************************************************************
71 *****************************************************************************/
73 /* called from outside */
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 * );
82 * Data access functions
85 #define DVDTell LB2OFF( p_dvd->i_vts_start + p_dvd->i_vts_lb ) \
86 - p_input->stream.p_selected_area->i_start
88 /*****************************************************************************
90 *****************************************************************************/
91 int E_(DVDOpen) ( vlc_object_t *p_this )
93 input_thread_t * p_input = (input_thread_t *)p_this;
95 thread_dvd_data_t * p_dvd;
96 input_area_t * p_area;
98 char * psz_dvdcss_env;
100 p_dvd = malloc( sizeof(thread_dvd_data_t) );
103 msg_Err( p_input, "out of memory" );
106 p_input->p_access_data = (void *)p_dvd;
108 p_input->pf_read = DVDRead;
109 p_input->pf_seek = DVDSeek;
110 p_input->pf_set_area = DVDSetArea;
111 p_input->pf_set_program = DVDSetProgram;
113 /* Parse command line */
114 if( !( psz_device = DVDParse( p_input ) ) )
125 /* override environment variable DVDCSS_METHOD with config option
126 * (FIXME: this creates a small memory leak) */
127 psz_dvdcss_env = config_GetPsz( p_input, "dvdcss-method" );
128 if( psz_dvdcss_env && *psz_dvdcss_env )
132 psz_env = malloc( strlen("DVDCSS_METHOD=") +
133 strlen( psz_dvdcss_env ) + 1 );
141 sprintf( psz_env, "%s%s", "DVDCSS_METHOD=", psz_dvdcss_env );
145 if( psz_dvdcss_env ) free( psz_dvdcss_env );
150 p_dvd->dvdhandle = dvdcss_open( psz_device );
152 /* free allocated string */
155 if( p_dvd->dvdhandle == NULL )
157 msg_Err( p_input, "dvdcss cannot open device" );
162 if( dvdcss_seek( p_dvd->dvdhandle, 0, DVDCSS_NOFLAGS ) < 0 )
164 msg_Err( p_input, "%s", dvdcss_error( p_dvd->dvdhandle ) );
165 dvdcss_close( p_dvd->dvdhandle );
170 /* Ifo allocation & initialisation */
171 if( IfoCreate( p_dvd ) < 0 )
173 msg_Err( p_input, "allcation error in ifo" );
174 dvdcss_close( p_dvd->dvdhandle );
179 if( IfoInit( p_dvd->p_ifo ) < 0 )
181 msg_Err( p_input, "fatal failure in ifo" );
182 IfoDestroy( p_dvd->p_ifo );
183 dvdcss_close( p_dvd->dvdhandle );
188 /* Set stream and area data */
189 vlc_mutex_lock( &p_input->stream.stream_lock );
191 p_input->stream.i_method = INPUT_METHOD_DVD;
192 p_input->stream.b_pace_control = 1;
193 p_input->stream.b_seekable = 1;
194 p_input->stream.b_connected = 1;
195 p_input->stream.p_selected_area->i_size = 0;
196 p_input->stream.p_selected_area->i_tell = 0;
198 /* Initialize ES structures */
199 input_InitStream( p_input, sizeof( stream_ps_data_t ) );
201 #define title_inf p_dvd->p_ifo->vmg.title_inf
202 msg_Dbg( p_input, "number of titles: %d", title_inf.i_title_nb );
204 #define area p_input->stream.pp_areas
205 /* We start from 1 here since the default area 0
206 * is reserved for video_ts.vob */
207 for( i = 1 ; i <= title_inf.i_title_nb ; i++ )
209 /* Titles are Program Chains */
210 input_AddArea( p_input, i, title_inf.p_attr[i-1].i_chapter_nb );
212 /* Absolute start offset and size
213 * We can only set that with vts ifo, so we do it during the
214 * first call to DVDSetArea */
215 area[i]->i_start = 0;
218 /* Default Chapter */
221 /* Offset to vts_i_0.ifo */
222 area[i]->i_plugin_data = p_dvd->p_ifo->i_start +
223 title_inf.p_attr[i-1].i_start_sector;
227 p_dvd->i_title = p_dvd->i_title <= title_inf.i_title_nb ?
231 p_area = p_input->stream.pp_areas[p_dvd->i_title];
233 p_area->i_part = p_dvd->i_chapter <= p_area->i_part_nb ?
234 p_dvd->i_chapter : 1;
235 p_dvd->i_chapter = 1;
237 p_dvd->b_new_chapter = 0;
238 p_dvd->i_audio_nb = 0;
241 /* set title, chapter, audio and subpic */
242 if( DVDSetArea( p_input, p_area ) < 0 )
244 vlc_mutex_unlock( &p_input->stream.stream_lock );
245 IfoDestroy( p_dvd->p_ifo );
246 dvdcss_close( p_dvd->dvdhandle );
251 vlc_mutex_unlock( &p_input->stream.stream_lock );
253 if( !p_input->psz_demux || !*p_input->psz_demux )
255 p_input->psz_demux = "dvdold";
261 /*****************************************************************************
262 * DVDClose: close dvd
263 *****************************************************************************/
264 void E_(DVDClose) ( vlc_object_t *p_this )
266 input_thread_t * p_input = (input_thread_t *)p_this;
267 thread_dvd_data_t *p_dvd = (thread_dvd_data_t*)p_input->p_access_data;
269 /* This is a very nasty side-effect in the DVD plug-in : language
270 * selection here influences language selection of other streams. So
271 * unset those variables (may not be what the user wants).
272 * FIXME FIXME FIXME FIXME FIXME FIXME FIXME --Meuuh */
273 config_PutInt( p_input, "audio-channel", -1 );
274 config_PutInt( p_input, "spu-channel", -1 );
276 IfoDestroy( p_dvd->p_ifo );
277 dvdcss_close( p_dvd->dvdhandle );
281 /*****************************************************************************
282 * DVDSetProgram: used to change angle
283 *****************************************************************************/
284 static int DVDSetProgram( input_thread_t * p_input,
285 pgrm_descriptor_t * p_program )
287 if( p_input->stream.p_selected_program != p_program )
289 thread_dvd_data_t * p_dvd;
293 p_dvd = (thread_dvd_data_t*)(p_input->p_access_data);
294 i_angle = p_program->i_number;
296 /* DVD is actually mono-program: we only need the current angle
297 * number, so copy the data between programs */
299 p_input->stream.p_selected_program,
300 sizeof(pgrm_descriptor_t) );
301 p_program->i_number = i_angle;
302 p_input->stream.p_selected_program = p_program;
305 p_dvd->p_ifo->vts.title_unit.p_title[p_dvd->i_title_id-1].title
306 if( title.p_cell_play[p_dvd->i_prg_cell].i_category & 0xf000 )
308 if( ( p_program->i_number - p_dvd->i_angle ) < 0 )
310 /* we have to go backwards */
311 p_dvd->i_map_cell = 0;
313 p_dvd->i_prg_cell += ( p_program->i_number - p_dvd->i_angle );
314 p_dvd->i_map_cell = CellPrg2Map( p_dvd );
315 p_dvd->i_map_cell += p_dvd->i_angle_cell;
316 p_dvd->i_vts_lb = CellFirstSector( p_dvd );
317 p_dvd->i_last_lb = CellLastSector( p_dvd );
318 p_dvd->i_angle = p_program->i_number;
322 p_dvd->i_angle = p_program->i_number;
325 msg_Dbg( p_input, "angle %d selected", p_dvd->i_angle );
327 /* Update the navigation variables without triggering a callback */
328 val.i_int = p_program->i_number;
329 var_Change( p_input, "program", VLC_VAR_SETVALUE, &val );
335 /*****************************************************************************
336 * DVDSetArea: initialize input data for title x, chapter y.
337 * It should be called for each user navigation request.
338 *****************************************************************************
339 * Take care that i_title starts from 0 (vmg) and i_chapter start from 1.
340 * Note that you have to take the lock before entering here.
341 *****************************************************************************/
342 #define vmg p_dvd->p_ifo->vmg
343 #define vts p_dvd->p_ifo->vts
345 static void DVDFlushStream( input_thread_t * p_input )
347 if( p_input->stream.pp_programs != NULL )
349 /* We don't use input_EndStream here since
350 * we keep area structures */
351 while( p_input->stream.i_es_number )
353 input_DelES( p_input, p_input->stream.pp_es[0] );
356 while( p_input->stream.i_pgrm_number )
358 input_DelProgram( p_input, p_input->stream.pp_programs[0] );
361 if( p_input->stream.pp_selected_es )
363 free( p_input->stream.pp_selected_es );
364 p_input->stream.pp_selected_es = NULL;
366 p_input->stream.i_selected_es_number = 0;
372 static int DVDReadAngle( input_thread_t * p_input )
374 thread_dvd_data_t * p_dvd;
378 p_dvd = (thread_dvd_data_t*)(p_input->p_access_data);
379 i_angle_nb = vmg.title_inf.p_attr[p_dvd->i_title-1].i_angle_nb;
381 input_AddProgram( p_input, 1, sizeof( stream_ps_data_t ) );
382 p_input->stream.p_selected_program = p_input->stream.pp_programs[0];
384 for( i = 1 ; i < i_angle_nb ; i++ )
386 input_AddProgram( p_input, i+1, 0 );
392 static int DVDSetArea( input_thread_t * p_input, input_area_t * p_area )
394 thread_dvd_data_t * p_dvd;
397 p_dvd = (thread_dvd_data_t*)(p_input->p_access_data);
399 /* we can't use the interface slider until initilization is complete */
400 p_input->stream.b_seekable = 0;
402 if( p_area != p_input->stream.p_selected_area )
409 /* Reset the Chapter position of the old title */
410 p_input->stream.p_selected_area->i_part = 1;
411 p_input->stream.p_selected_area = p_area;
414 * We have to load all title information
417 /* title number as it appears in the interface list */
418 p_dvd->i_title = p_area->i_id;
419 p_dvd->i_chapter_nb = p_area->i_part_nb;
421 if( IfoTitleSet( p_dvd->p_ifo, p_dvd->i_title ) < 0 )
423 msg_Err( p_input, "fatal error in vts ifo" );
428 /* title position inside the selected vts */
429 i_vts_title = vmg.title_inf.p_attr[p_dvd->i_title-1].i_title_num;
431 vts.title_inf.p_title_start[i_vts_title-1].i_title_id;
433 msg_Dbg( p_input, "title %d vts_title %d pgc %d",
434 p_dvd->i_title, i_vts_title, p_dvd->i_title_id );
436 /* title set offset XXX: convert to block values */
438 vts.i_pos + vts.manager_inf.i_title_vob_start_sector;
441 p_dvd->i_prg_cell = -1 +
442 vts.title_unit.p_title[p_dvd->i_title_id-1].title.i_cell_nb;
443 p_dvd->i_map_cell = 0;
444 p_dvd->i_map_cell = CellPrg2Map( p_dvd );
445 i_last = CellLastSector( p_dvd );
448 p_dvd->i_prg_cell = 0;
449 p_dvd->i_map_cell = 0;
450 p_dvd->i_angle_cell = 0;
451 p_dvd->i_map_cell = CellPrg2Map ( p_dvd );
452 p_dvd->i_vts_lb = CellFirstSector( p_dvd );
453 p_dvd->i_last_lb = CellLastSector ( p_dvd );
455 /* Force libdvdcss to check its title key.
456 * It is only useful for title cracking method. Methods using the
457 * decrypted disc key are fast enough to check the key at each seek */
458 i_first = dvdcss_seek( p_dvd->dvdhandle,
459 p_dvd->i_vts_start + p_dvd->i_vts_lb,
463 msg_Err( p_input, "%s", dvdcss_error( p_dvd->dvdhandle ) );
467 /* Area definition */
468 p_input->stream.p_selected_area->i_start = LB2OFF( i_first );
469 p_input->stream.p_selected_area->i_size =
470 LB2OFF( i_last + 1 - p_dvd->i_vts_lb );
472 /* Destroy obsolete ES by reinitializing programs */
473 DVDFlushStream( p_input );
475 /* Angle management: angles are handled through programs */
476 p_dvd->i_angle_nb = DVDReadAngle( p_input );
477 if( ( p_dvd->i_angle <= 0 ) || p_dvd->i_angle > p_dvd->i_angle_nb )
482 DVDSetProgram( p_input,
483 p_input->stream.pp_programs[p_dvd->i_angle-1] );
485 msg_Dbg( p_input, "title first %i, last %i, size %i",
486 i_first, i_last, i_last + 1 - p_dvd->i_vts_lb );
487 IfoPrintTitle( p_dvd );
489 /* No PSM to read in DVD mode, we already have all information */
490 p_input->stream.p_selected_program->b_is_ok = 1;
492 /* Find all ES in title with ifo data */
493 DVDReadVideo( p_input );
494 DVDReadAudio( p_input );
495 DVDReadSPU ( p_input );
497 if( p_input->p_demux )
499 DVDLaunchDecoders( p_input );
502 /* Update the navigation variables without triggering a callback */
503 val.i_int = p_area->i_id;
504 var_Change( p_input, "title", VLC_VAR_SETVALUE, &val );
505 var_Change( p_input, "chapter", VLC_VAR_CLEARCHOICES, NULL );
506 for( i = 1; i <= p_area->i_part_nb; i++ )
509 var_Change( p_input, "chapter", VLC_VAR_ADDCHOICE, &val );
515 p_area = p_input->stream.p_selected_area;
518 /* Chapter selection */
519 p_dvd->i_chapter = DVDSetChapter( p_dvd, p_area->i_part );
521 p_input->stream.p_selected_area->i_tell = DVDTell;
523 /* warn interface that something has changed */
524 p_input->stream.b_seekable = 1;
525 p_input->stream.b_changed = 1;
527 /* Update the navigation variables without triggering a callback */
528 val.i_int = p_area->i_part;
529 var_Change( p_input, "chapter", VLC_VAR_SETVALUE, &val );
537 p_dvd->p_ifo->vts.title_unit.p_title[p_dvd->i_title_id-1].title
539 /*****************************************************************************
540 * DVDRead: reads data packets.
541 *****************************************************************************
542 * Returns -1 in case of error, 0 in case of EOF, otherwise the number of
544 *****************************************************************************/
545 static ssize_t DVDRead( input_thread_t * p_input,
546 byte_t * p_buffer, size_t i_count )
548 thread_dvd_data_t * p_dvd;
551 int i_block_once = 0;
553 p_dvd = (thread_dvd_data_t *)(p_input->p_access_data);
556 i_blocks = OFF2LB(i_count);
560 i_block_once = LbMaxOnce( p_dvd );
561 if( i_block_once > i_blocks )
563 i_block_once = i_blocks;
565 else if( i_block_once <= 0 )
571 if( i_block_once != dvdcss_read( p_dvd->dvdhandle, p_buffer,
572 i_block_once, DVDCSS_READ_DECRYPT ) )
577 i_blocks -= i_block_once;
578 i_read += i_block_once;
579 p_buffer += LB2OFF( i_block_once );
581 /* Update global position */
582 p_dvd->i_vts_lb += i_block_once;
585 vlc_mutex_lock( &p_input->stream.stream_lock );
587 if( p_dvd->b_new_chapter )
589 p_input->stream.p_selected_area->i_part = p_dvd->i_chapter;
590 p_dvd->b_new_chapter = 0;
593 if( ( p_input->stream.p_selected_area->i_tell + LB2OFF( i_read )
594 >= p_input->stream.p_selected_area->i_size )
595 || ( i_block_once <= 0 ) )
597 if( ( p_dvd->i_title + 1 ) >= p_input->stream.i_area_nb )
600 vlc_mutex_unlock( &p_input->stream.stream_lock );
605 msg_Dbg( p_input, "new title" );
607 DVDSetArea( p_input, p_input->stream.pp_areas[p_dvd->i_title] );
610 vlc_mutex_unlock( &p_input->stream.stream_lock );
612 return LB2OFF( i_read );
615 /*****************************************************************************
616 * DVDSeek : Goes to a given position on the stream.
617 *****************************************************************************
618 * This one is used by the input and translate chronological position from
619 * input to logical position on the device.
620 * The lock should be taken before calling this function.
621 *****************************************************************************/
622 static void DVDSeek( input_thread_t * p_input, off_t i_off )
624 thread_dvd_data_t * p_dvd;
626 p_dvd = ( thread_dvd_data_t * )(p_input->p_access_data);
628 vlc_mutex_lock( &p_input->stream.stream_lock );
629 p_dvd->i_vts_lb = OFF2LB(i_off + p_input->stream.p_selected_area->i_start)
630 - p_dvd->i_vts_start;
631 vlc_mutex_unlock( &p_input->stream.stream_lock );
633 p_dvd->i_prg_cell = Lb2CellPrg( p_dvd );
634 p_dvd->i_map_cell = Lb2CellMap( p_dvd );
636 if( CellIsInterleaved( p_dvd ) )
638 /* if we're inside a multi-angle zone, we have to choose i_sector
639 * in the current angle ; we can't do it all the time since cells
640 * can be very wide out of such zones */
641 p_dvd->i_vts_lb = CellFirstSector( p_dvd );
644 p_dvd->i_last_lb = CellLastSector( p_dvd );
645 p_dvd->i_chapter = CellPrg2Chapter( p_dvd );
647 if( dvdcss_seek( p_dvd->dvdhandle, p_dvd->i_vts_start + p_dvd->i_vts_lb,
648 DVDCSS_SEEK_MPEG ) < 0 )
650 msg_Err( p_input, "%s", dvdcss_error( p_dvd->dvdhandle ) );
651 p_input->b_error = 1;
655 vlc_mutex_lock( &p_input->stream.stream_lock );
656 p_input->stream.p_selected_area->i_part = p_dvd->i_chapter;
657 p_input->stream.p_selected_area->i_tell = DVDTell;
658 vlc_mutex_unlock( &p_input->stream.stream_lock );
660 msg_Dbg( p_input, "program cell: %d cell: %d chapter: %d tell "I64Fd,
661 p_dvd->i_prg_cell, p_dvd->i_map_cell, p_dvd->i_chapter, DVDTell );
666 /*****************************************************************************
667 * DVDParse: parse command line
668 *****************************************************************************/
669 static char * DVDParse( input_thread_t * p_input )
671 thread_dvd_data_t * p_dvd;
672 struct stat stat_info;
677 vlc_bool_t b_options = 0;
683 p_dvd = (thread_dvd_data_t*)(p_input->p_access_data);
686 /* On Win32 we want the DVD access plugin to be explicitly requested,
687 * we end up with lots of problems otherwise */
688 if( !p_input->psz_access || !*p_input->psz_access ) return NULL;
691 psz_parser = psz_device = strdup( p_input->psz_name );
697 /* Parse input string :
698 * [device][@rawdevice][@[title][,[chapter][,angle]]] */
699 while( *psz_parser && *psz_parser != '@' )
704 if( *psz_parser == '@' )
706 /* Maybe found raw device or option list */
708 psz_raw = ++psz_parser;
715 if( *psz_parser && !strtol( psz_parser, NULL, 10 ) )
717 /* what we've found is either a raw device or a partial option
718 * list e.g. @,29 or both a device and a list ; search end of string */
719 while( *psz_parser && *psz_parser != '@' )
724 if( *psz_parser == '@' )
726 /* found end of raw device, and beginning of options */
733 psz_parser = psz_raw + 1;
734 for( i=0 ; i<3 ; i++ )
738 /* we have only a raw device */
741 if( strtol( psz_parser, NULL, 10 ) )
743 /* we have only a partial list of options, no device */
744 psz_parser = psz_raw;
755 /* found beginning of options ; no raw device specified */
763 i_title = (int)strtol( psz_parser, &psz_next, 10 );
766 psz_parser = psz_next + 1;
767 i_chapter = (int)strtol( psz_parser, &psz_next, 10 );
770 i_angle = (int)strtol( psz_next + 1, NULL, 10 );
774 p_dvd->i_title = i_title ? i_title : 1;
775 p_dvd->i_chapter = i_chapter ? i_chapter : 1;
776 p_dvd->i_angle = i_angle ? i_angle : 1;
783 /* check the raw device */
784 if( stat( psz_raw, &stat_info ) == -1 )
786 msg_Warn( p_input, "cannot stat() raw device `%s' (%s)",
787 psz_raw, strerror(errno));
789 *(psz_raw - 1) = '@';
797 if( !S_ISCHR(stat_info.st_mode) )
799 msg_Warn( p_input, "raw device %s is"
800 " not a valid char device", psz_raw );
802 *(psz_raw - 1) = '@';
808 psz_env = malloc( strlen("DVDCSS_RAW_DEVICE=")
809 + strlen( psz_raw ) + 1 );
810 sprintf( psz_env, "DVDCSS_RAW_DEVICE=%s", psz_raw );
825 if( !p_input->psz_access )
827 /* no device and no access specified: we probably don't want DVD */
830 psz_device = config_GetPsz( p_input, "dvd" );
834 /* check block device */
835 if( stat( psz_device, &stat_info ) == -1 )
837 msg_Warn( p_input, "cannot stat() device `%s' (%s)",
838 psz_device, strerror(errno));
843 if( !S_ISBLK(stat_info.st_mode) && !S_ISCHR(stat_info.st_mode) )
846 "dvd module discarded (not a valid block device)" );
852 msg_Dbg( p_input, "dvd=%s raw=%s title=%d chapter=%d angle=%d",
853 psz_device, psz_raw, p_dvd->i_title,
854 p_dvd->i_chapter, p_dvd->i_angle );