dvd_file.c
上传用户:aoeyumen
上传日期:2007-01-06
资源大小:3329k
文件大小:8k
源码类别:

DVD

开发平台:

Unix_Linux

  1. /*
  2.  * dvdfile: access to the content of a DVD Video via mounted filesystem
  3.  * Copyright (C) 1999 Christian Wolff for convergence integrated media GmbH
  4.  * 
  5.  * This program is free software; you can redistribute it and/or
  6.  * modify it under the terms of the GNU General Public License
  7.  * as published by the Free Software Foundation; either version 2
  8.  * of the License, or (at your option) any later version.
  9.  * 
  10.  * This program is distributed in the hope that it will be useful,
  11.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13.  * GNU General Public License for more details.
  14.  * 
  15.  * You should have received a copy of the GNU General Public License
  16.  * along with this program; if not, write to the Free Software
  17.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  18.  * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
  19.  * 
  20.  * The author can be reached at scarabaeus@convergence.de, 
  21.  * the project's page is at http://linuxtv.org/dvd/
  22.  */
  23. #include <stdio.h>
  24. #include <stdlib.h>
  25. #include <dirent.h>
  26. #include <limits.h>
  27. #include <string.h>
  28. #include "dvd_file.h"
  29. // hmm what would be the best place to put these def's?
  30. #define INFOFILE      ".IFO"           // File Extension of Info Files
  31. #define INFOBACKUP    ".BUP"           // File Extension of Info File Backups
  32. #define VIDEOOBJECT   ".VOB"           // File Extension of Video Objects
  33. #define VIDEOPATH     "VIDEO_TS"       // /dvd/VIDEO_TS
  34. #define DISCINDEX     "VIDEO_TS"       // /dvd/VIDEO_TS/VIDEO_TS.VOB or VIDEO_TS.IFO
  35. #define TITLEFORMAT   "VTS_%02d_%d"    // e.g. /dvd/VIDEO_TS/VTS_01_1.VOB or VTS_01_0.IFO
  36. // information for read_LB
  37. int currentvtsn;
  38. int currentsegment;
  39. long int segmentlength[10];
  40. FILE* movie;
  41. FILE* menumovie;
  42. char Videopath[PATH_MAX]="";  // Path to the DVD Video
  43. int LB_Len=2048;              // length of one logical block
  44. // searches for <file> in directory <path>, ignoring case
  45. // returns 0 and full filename in <filename>
  46. // or -1 on file not found
  47. // or -2 on path not found
  48. int find_file(const char *path, const char *file, char *filename) {
  49.   DIR *dir;
  50.   struct dirent *ent;
  51.   if ((dir=opendir(path))==NULL) return -2;
  52.   while ((ent=readdir(dir))!=NULL) {
  53.     if (!strcasecmp(ent->d_name,file)) {
  54.       sprintf(filename,"%s%s%s",path,((path[strlen(path)-1]=='/')?"":"/"),ent->d_name);
  55.       return 0;
  56.     }
  57.   }
  58.   return -1;
  59. }
  60. // Reads IFO File or IFO Backup File 
  61. // vtsn is 0 for VIDEO_TS.IFO, or 1 thru 99 for VTS_xx_0.IFO (where xx is vtsn)
  62. // if backup is zero, first the IFO and then, on failure, the BUP will be read.
  63. // if backup is not zero, only the backup file will be read (.BUP)
  64. // *infodata will be allocated to size of file
  65. // returns 0 on error, number of blocks read on success
  66. int FileReadIFO(int vtsn, int backup, unsigned char **infodata) {
  67.   char filename[PATH_MAX];
  68.   char filename_ifo[PATH_MAX];
  69.   char filename_bup[PATH_MAX];
  70.   long int infolength;
  71.   int blocks;
  72.   FILE* info;
  73.   *infodata=NULL;
  74.   if (strlen(Videopath)==0) return 0;  // No dvd root set
  75.   
  76.   if ((vtsn<0) || (vtsn>99)) return 0;  // illegal title number
  77.   if (vtsn) {
  78.     sprintf(filename_ifo,TITLEFORMAT,vtsn,0);
  79.   } else {
  80.     strcpy(filename_ifo,DISCINDEX);
  81.   }
  82.   strcpy(filename_bup,filename_ifo);
  83.   strcat(filename_ifo,INFOFILE);
  84.   strcat(filename_bup,INFOBACKUP);
  85.   while (1) {
  86.     if (backup) strcpy(filename_ifo,filename_bup);
  87.     if (find_file(Videopath,filename_ifo,filename)) {
  88.       if (backup++) return 0;
  89.       continue;
  90.     }
  91.     if ((info=fopen(filename,"r"))==NULL) {
  92.       if (backup++) return 0;
  93.       continue;
  94.     }
  95.     fseek(info,0L,SEEK_END);  // go to end
  96.     infolength=ftell(info);
  97.     fseek(info,0L,SEEK_SET);  // go to start
  98.     blocks=(infolength-1)/LB_Len;
  99.     if ((*infodata=(char *)malloc((blocks+1)*LB_Len))==NULL) return 0;
  100.     if (!fread(*infodata,(blocks+1)*LB_Len,1,info)) {
  101.       free(*infodata);
  102.       *infodata=NULL;
  103.       if (backup++) return 0;
  104.       continue;
  105.     } else return blocks;
  106.   }
  107. }
  108. // opens the vob file of the video manager
  109. // returns 0 on success, 1 on error
  110. int open_menumovie(void) {
  111.   char filename[PATH_MAX];
  112.   if (find_file(Videopath,DISCINDEX VIDEOOBJECT,filename)) return 1;  // file not existing
  113.   if ((menumovie=fopen(filename,"r"))==NULL) return 1;   // file not readable
  114.   return 0;
  115. }
  116. // reads Logical Block of a vmg menu (VIDEO_TS.VOB)
  117. // return 0 on success, >0 on error
  118. int FileReadVMGM(long int lbnum, unsigned char *data) {
  119.   if (strlen(Videopath)==0) return 1;  // No dvd root set
  120.   if (menumovie==NULL) open_menumovie();
  121.   if (fseek(menumovie,lbnum*LB_Len,SEEK_SET)<0) return 1; // position not found
  122.   return (!fread(data,LB_Len,1,menumovie));
  123. }
  124. // updates the segment length table of a video title set
  125. // stores the length of VTS_xx_0.VOB thru VTS_xx_9.VOB into an array
  126. // returns 0 on success, >0 on error
  127. int update_segments(int vtsn) {
  128.   char file[PATH_MAX];
  129.   char filename[PATH_MAX];
  130.   int segment;
  131.   if ((vtsn<1) || (vtsn>99)) return 1;  // wrong VTS number
  132.   currentvtsn=vtsn;
  133.   if (currentsegment>=0) fclose(movie);
  134.   currentsegment=-1;
  135.   for (segment=0; segment<10; segment++) {
  136.     sprintf(file,TITLEFORMAT VIDEOOBJECT,vtsn,segment);
  137.     if (find_file(Videopath,file,filename)) segmentlength[segment]=0;  // file not existing
  138.     else if ((movie=fopen(filename,"r"))==NULL) segmentlength[segment]=0;   // file not readable
  139.     else {
  140.       fseek(movie,0L,SEEK_END);
  141.       segmentlength[segment]=ftell(movie);
  142.       fclose(movie);
  143.     }
  144.   }
  145.   return 0;
  146. }
  147. // opens one sement of a VTS
  148. // returns 0 on success, >0 on error
  149. int open_segment(int vtsn, int segment) {
  150.   char file[PATH_MAX];
  151.   char filename[PATH_MAX];
  152.   if (currentsegment>=0) fclose(movie);
  153.   currentsegment=-1;
  154.   sprintf(file,TITLEFORMAT VIDEOOBJECT,vtsn,segment);
  155.   if (find_file(Videopath,file,filename)) return 1;  // file not existing
  156.   if ((movie=fopen(filename,"r"))==NULL) return 1;   // file not readable
  157.   currentsegment=segment;
  158.   return 0;
  159. }
  160. // reads Logical Block of a vts menu
  161. // vtsn is 1 thru 99 for VTS_xx_0.VOB (where xx is vtsn)
  162. // return 0 on success, >0 on error
  163. int FileReadVTSM(int vtsn, long int lbnum, unsigned char *data) {
  164.   long int offset;
  165.   if (strlen(Videopath)==0) return 1;             // No dvd root set
  166.   if ((vtsn<1) || (vtsn>99)) return 1;            // wrong vts number
  167.   offset=lbnum*LB_Len;
  168.   if (currentvtsn!=vtsn) {  // have to update segment table?
  169.     update_segments(vtsn);
  170.   }
  171.   if (offset>=segmentlength[0]) return 1;         // seek beyond EOF
  172.   if (currentsegment!=0)
  173.     if (open_segment(vtsn,0)) return 1;           // open failed
  174.   if (fseek(movie,offset,SEEK_SET)<0) return 1;   // position not found
  175.   return (!fread(data,LB_Len,1,movie));
  176. }
  177. // reads Logical Block of a video title set
  178. // vtsn is 1 thru 99 for VTS_xx_y.VOB (where xx is vtsn and y is 1 thru 9)
  179. // return 0 on success, 1 on error
  180. int FileReadVTS(int vtsn, long int lbnum, unsigned char *data) {
  181.   long int offset;
  182.   int segment;
  183.   if (strlen(Videopath)==0) return 1;             // No dvd root set
  184.   if ((vtsn<1) || (vtsn>99)) return 1;            // wrong vts number
  185.   offset=lbnum*LB_Len;
  186.   if (currentvtsn!=vtsn) {  // have to update segment table?
  187.     update_segments(vtsn);
  188.   }
  189.   segment=1;
  190.   while (segment<10) {
  191.     if (segmentlength[segment]<=offset) {  // that's not our segment yet
  192.       offset-=segmentlength[segment];  // skip to next segment
  193.       segment++;
  194.     } else {  // our segment
  195.       if (currentsegment!=segment)
  196.         if (open_segment(vtsn,segment)) return 1;
  197.       if (fseek(movie,offset,SEEK_SET)<0) break;  // position not found
  198.       return (!fread(data,LB_Len,1,movie));
  199.     }
  200.   }
  201.   return 1;  // seek beyond EOF
  202. }
  203. // Set the path to the UDF mounted DVD disc
  204. // Or the Path to the VIDEO_TS directory
  205. // returns 0 on success, -1 on 'dvd not found', -2 on 'path not found'
  206. int FileSetVideoPath(char *Path, int LB_Length) {
  207.   int err;
  208.   LB_Len=LB_Length;   // the Block Length we use
  209.   currentvtsn=-1;     // no VTS open yet
  210.   currentsegment=-1;  // no segment open yet
  211.   if ((err=find_file(Path,VIDEOPATH,Videopath))) {      // dvd inserted?
  212.     if (find_file(Path,DISCINDEX INFOFILE,Videopath)) {      // does path already point
  213.       if (find_file(Path,DISCINDEX INFOBACKUP,Videopath)) {  // into VIDEO_TS dir?
  214.         return err;
  215.       } else strcpy(Videopath,Path);
  216.     } else strcpy(Videopath,Path);
  217.   }
  218.   return 0;
  219. }