Added ioctl_GetCdText to our cdrom wrapper for linux and win32.
authorLaurent Aimar <fenrir@videolan.org>
Tue, 24 Feb 2009 22:02:34 +0000 (23:02 +0100)
committerLaurent Aimar <fenrir@videolan.org>
Tue, 24 Feb 2009 22:43:59 +0000 (23:43 +0100)
It is not yet used, but will allow CD-TEXT info support.

modules/access/vcd/cdrom.c
modules/access/vcd/cdrom.h
modules/access/vcd/cdrom_internals.h

index 715b0df..c132288 100644 (file)
@@ -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;
+}
+
index 238946e..9800918 100644 (file)
@@ -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 );
index eef3df0..ddaded1 100644 (file)
@@ -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 )