file.c
上传用户:riyaled888
上传日期:2009-03-27
资源大小:7338k
文件大小:17k
源码类别:

多媒体

开发平台:

MultiPlatform

  1. /*****************************************************************************
  2.  * file.c: file input (file: access plug-in)
  3.  *****************************************************************************
  4.  * Copyright (C) 2001-2004 VideoLAN
  5.  * $Id: file.c 8917 2004-10-05 15:31:22Z gbazin $
  6.  *
  7.  * Authors: Christophe Massiot <massiot@via.ecp.fr>
  8.  *
  9.  * This program is free software; you can redistribute it and/or modify
  10.  * it under the terms of the GNU General Public License as published by
  11.  * the Free Software Foundation; either version 2 of the License, or
  12.  * (at your option) any later version.
  13.  *
  14.  * This program is distributed in the hope that it will be useful,
  15.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17.  * GNU General Public License for more details.
  18.  *
  19.  * You should have received a copy of the GNU General Public License
  20.  * along with this program; if not, write to the Free Software
  21.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
  22.  *****************************************************************************/
  23. /*****************************************************************************
  24.  * Preamble
  25.  *****************************************************************************/
  26. #include <vlc/vlc.h>
  27. #include <vlc/input.h>
  28. #include <stdlib.h>
  29. #include <string.h>
  30. #include <errno.h>
  31. #ifdef HAVE_SYS_TYPES_H
  32. #   include <sys/types.h>
  33. #endif
  34. #ifdef HAVE_SYS_TIME_H
  35. #   include <sys/time.h>
  36. #endif
  37. #ifdef HAVE_SYS_STAT_H
  38. #   include <sys/stat.h>
  39. #endif
  40. #ifdef HAVE_FCNTL_H
  41. #   include <fcntl.h>
  42. #endif
  43. #ifdef HAVE_UNISTD_H
  44. #   include <unistd.h>
  45. #elif defined( WIN32 ) && !defined( UNDER_CE )
  46. #   include <io.h>
  47. #endif
  48. #if defined( WIN32 ) && !defined( UNDER_CE )
  49. /* stat() support for large files on win32 */
  50. #   define stat _stati64
  51. #   define fstat(a,b) _fstati64(a,b)
  52. #   ifdef lseek
  53. #      undef lseek
  54. #   endif
  55. #   define lseek _lseeki64
  56. #elif defined( UNDER_CE )
  57. #   ifdef read
  58. #      undef read
  59. #   endif
  60. #   define read(a,b,c) fread(b,1,c,a)
  61. #   define close(a) fclose(a)
  62. #   ifdef lseek
  63. #      undef lseek
  64. #   endif
  65. #   define lseek fseek
  66. #endif
  67. /*****************************************************************************
  68.  * Module descriptor
  69.  *****************************************************************************/
  70. static int  Open ( vlc_object_t * );
  71. static void Close( vlc_object_t * );
  72. #define CACHING_TEXT N_("Caching value in ms")
  73. #define CACHING_LONGTEXT N_( 
  74.     "Allows you to modify the default caching value for file streams. This " 
  75.     "value should be set in millisecond units." )
  76. #define CAT_TEXT N_("Concatenate with additional files")
  77. #define CAT_LONGTEXT N_( 
  78.     "Allows you to play split files as if they were part of a unique file. " 
  79.     "Specify a comma-separated list of files." )
  80. vlc_module_begin();
  81.     set_description( _("Standard filesystem file input") );
  82.     add_integer( "file-caching", DEFAULT_PTS_DELAY / 1000, NULL, CACHING_TEXT, CACHING_LONGTEXT, VLC_TRUE );
  83.     add_string( "file-cat", NULL, NULL, CAT_TEXT, CAT_LONGTEXT, VLC_TRUE );
  84.     set_capability( "access2", 50 );
  85.     add_shortcut( "file" );
  86.     add_shortcut( "stream" );
  87.     add_shortcut( "kfir" );
  88.     set_callbacks( Open, Close );
  89. vlc_module_end();
  90. /*****************************************************************************
  91.  * Exported prototypes
  92.  *****************************************************************************/
  93. static int  Seek( access_t *, int64_t );
  94. static int  Read( access_t *, uint8_t *, int );
  95. static int  Control( access_t *, int, va_list );
  96. static int  _OpenFile( access_t *, char * );
  97. typedef struct
  98. {
  99.     char     *psz_name;
  100.     int64_t  i_size;
  101. } file_entry_t;
  102. struct access_sys_t
  103. {
  104.     unsigned int i_nb_reads;
  105.     vlc_bool_t   b_kfir;
  106.     /* Files list */
  107.     int          i_file;
  108.     file_entry_t **file;
  109.     /* Current file */
  110.     int  i_index;
  111. #ifndef UNDER_CE
  112.     int  fd;
  113.     int  fd_backup;
  114. #else
  115.     FILE *fd;
  116.     FILE *fd_backup;
  117. #endif
  118.     /* */
  119.     vlc_bool_t b_seekable;
  120.     vlc_bool_t b_pace_control;
  121. };
  122. /*****************************************************************************
  123.  * Open: open the file
  124.  *****************************************************************************/
  125. static int Open( vlc_object_t *p_this )
  126. {
  127.     access_t     *p_access = (access_t*)p_this;
  128.     access_sys_t *p_sys;
  129.     char *psz_name = p_access->psz_path;
  130.     char *psz;
  131. #ifdef HAVE_SYS_STAT_H
  132.     int                 i_stat;
  133.     struct stat         stat_info;
  134. #endif
  135.     vlc_bool_t          b_stdin;
  136.     file_entry_t *      p_file;
  137.     b_stdin = psz_name[0] == '-' && psz_name[1] == '';
  138. #ifdef HAVE_SYS_STAT_H
  139.     if( !b_stdin && (i_stat = stat( psz_name, &stat_info )) == (-1) )
  140.     {
  141.         msg_Warn( p_access, "cannot stat() file `%s' (%s)",
  142.                   psz_name, strerror(errno));
  143.         return VLC_EGENERIC;
  144.     }
  145. #endif
  146.     p_access->pf_read = Read;
  147.     p_access->pf_block = NULL;
  148.     p_access->pf_seek = Seek;
  149.     p_access->pf_control = Control;
  150.     p_access->info.i_update = 0;
  151.     p_access->info.i_size = 0;
  152.     p_access->info.i_pos = 0;
  153.     p_access->info.b_eof = VLC_FALSE;
  154.     p_access->info.i_title = 0;
  155.     p_access->info.i_seekpoint = 0;
  156.     p_access->p_sys = p_sys = malloc( sizeof( access_sys_t ) );
  157.     p_sys->i_nb_reads = 0;
  158.     p_sys->b_kfir = VLC_FALSE;
  159.     p_sys->file = NULL;
  160.     p_sys->i_file = 0;
  161.     p_sys->i_index = 0;
  162.     p_sys->fd = -1;
  163.     if( !strcasecmp( p_access->psz_access, "stream" ) )
  164.     {
  165.         p_sys->b_seekable = VLC_FALSE;
  166.         p_sys->b_pace_control = VLC_FALSE;
  167.     }
  168.     else if( !strcasecmp( p_access->psz_access, "kfir" ) )
  169.     {
  170.         p_sys->b_seekable = VLC_FALSE;
  171.         p_sys->b_pace_control = VLC_FALSE;
  172.         p_sys->b_kfir = VLC_TRUE;
  173.     }
  174.     else
  175.     {
  176.         /* file:%s or %s */
  177.         p_sys->b_pace_control = VLC_TRUE;
  178.         if( b_stdin )
  179.         {
  180.             p_sys->b_seekable = VLC_FALSE;
  181.         }
  182. #ifdef UNDER_CE
  183.         else if( VLC_TRUE )
  184.         {
  185.             /* We'll update i_size after it's been opened */
  186.             p_sys->b_seekable = VLC_TRUE;
  187.         }
  188. #elif defined( HAVE_SYS_STAT_H )
  189.         else if( S_ISREG(stat_info.st_mode) || S_ISCHR(stat_info.st_mode) ||
  190.                  S_ISBLK(stat_info.st_mode) )
  191.         {
  192.             p_sys->b_seekable = VLC_TRUE;
  193.             p_access->info.i_size = stat_info.st_size;
  194.         }
  195.         else if( S_ISFIFO(stat_info.st_mode)
  196. #   if !defined( SYS_BEOS ) && !defined( WIN32 )
  197.                   || S_ISSOCK(stat_info.st_mode)
  198. #   endif
  199.                )
  200.         {
  201.             p_sys->b_seekable = VLC_FALSE;
  202.         }
  203. #endif
  204.         else
  205.         {
  206.             msg_Err( p_access, "unknown file type for `%s'", psz_name );
  207.             return VLC_EGENERIC;
  208.         }
  209.     }
  210.     msg_Dbg( p_access, "opening file `%s'", psz_name );
  211.     if( b_stdin )
  212.     {
  213.         p_sys->fd = 0;
  214.     }
  215.     else if( _OpenFile( p_access, psz_name ) )
  216.     {
  217.         free( p_sys );
  218.         return VLC_EGENERIC;
  219.     }
  220.     if( p_sys->b_seekable && !p_access->info.i_size )
  221.     {
  222.         /* FIXME that's bad because all others access will be probed */
  223.         msg_Err( p_access, "file %s is empty, aborting", psz_name );
  224.         free( p_sys );
  225.         return VLC_EGENERIC;
  226.     }
  227.     /* Update default_pts to a suitable value for file access */
  228.     var_Create( p_access, "file-caching", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
  229.     /*
  230.      * Get the additional list of files
  231.      */
  232.     p_file = malloc( sizeof(file_entry_t) );
  233.     p_file->i_size = p_access->info.i_size;
  234.     p_file->psz_name = strdup( psz_name );
  235.     TAB_APPEND( p_sys->i_file, p_sys->file, p_file );
  236.     psz = var_CreateGetString( p_access, "file-cat" );
  237.     if( *psz )
  238.     {
  239.         char *psz_parser = psz_name = psz;
  240.         int64_t i_size;
  241.         while( psz_name && *psz_name )
  242.         {
  243.             psz_parser = strchr( psz_name, ',' );
  244.             if( psz_parser ) *psz_parser = 0;
  245.             psz_name = strdup( psz_name );
  246.             if( psz_name )
  247.             {
  248.                 msg_Dbg( p_access, "adding file `%s'", psz_name );
  249.                 i_size = 0;
  250. #ifdef HAVE_SYS_STAT_H
  251.                 if( !stat( psz_name, &stat_info ) )
  252.                 {
  253.                     p_access->info.i_size += stat_info.st_size;
  254.                     i_size = stat_info.st_size;
  255.                 }
  256.                 else
  257.                 {
  258.                     msg_Dbg( p_access, "cannot stat() file `%s'", psz_name );
  259.                 }
  260. #endif
  261.                 p_file = malloc( sizeof(file_entry_t) );
  262.                 p_file->i_size = i_size;
  263.                 p_file->psz_name = psz_name;
  264.                 TAB_APPEND( p_sys->i_file, p_sys->file, p_file );
  265.             }
  266.             psz_name = psz_parser;
  267.             if( psz_name ) psz_name++;
  268.         }
  269.     }
  270.     free( psz );
  271.     return VLC_SUCCESS;
  272. }
  273. /*****************************************************************************
  274.  * Close: close the target
  275.  *****************************************************************************/
  276. static void Close( vlc_object_t * p_this )
  277. {
  278.     access_t     *p_access = (access_t*)p_this;
  279.     access_sys_t *p_sys = p_access->p_sys;
  280.     int i;
  281.     close( p_sys->fd );
  282.     for( i = 0; i < p_sys->i_file; i++ )
  283.     {
  284.         free( p_sys->file[i]->psz_name );
  285.         free( p_sys->file[i] );
  286.     }
  287.     free( p_sys->file );
  288.     free( p_sys );
  289. }
  290. /*****************************************************************************
  291.  * Read: standard read on a file descriptor.
  292.  *****************************************************************************/
  293. static int Read( access_t *p_access, uint8_t *p_buffer, int i_len )
  294. {
  295.     access_sys_t *p_sys = p_access->p_sys;
  296.     int i_ret;
  297. #if !defined(WIN32) && !defined(UNDER_CE)
  298.     if( !p_sys->b_pace_control )
  299.     {
  300.         if( !p_sys->b_kfir )
  301.         {
  302.             /* Find if some data is available. This won't work under Windows. */
  303.             struct timeval  timeout;
  304.             fd_set          fds;
  305.             /* Initialize file descriptor set */
  306.             FD_ZERO( &fds );
  307.             FD_SET( p_sys->fd, &fds );
  308.             /* We'll wait 0.5 second if nothing happens */
  309.             timeout.tv_sec = 0;
  310.             timeout.tv_usec = 500000;
  311.             /* Find if some data is available */
  312.             while( (i_ret = select( p_sys->fd + 1, &fds, NULL, NULL, &timeout )) == 0
  313.                     || (i_ret < 0 && errno == EINTR) )
  314.             {
  315.                 FD_ZERO( &fds );
  316.                 FD_SET( p_sys->fd, &fds );
  317.                 timeout.tv_sec = 0;
  318.                 timeout.tv_usec = 500000;
  319.                 if( p_access->b_die )
  320.                     return 0;
  321.             }
  322.             if( i_ret < 0 )
  323.             {
  324.                 msg_Err( p_access, "select error (%s)", strerror(errno) );
  325.                 return -1;
  326.             }
  327.             i_ret = read( p_sys->fd, p_buffer, i_len );
  328.         }
  329.         else
  330.         {
  331.             /* b_kfir ; work around a buggy poll() driver implementation */
  332.             while ( (i_ret = read( p_sys->fd, p_buffer, i_len )) == 0 &&
  333.                     !p_access->b_die )
  334.             {
  335.                 msleep( INPUT_ERROR_SLEEP );
  336.             }
  337.         }
  338.     }
  339.     else
  340. #endif /* WIN32 || UNDER_CE */
  341.     {
  342.         /* b_pace_control || WIN32 */
  343.         i_ret = read( p_sys->fd, p_buffer, i_len );
  344.     }
  345.     if( i_ret < 0 )
  346.     {
  347.         if( errno != EINTR && errno != EAGAIN )
  348.             msg_Err( p_access, "read failed (%s)", strerror(errno) );
  349.         /* Delay a bit to avoid consuming all the CPU. This is particularly
  350.          * useful when reading from an unconnected FIFO. */
  351.         msleep( INPUT_ERROR_SLEEP );
  352.     }
  353.     p_sys->i_nb_reads++;
  354. #ifdef HAVE_SYS_STAT_H
  355.     if( p_access->info.i_size != 0 &&
  356.         (p_sys->i_nb_reads % INPUT_FSTAT_NB_READS) == 0 )
  357.     {
  358.         struct stat stat_info;
  359.         int i_file = p_sys->i_index;
  360.         if ( fstat( p_sys->fd, &stat_info ) == -1 )
  361.         {
  362.             msg_Warn( p_access, "couldn't stat again the file (%s)", strerror(errno) );
  363.         }
  364.         else if ( p_sys->file[i_file]->i_size != stat_info.st_size )
  365.         {
  366.             p_access->info.i_size += (stat_info.st_size - p_sys->file[i_file]->i_size );
  367.             p_access->info.i_update |= INPUT_UPDATE_SIZE;
  368.         }
  369.     }
  370. #endif
  371.     /* If we reached an EOF then switch to the next file in the list */
  372.     if ( i_ret == 0 && p_sys->i_index + 1 < p_sys->i_file )
  373.     {
  374.         char *psz_name = p_sys->file[++p_sys->i_index]->psz_name;
  375.         p_sys->fd_backup = p_sys->fd;
  376.         msg_Dbg( p_access, "opening file `%s'", psz_name );
  377.         if ( _OpenFile( p_access, psz_name ) )
  378.         {
  379.             p_sys->fd = p_sys->fd_backup;
  380.             return 0;
  381.         }
  382.         close( p_sys->fd_backup );
  383.         /* We have to read some data */
  384.         return Read( p_access, p_buffer, i_len );
  385.     }
  386.     if( i_ret > 0 )
  387.         p_access->info.i_pos += i_ret;
  388.     else if( i_ret == 0 )
  389.         p_access->info.b_eof = VLC_TRUE;
  390.     return i_ret;
  391. }
  392. /*****************************************************************************
  393.  * Seek: seek to a specific location in a file
  394.  *****************************************************************************/
  395. static int Seek( access_t *p_access, int64_t i_pos )
  396. {
  397.     access_sys_t *p_sys = p_access->p_sys;
  398.     int64_t i_size = 0;
  399.     /* Check which file we need to access */
  400.     if( p_sys->i_file > 1 )
  401.     {
  402.         int i;
  403.         char *psz_name;
  404.         p_sys->fd_backup = p_sys->fd;
  405.         for( i = 0; i < p_sys->i_file - 1; i++ )
  406.         {
  407.             if( i_pos < p_sys->file[i]->i_size + i_size )
  408.                 break;
  409.             i_size += p_sys->file[i]->i_size;
  410.         }
  411.         psz_name = p_sys->file[i]->psz_name;
  412.         msg_Dbg( p_access, "opening file `%s'", psz_name );
  413.         if ( i != p_sys->i_index && !_OpenFile( p_access, psz_name ) )
  414.         {
  415.             /* Close old file */
  416.             close( p_sys->fd_backup );
  417.             p_sys->i_index = i;
  418.         }
  419.         else
  420.         {
  421.             p_sys->fd = p_sys->fd_backup;
  422.         }
  423.     }
  424.     lseek( p_sys->fd, i_pos - i_size, SEEK_SET );
  425.     p_access->info.i_pos = i_pos;
  426.     if( p_access->info.i_size < p_access->info.i_pos )
  427.     {
  428.         msg_Err( p_access, "seeking too far" );
  429.         p_access->info.i_pos = p_access->info.i_size;
  430.     }
  431.     else if( p_access->info.i_pos < 0 )
  432.     {
  433.         msg_Err( p_access, "seeking too early" );
  434.         p_access->info.i_pos = 0;
  435.     }
  436.     /* Reset eof */
  437.     p_access->info.b_eof = VLC_FALSE;
  438.     /* FIXME */
  439.     return VLC_SUCCESS;
  440. }
  441. /*****************************************************************************
  442.  * Control:
  443.  *****************************************************************************/
  444. static int Control( access_t *p_access, int i_query, va_list args )
  445. {
  446.     access_sys_t *p_sys = p_access->p_sys;
  447.     vlc_bool_t   *pb_bool;
  448.     int          *pi_int;
  449.     int64_t      *pi_64;
  450.     switch( i_query )
  451.     {
  452.         /* */
  453.         case ACCESS_CAN_SEEK:
  454.         case ACCESS_CAN_FASTSEEK:
  455.             pb_bool = (vlc_bool_t*)va_arg( args, vlc_bool_t* );
  456.             *pb_bool = p_sys->b_seekable;
  457.             break;
  458.         case ACCESS_CAN_PAUSE:
  459.         case ACCESS_CAN_CONTROL_PACE:
  460.             pb_bool = (vlc_bool_t*)va_arg( args, vlc_bool_t* );
  461.             *pb_bool = p_sys->b_pace_control;
  462.             break;
  463.         /* */
  464.         case ACCESS_GET_MTU:
  465.             pi_int = (int*)va_arg( args, int * );
  466.             *pi_int = 0;
  467.             break;
  468.         case ACCESS_GET_PTS_DELAY:
  469.             pi_64 = (int64_t*)va_arg( args, int64_t * );
  470.             *pi_64 = var_GetInteger( p_access, "file-caching" ) * I64C(1000);
  471.             break;
  472.         /* */
  473.         case ACCESS_SET_PAUSE_STATE:
  474.             /* Nothing to do */
  475.             break;
  476.         case ACCESS_GET_TITLE_INFO:
  477.         case ACCESS_SET_TITLE:
  478.         case ACCESS_SET_SEEKPOINT:
  479.         case ACCESS_SET_PRIVATE_ID_STATE:
  480.             return VLC_EGENERIC;
  481.         default:
  482.             msg_Warn( p_access, "unimplemented query in control" );
  483.             return VLC_EGENERIC;
  484.     }
  485.     return VLC_SUCCESS;
  486. }
  487. /*****************************************************************************
  488.  * OpenFile: Opens a specific file
  489.  *****************************************************************************/
  490. static int _OpenFile( access_t * p_access, char * psz_name )
  491. {
  492.     access_sys_t *p_sys = p_access->p_sys;
  493. #ifdef UNDER_CE
  494.     p_sys->fd = fopen( psz_name, "rb" );
  495.     if ( !p_sys->fd )
  496.     {
  497.         msg_Err( p_access, "cannot open file %s" );
  498.         return VLC_EGENERIC;
  499.     }
  500.     fseek( p_sys->fd, 0, SEEK_END );
  501.     p_access->info.i_size = ftell( p_sys->fd );
  502.     p_access->info.i_update |= INPUT_UPDATE_SIZE;
  503.     fseek( p_sys->fd, 0, SEEK_SET );
  504. #else
  505.     p_sys->fd = open( psz_name, O_NONBLOCK /*| O_LARGEFILE*/ );
  506.     if ( p_sys->fd == -1 )
  507.     {
  508.         msg_Err( p_access, "cannot open file %s (%s)", psz_name,
  509.                  strerror(errno) );
  510.         return VLC_EGENERIC;
  511.     }
  512. #endif
  513.     return VLC_SUCCESS;
  514. }