PDA

View Full Version : Reading 2352 bytes/sector from VCD



OneThirty8
June 28th, 2006, 09:49
I found this last week searching through the KOS mailing list archives, and I found the information extremely useful for a project I'm working on. I thought I'd copy it here so others won't have to look too hard to find it:



My last project was a Playstation movie player for Windows, since then I"ve
always been obsessed by the 2352-bytes/sector CD read mode ^_^
I couldn"t believe the Dreamcast wouldn"t provide a "RAW" CD read mode, so
I started a little investigation...

The most obvious and probable place to look at was GD/CD-ROM superfunction
GDROM_SECTOR_MODE, currently defined in
\kernel\arch\dreamcast\hardware\cdrom.c to receive the following parameters:
params[0] = 0; /* 0 = set, 1 = get */
params[1] = 8192; /* ? */
params[2] = cdxa ? 2048 : 1024; /* CD-XA mode 1/2 */
params[3] = 2048; /* sector size */

The tools used were:
- dc-load ip to make a dump of the memory at 8C000000 - 8C008000
- dcdis.exe (thanx to the author !) to convert this memory dump into SH4
assembler

Result:
here"s the core of set GDROM_SECTOR_MODE in pseudo-code:

[...]
if (params[1] == 4096) {
if (params[2] in {0x0200, 0x0400, 0x0600, 0x0800, 0x0a00, 0x0c00})
write_params_to_mem;
} else write_params_to_mem;
[...]

In extenso: there isn"t any check when you set params[1] to 8192, it just
writes your values into memory. If you set params[1] to 4096, it will check
if the value params[2] is a valid value before saving your params into memory.
After understanding this, all I had to do was to test the read functions
with params[1] = 4096, different params[2] and different cd types.

These are the results so far:
setting the parameters with params[0]=0 and params[1] = 4096 and reading a
sector after that.

Mode (params[2])
0x0200 seems to work with Audio CD
0x0400 seems to work with MODE 1 CD & GD-ROM
0x0600 seems to work with PSX cd (CD-XA) & VideoCD
0x0800 seems to work with PSX cd (CD-XA) & VideoCD
0x0a00 ?
0x0c00 ?

Not everything has been discovered /tested yet, a lot has still to be
investigated, but you should be able to use this info to do some nice
things... I"ll try to grab some special format cds (CD-I, ...) next week to
do some extra tests...
I can't speak for all of what is reported above, but all of what I needed for my project is dead on. By setting params[1] to 4096 and params[2] to 0x600 and calling gdc_change_data_type(params); I can access the data in tracks 2-99 on a VideoCD. In simple terms, I made a copy of the cdrom_reinit() function in kernel/arch/dreamcast/hardware/cdrom.c with these different values for params[1] and params[2] to switch the read mode if I found that I was dealing with a (S)VCD, which I learned how to do by reading the documentation and source code to the GNU VCDImager.

In more complex terms, here's pseudocode to begin reading a VideoCD on the Dreamcast (this actually does work, and I will be releasing a player with source code in the near future):


int disc_status, disc_type;
uint32 params[4];
char info_vcd[2048];

/* Figure out if we're dealing with a CDROM_XA */
cdrom_get_status(&disc_status, &disc_type);

/* If we have a CDROM_XA disc, see if it is a VCD */
if (disc_type==0x20)
{
cdrom_read_sectors(info_vcd, 300,1);
if (
(
info_vcd[0] == 'V' &&
info_vcd[1] == 'I' &&
info_vcd[2] == 'D' &&
info_vcd[3] == 'E' &&
info_vcd[4] == 'O' &&
info_vcd[5] == '_' &&
info_vcd[6] == 'C' &&
info_vcd[7] == 'D' ) ||
( /* for SVCD, it could also read "'SUPERVCD' or 'HQ-VCD ' (two spaces after VCD) */)
)
{
params[0] = 0;
params[1] = 4096;
params[2] = 0x600;
params[3] = 2352;

/* You'll need to copy in this function and the MAKE_SYSCALL macro from cdrom.c in KOS */
gdc_change_data_type(params);

play_VCD(); /* of course, you'll have to write this one yourself. */
}
}


In case anyone is interested, I know there is at least one port of SMPEG floating around out there, and with KOS 1.3.x SMPEG should compile without making very many changes at all.

Also, be aware that every time you read a sector from a VCD now, you'll get back 2352 bytes. You only want 2324. I'm pretty sure that the bytes you want to ignore are the first 24 and the last 4. What I do is read the data into a 2352-byte buffer, but give the demuxer buffer+24, and tell it that the data ends at buffer+2348.