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

多媒体

开发平台:

MultiPlatform

  1. /*****************************************************************************
  2.  * vcd.c : VCD input module for vlc
  3.  *****************************************************************************
  4.  * Copyright (C) 2000-2004 VideoLAN
  5.  * $Id: vcd.c 8606 2004-08-31 18:32:54Z hartman $
  6.  *
  7.  * Author: Johan Bilien <jobi@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 <stdlib.h>
  27. #include <vlc/vlc.h>
  28. #include <vlc/input.h>
  29. #include "cdrom.h"
  30. /*****************************************************************************
  31.  * Module descriptior
  32.  *****************************************************************************/
  33. static int  Open ( vlc_object_t * );
  34. static void Close( vlc_object_t * );
  35. #define CACHING_TEXT N_("Caching value in ms")
  36. #define CACHING_LONGTEXT N_( 
  37.     "Allows you to modify the default caching value for cdda streams. This " 
  38.     "value should be set in milliseconds units." )
  39. vlc_module_begin();
  40.     set_description( _("VCD input") );
  41.     set_capability( "access2", 60 );
  42.     set_callbacks( Open, Close );
  43.     add_usage_hint( N_("[vcd:][device][@[title][,[chapter]]]") );
  44.     add_integer( "vcd-caching", DEFAULT_PTS_DELAY / 1000, NULL, CACHING_TEXT,
  45.                  CACHING_LONGTEXT, VLC_TRUE );
  46.     add_shortcut( "vcd" );
  47.     add_shortcut( "svcd" );
  48. vlc_module_end();
  49. /*****************************************************************************
  50.  * Local prototypes
  51.  *****************************************************************************/
  52. /* how many blocks VCDRead will read in each loop */
  53. #define VCD_BLOCKS_ONCE 20
  54. #define VCD_DATA_ONCE   (VCD_BLOCKS_ONCE * VCD_DATA_SIZE)
  55. struct access_sys_t
  56. {
  57.     vcddev_t    *vcddev;                            /* vcd device descriptor */
  58.     /* Title infos */
  59.     int           i_titles;
  60.     input_title_t *title[99];            /* No more that 99 track in a vcd ? */
  61.     int         i_sector;                                  /* Current Sector */
  62.     int         *p_sectors;                                 /* Track sectors */
  63. };
  64. static block_t *Block( access_t * );
  65. static int      Seek( access_t *, int64_t );
  66. static int      Control( access_t *, int, va_list );
  67. static int      EntryPoints( access_t * );
  68. /*****************************************************************************
  69.  * VCDOpen: open vcd
  70.  *****************************************************************************/
  71. static int Open( vlc_object_t *p_this )
  72. {
  73.     access_t     *p_access = (access_t *)p_this;
  74.     access_sys_t *p_sys;
  75.     char *psz_dup = strdup( p_access->psz_path );
  76.     char *psz;
  77.     int i_title = 0;
  78.     int i_chapter = 0;
  79.     int i;
  80.     vcddev_t *vcddev;
  81.     /* Command line: vcd://[dev_path][@title[,chapter]] */
  82.     if( ( psz = strchr( psz_dup, '@' ) ) )
  83.     {
  84.         *psz++ = '';
  85.         i_title = strtol( psz, &psz, 0 );
  86.         if( *psz )
  87.             i_chapter = strtol( psz+1, &psz, 0 );
  88.     }
  89.     if( *psz_dup == '' )
  90.     {
  91.         free( psz_dup );
  92.         /* Only when selected */
  93.         if( strcmp( p_access->psz_access, "vcd" ) &&
  94.             strcmp( p_access->psz_access, "svcd" ) )
  95.             return VLC_EGENERIC;
  96.         psz_dup = var_CreateGetString( p_access, "vcd" );
  97.         if( *psz_dup == '' )
  98.         {
  99.             free( psz_dup );
  100.             return VLC_EGENERIC;
  101.         }
  102.     }
  103.     /* Open VCD */
  104.     if( !(vcddev = ioctl_Open( p_this, psz_dup )) )
  105.     {
  106.         msg_Warn( p_access, "could not open %s", psz_dup );
  107.         free( psz_dup );
  108.         return VLC_EGENERIC;
  109.     }
  110.     free( psz_dup );
  111.     /* Set up p_access */
  112.     p_access->pf_read = NULL;
  113.     p_access->pf_block = Block;
  114.     p_access->pf_control = Control;
  115.     p_access->pf_seek = Seek;
  116.     p_access->info.i_update = 0;
  117.     p_access->info.i_size = 0;
  118.     p_access->info.i_pos = 0;
  119.     p_access->info.b_eof = VLC_FALSE;
  120.     p_access->info.i_title = 0;
  121.     p_access->info.i_seekpoint = 0;
  122.     p_access->p_sys = p_sys = malloc( sizeof( access_sys_t ) );
  123.     memset( p_sys, 0, sizeof( access_sys_t ) );
  124.     p_sys->vcddev = vcddev;
  125.     /* We read the Table Of Content information */
  126.     p_sys->i_titles = ioctl_GetTracksMap( VLC_OBJECT(p_access),
  127.                                           p_sys->vcddev, &p_sys->p_sectors );
  128.     if( p_sys->i_titles < 0 )
  129.     {
  130.         msg_Err( p_access, "unable to count tracks" );
  131.         goto error;
  132.     }
  133.     else if( p_sys->i_titles <= 1 )
  134.     {
  135.         msg_Err( p_access, "no movie tracks found" );
  136.         goto error;
  137.     }
  138.     /* The first title isn't usable */
  139.     p_sys->i_titles--;
  140.     /* Build title table */
  141.     for( i = 0; i < p_sys->i_titles; i++ )
  142.     {
  143.         input_title_t *t = p_sys->title[i] = vlc_input_title_New();
  144.         fprintf( stderr, "title[%d] start=%dn", i, p_sys->p_sectors[1+i] );
  145.         fprintf( stderr, "title[%d] end=%dn", i, p_sys->p_sectors[i+2] );
  146.         t->i_size = ( p_sys->p_sectors[i+2] - p_sys->p_sectors[i+1] ) *
  147.                     (int64_t)VCD_DATA_SIZE;
  148.     }
  149.     /* Map entry points into chapters */
  150.     if( EntryPoints( p_access ) )
  151.     {
  152.         msg_Warn( p_access, "could not read entry points, will not use them" );
  153.     }
  154.     /* Starting title/chapter and sector */
  155.     if( i_title >= p_sys->i_titles )
  156.         i_title = 0;
  157.     if( i_chapter >= p_sys->title[i_title]->i_seekpoint )
  158.         i_chapter = 0;
  159.     p_sys->i_sector = p_sys->p_sectors[1+i_title];
  160.     if( i_chapter > 0 )
  161.     {
  162.         p_sys->i_sector +=
  163.             ( p_sys->title[i_title]->seekpoint[i_chapter]->i_byte_offset /
  164.               VCD_DATA_SIZE );
  165.     }
  166.     p_access->info.i_title = i_title;
  167.     p_access->info.i_seekpoint = i_chapter;
  168.     p_access->info.i_size = p_sys->title[i_title]->i_size;
  169.     p_access->info.i_pos = ( p_sys->i_sector - p_sys->p_sectors[1+i_title] ) *
  170.         VCD_DATA_SIZE;
  171.     p_access->psz_demux = strdup( "ps" );
  172.     return VLC_SUCCESS;
  173. error:
  174.     ioctl_Close( VLC_OBJECT(p_access), p_sys->vcddev );
  175.     free( p_sys );
  176.     return VLC_EGENERIC;
  177. }
  178. /*****************************************************************************
  179.  * Close: closes vcd
  180.  *****************************************************************************/
  181. static void Close( vlc_object_t *p_this )
  182. {
  183.     access_t     *p_access = (access_t *)p_this;
  184.     access_sys_t *p_sys = p_access->p_sys;
  185.     ioctl_Close( p_this, p_sys->vcddev );
  186.     free( p_sys );
  187. }
  188. /*****************************************************************************
  189.  * Control:
  190.  *****************************************************************************/
  191. static int Control( access_t *p_access, int i_query, va_list args )
  192. {
  193.     access_sys_t *p_sys = p_access->p_sys;
  194.     vlc_bool_t   *pb_bool;
  195.     int          *pi_int;
  196.     int64_t      *pi_64;
  197.     input_title_t ***ppp_title;
  198.     int i;
  199.     switch( i_query )
  200.     {
  201.         /* */
  202.         case ACCESS_CAN_SEEK:
  203.         case ACCESS_CAN_FASTSEEK:
  204.         case ACCESS_CAN_PAUSE:
  205.         case ACCESS_CAN_CONTROL_PACE:
  206.             pb_bool = (vlc_bool_t*)va_arg( args, vlc_bool_t* );
  207.             *pb_bool = VLC_TRUE;
  208.             break;
  209.         /* */
  210.         case ACCESS_GET_MTU:
  211.             pi_int = (int*)va_arg( args, int * );
  212.             *pi_int = VCD_DATA_ONCE;
  213.             break;
  214.         case ACCESS_GET_PTS_DELAY:
  215.             pi_64 = (int64_t*)va_arg( args, int64_t * );
  216.             *pi_64 = var_GetInteger( p_access, "vcd-caching" ) * 1000;
  217.             break;
  218.         /* */
  219.         case ACCESS_SET_PAUSE_STATE:
  220.             break;
  221.         case ACCESS_GET_TITLE_INFO:
  222.             ppp_title = (input_title_t***)va_arg( args, input_title_t*** );
  223.             pi_int    = (int*)va_arg( args, int* );
  224.             /* Duplicate title infos */
  225.             *pi_int = p_sys->i_titles;
  226.             *ppp_title = malloc( sizeof(input_title_t **) * p_sys->i_titles );
  227.             for( i = 0; i < p_sys->i_titles; i++ )
  228.             {
  229.                 (*ppp_title)[i] = vlc_input_title_Duplicate( p_sys->title[i] );
  230.             }
  231.             break;
  232.         case ACCESS_SET_TITLE:
  233.             i = (int)va_arg( args, int );
  234.             if( i != p_access->info.i_title )
  235.             {
  236.                 /* Update info */
  237.                 p_access->info.i_update |=
  238.                   INPUT_UPDATE_TITLE|INPUT_UPDATE_SEEKPOINT|INPUT_UPDATE_SIZE;
  239.                 p_access->info.i_title = i;
  240.                 p_access->info.i_seekpoint = 0;
  241.                 p_access->info.i_size = p_sys->title[i]->i_size;
  242.                 p_access->info.i_pos  = 0;
  243.                 /* Next sector to read */
  244.                 p_sys->i_sector = p_sys->p_sectors[1+i];
  245.             }
  246.             break;
  247.         case ACCESS_SET_SEEKPOINT:
  248.         {
  249.             input_title_t *t = p_sys->title[p_access->info.i_title];
  250.             i = (int)va_arg( args, int );
  251.             if( t->i_seekpoint > 0 )
  252.             {
  253.                 p_access->info.i_update |= INPUT_UPDATE_SEEKPOINT;
  254.                 p_access->info.i_seekpoint = i;
  255.                 p_sys->i_sector = p_sys->p_sectors[1+p_access->info.i_title] +
  256.                     t->seekpoint[i]->i_byte_offset / VCD_DATA_SIZE;
  257.                 p_access->info.i_pos = (int64_t)(p_sys->i_sector -
  258.                     p_sys->p_sectors[1+p_access->info.i_title]) *VCD_DATA_SIZE;
  259.             }
  260.             return VLC_SUCCESS;
  261.         }
  262.         case ACCESS_SET_PRIVATE_ID_STATE:
  263.             return VLC_EGENERIC;
  264.         default:
  265.             msg_Warn( p_access, "unimplemented query in control" );
  266.             return VLC_EGENERIC;
  267.     }
  268.     return VLC_SUCCESS;
  269. }
  270. /*****************************************************************************
  271.  * Block:
  272.  *****************************************************************************/
  273. static block_t *Block( access_t *p_access )
  274. {
  275.     access_sys_t *p_sys = p_access->p_sys;
  276.     int i_blocks = VCD_BLOCKS_ONCE;
  277.     block_t *p_block;
  278.     int i_read;
  279.     /* Check end of file */
  280.     if( p_access->info.b_eof ) return NULL;
  281.     /* Check end of title */
  282.     while( p_sys->i_sector >= p_sys->p_sectors[p_access->info.i_title + 2] )
  283.     {
  284.         if( p_access->info.i_title + 2 >= p_sys->i_titles )
  285.         {
  286.             p_access->info.b_eof = VLC_TRUE;
  287.             return NULL;
  288.         }
  289.         p_access->info.i_update |=
  290.             INPUT_UPDATE_TITLE | INPUT_UPDATE_SEEKPOINT | INPUT_UPDATE_SIZE;
  291.         p_access->info.i_title++;
  292.         p_access->info.i_seekpoint = 0;
  293.         p_access->info.i_size =
  294.             p_sys->title[p_access->info.i_title]->i_size;
  295.         p_access->info.i_pos = 0;
  296.     }
  297.     /* Don't read after the end of a title */
  298.     if( p_sys->i_sector + i_blocks >=
  299.         p_sys->p_sectors[p_access->info.i_title + 2] )
  300.     {
  301.         i_blocks = p_sys->p_sectors[p_access->info.i_title + 2 ] -
  302.                    p_sys->i_sector;
  303.     }
  304.     /* Do the actual reading */
  305.     if( !( p_block = block_New( p_access, i_blocks * VCD_DATA_SIZE ) ) )
  306.     {
  307.         msg_Err( p_access, "cannot get a new block of size: %i",
  308.                  i_blocks * VCD_DATA_SIZE );
  309.         return NULL;
  310.     }
  311.     if( ioctl_ReadSectors( VLC_OBJECT(p_access), p_sys->vcddev,
  312.             p_sys->i_sector, p_block->p_buffer, i_blocks, VCD_TYPE ) < 0 )
  313.     {
  314.         msg_Err( p_access, "cannot read sector %i", p_sys->i_sector );
  315.         block_Release( p_block );
  316.         /* Try to skip one sector (in case of bad sectors) */
  317.         p_sys->i_sector++;
  318.         p_access->info.i_pos += VCD_DATA_SIZE;
  319.         return NULL;
  320.     }
  321.     /* Update seekpoints */
  322.     for( i_read = 0; i_read < i_blocks; i_read++ )
  323.     {
  324.         input_title_t *t = p_sys->title[p_access->info.i_title];
  325.         if( t->i_seekpoint > 0 &&
  326.             p_access->info.i_seekpoint + 1 < t->i_seekpoint &&
  327.             p_access->info.i_pos + i_read * VCD_DATA_SIZE >=
  328.             t->seekpoint[p_access->info.i_seekpoint+1]->i_byte_offset )
  329.         {
  330.             msg_Dbg( p_access, "seekpoint change" );
  331.             p_access->info.i_update |= INPUT_UPDATE_SEEKPOINT;
  332.             p_access->info.i_seekpoint++;
  333.         }
  334.     }
  335.     /* Update a few values */
  336.     p_sys->i_sector += i_blocks;
  337.     p_access->info.i_pos += p_block->i_buffer;
  338.     return p_block;
  339. }
  340. /*****************************************************************************
  341.  * Seek:
  342.  *****************************************************************************/
  343. static int Seek( access_t *p_access, int64_t i_pos )
  344. {
  345.     access_sys_t *p_sys = p_access->p_sys;
  346.     input_title_t *t = p_sys->title[p_access->info.i_title];
  347.     int i_seekpoint;
  348.     /* Next sector to read */
  349.     p_access->info.i_pos = i_pos;
  350.     p_sys->i_sector = i_pos / VCD_DATA_SIZE +
  351.         p_sys->p_sectors[p_access->info.i_title + 1];
  352.     /* Update current seekpoint */
  353.     for( i_seekpoint = 0; i_seekpoint < t->i_seekpoint; i_seekpoint++ )
  354.     {
  355.         if( i_seekpoint + 1 >= t->i_seekpoint ) break;
  356.         if( i_pos < t->seekpoint[i_seekpoint + 1]->i_byte_offset ) break;
  357.     }
  358.     if( i_seekpoint != p_access->info.i_seekpoint )
  359.     {
  360.         msg_Dbg( p_access, "seekpoint change" );
  361.         p_access->info.i_update |= INPUT_UPDATE_SEEKPOINT;
  362.         p_access->info.i_seekpoint = i_seekpoint;
  363.     }
  364.     return VLC_SUCCESS;
  365. }
  366. /*****************************************************************************
  367.  * EntryPoints: Reads the information about the entry points on the disc.
  368.  *****************************************************************************/
  369. static int EntryPoints( access_t *p_access )
  370. {
  371.     access_sys_t *p_sys = p_access->p_sys;
  372.     uint8_t      sector[VCD_DATA_SIZE];
  373.     entries_sect_t entries;
  374.     int i_nb, i;
  375.     /* Read the entry point sector */
  376.     if( ioctl_ReadSectors( VLC_OBJECT(p_access), p_sys->vcddev,
  377.         VCD_ENTRIES_SECTOR, sector, 1, VCD_TYPE ) < 0 )
  378.     {
  379.         msg_Err( p_access, "could not read entry points sector" );
  380.         return VLC_EGENERIC;
  381.     }
  382.     memcpy( &entries, sector, CD_SECTOR_SIZE );
  383.     i_nb = GetWBE( &entries.i_entries_nb );
  384.     if( i_nb > 500 )
  385.     {
  386.         msg_Err( p_access, "invalid entry points number" );
  387.         return VLC_EGENERIC;
  388.     }
  389.     if( strncmp( entries.psz_id, "ENTRYVCD", sizeof( entries.psz_id ) ) &&
  390.         strncmp( entries.psz_id, "ENTRYSVD", sizeof( entries.psz_id ) ) )
  391.     {
  392.         msg_Err( p_access, "unrecognized entry points format" );
  393.         return VLC_EGENERIC;
  394.     }
  395.     for( i = 0; i < i_nb; i++ )
  396.     {
  397.         const int i_title = BCD_TO_BIN(entries.entry[i].i_track) - 2;
  398.         const int i_sector =
  399.             (MSF_TO_LBA2( BCD_TO_BIN( entries.entry[i].msf.minute ),
  400.                           BCD_TO_BIN( entries.entry[i].msf.second ),
  401.                           BCD_TO_BIN( entries.entry[i].msf.frame  ) ));
  402.         seekpoint_t *s;
  403.         if( i_title < 0 ) continue;   /* Should not occur */
  404.         if( i_title >= p_sys->i_titles ) continue;
  405.         msg_Dbg( p_access, "Entry[%d] title=%d sector=%dn",
  406.                  i, i_title, i_sector );
  407.         s = vlc_seekpoint_New();
  408.         s->i_byte_offset = (i_sector - p_sys->p_sectors[i_title+1]) *
  409.             VCD_DATA_SIZE;
  410.         TAB_APPEND( p_sys->title[i_title]->i_seekpoint,
  411.                     p_sys->title[i_title]->seekpoint, s );
  412.     }
  413.     return VLC_SUCCESS;
  414. }