Commit 235dfe29 authored by Gildas Bazin's avatar Gildas Bazin

* modules/access/vcd/*, configure.ac.in:
   - Major changes to allow reading vcd images directly from the hard drive
      (you need a .cue and .bin file).
   - Removed duplicated code by merging ioctl_GetTrackCount and ioctl_GetSectors.
   - Implemented necessary ioctls for Win9x/NT/2K/XP.
parent 954bdeb8
......@@ -305,7 +305,7 @@ AC_EGREP_HEADER(strncasecmp,strings.h,[
dnl Check for headers
AC_CHECK_HEADERS(stdint.h getopt.h strings.h inttypes.h sys/int_types.h)
AC_CHECK_HEADERS(sys/sockio.h fcntl.h sys/types.h sys/time.h sys/times.h)
AC_CHECK_HEADERS(sys/sockio.h fcntl.h sys/types.h sys/time.h sys/times.h sys/ioctl.h)
AC_CHECK_HEADERS(dlfcn.h image.h)
AC_CHECK_HEADERS(arpa/inet.h net/if.h netinet/in.h sys/socket.h)
AC_CHECK_HEADERS(machine/param.h sys/shm.h)
......@@ -965,7 +965,7 @@ dnl
dnl VCD module
dnl
AC_ARG_ENABLE(vcd,
[ --enable-vcd VCD support for Linux, FreeBSD and MacOS X (default enabled)])
[ --enable-vcd VCD support for Linux, FreeBSD, MacOS X and Win32 (default enabled)])
if test "x${enable_vcd}" != "xno"
then
......@@ -978,7 +978,7 @@ then
AC_DEFINE(HAVE_IOC_TOC_HEADER_IN_SYS_CDIO_H, 1, For FreeBSD VCD support)
])
if test "x${SYS}" = "xbsdi"
if test "x${SYS}" = "xbsdi" -o "x${SYS}" = "xmingw32"
then
PLUGINS="${PLUGINS} vcd"
fi
......
......@@ -2,10 +2,11 @@
* cdrom.c: cdrom tools
*****************************************************************************
* Copyright (C) 1998-2001 VideoLAN
* $Id: cdrom.c,v 1.3 2002/08/09 23:47:22 massiot Exp $
* $Id: cdrom.c,v 1.4 2002/10/15 19:56:59 gbazin Exp $
*
* Author: Johan Bilien <jobi@via.ecp.fr>
* Jon Lech Johansen <jon-vl@nanocrew.net>
* Authors: Johan Bilien <jobi@via.ecp.fr>
* Gildas Bazin <gbazin@netcourrier.com>
* Jon Lech Johansen <jon-vl@nanocrew.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
......@@ -39,7 +40,9 @@
#include <string.h>
#include <errno.h>
#include <sys/ioctl.h>
#ifdef HAVE_SYS_IOCTL_H
# include <sys/ioctl.h>
#endif
#if defined( SYS_BSDI )
# include <dvd.h>
......@@ -52,289 +55,820 @@
#elif defined( HAVE_IOC_TOC_HEADER_IN_SYS_CDIO_H )
# include <sys/cdio.h>
# include <sys/cdrio.h>
#elif defined( WIN32 )
# include <windows.h>
# include <winioctl.h>
#else
# include <linux/cdrom.h>
#endif
#include "cdrom.h"
#include "vcd.h"
/*****************************************************************************
* Platform specific
* ioctl_Open: Opens a VCD device or file and returns an opaque handle
*****************************************************************************/
#if defined( SYS_DARWIN )
CDTOC *getTOC( vlc_object_t *, const char * );
#define freeTOC( p ) free( (void*)p )
int getNumberOfDescriptors( CDTOC * );
int getNumberOfTracks( CDTOC *, int );
#define CD_MIN_TRACK_NO 01
#define CD_MAX_TRACK_NO 99
vcddev_t *ioctl_Open( vlc_object_t *p_this, const char *psz_dev )
{
int i_ret;
int b_is_file;
vcddev_t *p_vcddev;
#ifndef WIN32
struct stat fileinfo;
#endif
/*****************************************************************************
* ioctl_ReadTocHeader: Read the TOC header and return the track number.
*****************************************************************************/
int ioctl_GetTrackCount( vlc_object_t * p_this, int i_fd, const char *psz_dev )
{
int i_count = -1;
if( !psz_dev ) return NULL;
#if defined( SYS_DARWIN )
CDTOC *pTOC;
int i_descriptors;
if( ( pTOC = getTOC( p_this, psz_dev ) ) == NULL )
/*
* Initialize structure with default values
*/
p_vcddev = (vcddev_t *)malloc( sizeof(vcddev_t) );
if( p_vcddev == NULL )
{
msg_Err( p_this, "failed to get the TOC" );
return( -1 );
msg_Err( p_this, "out of memory" );
return NULL;
}
p_vcddev->i_vcdimage_handle = -1;
p_vcddev->psz_dev = NULL;
b_is_file = 1;
/*
* Check if we are dealing with a device or a file (vcd image)
*/
#ifdef WIN32
if( strlen( psz_dev ) == 1 ||
(strlen( psz_dev ) == 2 && psz_dev[1] == ':') )
{
b_is_file = 0;
}
i_descriptors = getNumberOfDescriptors( pTOC );
i_count = getNumberOfTracks( pTOC, i_descriptors );
#else
if( stat( psz_dev, &fileinfo ) < 0 )
{
free( p_vcddev );
return NULL;
}
freeTOC( pTOC );
/* Check if this is a block/char device */
if( S_ISBLK( fileinfo.st_mode ) || S_ISCHR( fileinfo.st_mode ) )
b_is_file = 0;
#endif
#elif defined( HAVE_IOC_TOC_HEADER_IN_SYS_CDIO_H )
struct ioc_toc_header tochdr;
if( ioctl( i_fd, CDIOREADTOCHEADER, &tochdr ) == -1 )
if( b_is_file )
{
msg_Err( p_this, "could not read TOCHDR" );
return -1;
i_ret = OpenVCDImage( p_this, psz_dev, p_vcddev );
}
else
{
/*
* open the vcd device
*/
i_count = tochdr.ending_track - tochdr.starting_track + 1;
#ifdef WIN32
i_ret = win32_vcd_open( p_this, psz_dev, p_vcddev );
#else
struct cdrom_tochdr tochdr;
p_vcddev->i_device_handle = -1;
p_vcddev->i_device_handle = open( psz_dev, O_RDONLY | O_NONBLOCK );
i_ret = (p_vcddev->i_device_handle == -1) ? -1 : 0;
#endif
}
/* First we read the TOC header */
if( ioctl( i_fd, CDROMREADTOCHDR, &tochdr ) == -1 )
if( i_ret == 0 )
{
msg_Err( p_this, "could not read TOCHDR" );
return -1;
p_vcddev->psz_dev = (char *)strdup( psz_dev );
}
else
{
free( p_vcddev );
p_vcddev = NULL;
}
i_count = tochdr.cdth_trk1 - tochdr.cdth_trk0 + 1;
#endif
return( i_count );
return p_vcddev;
}
/*****************************************************************************
* ioctl_GetSectors: Read the Table of Contents and fill p_vcd.
* ioctl_Close: Closes an already opened VCD device or file.
*****************************************************************************/
int * ioctl_GetSectors( vlc_object_t *p_this, int i_fd, const char *psz_dev )
void ioctl_Close( vlc_object_t * p_this, vcddev_t *p_vcddev )
{
int i, i_tracks;
int *p_sectors = NULL;
#if defined( SYS_DARWIN )
CDTOC *pTOC;
u_char track;
int i_descriptors;
int i_leadout = -1;
CDTOCDescriptor *pTrackDescriptors;
if( p_vcddev->psz_dev ) free( p_vcddev->psz_dev );
if( ( pTOC = getTOC( p_this, psz_dev ) ) == NULL )
if( p_vcddev->i_vcdimage_handle != -1 )
{
msg_Err( p_this, "failed to get the TOC" );
return( NULL );
/*
* vcd image mode
*/
CloseVCDImage( p_this, p_vcddev );
return;
}
i_descriptors = getNumberOfDescriptors( pTOC );
i_tracks = getNumberOfTracks( pTOC, i_descriptors );
/*
* vcd device mode
*/
p_sectors = malloc( (i_tracks + 1) * sizeof(int) );
if( p_sectors == NULL )
{
msg_Err( p_this, "out of memory" );
freeTOC( pTOC );
return NULL;
}
pTrackDescriptors = pTOC->descriptors;
#ifdef WIN32
if( p_vcddev->h_device_handle )
CloseHandle( p_vcddev->h_device_handle );
if( p_vcddev->hASPI )
FreeLibrary( (HMODULE)p_vcddev->hASPI );
#else
if( p_vcddev->i_device_handle != -1 )
close( p_vcddev->i_device_handle );
#endif
}
for( i_tracks = 0, i = 0; i <= i_descriptors; i++ )
/*****************************************************************************
* ioctl_GetTracksMap: Read the Table of Content, fill in the pp_sectors map
* if pp_sectors is not null and return the number of
* tracks available.
*****************************************************************************/
int ioctl_GetTracksMap( vlc_object_t *p_this, const vcddev_t *p_vcddev,
int **pp_sectors )
{
int i_tracks = 0;
if( p_vcddev->i_vcdimage_handle != -1 )
{
track = pTrackDescriptors[i].point;
/*
* vcd image mode
*/
if( track == 0xA2 )
i_leadout = i;
i_tracks = p_vcddev->i_tracks;
if( track > CD_MAX_TRACK_NO || track < CD_MIN_TRACK_NO )
continue;
if( pp_sectors )
{
*pp_sectors = malloc( (i_tracks + 1) * sizeof(int) );
if( *pp_sectors == NULL )
{
msg_Err( p_this, "out of memory" );
return 0;
}
memcpy( *pp_sectors, p_vcddev->p_sectors,
(i_tracks + 1) * sizeof(int) );
}
p_sectors[i_tracks++] =
CDConvertMSFToLBA( pTrackDescriptors[i].p );
return i_tracks;
}
if( i_leadout == -1 )
else
{
msg_Err( p_this, "leadout not found" );
free( p_sectors );
freeTOC( pTOC );
return( NULL );
}
/* set leadout sector */
p_sectors[i_tracks] =
CDConvertMSFToLBA( pTrackDescriptors[i_leadout].p );
/*
* vcd device mode
*/
freeTOC( pTOC );
#if defined( SYS_DARWIN )
CDTOC *pTOC;
int i_descriptors;
if( ( pTOC = darwin_getTOC( p_this, p_vcddev->psz_dev ) ) == NULL )
{
msg_Err( p_this, "failed to get the TOC" );
return 0;
}
i_descriptors = darwin_getNumberOfDescriptors( pTOC );
i_tracks = darwin_getNumberOfTracks( pTOC, i_descriptors );
if( pp_sectors )
{
int i, i_leadout = -1;
CDTOCDescriptor *pTrackDescriptors;
u_char track;
*pp_sectors = malloc( (i_tracks + 1) * sizeof(int) );
if( *pp_sectors == NULL )
{
msg_Err( p_this, "out of memory" );
darwin_freeTOC( pTOC );
return 0;
}
pTrackDescriptors = pTOC->descriptors;
for( i_tracks = 0, i = 0; i <= i_descriptors; i++ )
{
track = pTrackDescriptors[i].point;
if( track == 0xA2 )
i_leadout = i;
if( track > CD_MAX_TRACK_NO || track < CD_MIN_TRACK_NO )
continue;
(*pp_sectors)[i_tracks++] =
CDConvertMSFToLBA( pTrackDescriptors[i].p );
}
if( i_leadout == -1 )
{
msg_Err( p_this, "leadout not found" );
free( *pp_sectors );
darwin_freeTOC( pTOC );
return 0;
}
/* set leadout sector */
(*pp_sectors)[i_tracks] =
CDConvertMSFToLBA( pTrackDescriptors[i_leadout].p );
}
darwin_freeTOC( pTOC );
#elif defined( WIN32 )
if( p_vcddev->hASPI )
{
HANDLE hEvent;
struct SRB_ExecSCSICmd ssc;
byte_t p_tocheader[ 4 ];
/* Create the transfer completion event */
hEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
if( hEvent == NULL )
{
return -1;
}
memset( &ssc, 0, sizeof( ssc ) );
ssc.SRB_Cmd = SC_EXEC_SCSI_CMD;
ssc.SRB_Flags = SRB_DIR_IN | SRB_EVENT_NOTIFY;
ssc.SRB_HaId = LOBYTE( p_vcddev->i_sid );
ssc.SRB_Target = HIBYTE( p_vcddev->i_sid );
ssc.SRB_SenseLen = SENSE_LEN;
ssc.SRB_PostProc = (LPVOID) hEvent;
ssc.SRB_CDBLen = 10;
/* Operation code */
ssc.CDBByte[ 0 ] = READ_TOC;
/* Format */
ssc.CDBByte[ 2 ] = READ_TOC_FORMAT_TOC;
/* Starting track */
ssc.CDBByte[ 6 ] = 0;
/* Allocation length and buffer */
ssc.SRB_BufLen = sizeof( p_tocheader );
ssc.SRB_BufPointer = p_tocheader;
ssc.CDBByte[ 7 ] = ( ssc.SRB_BufLen >> 8 ) & 0xff;
ssc.CDBByte[ 8 ] = ( ssc.SRB_BufLen ) & 0xff;
/* Initiate transfer */
ResetEvent( hEvent );
p_vcddev->lpSendCommand( (void*) &ssc );
/* If the command has still not been processed, wait until it's
* finished */
if( ssc.SRB_Status == SS_PENDING )
WaitForSingleObject( hEvent, INFINITE );
/* check that the transfer went as planned */
if( ssc.SRB_Status != SS_COMP )
{
CloseHandle( hEvent );
return 0;
}
i_tracks = p_tocheader[3] - p_tocheader[2] + 1;
if( pp_sectors )
{
int i, i_toclength;
byte_t *p_fulltoc;
i_toclength = 4 /* header */ + p_tocheader[0] +
((unsigned int)p_tocheader[1] << 8);
p_fulltoc = malloc( i_toclength );
*pp_sectors = malloc( (i_tracks + 1) * sizeof(int) );
if( *pp_sectors == NULL || p_fulltoc == NULL )
{
if( *pp_sectors ) free( *pp_sectors );
if( p_fulltoc ) free( p_fulltoc );
msg_Err( p_this, "out of memory" );
CloseHandle( hEvent );
return 0;
}
/* Allocation length and buffer */
ssc.SRB_BufLen = i_toclength;
ssc.SRB_BufPointer = p_fulltoc;
ssc.CDBByte[ 7 ] = ( ssc.SRB_BufLen >> 8 ) & 0xff;
ssc.CDBByte[ 8 ] = ( ssc.SRB_BufLen ) & 0xff;
/* Initiate transfer */
ResetEvent( hEvent );
p_vcddev->lpSendCommand( (void*) &ssc );
/* If the command has still not been processed, wait until it's
* finished */
if( ssc.SRB_Status == SS_PENDING )
WaitForSingleObject( hEvent, INFINITE );
/* check that the transfer went as planned */
if( ssc.SRB_Status != SS_COMP )
i_tracks = 0;
for( i = 0 ; i <= i_tracks ; i++ )
{
int i_index = 8 + 8 * i;
(*pp_sectors)[ i ] = ((int)p_fulltoc[ i_index ] << 24) +
((int)p_fulltoc[ i_index+1 ] << 16) +
((int)p_fulltoc[ i_index+2 ] << 8) +
(int)p_fulltoc[ i_index+3 ];
msg_Dbg( p_this, "p_sectors: %i, %i", i, (*pp_sectors)[i]);
}
free( p_fulltoc );
}
CloseHandle( hEvent );
}
else
{
DWORD dwBytesReturned;
CDROM_TOC cdrom_toc;
if( DeviceIoControl( p_vcddev->h_device_handle,
IOCTL_CDROM_READ_TOC,
NULL, 0, &cdrom_toc, sizeof(CDROM_TOC),
&dwBytesReturned, NULL ) == 0 )
{
msg_Err( p_this, "could not read TOCHDR" );
return 0;
}
i_tracks = cdrom_toc.LastTrack - cdrom_toc.FirstTrack + 1;
if( pp_sectors )
{
int i;
*pp_sectors = malloc( (i_tracks + 1) * sizeof(int) );
if( *pp_sectors == NULL )
{
msg_Err( p_this, "out of memory" );
return 0;
}
for( i = 0 ; i <= i_tracks ; i++ )
{
(*pp_sectors)[ i ] = MSF_TO_LBA2(
cdrom_toc.TrackData[i].Address[1],
cdrom_toc.TrackData[i].Address[2],
cdrom_toc.TrackData[i].Address[3] );
msg_Dbg( p_this, "p_sectors: %i, %i", i, (*pp_sectors)[i]);
}
}
}
#elif defined( HAVE_IOC_TOC_HEADER_IN_SYS_CDIO_H )
struct ioc_read_toc_entry toc_entries;
struct ioc_toc_header tochdr;
struct ioc_read_toc_entry toc_entries;
i_tracks = ioctl_GetTrackCount( p_this, i_fd, psz_dev );
p_sectors = malloc( (i_tracks + 1) * sizeof(int) );
if( p_sectors == NULL )
{
msg_Err( p_this, "out of memory" );
return NULL;
}
if( ioctl( p_vcddev->i_devicd_handle, CDIOREADTOCHEADER, &tochdr )
== -1 )
{
msg_Err( p_this, "could not read TOCHDR" );
return 0;
}
toc_entries.address_format = CD_LBA_FORMAT;
toc_entries.starting_track = 0;
toc_entries.data_len = ( i_tracks + 1 ) * sizeof( struct cd_toc_entry );
toc_entries.data = (struct cd_toc_entry *) malloc( toc_entries.data_len );
if( toc_entries.data == NULL )
{
msg_Err( p_this, "out of memory" );
free( p_sectors );
return NULL;
}
i_tracks = tochdr.ending_track - tochdr.starting_track + 1;
if( pp_sectors )
{
int i;
*pp_sectors = malloc( (i_tracks + 1) * sizeof(int) );
if( *pp_sectors == NULL )
{
msg_Err( p_this, "out of memory" );
return NULL;
}
toc_entries.address_format = CD_LBA_FORMAT;
toc_entries.starting_track = 0;
toc_entries.data_len = ( i_tracks + 1 ) *
sizeof( struct cd_toc_entry );
toc_entries.data = (struct cd_toc_entry *)
malloc( toc_entries.data_len );
if( toc_entries.data == NULL )
{
msg_Err( p_this, "out of memory" );
free( *pp_sectors );
return 0;
}
/* Read the TOC */
if( ioctl( i_fd, CDIOREADTOCENTRYS, &toc_entries ) == -1 )
{
msg_Err( p_this, "could not read the TOC" );
free( p_sectors );
free( toc_entries.data );
return NULL;
}
/* Read the TOC */
if( ioctl( p_vcddev->i_device_handle, CDIOREADTOCENTRYS,
&toc_entries ) == -1 )
{
msg_Err( p_this, "could not read the TOC" );
free( *pp_sectors );
free( toc_entries.data );
return 0;
}
/* Fill the p_sectors structure with the track/sector matches */
for( i = 0 ; i <= i_tracks ; i++ )
{
p_sectors[ i ] = ntohl( toc_entries.data[i].addr.lba );
}
/* Fill the p_sectors structure with the track/sector matches */
for( i = 0 ; i <= i_tracks ; i++ )
{
(*pp_sectors)[ i ] = ntohl( toc_entries.data[i].addr.lba );
}
}
#else
struct cdrom_tochdr tochdr;
struct cdrom_tocentry tocent;
/* First we read the TOC header */
if( ioctl( i_fd, CDROMREADTOCHDR, &tochdr ) == -1 )
{
msg_Err( p_this, "could not read TOCHDR" );
return NULL;
}
struct cdrom_tochdr tochdr;
struct cdrom_tocentry tocent;
i_tracks = tochdr.cdth_trk1 - tochdr.cdth_trk0 + 1;
p_sectors = malloc( (i_tracks + 1) * sizeof(int) );
if( p_sectors == NULL )
{
msg_Err( p_this, "out of memory" );
return NULL;
}
/* First we read the TOC header */
if( ioctl( p_vcddev->i_device_handle, CDROMREADTOCHDR, &tochdr )
== -1 )
{
msg_Err( p_this, "could not read TOCHDR" );
return 0;
}
/* Fill the p_sectors structure with the track/sector matches */
for( i = 0 ; i <= i_tracks ; i++ )
{
tocent.cdte_format = CDROM_LBA;
tocent.cdte_track =
( i == i_tracks ) ? CDROM_LEADOUT : tochdr.cdth_trk0 + i;
i_tracks = tochdr.cdth_trk1 - tochdr.cdth_trk0 + 1;
if( ioctl( i_fd, CDROMREADTOCENTRY, &tocent ) == -1 )
if( pp_sectors )
{
msg_Err( p_this, "could not read TOCENTRY" );
free( p_sectors );
return NULL;
int i;
*pp_sectors = malloc( (i_tracks + 1) * sizeof(int) );
if( *pp_sectors == NULL )
{
msg_Err( p_this, "out of memory" );
return 0;
}
/* Fill the p_sectors structure with the track/sector matches */
for( i = 0 ; i <= i_tracks ; i++ )
{
tocent.cdte_format = CDROM_LBA;
tocent.cdte_track =
( i == i_tracks ) ? CDROM_LEADOUT : tochdr.cdth_trk0 + i;
if( ioctl( p_vcddev->i_device_handle, CDROMREADTOCENTRY,
&tocent ) == -1 )
{
msg_Err( p_this, "could not read TOCENTRY" );
free( *pp_sectors );
return 0;
}
(*pp_sectors)[ i ] = tocent.cdte_addr.lba;
}
}
p_sectors[ i ] = tocent.cdte_addr.lba;
}
#endif
return p_sectors;
return i_tracks;
}
}
/****************************************************************************
* ioctl_ReadSector: Read a sector (2324 bytes)
****************************************************************************/
int ioctl_ReadSector( vlc_object_t *p_this,
int i_fd, int i_sector, byte_t * p_buffer )
int ioctl_ReadSector( vlc_object_t *p_this, const vcddev_t *p_vcddev,
int i_sector, byte_t * p_buffer )
{
byte_t p_block[ VCD_SECTOR_SIZE ];
if( p_vcddev->i_vcdimage_handle != -1 )
{
/*
* vcd image mode
*/
if( lseek( p_vcddev->i_vcdimage_handle, i_sector * VCD_SECTOR_SIZE,
SEEK_SET ) == -1 )
{
msg_Err( p_this, "Could not lseek to sector %d", i_sector );
return -1;
}
if( read( p_vcddev->i_vcdimage_handle, p_block, VCD_SECTOR_SIZE )
== -1 )
{
// msg_Err( p_this, "Could not read sector %d", i_sector );
return -1;
}
/* We don't want to keep the header of the read sector */
memcpy( p_buffer, p_block + VCD_DATA_START, VCD_DATA_SIZE );
return 0;
}
else
{
/*
* vcd device mode
*/
#if defined( SYS_DARWIN )
dk_cd_read_t cd_read;
dk_cd_read_t cd_read;
memset( &cd_read, 0, sizeof(cd_read) );
memset( &cd_read, 0, sizeof(cd_read) );
cd_read.offset = i_sector * VCD_SECTOR_SIZE;
cd_read.sectorArea = kCDSectorAreaSync | kCDSectorAreaHeader |
kCDSectorAreaSubHeader | kCDSectorAreaUser |
kCDSectorAreaAuxiliary;
cd_read.sectorType = kCDSectorTypeUnknown;
cd_read.offset = i_sector * VCD_SECTOR_SIZE;
cd_read.sectorArea = kCDSectorAreaSync | kCDSectorAreaHeader |
kCDSectorAreaSubHeader | kCDSectorAreaUser |
kCDSectorAreaAuxiliary;
cd_read.sectorType = kCDSectorTypeUnknown;
cd_read.buffer = p_block;
cd_read.bufferLength = sizeof(p_block);
cd_read.buffer = p_block;
cd_read.bufferLength = sizeof(p_block);
if( ioctl( i_fd, DKIOCCDREAD, &cd_read ) == -1 )
{
msg_Err( p_this, "could not read block %d", i_sector );
return( -1 );
}
if( ioctl( p_vcddev->i_device_handle, DKIOCCDREAD, &cd_read ) == -1 )
{
msg_Err( p_this, "could not read block %d", i_sector );
return -1;
}
#elif defined( WIN32 )
if( p_vcddev->hASPI )
{
HANDLE hEvent;
struct SRB_ExecSCSICmd ssc;
/* Create the transfer completion event */
hEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
if( hEvent == NULL )
{
return -1;
}
memset( &ssc, 0, sizeof( ssc ) );
ssc.SRB_Cmd = SC_EXEC_SCSI_CMD;
ssc.SRB_Flags = SRB_DIR_IN | SRB_EVENT_NOTIFY;
ssc.SRB_HaId = LOBYTE( p_vcddev->i_sid );
ssc.SRB_Target = HIBYTE( p_vcddev->i_sid );
ssc.SRB_SenseLen = SENSE_LEN;
ssc.SRB_PostProc = (LPVOID) hEvent;
ssc.SRB_CDBLen = 12;
/* Operation code */
ssc.CDBByte[ 0 ] = READ_CD;
/* Start of LBA */
ssc.CDBByte[ 2 ] = ( i_sector >> 24 ) & 0xff;
ssc.CDBByte[ 3 ] = ( i_sector >> 16 ) & 0xff;
ssc.CDBByte[ 4 ] = ( i_sector >> 8 ) & 0xff;
ssc.CDBByte[ 5 ] = ( i_sector ) & 0xff;
/* Transfer length */
ssc.CDBByte[ 6 ] = 0;
ssc.CDBByte[ 7 ] = 0;
ssc.CDBByte[ 8 ] = 1;
/* Data selection */
ssc.CDBByte[ 9 ] = READ_CD_USERDATA_MODE2;
/* Result buffer */
ssc.SRB_BufPointer = p_block;
ssc.SRB_BufLen = VCD_SECTOR_SIZE;
/* Initiate transfer */
ResetEvent( hEvent );
p_vcddev->lpSendCommand( (void*) &ssc );
/* If the command has still not been processed, wait until it's
* finished */
if( ssc.SRB_Status == SS_PENDING )
{
WaitForSingleObject( hEvent, INFINITE );
}
CloseHandle( hEvent );
/* check that the transfer went as planned */
if( ssc.SRB_Status != SS_COMP )
{
return -1;
}
/* We don't want to keep the footer of the read sector */
memcpy( p_buffer, p_block, VCD_DATA_SIZE );
return 0;
}
else
{
DWORD dwBytesReturned;
RAW_READ_INFO cdrom_raw;
/* Initialize CDROM_RAW_READ structure */
cdrom_raw.DiskOffset.QuadPart = CD_SECTOR_SIZE * i_sector;
cdrom_raw.SectorCount = 1;
cdrom_raw.TrackMode = XAForm2;
if( DeviceIoControl( p_vcddev->h_device_handle,
IOCTL_CDROM_RAW_READ, &cdrom_raw,
sizeof(RAW_READ_INFO), p_block,
sizeof(p_block), &dwBytesReturned, NULL )
== 0 )
{
return -1;
}
/* We don't want to keep the header of the read sector */
memcpy( p_buffer, p_block + VCD_DATA_START, VCD_DATA_SIZE );
return 0;
}
#elif defined( HAVE_IOC_TOC_HEADER_IN_SYS_CDIO_H )
int i_size = VCD_SECTOR_SIZE;
if( ioctl( i_fd, CDRIOCSETBLOCKSIZE, &i_size ) == -1 )
int i_size = VCD_SECTOR_SIZE;
if( ioctl( p_vcddev->i_device_handle, CDRIOCSETBLOCKSIZE, &i_size )
== -1 )
{
msg_Err( p_this, "Could not set block size" );
return( -1 );
}
if( lseek( p_vcddev->i_device_handle,
i_sector * VCD_SECTOR_SIZE, SEEK_SET ) == -1 )
{
msg_Err( p_this, "Could not lseek to sector %d", i_sector );
return( -1 );
}
if( read( p_vcddev->i_device_handle, p_block, VCD_SECTOR_SIZE ) == -1 )
{
msg_Err( p_this, "Could not read sector %d", i_sector );
return( -1 );
}
#else
int i_dummy = i_sector + 2 * CD_FRAMES;
#define p_msf ((struct cdrom_msf0 *)p_block)
p_msf->minute = i_dummy / (CD_FRAMES * CD_SECS);
p_msf->second = ( i_dummy % (CD_FRAMES * CD_SECS) ) / CD_FRAMES;
p_msf->frame = ( i_dummy % (CD_FRAMES * CD_SECS) ) % CD_FRAMES;
#undef p_msf
if( ioctl(p_vcddev->i_device_handle, CDROMREADRAW, p_block) == -1 )
{
msg_Err( p_this, "could not read block %i from disc", i_sector );
return( -1 );
}
#endif
/* We don't want to keep the header of the read sector */
memcpy( p_buffer, p_block + VCD_DATA_START, VCD_DATA_SIZE );
return( 0 );
}
}
/****************************************************************************
* Private functions
****************************************************************************/
/****************************************************************************
* OpenVCDImage: try to open a vcd image from a .cue file
****************************************************************************/
static int OpenVCDImage( vlc_object_t * p_this, const char *psz_dev,
vcddev_t *p_vcddev )
{
int i_ret = -1;
char *p_pos;
char *psz_vcdfile = NULL;
char *psz_cuefile = NULL;
FILE *cuefile;
char line[1024];
/* Check if we are dealing with a .cue file */
p_pos = strrchr( psz_dev, '.' );
if( p_pos && !strcmp( p_pos, ".cue" ) )
{
msg_Err( p_this, "Could not set block size" );
return( -1 );
psz_cuefile = strdup( psz_dev );
}
else
{
/* psz_dev must be the actual vcd file. Let's assume there's a .cue
* file with the same filename */
if( p_pos )
{
psz_cuefile = malloc( p_pos - psz_dev + 5 /* ".cue" */ );
strncpy( psz_cuefile, psz_dev, p_pos - psz_dev );
strcpy( psz_cuefile + (p_pos - psz_dev), ".cue");
}
else
{
psz_cuefile = malloc( strlen(psz_dev) + 5 /* ".cue" */ );
sprintf( psz_cuefile, "%s.cue", psz_dev );
}
}
if( lseek( i_fd, i_sector * VCD_SECTOR_SIZE, SEEK_SET ) == -1 )
/* Open the cue file and try to parse it */
msg_Dbg( p_this,"using .cue file: %s", psz_cuefile );
cuefile = fopen( psz_cuefile, "rt" );
if( cuefile && fscanf( cuefile, "FILE %c", line ) &&
fgets( line, 1024, cuefile ) )
{
msg_Err( p_this, "Could not lseek to sector %d", i_sector );
return( -1 );
p_pos = strchr( line, '"' );
if( p_pos )
{
*p_pos = 0;
/* Take care of path standardization */
if( *line != '/' && (p_pos = strrchr( psz_cuefile, '/' )) )
{
psz_vcdfile = malloc( strlen(line) +
(p_pos - psz_cuefile + 1) + 1 );
strncpy( psz_vcdfile, psz_cuefile, (p_pos - psz_cuefile + 1) );
strcpy( psz_vcdfile + (p_pos - psz_cuefile + 1), line );
}
else psz_vcdfile = strdup( line );
}
}
if( read( i_fd, p_block, VCD_SECTOR_SIZE ) == -1 )
if( psz_vcdfile )
{
msg_Err( p_this, "Could not read sector %d", i_sector );
return( -1 );
msg_Dbg( p_this,"using vcd image file: %s", psz_vcdfile );
p_vcddev->i_vcdimage_handle = open( psz_vcdfile,
O_RDONLY | O_NONBLOCK | O_BINARY );
i_ret = (p_vcddev->i_vcdimage_handle == -1) ? -1 : 0;
}
#else
int i_dummy = i_sector + 2 * CD_FRAMES;
/* Try to parse the i_tracks and p_sectors info so we can just forget
* about the cuefile */
if( i_ret == 0 )
{
int p_sectors[100];
int i_tracks = 0;
int i_num;
char psz_dummy[10];
#define p_msf ((struct cdrom_msf0 *)p_block)
p_msf->minute = i_dummy / (CD_FRAMES * CD_SECS);
p_msf->second = ( i_dummy % (CD_FRAMES * CD_SECS) ) / CD_FRAMES;
p_msf->frame = ( i_dummy % (CD_FRAMES * CD_SECS) ) % CD_FRAMES;
#undef p_msf
while( fgets( line, 1024, cuefile ) )
{
/* look for a TRACK line */
if( !sscanf( line, "%9s", psz_dummy ) ||
strcmp(psz_dummy, "TRACK") )
continue;
/* look for an INDEX line */
while( fgets( line, 1024, cuefile ) )
{
int i_min, i_sec, i_frame;
if( (sscanf( line, "%9s %2u %2u:%2u:%2u", psz_dummy, &i_num,
&i_min, &i_sec, &i_frame ) != 5) || (i_num != 1) )
continue;
i_tracks++;
p_sectors[i_tracks - 1] = MSF_TO_LBA(i_min, i_sec, i_frame);
msg_Dbg( p_this, "vcd track %i begins at sector:%i",
i_tracks - 1, p_sectors[i_tracks - 1] );
break;
}
}
/* fill in the last entry */
p_sectors[i_tracks] = lseek(p_vcddev->i_vcdimage_handle, 0, SEEK_END)
/ VCD_SECTOR_SIZE;
msg_Dbg( p_this, "vcd track %i, begins at sector:%i",
i_tracks, p_sectors[i_tracks] );
p_vcddev->i_tracks = i_tracks;
p_vcddev->p_sectors = malloc( (i_tracks + 1) * sizeof(int) );
memcpy( p_vcddev->p_sectors, p_sectors, (i_tracks + 1) * sizeof(int) );
if( ioctl(i_fd, CDROMREADRAW, p_block) == -1 )
{
msg_Err( p_this, "could not read block %i from disc", i_sector );
return( -1 );
}
#endif
/* We don't want to keep the header of the read sector */
memcpy( p_buffer, p_block + VCD_DATA_START, VCD_DATA_SIZE );
if( cuefile ) fclose( cuefile );
if( psz_cuefile ) free( psz_cuefile );
if( psz_vcdfile ) free( psz_vcdfile );
return( 0 );
return i_ret;
}
/****************************************************************************
* CloseVCDImage: closes a vcd image opened by OpenVCDImage
****************************************************************************/
static void CloseVCDImage( vlc_object_t * p_this, vcddev_t *p_vcddev )
{
if( p_vcddev->i_vcdimage_handle != -1 )
close( p_vcddev->i_vcdimage_handle );
else
return;
if( p_vcddev->p_sectors )
free( p_vcddev->p_sectors );
}
#if defined( SYS_DARWIN )
/****************************************************************************
* getTOC: get the TOC
* darwin_getTOC: get the TOC
****************************************************************************/
CDTOC *getTOC( vlc_object_t * p_this, const char *psz_dev )
static CDTOC *darwin_getTOC( vlc_object_t * p_this, vcddev_t *p_vcddev )
{
mach_port_t port;
char *psz_devname;
......@@ -345,17 +879,11 @@ CDTOC *getTOC( vlc_object_t * p_this, const char *psz_dev )
CFDictionaryRef properties;
CFDataRef data;
if( psz_dev == NULL )
{
msg_Err( p_this, "invalid device path" );
return( NULL );
}
/* get the device name */
if( ( psz_devname = strrchr( psz_dev, '/') ) != NULL )
if( ( psz_devname = strrchr( p_vcddev->psz_dev, '/') ) != NULL )
++psz_devname;
else
psz_devname = (char *)psz_dev;
psz_devname = p_vcddev->psz_dev;
/* unraw the device name */
if( *psz_devname == 'r' )
......@@ -439,9 +967,9 @@ CDTOC *getTOC( vlc_object_t * p_this, const char *psz_dev )
}
/****************************************************************************
* getNumberOfDescriptors: get number of descriptors in TOC
* darwin_getNumberOfDescriptors: get number of descriptors in TOC
****************************************************************************/
int getNumberOfDescriptors( CDTOC *pTOC )
static int darwin_getNumberOfDescriptors( CDTOC *pTOC )
{
int i_descriptors;
......@@ -459,9 +987,9 @@ int getNumberOfDescriptors( CDTOC *pTOC )
}
/****************************************************************************
* getNumberOfTracks: get number of tracks in TOC
* darwin_getNumberOfTracks: get number of tracks in TOC
****************************************************************************/
int getNumberOfTracks( CDTOC *pTOC, int i_descriptors )
static int darwin_getNumberOfTracks( CDTOC *pTOC, int i_descriptors )
{
u_char track;
int i, i_tracks = 0;
......@@ -481,4 +1009,146 @@ int getNumberOfTracks( CDTOC *pTOC, int i_descriptors )
return( i_tracks );
}
#endif
#endif /* SYS_DARWIN */
#if defined( WIN32 )
/*****************************************************************************
* win32_vcd_open: open vcd drive
*****************************************************************************
* Load and use aspi if it is available, otherwise use IOCTLs on WinNT/2K/XP.
*****************************************************************************/
static int win32_vcd_open( vlc_object_t * p_this, const char *psz_dev,
vcddev_t *p_vcddev )
{
/* Initializations */
p_vcddev->h_device_handle = NULL;
p_vcddev->i_sid = 0;
p_vcddev->hASPI = 0;
p_vcddev->lpSendCommand = 0;
if( WIN_NT )
{
char psz_win32_drive[7];
msg_Dbg( p_this, "using winNT/2K/XP ioctl layer" );
sprintf( psz_win32_drive, "\\\\.\\%c:", psz_dev[0] );
p_vcddev->h_device_handle = CreateFile( psz_win32_drive, GENERIC_READ,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL, OPEN_EXISTING,
FILE_FLAG_NO_BUFFERING |
FILE_FLAG_RANDOM_ACCESS, NULL );
return (p_vcddev->h_device_handle == NULL) ? -1 : 0;
}
else
{
HMODULE hASPI = NULL;
long (*lpGetSupport)( void ) = NULL;
long (*lpSendCommand)( void* ) = NULL;
DWORD dwSupportInfo;
int i, j, i_hostadapters;
char c_drive = psz_dev[0];
hASPI = LoadLibrary( "wnaspi32.dll" );
if( hASPI != NULL )
{
(FARPROC) lpGetSupport = GetProcAddress( hASPI,
"GetASPI32SupportInfo" );
(FARPROC) lpSendCommand = GetProcAddress( hASPI,
"SendASPI32Command" );
}
if( hASPI == NULL || lpGetSupport == NULL || lpSendCommand == NULL )
{
msg_Dbg( p_this,
"unable to load aspi or get aspi function pointers" );
if( hASPI ) FreeLibrary( hASPI );
return -1;
}
/* ASPI support seems to be there */
dwSupportInfo = lpGetSupport();
if( HIBYTE( LOWORD ( dwSupportInfo ) ) == SS_NO_ADAPTERS )
{
msg_Dbg( p_this, "no host adapters found (aspi)" );
FreeLibrary( hASPI );
return -1;
}
if( HIBYTE( LOWORD ( dwSupportInfo ) ) != SS_COMP )
{
msg_Dbg( p_this, "unable to initalize aspi layer" );
FreeLibrary( hASPI );
return -1;
}
i_hostadapters = LOBYTE( LOWORD( dwSupportInfo ) );
if( i_hostadapters == 0 )
{
FreeLibrary( hASPI );
return -1;
}
c_drive = c_drive > 'Z' ? c_drive - 'a' : c_drive - 'A';
for( i = 0; i < i_hostadapters; i++ )
{
for( j = 0; j < 15; j++ )
{
struct SRB_GetDiskInfo srbDiskInfo;
srbDiskInfo.SRB_Cmd = SC_GET_DISK_INFO;
srbDiskInfo.SRB_HaId = i;
srbDiskInfo.SRB_Flags = 0;
srbDiskInfo.SRB_Hdr_Rsvd = 0;
srbDiskInfo.SRB_Target = j;
srbDiskInfo.SRB_Lun = 0;
lpSendCommand( (void*) &srbDiskInfo );
if( (srbDiskInfo.SRB_Status == SS_COMP) &&
(srbDiskInfo.SRB_Int13HDriveInfo == c_drive) )
{
/* Make sure this is a cdrom device */
struct SRB_GDEVBlock srbGDEVBlock;
memset( &srbGDEVBlock, 0, sizeof(struct SRB_GDEVBlock) );
srbGDEVBlock.SRB_Cmd = SC_GET_DEV_TYPE;
srbGDEVBlock.SRB_HaId = i;
srbGDEVBlock.SRB_Target = j;
lpSendCommand( (void*) &srbGDEVBlock );
if( ( srbGDEVBlock.SRB_Status == SS_COMP ) &&
( srbGDEVBlock.SRB_DeviceType == DTYPE_CDROM ) )
{
p_vcddev->i_sid = MAKEWORD( i, j );
p_vcddev->hASPI = (long)hASPI;
p_vcddev->lpSendCommand = lpSendCommand;
msg_Dbg( p_this, "using aspi layer" );
return 0;
}
else
{
FreeLibrary( hASPI );
msg_Dbg( p_this, "%s: is not a cdrom drive",
psz_dev[0] );
return -1;
}
}
}
}
FreeLibrary( hASPI );
msg_Dbg( p_this, "unable to get haid and target (aspi)" );
}
return -1;
}
#endif /* WIN32 */
......@@ -2,9 +2,10 @@
* cdrom.h: cdrom tools header
*****************************************************************************
* Copyright (C) 1998-2001 VideoLAN
* $Id: cdrom.h,v 1.2 2002/08/08 22:28:22 sam Exp $
* $Id: cdrom.h,v 1.3 2002/10/15 19:56:59 gbazin Exp $
*
* Author: Johan Bilien <jobi@via.ecp.fr>
* Authors: Johan Bilien <jobi@via.ecp.fr>
* Gildas Bazin <gbazin@netcourrier.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
......@@ -21,17 +22,191 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
*****************************************************************************/
/* where the data start on a VCD sector */
#define VCD_DATA_START 24
/* size of the availablr data on a VCD sector */
#define VCD_DATA_SIZE 2324
/* size of a VCD sector, header and tail included */
#define VCD_SECTOR_SIZE 2352
/*****************************************************************************
* The vcddev structure
*****************************************************************************/
typedef struct vcddev_s
{
char *psz_dev; /* vcd device name */
/* Section used in vcd image mode */
int i_vcdimage_handle; /* vcd image file descriptor */
int i_tracks; /* number of tracks of the vcd */
int *p_sectors; /* tracks layout on the vcd */
/* Section used in vcd device mode */
#ifdef WIN32
HANDLE h_device_handle; /* vcd device descriptor */
long hASPI;
short i_sid;
long (*lpSendCommand)( void* );
#else
int i_device_handle; /* vcd device descriptor */
#endif
} vcddev_t;
/*****************************************************************************
* Misc. Macros
*****************************************************************************/
/* LBA = msf.frame + 75 * ( msf.second + 60 * msf.minute ) */
#define MSF_TO_LBA(min, sec, frame) ((int)frame + 75 * (sec + 60 * min))
/* LBA = msf.frame + 75 * ( msf.second - 2 + 60 * msf.minute ) */
#define MSF_TO_LBA2(min, sec, frame) ((int)frame + 75 * (sec -2 + 60 * min))
#ifndef O_BINARY
# define O_BINARY 0
#endif
#define VCDDEV_T 1
/*****************************************************************************
* Platform specifics
*****************************************************************************/
#if defined( SYS_DARWIN )
#define darwin_freeTOC( p ) free( (void*)p )
#define CD_MIN_TRACK_NO 01
#define CD_MAX_TRACK_NO 99
#endif
#if defined( WIN32 )
/* Win32 DeviceIoControl specifics */
#ifndef MAXIMUM_NUMBER_TRACKS
# define MAXIMUM_NUMBER_TRACKS 100
#endif
typedef struct _TRACK_DATA {
UCHAR Reserved;
UCHAR Control : 4;
UCHAR Adr : 4;
UCHAR TrackNumber;
UCHAR Reserved1;
UCHAR Address[4];
} TRACK_DATA, *PTRACK_DATA;
typedef struct _CDROM_TOC {
UCHAR Length[2];
UCHAR FirstTrack;
UCHAR LastTrack;
TRACK_DATA TrackData[MAXIMUM_NUMBER_TRACKS];
} CDROM_TOC, *PCDROM_TOC;
typedef enum _TRACK_MODE_TYPE {
YellowMode2,
XAForm2,
CDDA
} TRACK_MODE_TYPE, *PTRACK_MODE_TYPE;
typedef struct __RAW_READ_INFO {
LARGE_INTEGER DiskOffset;
ULONG SectorCount;
TRACK_MODE_TYPE TrackMode;
} RAW_READ_INFO, *PRAW_READ_INFO;
#ifndef IOCTL_CDROM_BASE
# define IOCTL_CDROM_BASE FILE_DEVICE_CD_ROM
#endif
#ifndef IOCTL_CDROM_READ_TOC
# define IOCTL_CDROM_READ_TOC CTL_CODE(IOCTL_CDROM_BASE, 0x0000, \
METHOD_BUFFERED, FILE_READ_ACCESS)
#endif
#ifndef IOCTL_CDROM_RAW_READ
#define IOCTL_CDROM_RAW_READ CTL_CODE(IOCTL_CDROM_BASE, 0x000F, \
METHOD_OUT_DIRECT, FILE_READ_ACCESS)
#endif
/* Win32 aspi specific */
#define WIN_NT ( GetVersion() < 0x80000000 )
#define ASPI_HAID 0
#define ASPI_TARGET 0
#define DTYPE_CDROM 0x05
#define SENSE_LEN 0x0E
#define SC_GET_DEV_TYPE 0x01
#define SC_EXEC_SCSI_CMD 0x02
#define SC_GET_DISK_INFO 0x06
#define SS_COMP 0x01
#define SS_PENDING 0x00
#define SS_NO_ADAPTERS 0xE8
#define SRB_DIR_IN 0x08
#define SRB_DIR_OUT 0x10
#define SRB_EVENT_NOTIFY 0x40
#define READ_CD 0xbe
#define SECTOR_TYPE_MODE2 0x14
#define READ_CD_USERDATA_MODE2 0x10
#define READ_TOC 0x43
#define READ_TOC_FORMAT_TOC 0x0
#pragma pack(1)
struct SRB_GetDiskInfo
{
unsigned char SRB_Cmd;
unsigned char SRB_Status;
unsigned char SRB_HaId;
unsigned char SRB_Flags;
unsigned long SRB_Hdr_Rsvd;
unsigned char SRB_Target;
unsigned char SRB_Lun;
unsigned char SRB_DriveFlags;
unsigned char SRB_Int13HDriveInfo;
unsigned char SRB_Heads;
unsigned char SRB_Sectors;
unsigned char SRB_Rsvd1[22];
};
struct SRB_GDEVBlock
{
unsigned char SRB_Cmd;
unsigned char SRB_Status;
unsigned char SRB_HaId;
unsigned char SRB_Flags;
unsigned long SRB_Hdr_Rsvd;
unsigned char SRB_Target;
unsigned char SRB_Lun;
unsigned char SRB_DeviceType;
unsigned char SRB_Rsvd1;
};
struct SRB_ExecSCSICmd
{
unsigned char SRB_Cmd;
unsigned char SRB_Status;
unsigned char SRB_HaId;
unsigned char SRB_Flags;
unsigned long SRB_Hdr_Rsvd;
unsigned char SRB_Target;
unsigned char SRB_Lun;
unsigned short SRB_Rsvd1;
unsigned long SRB_BufLen;
unsigned char *SRB_BufPointer;
unsigned char SRB_SenseLen;
unsigned char SRB_CDBLen;
unsigned char SRB_HaStat;
unsigned char SRB_TargStat;
unsigned long *SRB_PostProc;
unsigned char SRB_Rsvd2[20];
unsigned char CDBByte[16];
unsigned char SenseArea[SENSE_LEN+2];
};
#pragma pack()
#endif /* WIN32 */
/*****************************************************************************
* Local Prototypes
*****************************************************************************/
static int OpenVCDImage( vlc_object_t *, const char *, vcddev_t * );
static void CloseVCDImage( vlc_object_t *, vcddev_t * );
/******************************************************************************
* Prototypes *
******************************************************************************/
int ioctl_GetTrackCount ( vlc_object_t *, int, const char *psz_dev );
int * ioctl_GetSectors ( vlc_object_t *, int, const char *psz_dev );
int ioctl_ReadSector ( vlc_object_t *, int, int, byte_t * );
#if defined( SYS_DARWIN )
static CDTOC *darwin_getTOC( vlc_object_t *, const char * );
static int darwin_getNumberOfDescriptors( CDTOC * );
static int darwin_getNumberOfTracks( CDTOC *, int );
#elif defined( WIN32 )
static int win32_vcd_open( vlc_object_t *, const char *, vcddev_t * );
#endif
......@@ -2,7 +2,7 @@
* vcd.c : VCD input module for vlc
*****************************************************************************
* Copyright (C) 2000 VideoLAN
* $Id: vcd.c,v 1.6 2002/10/04 18:07:21 sam Exp $
* $Id: vcd.c,v 1.7 2002/10/15 19:56:59 gbazin Exp $
*
* Author: Johan Bilien <jobi@via.ecp.fr>
*
......@@ -36,23 +36,28 @@
# include <unistd.h>
#endif
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <errno.h>
#if defined( WIN32 )
# include <io.h> /* read() */
#endif
#include "vcd.h"
#include "cdrom.h"
/* how many blocks VCDRead will read in each loop */
#define VCD_BLOCKS_ONCE 20
#define VCD_DATA_ONCE (VCD_BLOCKS_ONCE * VCD_DATA_SIZE)
/*****************************************************************************
* thread_vcd_data_t: VCD information
*****************************************************************************/
typedef struct thread_vcd_data_s
{
vcddev_t *vcddev; /* vcd device descriptor */
int nb_tracks; /* Nb of tracks (titles) */
int i_track; /* Current track */
int i_sector; /* Current Sector */
int * p_sectors; /* Track sectors */
vlc_bool_t b_end_of_track; /* If the end of track was reached */
} thread_vcd_data_t;
/*****************************************************************************
* Local prototypes
*****************************************************************************/
......@@ -87,7 +92,6 @@ static int VCDOpen( vlc_object_t *p_this )
char * psz_parser;
char * psz_source;
char * psz_next;
struct stat stat_info;
thread_vcd_data_t * p_vcd;
int i;
input_area_t * p_area;
......@@ -99,6 +103,12 @@ static int VCDOpen( vlc_object_t *p_this )
p_input->pf_set_area = VCDSetArea;
p_input->pf_set_program = VCDSetProgram;
#ifdef WIN32
/* On Win32 we want the VCD access plugin to be explicitly requested,
* we end up with lots of problems otherwise */
if( !p_input->psz_access || !*p_input->psz_access ) return( -1 );
#endif
/* parse the options passed in command line : */
psz_orig = psz_parser = psz_source = strdup( p_input->psz_name );
......@@ -137,29 +147,15 @@ static int VCDOpen( vlc_object_t *p_this )
return -1;
}
psz_source = config_GetPsz( p_input, "vcd" );
if( !psz_source ) return -1;
}
/* test the type of file given */
if( stat( psz_source, &stat_info ) == -1 )
{
msg_Err( p_input, "cannot stat() source `%s' (%s)",
psz_source, strerror(errno));
return( -1 );
}
if( !S_ISBLK(stat_info.st_mode) && !S_ISCHR(stat_info.st_mode))
{
msg_Warn( p_input, "vcd module discarded (not a valid drive)" );
return -1;
}
p_vcd = malloc( sizeof(thread_vcd_data_t) );
if( p_vcd == NULL )
{
msg_Err( p_input, "out of memory" );
free( psz_source );
return -1;
}
......@@ -177,39 +173,26 @@ static int VCDOpen( vlc_object_t *p_this )
vlc_mutex_unlock( &p_input->stream.stream_lock );
p_vcd->i_handle = open( psz_source, O_RDONLY | O_NONBLOCK );
if( p_vcd->i_handle == -1 )
if( !(p_vcd->vcddev = ioctl_Open( p_this, psz_source )) )
{
msg_Err( p_input, "could not open %s", psz_source );
free (p_vcd);
free( psz_source );
free( p_vcd );
return -1;
}
/* We read the Table Of Content information */
p_vcd->nb_tracks = ioctl_GetTrackCount( VLC_OBJECT( p_input),
p_vcd->i_handle, psz_source );
p_vcd->nb_tracks = ioctl_GetTracksMap( VLC_OBJECT(p_input),
p_vcd->vcddev, &p_vcd->p_sectors );
free( psz_source );
if( p_vcd->nb_tracks < 0 )
{
msg_Err( p_input, "unable to count tracks" );
close( p_vcd->i_handle );
free( p_vcd );
return -1;
}
else if( p_vcd->nb_tracks <= 1 )
{
msg_Err( p_input, "no movie tracks found" );
close( p_vcd->i_handle );
free( p_vcd );
return -1;
}
p_vcd->p_sectors = ioctl_GetSectors( VLC_OBJECT( p_input),
p_vcd->i_handle, psz_source );
if( p_vcd->p_sectors == NULL )
if( p_vcd->nb_tracks <= 1)
{
input_BuffersEnd( p_input, p_input->p_method_data );
close( p_vcd->i_handle );
//input_BuffersEnd( p_input, p_input->p_method_data ); /* ??? */
ioctl_Close( p_this, p_vcd->vcddev );
free( p_vcd );
return -1;
}
......@@ -263,7 +246,7 @@ static void VCDClose( vlc_object_t *p_this )
input_thread_t * p_input = (input_thread_t *)p_this;
thread_vcd_data_t *p_vcd = (thread_vcd_data_t *)p_input->p_access_data;
close( p_vcd->i_handle );
ioctl_Close( p_this, p_vcd->vcddev );
free( p_vcd );
}
......@@ -292,7 +275,7 @@ static int VCDRead( input_thread_t * p_input, byte_t * p_buffer,
for ( i_index = 0 ; i_index < i_blocks ; i_index++ )
{
if ( ioctl_ReadSector( VLC_OBJECT(p_input), p_vcd->i_handle,
if ( ioctl_ReadSector( VLC_OBJECT(p_input), p_vcd->vcddev,
p_vcd->i_sector, p_buffer + i_index * VCD_DATA_SIZE ) < 0 )
{
msg_Err( p_input, "could not read sector %d", p_vcd->i_sector );
......@@ -321,7 +304,7 @@ static int VCDRead( input_thread_t * p_input, byte_t * p_buffer,
if ( i_len % VCD_DATA_SIZE ) /* this should not happen */
{
if ( ioctl_ReadSector( VLC_OBJECT(p_input), p_vcd->i_handle,
if ( ioctl_ReadSector( VLC_OBJECT(p_input), p_vcd->vcddev,
p_vcd->i_sector, p_last_sector ) < 0 )
{
msg_Err( p_input, "could not read sector %d", p_vcd->i_sector );
......
......@@ -2,7 +2,7 @@
* vcd.h: thread structure of the VCD plugin
*****************************************************************************
* Copyright (C) 1999-2001 VideoLAN
* $Id: vcd.h,v 1.1 2002/08/04 17:23:42 sam Exp $
* $Id: vcd.h,v 1.2 2002/10/15 19:56:59 gbazin Exp $
*
* Author: Johan Bilien <jobi@via.ecp.fr>
*
......@@ -21,17 +21,24 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
*****************************************************************************/
/*****************************************************************************
* thread_vcd_data_t: VCD information
*****************************************************************************/
typedef struct thread_vcd_data_s
{
int i_handle; /* File descriptor */
int nb_tracks; /* Nb of tracks (titles) */
int i_track; /* Current track */
int i_sector; /* Current Sector */
int * p_sectors; /* Track sectors */
vlc_bool_t b_end_of_track; /* If the end of track was reached */
/* where the data start on a VCD sector */
#define VCD_DATA_START 24
/* size of the availablr data on a VCD sector */
#define VCD_DATA_SIZE 2324
/* size of a VCD sector, header and tail included */
#define VCD_SECTOR_SIZE 2352
/* size of a CD sector */
#define CD_SECTOR_SIZE 2048
} thread_vcd_data_t;
#ifndef VCDDEV_T
typedef struct vcddev_s vcddev_t;
#endif
/*****************************************************************************
* Prototypes
*****************************************************************************/
vcddev_t *ioctl_Open ( vlc_object_t *, const char * );
void ioctl_Close ( vlc_object_t *, vcddev_t * );
int ioctl_GetTracksMap ( vlc_object_t *, const vcddev_t *, int ** );
int ioctl_ReadSector ( vlc_object_t *, const vcddev_t *,
int, byte_t * );
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment