Commit 87513511 authored by Laurent Aimar's avatar Laurent Aimar

Added ioctl_GetCdText to our cdrom wrapper for linux and win32.

It is not yet used, but will allow CD-TEXT info support.
parent 0d80d151
......@@ -76,6 +76,7 @@
#include "cdrom_internals.h"
#include "cdrom.h"
#include <vlc_charset.h>
#include <vlc_meta.h>
/*****************************************************************************
* ioctl_Open: Opens a VCD device or file and returns an opaque handle
......@@ -1243,3 +1244,275 @@ static int win32_vcd_open( vlc_object_t * p_this, const char *psz_dev,
}
#endif /* WIN32 */
/* */
static void astrcat( char **ppsz_dst, char *psz_src )
{
char *psz_old = *ppsz_dst;
if( !psz_old )
{
*ppsz_dst = strdup( psz_src );
}
else if( psz_src )
{
if( asprintf( ppsz_dst, "%s%s", psz_old, psz_src ) < 0 )
*ppsz_dst = psz_old;
else
free( psz_old );
}
}
/* */
static int CdTextParse( vlc_meta_t ***ppp_tracks, int *pi_tracks,
const uint8_t *p_buffer, int i_buffer )
{
char *pppsz_info[128][0x10];
int i_track_last = -1;
if( i_buffer < 4 )
return -1;
memset( pppsz_info, 0, sizeof(pppsz_info) );
for( int i = 0; i < (i_buffer-4)/18; i++ )
{
const uint8_t *p_block = &p_buffer[4 + 18*i];
char psz_text[12+1];
const int i_pack_type = p_block[0];
if( i_pack_type < 0x80 || i_pack_type > 0x8f )
continue;
const int i_track_number = (p_block[1] >> 0)&0x7f;
const int i_extension_flag = ( p_block[1] >> 7)& 0x01;
if( i_extension_flag )
continue;
//const int i_sequence_number = p_block[2];
//const int i_charater_position = (p_block[3] >> 0) &0x0f;
//const int i_block_number = (p_block[3] >> 4) &0x07;
/* TODO unicode support
* I need a sample */
//const int i_unicode = ( p_block[3] >> 7)&0x01;
//const int i_crc = (p_block[4+12] << 8) | (p_block[4+13] << 0);
/* */
memcpy( psz_text, &p_block[4], 12 );
psz_text[12] = '\0';
/* */
int i_track = i_track_number;
char *psz_track = &psz_text[0];
while( i_track <= 127 && psz_track < &psz_text[12] )
{
//fprintf( stderr, "t=%d psz_track=%p end=%p", i_track, psz_track, &psz_text[12] );
if( *psz_track )
{
astrcat( &pppsz_info[i_track][i_pack_type-0x80], psz_track );
i_track_last = __MAX( i_track_last, i_track );
}
i_track++;
psz_track += 1 + strlen(psz_track);
}
}
if( i_track_last < 0 )
return -1;
vlc_meta_t **pp_tracks = calloc( i_track_last+1, sizeof(*pp_tracks) );
if( !pp_tracks )
goto exit;
for( int j = 0; j < 0x10; j++ )
{
const char *psz_default = pppsz_info[0][j];
for( int i = 0; i <= i_track_last; i++ )
{
const char *psz_value = pppsz_info[i][j];
if( !psz_value && !psz_default )
continue;
vlc_meta_t *p_track = pp_tracks[i];
if( !p_track )
{
p_track = pp_tracks[i] = vlc_meta_New();
if( !p_track )
continue;
}
switch( j )
{
case 0x00: /* Album/Title */
if( i == 0 )
{
vlc_meta_SetAlbum( p_track, psz_value );
}
else
{
if( psz_value )
vlc_meta_SetTitle( p_track, psz_value );
if( psz_default )
vlc_meta_SetAlbum( p_track, psz_default );
}
break;
case 0x01: /* Performer */
vlc_meta_SetArtist( p_track, psz_value ?: psz_default );
break;
case 0x05: /* Messages */
vlc_meta_SetDescription( p_track, psz_value ?: psz_default );
break;
case 0x07: /* Genre */
vlc_meta_SetGenre( p_track, psz_value ?: psz_default );
break;
/* FIXME unsupported:
* 0x02: songwriter
* 0x03: composer
* 0x04: arrenger
* 0x06: disc id */
}
}
}
/* */
exit:
for( int j = 0; j < 0x10; j++ )
for( int i = 0; i <= i_track_last; i++ )
free( pppsz_info[i][j] );
*ppp_tracks = pp_tracks;
*pi_tracks = i_track_last+1;
return pp_tracks ? 0 : -1;
}
#if defined( __APPLE__ ) || \
defined( HAVE_IOC_TOC_HEADER_IN_SYS_CDIO_H ) || \
defined( HAVE_SCSIREQ_IN_SYS_SCSIIO_H )
static int CdTextRead( vlc_object_t *p_object, const vcddev_t *p_vcddev,
uint8_t **pp_buffer, int *pi_buffer )
{
VLC_UNUSED( p_object );
return -1;
}
#elif defined( WIN32 )
static int CdTextRead( vlc_object_t *p_object, const vcddev_t *p_vcddev,
uint8_t **pp_buffer, int *pi_buffer )
{
if( p_vcddev->hASPI )
{
msg_Err( p_object, "mode ASPI unsupported for CD-TEXT" );
return -1;
}
CDROM_READ_TOC_EX TOCEx;
memset(&TOCEx, 0, sizeof(TOCEx));
TOCEx.Format = CDROM_READ_TOC_EX_FORMAT_CDTEXT;
const int i_header_size = __MAX( 4, MINIMUM_CDROM_READ_TOC_EX_SIZE );
uint8_t header[i_header_size];
DWORD i_read;
if( !DeviceIoControl( p_vcddev->h_device_handle, IOCTL_CDROM_READ_TOC_EX,
&TOCEx, sizeof(TOCEx), header, i_header_size, &i_read, 0 ) )
return -1;
const int i_text = 2 + (header[0] << 8) + header[1];
if( i_text <= 4 )
return -1;
/* Read complete CD-TEXT */
uint8_t *p_text = calloc( 1, i_text );
if( !p_text )
return VLC_EGENERIC;
if( !DeviceIoControl( p_vcddev->h_device_handle, IOCTL_CDROM_READ_TOC_EX,
&TOCEx, sizeof(TOCEx), p_text, i_text, &i_read, 0 ) )
{
free( p_text );
return VLC_EGENERIC;
}
/* */
*pp_buffer = p_text;
*pi_buffer = i_text;
return VLC_SUCCESS;
}
#else
static int CdTextRead( vlc_object_t *p_object, const vcddev_t *p_vcddev,
uint8_t **pp_buffer, int *pi_buffer )
{
VLC_UNUSED( p_object );
if( p_vcddev->i_device_handle == -1 )
return -1;
struct cdrom_generic_command gc;
uint8_t header[4];
/* Read CD-TEXT size */
memset( header, 0, sizeof(header) );
memset( &gc, 0, sizeof(gc) );
gc.cmd[0] = 0x43; /* Read TOC */
gc.cmd[1] = 0x02; /* MSF */
gc.cmd[2] = 5; /* CD-Text */
gc.cmd[7] = ( sizeof(header) >> 8 ) & 0xff;
gc.cmd[8] = ( sizeof(header) >> 0 ) & 0xff;
gc.buflen = sizeof(header);
gc.buffer = header;
gc.data_direction = CGC_DATA_READ;
gc.timeout = 1000;
if( ioctl( p_vcddev->i_device_handle, CDROM_SEND_PACKET, &gc ) == -1 )
return VLC_EGENERIC;
/* If the size is less than 4 it is an error, if it 4 then
* it means no text data */
const int i_text = 2 + (header[0] << 8) + header[1];
if( i_text <= 4 )
return VLC_EGENERIC;
/* Read complete CD-TEXT */
uint8_t *p_text = calloc( 1, i_text );
if( !p_text )
return VLC_EGENERIC;
memset( &gc, 0, sizeof(gc) );
gc.cmd[0] = 0x43; /* Read TOC */
gc.cmd[1] = 0x02; /* MSF */
gc.cmd[2] = 5; /* CD-Text */
gc.cmd[7] = ( i_text >> 8 ) & 0xff;
gc.cmd[8] = ( i_text >> 0 ) & 0xff;
gc.buflen = i_text;
gc.buffer = p_text;
gc.data_direction = CGC_DATA_READ;
gc.timeout = 1000;
if( ioctl( p_vcddev->i_device_handle, CDROM_SEND_PACKET, &gc ) == -1 )
{
free( p_text );
return VLC_EGENERIC;
}
/* */
*pp_buffer = p_text;
*pi_buffer = i_text;
return VLC_SUCCESS;
}
#endif
int ioctl_GetCdText( vlc_object_t *p_object, const vcddev_t *p_vcddev,
vlc_meta_t ***ppp_tracks, int *pi_tracks )
{
uint8_t *p_text;
int i_text;
if( p_vcddev->i_vcdimage_handle != -1 )
return -1;
if( CdTextRead( p_object, p_vcddev, &p_text, &i_text ) )
return -1;
CdTextParse( ppp_tracks, pi_tracks, p_text, i_text );
free( p_text );
return 0;
}
......@@ -95,3 +95,8 @@ void ioctl_Close ( vlc_object_t *, vcddev_t * );
int ioctl_GetTracksMap ( vlc_object_t *, const vcddev_t *, int ** );
int ioctl_ReadSectors ( vlc_object_t *, const vcddev_t *,
int, uint8_t *, int, int );
/* CDDA only
* The track 0 is for album meta data */
int ioctl_GetCdText( vlc_object_t *, const vcddev_t *,
vlc_meta_t ***ppp_tracks, int *pi_tracks );
......@@ -102,6 +102,14 @@ typedef struct __RAW_READ_INFO {
ULONG SectorCount;
TRACK_MODE_TYPE TrackMode;
} RAW_READ_INFO, *PRAW_READ_INFO;
typedef struct _CDROM_READ_TOC_EX {
UCHAR Format : 4;
UCHAR Reserved1 : 3;
UCHAR Msf : 1;
UCHAR SessionTrack;
UCHAR Reserved2;
UCHAR Reserved3;
} CDROM_READ_TOC_EX, *PCDROM_READ_TOC_EX;
#ifndef IOCTL_CDROM_BASE
# define IOCTL_CDROM_BASE FILE_DEVICE_CD_ROM
......@@ -114,6 +122,12 @@ typedef struct __RAW_READ_INFO {
#define IOCTL_CDROM_RAW_READ CTL_CODE(IOCTL_CDROM_BASE, 0x000F, \
METHOD_OUT_DIRECT, FILE_READ_ACCESS)
#endif
#define IOCTL_CDROM_READ_TOC_EX CTL_CODE(IOCTL_CDROM_BASE, 0x0015, \
METHOD_BUFFERED, FILE_READ_ACCESS)
#define MINIMUM_CDROM_READ_TOC_EX_SIZE 2
#define CDROM_READ_TOC_EX_FORMAT_CDTEXT 0x05
/* Win32 aspi specific */
#define WIN_NT ( GetVersion() < 0x80000000 )
......
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