Commit 182133ea authored by François Cartegnie's avatar François Cartegnie 🤞

access: cdda: fix audio/data mixed mode

best way to kill your speakers
parent e8f5c617
......@@ -39,6 +39,7 @@ Access:
* Enable SMB2 / SMB3 support on mobile ports with libsmb2
* Added support for the RIST (Reliable Internet Stream Transport) Protocol
* Added avaudiocapture module as a replacement for qtsound, which is removed now
* Audio CD data tracks are now correctly detected and skipped
Access output:
* Added support for the RIST (Reliable Internet Stream Transport) Protocol
......
......@@ -211,6 +211,67 @@ static int DemuxControl(demux_t *demux, int query, va_list args)
return VLC_SUCCESS;
}
/*
* Check for Mixed Audio/CDROM data
*
* ioctl will return first track # and last track # from last TOC
* (this could start > 1.. but where's the case ?)
*
* vcdev_toc stores i_tracks as the number of STORED sectors info,
* this is last - first track, plus one (the LEADOUT one)
*
* tracks can be DATA in mixed data/audio mode (CDROM spec, not CDDA)
* and this is control flag (Subcode Channel Q)
*
* first: 1 last 13
* track: 1 lba: 0 ( 0) 00:02:00 adr: 1 control: 0 mode: -1
* track: 2 lba: 16462 ( 65848) 03:41:37 adr: 1 control: 0 mode: -1
* ...
* track: 12 lba: 212405 ( 849620) 47:14:05 adr: 1 control: 0 mode: -1
* track: 13 lba: 250948 ( 1003792) 55:47:73 adr: 1 control: 4 mode: -1
* track:lout lba: 266286 ( 1065144) 59:12:36 adr: 1 control: 4 mode: -1
*/
static int TOC_GetAudioRange(vcddev_toc_t *p_toc,
int *pi_first, int *pi_last)
{
if( p_toc->i_tracks < 1 )
return 0;
int i_first = p_toc->i_first_track;
int i_last = p_toc->i_last_track;
for(int i=i_first; i<p_toc->i_tracks; i++)
{
if((p_toc->p_sectors[i - 1].i_control & CD_ROM_DATA_FLAG) == 0)
break;
i_first++;
}
for(int i=i_last; i > 0; i--)
{
if((p_toc->p_sectors[i - 1].i_control & CD_ROM_DATA_FLAG) == 0)
break;
i_last--;
}
/* FIX copy protection TOC
* https://github.com/metabrainz/libdiscid/blob/e46249415eb6d657ecc63667b03d670a4347712f/src/toc.c#L101 */
do
{
vcddev_sector_t *p_last = &p_toc->p_sectors[i_last - p_toc->i_first_track];
vcddev_sector_t *p_lout = &p_toc->p_sectors[p_toc->i_tracks];
if(p_lout->i_lba > p_last->i_lba || i_last <= i_first)
break;
/* last audio is invalid, bigger than lead out */
i_last = i_last - 1;
p_toc->i_last_track = i_last;
p_last->i_lba -= CD_ROM_XA_INTERVAL;
p_toc->i_tracks--; /* change lead out */
} while( i_last > i_first );
*pi_first = i_first;
*pi_last = i_last;
return (i_last >= i_first) ? i_last - i_first + 1 : 0;
}
static int DemuxOpen(vlc_object_t *obj, vcddev_t *dev, unsigned track)
{
demux_t *demux = (demux_t *)obj;
......@@ -233,15 +294,25 @@ static int DemuxOpen(vlc_object_t *obj, vcddev_t *dev, unsigned track)
vcddev_toc_t *p_toc = ioctl_GetTOC(obj, dev, true);
if(p_toc == NULL)
goto error;
if (track > (unsigned)p_toc->i_tracks)
int i_cdda_tracks, i_cdda_first, i_cdda_last;
i_cdda_tracks = TOC_GetAudioRange(p_toc, &i_cdda_first, &i_cdda_last);
if (track == 0 || track > (unsigned) i_cdda_tracks)
{
msg_Err(obj, "invalid track number: %u/%i", track, p_toc->i_tracks);
msg_Err(obj, "invalid track number: %u/%i", track, i_cdda_tracks);
vcddev_toc_Free(p_toc);
goto error;
}
sys->start = p_toc->p_sectors[track - 1].i_lba;
sys->length = p_toc->p_sectors[track].i_lba - sys->start;
track--;
int i_first_sector = p_toc->p_sectors[track].i_lba;
int i_last_sector = p_toc->p_sectors[track + 1].i_lba;
if(i_cdda_first + track == (unsigned) i_cdda_last && p_toc->i_last_track > i_cdda_last)
i_last_sector -= CD_ROM_XA_INTERVAL;
sys->start = i_first_sector;
sys->length = i_last_sector - i_first_sector;
vcddev_toc_Free(p_toc);
}
......@@ -272,6 +343,9 @@ typedef struct
{
vcddev_t *vcddev; /* vcd device descriptor */
vcddev_toc_t *p_toc; /* Tracks TOC */
int i_cdda_tracks; /* # of audio tracks in TOC */
int i_cdda_first; /* First .. */
int i_cdda_last; /* Last .. */
int cdtextc;
vlc_meta_t **cdtextv;
#ifdef HAVE_LIBCDDB
......@@ -455,19 +529,30 @@ static int ReadDir(stream_t *access, input_item_node_t *node)
const vcddev_toc_t *p_toc = sys->p_toc;
/* Build title table */
for (int i = 0; i < p_toc->i_tracks; i++)
const int i_start_track_offset = sys->i_cdda_first - sys->p_toc->i_first_track;
for (int i = 0; i < sys->i_cdda_tracks; i++)
{
if(i < i_start_track_offset)
continue;
msg_Dbg(access, "track[%d] start=%d", i, p_toc->p_sectors[i].i_lba);
/* Initial/default name */
char *name;
if (unlikely(asprintf(&name, _("Audio CD - Track %02i"), i + 1) == -1))
if (unlikely(asprintf(&name, _("Audio CD - Track %02i"),
i - i_start_track_offset + 1 ) == -1))
name = NULL;
/* Create playlist items */
int i_first_sector = p_toc->p_sectors[i].i_lba;
int i_last_sector = p_toc->p_sectors[i + 1].i_lba;
if(sys->i_cdda_first + i == sys->i_cdda_last &&
p_toc->i_last_track > sys->i_cdda_last)
i_last_sector -= CD_ROM_XA_INTERVAL;
const vlc_tick_t duration =
(vlc_tick_t)(p_toc->p_sectors[i + 1].i_lba - p_toc->p_sectors[i].i_lba)
(vlc_tick_t)(i_last_sector - i_first_sector)
* CDDA_DATA_SIZE * CLOCK_FREQ / 44100 / 2 / 2;
input_item_t *item = input_item_NewDisc(access->psz_url,
......@@ -492,8 +577,7 @@ static int ReadDir(stream_t *access, input_item_node_t *node)
free(opt);
}
if (likely(asprintf(&opt, "cdda-last-sector=%i",
p_toc->p_sectors[i + 1].i_lba) != -1))
if (likely(asprintf(&opt, "cdda-last-sector=%i", i_last_sector) != -1))
{
input_item_AddOption(item, opt, VLC_INPUT_OPTION_TRUSTED);
free(opt);
......@@ -607,7 +691,8 @@ static int AccessOpen(vlc_object_t *obj, vcddev_t *dev)
goto error;
}
if (sys->p_toc->i_tracks == 0)
sys->i_cdda_tracks = TOC_GetAudioRange(sys->p_toc, &sys->i_cdda_first, &sys->i_cdda_last);
if (sys->i_cdda_tracks == 0)
{
msg_Err(obj, "no audio tracks found");
vcddev_toc_Free(sys->p_toc);
......
......@@ -37,6 +37,12 @@ enum {
#define CD_ROM_XA_MODE2_F1_DATA_SIZE 2048
#define CD_ROM_XA_MODE2_F2_DATA_SIZE 2324
#define CD_ROM_XA_FRAMES 75
#define CD_ROM_XA_INTERVAL ((60 + 90 + 2) * CD_ROM_XA_FRAMES)
/* Subcode control flag */
#define CD_ROM_DATA_FLAG 0x04
/* size of a CD sector */
#define CD_SECTOR_SIZE CD_ROM_MODE1_DATA_SIZE
......
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