From daabc5f7742e31fb3b57f83f49619dbe1a470f64 Mon Sep 17 00:00:00 2001 From: arpi Date: Mon, 20 Aug 2001 21:20:03 +0000 Subject: [PATCH] libDVDread support git-svn-id: svn://svn.mplayerhq.hu/mplayer/trunk@1597 b3059339-0415-0410-9bf9-f77b7e298cf2 --- cfg-mplayer.h | 19 +++- configure | 37 ++++++- mplayer.c | 9 +- open.c | 295 ++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 349 insertions(+), 11 deletions(-) diff --git a/cfg-mplayer.h b/cfg-mplayer.h index c0027487c5..cba21d8215 100644 --- a/cfg-mplayer.h +++ b/cfg-mplayer.h @@ -54,6 +54,12 @@ extern char *mDisplayName; extern int vo_aa_parseoption(struct config * conf, char *opt, char * param); #endif +#ifdef USE_DVDREAD +extern int dvd_title; +extern int dvd_chapter; +extern int dvd_angle; +#endif + /* * CONF_TYPE_FUNC_FULL : * allows own implemtations for passing the params @@ -85,10 +91,10 @@ struct config conf[]={ #ifdef HAVE_LIBCSS {"dvdauth", &dvd_auth_device, CONF_TYPE_STRING, 0, 0, 0}, {"dvdkey", &dvdimportkey, CONF_TYPE_STRING, 0, 0, 0}, - {"dvd", "Option -dvd will be \"full disk\" mode, old meaning has been renamed to -dvdauth.\n", CONF_TYPE_PRINT, CONF_NOCFG, 0, 0}, +// {"dvd", "Option -dvd will be \"full disk\" mode, old meaning has been renamed to -dvdauth.\n", CONF_TYPE_PRINT, CONF_NOCFG, 0, 0}, #else - {"dvd", "DVD support was not compiled in. See file DOCS/DVD.\n", - CONF_TYPE_PRINT, CONF_NOCFG, 0 , 0}, +// {"dvd", "DVD support was not compiled in. See file DOCS/DVD.\n", +// CONF_TYPE_PRINT, CONF_NOCFG, 0 , 0}, {"dvdkey", "DVD support was not compiled in. See file DOCS/DVD.\n", CONF_TYPE_PRINT, CONF_NOCFG, 0 , 0}, {"dvdauth", "DVD support was not compiled in. See file DOCS/DVD.\n", @@ -174,6 +180,13 @@ struct config conf[]={ {"dshow", &allow_dshow, CONF_TYPE_FLAG, 0, 0, 1}, // Is this still needed? atmos :: {"nodshow", &allow_dshow, CONF_TYPE_FLAG, 0, 1, 0}, {"vcd", &vcd_track, CONF_TYPE_INT, CONF_RANGE, 1, 99}, +#ifdef USE_DVDREAD + {"dvd", &dvd_title, CONF_TYPE_INT, CONF_RANGE, 1, 99}, + {"dvdangle", &dvd_angle, CONF_TYPE_INT, CONF_RANGE, 1, 99}, + {"chapter", &dvd_chapter, CONF_TYPE_INT, CONF_RANGE, 1, 99}, +#else + {"dvd", "MPlayer was compiled WITHOUT libdvdread support!\n", CONF_TYPE_PRINT, CONF_NOCFG, 0, 0}, +#endif {"divxq", "Option -divxq has been renamed to -pp (postprocessing), use -pp !\n", CONF_TYPE_PRINT, 0, 0, 0}, {"pp", &divx_quality, CONF_TYPE_INT, CONF_RANGE, 0, 63}, diff --git a/configure b/configure index d8d5222d7b..1978adc342 100755 --- a/configure +++ b/configure @@ -457,6 +457,7 @@ _fbdev=no [ "$system_name" = Linux ] && _fbdev=yes _lirc=no _css=no +_dvdread=no _win32dll=yes _dshow=yes [ "$host_arch" != i386 ] && _dshow=no _win32dll=no _fastmemcpy=yes @@ -872,6 +873,17 @@ EOF $_cc $_extraincdir $_extralibdir $TMPC -o $TMPO -ldivxdecore > /dev/null 2>&1 || \ { _divx4linux=no; echo "DivX4Linux includes (decore.h) not found!";} +cat > $TMPC << EOF +#include +#include +#include +#include +#include +int main( void ) { return 0; } +EOF +$_cc $_extraincdir $_extralibdir -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE64_SOURCE $TMPC -o $TMPO -ldvdread > /dev/null 2>&1 && \ + { _dvdread=yes;_largefiles=yes; } + rm -f $TMPC $TMPO @@ -1412,6 +1424,7 @@ echo "Checking for ALSA Audio ... $_alsaver" echo "Checking for ESD Audio ... $_esd" echo "Checking for Sun Audio ... $_sun_audio" echo "Checking for DeCSS support ... $_css" +echo "Checking for DVDread support ... $_dvdread" echo "Checking for PNG support ... $_png" echo "Checking for Win32 DLL support ... $_win32dll" echo "Checking for DirectShow ... $_dshow" @@ -1442,6 +1455,16 @@ if [ $_gl = yes ]; then fi fi +_css='#undef HAVE_LIBCSS' +_csslib='' +_cssinc='' + +if [ $_dvdread = yes ]; then + _csslib='-ldvdread' + _dvdreaddef='#define USE_DVDREAD' +else + _dvdreaddef='#undef USE_DVDREAD' + if [ $_css = yes ]; then if [ ! -z "$_csslibdir" ]; then _csslib="-L${_csslibdir} -lcss" @@ -1454,10 +1477,8 @@ if [ $_css = yes ]; then else _cssinc="" fi -else - _css='#undef HAVE_LIBCSS' - _csslib='' - _cssinc='' +fi + fi @@ -1641,6 +1662,10 @@ fi # 64 bit file offsets? if [ "$_largefiles" = "yes" -o "$system_name" = "FreeBSD" ]; then CFLAGS="$CFLAGS -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64" + if [ "$_dvdread" = "yes" ]; then + # dvdread support requires this (for off64_t) + CFLAGS="$CFLAGS -D_LARGEFILE64_SOURCE" + fi fi # echo 'CFLAGS=$(OPTFLAGS) -Wall -DMPG12PLAY' >> config.mak @@ -1899,6 +1924,8 @@ cat > $CCONF << EOF $_debugdef +$_dvdreaddef + /* Common data directory (for fonts, etc) */ #define DATADIR "$_datadir" @@ -2019,6 +2046,8 @@ $_confwin32 #define DEFAULT_CDROM_DEVICE "/dev/cdrom" #endif +#define DEFAULT_DVD_DEVICE "/dev/dvd" + /*---------------------------------------------------------------------------- ** ** NOTE: Instead of modifying these definitions here, use the diff --git a/mplayer.c b/mplayer.c index 56f6f94f21..b7b31dd230 100644 --- a/mplayer.c +++ b/mplayer.c @@ -233,6 +233,8 @@ static int vcd_track=0; static char *stream_dump_name=NULL; static int stream_dump_type=0; +extern int dvd_title; + int index_mode=-1; // -1=untouched 0=don't use index 1=use (geneate) index int force_ni=0; @@ -495,8 +497,7 @@ int use_stdin=0; //int f; // filedes #endif if(!filename){ - if(vcd_track) filename=DEFAULT_CDROM_DEVICE; - else { + if(!vcd_track && !dvd_title){ printf("%s",help_text); exit(0); } } @@ -591,7 +592,7 @@ if(!parse_codec_cfg(get_path("codecs.conf"))){ subtitles=sub_read_file(sub_name); if(!subtitles) mp_msg(MSGT_CPLAYER,MSGL_ERR,MSGTR_CantLoadSub,sub_name); } else { - if(sub_auto) // auto load sub file ... + if(sub_auto && filename) // auto load sub file ... subtitles=sub_read_file( sub_filename( get_path("sub/"), filename ) ); if(!subtitles) subtitles=sub_read_file(get_path("default.sub")); // try default } @@ -599,7 +600,7 @@ if(!parse_codec_cfg(get_path("codecs.conf"))){ stream=open_stream(filename,vcd_track,&file_format); if(!stream) return 1; // error... - use_stdin=(!strcmp(filename,"-")); + use_stdin=filename && (!strcmp(filename,"-")); stream->start_pos+=seek_to_byte; #ifdef HAVE_LIBCSS diff --git a/open.c b/open.c index fe141a27da..bbf77e2771 100644 --- a/open.c +++ b/open.c @@ -22,6 +22,38 @@ static URL_t* url; #endif +int dvd_title=0; +int dvd_chapter=1; +int dvd_angle=1; + +#ifdef USE_DVDREAD + +#include +#include +#include +#include +#include +//#include + +typedef struct { + dvd_reader_t *dvd; + dvd_file_t *title; + ifo_handle_t *vmg_file; + tt_srpt_t *tt_srpt; + ifo_handle_t *vts_file; + vts_ptt_srpt_t *vts_ptt_srpt; + pgc_t *cur_pgc; + // + int cur_cell; + int cur_pack; + int cell_last_pack; + // Navi: + int packs_left; + dsi_t dsi_pack; +} dvd_priv_t; + +#endif + extern int vcd_get_track_end(int fd,int track); // Open a new stream (stdin/file/vcd/url) @@ -40,6 +72,7 @@ int bsize = VCD_SECTOR_SIZE; //============ Open VideoCD track ============== if(vcd_track){ int ret,ret2; + if(!filename) filename=DEFAULT_CDROM_DEVICE; f=open(filename,O_RDONLY); if(f<0){ mp_msg(MSGT_OPEN,MSGL_ERR,MSGTR_CdDevNotfound,filename);return NULL; } vcd_read_toc(f); @@ -63,6 +96,136 @@ if(vcd_track){ return stream; } +//============ Open DVD title ============== +#ifdef USE_DVDREAD +if(dvd_title){ + int ret,ret2; + dvd_priv_t *d; + int ttn,pgc_id,pgn; + dvd_reader_t *dvd; + dvd_file_t *title; + ifo_handle_t *vmg_file; + tt_srpt_t *tt_srpt; + ifo_handle_t *vts_file; + /** + * Open the disc. + */ + if(!filename) filename=DEFAULT_DVD_DEVICE; + dvd = DVDOpen(filename); + if( !dvd ) { + mp_msg(MSGT_OPEN,MSGL_ERR, "Couldn't open DVD: %s\n",filename); + return NULL; + } + + mp_msg(MSGT_OPEN,MSGL_INFO, "Reading disc structure, please wait...\n"); + + /** + * Load the video manager to find out the information about the titles on + * this disc. + */ + vmg_file = ifoOpen( dvd, 0 ); + if( !vmg_file ) { + mp_msg(MSGT_OPEN,MSGL_ERR, "Can't open VMG info!\n"); + DVDClose( dvd ); + return NULL; + } + tt_srpt = vmg_file->tt_srpt; + /** + * Make sure our title number is valid. + */ + mp_msg(MSGT_OPEN,MSGL_INFO, "There are %d titles on this DVD.\n", + tt_srpt->nr_of_srpts ); + if( dvd_title < 1 || dvd_title > tt_srpt->nr_of_srpts ) { + mp_msg(MSGT_OPEN,MSGL_ERR, "Invalid DVD title number: %d\n", dvd_title); + ifoClose( vmg_file ); + DVDClose( dvd ); + return NULL; + } + --dvd_title; // remap 1.. -> 0.. + /** + * Make sure the chapter number is valid for this title. + */ + mp_msg(MSGT_OPEN,MSGL_INFO, "There are %d chapters in this DVD title.\n", + tt_srpt->title[dvd_title].nr_of_ptts ); + if( dvd_chapter<1 || dvd_chapter>tt_srpt->title[dvd_title].nr_of_ptts ) { + mp_msg(MSGT_OPEN,MSGL_ERR, "Invalid DVD chapter number: %d\n", dvd_chapter); + ifoClose( vmg_file ); + DVDClose( dvd ); + return NULL; + } + --dvd_chapter; // remap 1.. -> 0.. + /** + * Make sure the angle number is valid for this title. + */ + mp_msg(MSGT_OPEN,MSGL_INFO, "There are %d angles in this DVD title.\n", + tt_srpt->title[dvd_title].nr_of_angles ); + if( dvd_angle<1 || dvd_angle>tt_srpt->title[dvd_title].nr_of_angles ) { + mp_msg(MSGT_OPEN,MSGL_ERR, "Invalid DVD angle number: %d\n", dvd_angle); + ifoClose( vmg_file ); + DVDClose( dvd ); + return NULL; + } + /** + * Load the VTS information for the title set our title is in. + */ + vts_file = ifoOpen( dvd, tt_srpt->title[dvd_title].title_set_nr ); + if( !vts_file ) { + mp_msg(MSGT_OPEN,MSGL_ERR, "Can't open the IFO file for DVD title %d.\n", + tt_srpt->title[dvd_title].title_set_nr ); + ifoClose( vmg_file ); + DVDClose( dvd ); + return NULL; + } + /** + * We've got enough info, time to open the title set data. + */ + title = DVDOpenFile( dvd, tt_srpt->title[dvd_title].title_set_nr, + DVD_READ_TITLE_VOBS ); + if( !title ) { + mp_msg(MSGT_OPEN,MSGL_ERR, "Can't open title VOBS (VTS_%02d_1.VOB).\n", + tt_srpt->title[dvd_title].title_set_nr ); + ifoClose( vts_file ); + ifoClose( vmg_file ); + DVDClose( dvd ); + return NULL; + } + + mp_msg(MSGT_OPEN,MSGL_INFO, "DVD successfully opened!\n"); + // store data + d=malloc(sizeof(dvd_priv_t)); memset(d,0,sizeof(dvd_priv_t)); + d->dvd=dvd; + d->title=title; + d->vmg_file=vmg_file; + d->tt_srpt=tt_srpt; + d->vts_file=vts_file; + + /** + * Determine which program chain we want to watch. This is based on the + * chapter number. + */ + ttn = tt_srpt->title[ dvd_title ].vts_ttn; // local + pgc_id = vts_file->vts_ptt_srpt->title[ttn-1].ptt[dvd_chapter].pgcn; // local + pgn = vts_file->vts_ptt_srpt->title[ttn-1].ptt[dvd_chapter].pgn; // local + d->cur_pgc = vts_file->vts_pgcit->pgci_srp[pgc_id-1].pgc; + d->cur_cell = d->cur_pgc->program_map[pgn-1] - 1; // start playback here + d->packs_left=-1; // for Navi stuff + + if( d->cur_pgc->cell_playback[d->cur_cell].block_type + == BLOCK_TYPE_ANGLE_BLOCK ) d->cur_cell+=dvd_angle; + d->cur_pack = d->cur_pgc->cell_playback[ d->cur_cell ].first_sector; + d->cell_last_pack=d->cur_pgc->cell_playback[ d->cur_cell ].last_sector; + mp_msg(MSGT_DVD,MSGL_V, "DVD start cell: %d pack: 0x%X-0x%X \n",d->cur_cell,d->cur_pack,d->cell_last_pack); + + // ... (unimplemented) +// return NULL; + stream=new_stream(-1,STREAMTYPE_DVD); + stream->start_pos=(off_t)d->cur_pack*2048; + //stream->end_pos=0; + stream->priv=(void*)d; + return stream; +} +#endif + //============ Open STDIN ============ if(!strcmp(filename,"-")){ // read from stdin @@ -107,3 +270,135 @@ if(vcd_track){ return stream; } + + +#ifdef USE_DVDREAD + +static int dvd_next_cell(dvd_priv_t *d){ + int next_cell=d->cur_cell; + + if( d->cur_pgc->cell_playback[ next_cell ].block_type + == BLOCK_TYPE_ANGLE_BLOCK ) { + int i; + while(next_cellcur_pgc->nr_of_cells){ + if( d->cur_pgc->cell_playback[next_cell].block_mode + == BLOCK_MODE_LAST_CELL ) break; + ++next_cell; + } + } + + ++next_cell; + if(next_cell>=d->cur_pgc->nr_of_cells) return -1; // EOF + if( d->cur_pgc->cell_playback[next_cell].block_type == BLOCK_TYPE_ANGLE_BLOCK ){ + next_cell+=dvd_angle; + if(next_cell>=d->cur_pgc->nr_of_cells) return -1; // EOF + } + return next_cell; +} + +int dvd_read_sector(dvd_priv_t *d,unsigned char* data){ + int len; + + if(d->packs_left==0){ + /** + * If we're not at the end of this cell, we can determine the next + * VOBU to display using the VOBU_SRI information section of the + * DSI. Using this value correctly follows the current angle, + * avoiding the doubled scenes in The Matrix, and makes our life + * really happy. + * + * Otherwise, we set our next address past the end of this cell to + * force the code above to go to the next cell in the program. + */ + if( d->dsi_pack.vobu_sri.next_vobu != SRI_END_OF_CELL ) { + d->cur_pack= d->dsi_pack.dsi_gi.nv_pck_lbn + + ( d->dsi_pack.vobu_sri.next_vobu & 0x7fffffff ); + mp_msg(MSGT_DVD,MSGL_DBG2, "Navi new pos=0x%X \n",d->cur_pack); + } else { + // end of cell! find next cell! + mp_msg(MSGT_DVD,MSGL_V, "--- END OF CELL !!! ---\n"); + d->cur_pack=d->cell_last_pack+1; + } + } + +read_next: + + if(d->cur_pack>d->cell_last_pack){ + // end of cell! + int next=dvd_next_cell(d); + if(next>=0){ + d->cur_cell=next; + + if( d->cur_pgc->cell_playback[d->cur_cell].block_type + == BLOCK_TYPE_ANGLE_BLOCK ) d->cur_cell+=dvd_angle; + d->cur_pack = d->cur_pgc->cell_playback[ d->cur_cell ].first_sector; + d->cell_last_pack=d->cur_pgc->cell_playback[ d->cur_cell ].last_sector; + mp_msg(MSGT_DVD,MSGL_V, "DVD next cell: %d pack: 0x%X-0x%X \n",d->cur_cell,d->cur_pack,d->cell_last_pack); + + } else return -1; // EOF + } + + len = DVDReadBlocks( d->title, d->cur_pack, 1, data ); + if(!len) return -1; //error + + if(data[38]==0 && data[39]==0 && data[40]==1 && data[41]==0xBF && + data[1024]==0 && data[1025]==0 && data[1026]==1 && data[1027]==0xBF){ + // found a Navi packet!!! + navRead_DSI( &d->dsi_pack, &(data[ DSI_START_BYTE ]), sizeof(dsi_t) ); + if(d->cur_pack != d->dsi_pack.dsi_gi.nv_pck_lbn ){ + mp_msg(MSGT_DVD,MSGL_V, "Invalid NAVI packet! lba=0x%X navi=0x%X \n", + d->cur_pack,d->dsi_pack.dsi_gi.nv_pck_lbn); + } else { + // process! + d->packs_left = d->dsi_pack.dsi_gi.vobu_ea; + mp_msg(MSGT_DVD,MSGL_DBG2, "Found NAVI packet! lba=0x%X len=%d \n",d->cur_pack,d->packs_left); + } + ++d->cur_pack; + goto read_next; + } + + ++d->cur_pack; + if(d->packs_left>=0) --d->packs_left; + + return d->cur_pack-1; +} + +void dvd_seek(dvd_priv_t *d,int pos){ + d->packs_left=-1; + d->cur_pack=pos; + +// check if we stay in current cell (speedup things, and avoid angle skip) +if(d->cur_pack>d->cell_last_pack && + d->cur_packcur_pgc->cell_playback[ d->cur_cell ].first_sector){ + + // ok, cell change, find the right cell! + d->cur_cell=0; + if( d->cur_pgc->cell_playback[d->cur_cell].block_type + == BLOCK_TYPE_ANGLE_BLOCK ) d->cur_cell+=dvd_angle; + + while(1){ + int next; + d->cell_last_pack=d->cur_pgc->cell_playback[ d->cur_cell ].last_sector; + if(d->cur_packcur_pgc->cell_playback[ d->cur_cell ].first_sector){ + d->cur_pack=d->cur_pgc->cell_playback[ d->cur_cell ].first_sector; + break; + } + if(d->cur_pack<=d->cell_last_pack) break; // ok, we find it! :) + next=dvd_next_cell(d); + if(next<0){ +// d->cur_pack=d->cell_last_pack+1; + break; // we're after the last cell + } + d->cur_cell=next; + } +} + +mp_msg(MSGT_DVD,MSGL_V, "DVD Seek! lba=0x%X cell=%d packs: 0x%X-0x%X \n", + d->cur_pack,d->cur_cell,d->cur_pgc->cell_playback[ d->cur_cell ].first_sector,d->cell_last_pack); + +// TODO: if we're in interleaved multi-angle cell, find the right angle chain! +// (read Navi block, and use the seamless angle jump table) + +} + +#endif