Mercurial > mplayer.hg
diff libmpdemux/open.c @ 2310:9e059416eea6
libdemuxer...
author | arpi |
---|---|
date | Sat, 20 Oct 2001 18:49:08 +0000 |
parents | open.c@18f4dd5d568f |
children | d0e1c32ad432 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmpdemux/open.c Sat Oct 20 18:49:08 2001 +0000 @@ -0,0 +1,437 @@ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <fcntl.h> + +#include "config.h" +#include "mp_msg.h" +#include "help_mp.h" + +#ifdef __FreeBSD__ +#include <sys/cdrio.h> +#endif + +#include "stream.h" +#include "demuxer.h" + +#ifdef STREAMING +#include "url.h" +#include "network.h" +static URL_t* url; +#endif + +int dvd_title=0; +int dvd_chapter=1; +int dvd_angle=1; + +#ifdef USE_DVDREAD + +#include <dvdread/dvd_reader.h> +#include <dvdread/ifo_types.h> +#include <dvdread/ifo_read.h> +#include <dvdread/nav_read.h> + +#define DVDREAD_VERSION(maj,min,micro) ((maj)*10000 + (min)*100 + (micro)) + +/* + * Try to autodetect the libdvd-0.9.0 library + * (0.9.0 removed the <dvdread/dvd_udf.h> header, and moved the two defines + * DVD_VIDEO_LB_LEN and MAX_UDF_FILE_NAME_LEN from it to + * <dvdread/dvd_reader.h>) + */ +#if defined(DVD_VIDEO_LB_LEN) && defined(MAX_UDF_FILE_NAME_LEN) +#define LIBDVDREAD_VERSION DVDREAD_VERSION(0,9,0) +#else +#define LIBDVDREAD_VERSION DVDREAD_VERSION(0,8,0) +#endif + + +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; + int angle_seek; +} dvd_priv_t; + +#endif + +extern int vcd_get_track_end(int fd,int track); + +// Open a new stream (stdin/file/vcd/url) + +stream_t* open_stream(char* filename,int vcd_track,int* file_format){ +stream_t* stream=NULL; +int f=-1; +off_t len; +#ifdef VCD_CACHE +int vcd_cache_size=128; +#endif +#ifdef __FreeBSD__ +int bsize = VCD_SECTOR_SIZE; +#endif + +//============ 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); + ret2=vcd_get_track_end(f,vcd_track); + if(ret2<0){ mp_msg(MSGT_OPEN,MSGL_ERR,MSGTR_ErrTrackSelect " (get)\n");return NULL;} + ret=vcd_seek_to_track(f,vcd_track); + if(ret<0){ mp_msg(MSGT_OPEN,MSGL_ERR,MSGTR_ErrTrackSelect " (seek)\n");return NULL;} +// seek_to_byte+=ret; + mp_msg(MSGT_OPEN,MSGL_V,"VCD start byte position: 0x%X end: 0x%X\n",ret,ret2); +#ifdef VCD_CACHE + vcd_cache_init(vcd_cache_size); +#endif +#ifdef __FreeBSD__ + if (ioctl (f, CDRIOCSETBLOCKSIZE, &bsize) == -1) { + perror ( "Error in CDRIOCSETBLOCKSIZE"); + } +#endif + stream=new_stream(f,STREAMTYPE_VCD); + stream->start_pos=ret; + stream->end_pos=ret2; + 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,MSGTR_CantOpenDVD,filename); + return NULL; + } + + mp_msg(MSGT_OPEN,MSGL_INFO,MSGTR_DVDwait); + + /** + * 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, MSGTR_DVDnumTitles, + tt_srpt->nr_of_srpts ); + if( dvd_title < 1 || dvd_title > tt_srpt->nr_of_srpts ) { + mp_msg(MSGT_OPEN,MSGL_ERR, MSGTR_DVDinvalidTitle, 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, MSGTR_DVDnumChapters, + 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, MSGTR_DVDinvalidChapter, 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, MSGTR_DVDnumAngles, + 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, MSGTR_DVDinvalidAngle, dvd_angle); + ifoClose( vmg_file ); + DVDClose( dvd ); + return NULL; + } + --dvd_angle; // remap 1.. -> 0.. + /** + * 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, MSGTR_DVDnoIFO, + 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, MSGTR_DVDnoVOBs, + tt_srpt->title[dvd_title].title_set_nr ); + ifoClose( vts_file ); + ifoClose( vmg_file ); + DVDClose( dvd ); + return NULL; + } + + mp_msg(MSGT_OPEN,MSGL_INFO, MSGTR_DVDopenOk); + // 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 + d->angle_seek=0; + + 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 + mp_msg(MSGT_OPEN,MSGL_INFO,MSGTR_ReadSTDIN); + f=0; // 0=stdin + stream=new_stream(f,STREAMTYPE_STREAM); + return stream; + } + +#ifdef STREAMING + url = url_new(filename); + if(url) { + (*file_format)=autodetectProtocol( url, &f ); + if( (*file_format)==DEMUXER_TYPE_UNKNOWN ) { + mp_msg(MSGT_OPEN,MSGL_ERR,MSGTR_UnableOpenURL, filename); + url_free(url); + return NULL; + } + f=streaming_start( &url, f, *file_format ); + if(f<0){ mp_msg(MSGT_OPEN,MSGL_ERR,MSGTR_UnableOpenURL, url->url); return NULL; } + mp_msg(MSGT_OPEN,MSGL_INFO,MSGTR_ConnToServer, url->hostname ); + stream=new_stream(f,STREAMTYPE_STREAM); + return NULL; + } +#endif + +//============ Open plain FILE ============ + f=open(filename,O_RDONLY); + if(f<0){ mp_msg(MSGT_OPEN,MSGL_ERR,MSGTR_FileNotFound,filename);return NULL; } + len=lseek(f,0,SEEK_END); lseek(f,0,SEEK_SET); + if (len == -1) + perror("Error: lseek failed to obtain video file size"); + else + if(verbose) +#ifdef _LARGEFILE_SOURCE + mp_msg(MSGT_OPEN,MSGL_V,"File size is %lld bytes\n", (long long)len); +#else + mp_msg(MSGT_OPEN,MSGL_V,"File size is %u bytes\n", (unsigned int)len); +#endif + stream=new_stream(f,STREAMTYPE_FILE); + stream->end_pos=len; + return stream; + +} + + +#ifdef USE_DVDREAD + +static int dvd_next_cell(dvd_priv_t *d){ + int next_cell=d->cur_cell; + + mp_msg(MSGT_DVD,MSGL_V, "dvd_next_cell: next1=0x%X \n",next_cell); + + if( d->cur_pgc->cell_playback[ next_cell ].block_type + == BLOCK_TYPE_ANGLE_BLOCK ) { + while(next_cell<d->cur_pgc->nr_of_cells){ + if( d->cur_pgc->cell_playback[next_cell].block_mode + == BLOCK_MODE_LAST_CELL ) break; + ++next_cell; + } + } + mp_msg(MSGT_DVD,MSGL_V, "dvd_next_cell: next2=0x%X \n",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 + } + mp_msg(MSGT_DVD,MSGL_V, "dvd_next_cell: next3=0x%X \n",next_cell); + 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!!! +#if LIBDVDREAD_VERSION >= DVDREAD_VERSION(0,9,0) + navRead_DSI( &d->dsi_pack, &(data[ DSI_START_BYTE ]) ); +#else + navRead_DSI( &d->dsi_pack, &(data[ DSI_START_BYTE ]), sizeof(dsi_t) ); +#endif + 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); + if(d->angle_seek){ + int skip=d->dsi_pack.sml_agli.data[dvd_angle].address; + if(skip) d->cur_pack=d->dsi_pack.dsi_gi.nv_pck_lbn+skip; + d->angle_seek=0; + mp_msg(MSGT_DVD,MSGL_V, "Angle-seek synced! skip=%d new_lba=0x%X \n",skip,d->cur_pack); + } + } + ++d->cur_pack; + goto read_next; + } + + ++d->cur_pack; + if(d->packs_left>=0) --d->packs_left; + + if(d->angle_seek) goto read_next; // searching for Navi packet + + 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_pack<d->cur_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_pack<d->cur_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); + +// if we're in interleaved multi-angle cell, find the right angle chain! +// (read Navi block, and use the seamless angle jump table) +d->angle_seek=1; + +} + +#endif