CDROM Video CDs (VCD)
VCDs are Video CDs with MPEG compression, yielding a playtime of 72 minutes per
disc (whole movies usually being stored on two CDs). VCDs are popular in asia
(as opposed to VHS tapes used in western world).
VCDs on Playstation
For the Playstation, the asian SCPH-5903 model includes a special daughterboard
with MPEG decoding hardware for playing VCDs.
CDROM - Video CD Commands
Pinouts - VCD Pinouts
Without that hardware it has been widely believed to be impossible to play VCDs on Playstations, although, as of 2017, it turned out that the Playstation's CPU and MDEC decoder are fast enough for that purpose (when skipping B-frames, rendering the movie in monochrome without colors, and reducing audio output to 11kHz/mono).
ISO Filesystem (Track 1)
VCD ISO Basic Files (INFO, ENTRIES, AVSEQnn, ISO Filesystem)
VCD ISO Playback Control PBC Files (PSD, LOT, ITEMnnnn)
VCD ISO Search Files (SCANDATA, SEARCH, TRACKS, SPICONTX)
VCD ISO Misc files (CAPTnn, AUDIOnn, KARINFO, PICTURES, CDI)
MPEG Streams (Track 2 and up)
VCD Versions & Variants
VCD ISO Basic Files (INFO, ENTRIES, AVSEQnn, ISO Filesystem)
Primary Volume Descriptor (00:02:16)
VCDs are having a standard ISO Primary Volume Descriptor, with some VCD
008h 32 System Identifier (always "CD-RTOS CD-BRIDGE" for VCDs) 028h 32 Volume Identifier (often nonsense, eg. "" or "__" or "VolumeLabel") 23Eh 128 Application Identifier ("CDI/CDI_APPL.VCD;1" or "CDI/CDI_VCD.APP;1") 400h 8 CD-XA Identifying Signature ("CD-XA001" for PSX and VCD)
There are some more differences to normal CDROMs:
VCDs are using MODE2 (with 800h-byte and 914h-byte sectors) MPEG videos are on extra data tracks (outside of the ISO area on Track 1) Files in VCD or SVCD folders use fixed sectors numbers (00:04:00 and up) All 16bit/32bit values in files in VCD,SVCD,EXT,etc are BIG-ENDIAN
Due to the fixed sector numbers, VCDs players can completely ignore the ISO
filesystem with filenames and folders, and just address everything via sector
numbers (though accessing files in EXT and CDI folders seem to require using
VCD\INFO.VCD or SVCD\INFO.SVD (00:04:00) (800h bytes, one sector)
000h 8 ID "VIDEO_CD" for VCD (or "SUPERVCD"/"HQ-VCD " for SVCD) 008h 1 Version ;Version Major (01h) (or 02h for VCD 2.0) 009h 1 System Profile Tag ;Version Minor (00h) (or 01h for VCD 1.1 or HQ) 00Ah 16 Album ID/Desc (name in ASCII, padded with SPC) (usually empty) 01Ah 2 Total Number of CDs in Album (1..N) ;\usually always 1,1 (even 01Ch 2 Number of this CD in Album (1..N) ;/for movies with 2 discs) 01Eh 13 PAL Flags, 98x1bit, for each Track? (0=NTSC, 1=PAL) 02Bh 1 InfoStatusFlags (see below) Below is usually zero-filled when not using PBC 02Ch 4 Size of PSD.VCD file (or PSD.SVD?) (0=None) 030h 3 First segment addr MM:SS:00 in BCD (00:02:00 ???) 033h 1 Offset Multiplier for "PsdOffset" values in PSD.VCD (must be 8) 034h 2 Number of ListIDs in LOT.VCD file (1..7FFFh, plus 1 in some discs) 036h 2 Number of ITEMnnnn.DAT files (plus nonsense in some discs?) Below is usually zero-filled (maybe exists on SVCD only?) 038h 1980 SegmentContent[1..1980] (b0-1=Audio, b2-4=Video, b5=Cont, b6-7=OGT) 7F4h 5*2 volume start time: 5x16bit ;aka playing_time in seconds (?) 7FEh 2 Reserved (0)
InfoStatusFlags at [02Bh] describes certain characteristics of the disc:
bit0 Reserved, must be zero bit1-2 Restriction (0=No, 1..3=Restricted category 1..3) (eg. "not for kids") bit3 Special Information is encoded in the pictures, uh? bit4 MPEG User Data is used for Closed Caption (user_data_cc) (0=No, 1=Yes) bit5 Next Disc with PBC (0=Start at ListID#1, 1=Start at ListID#2) bit6 Next Disc without PBC (0=Start at Track #2, 1=Start at Track #3) bit7 Extended PBC available (0=No, 1=Yes... aka EXT\PSD_X exists?)
Note: Bit5/6 are used only if the next disc has the same Album ID (eg. the
feature allows to skip copyright messages if the same message was already shown
on another disc).
First_segment_addr: The location of the first sector of the Segment Play Item Area [that is... the first ITEMnnnn.DAT file?], in the form mm:ss:00. Must be 00:00:00 if PSD size is zero. If PSD size is nonzero, but no segments used: Usually set to 00:02:00.
VCD\ENTRIES.VCD or SVCD\ENTRIES.SVD (00:04:01) (800h bytes, one sector)
000h 8 ID "ENTRYVCD" for VCD and SVCD (or "ENTRYSVD" for VCD30) 008h 1 Version ;\same as in INFO.VCD/SVD 009h 1 System Profile Tag ;/ 00Ah 2 Number of Entries/Chapters (1..500) 00Ch 4*500 Entry[N] (Track 02h..99h, and MM:SS:FF) (all 4 bytes in BCD) 7DCh 36 Reserved (0)
0x02 --- VCD2.0 0x01 --- SVCD, should be same as version in INFO.SVD
0x01 if VCD1.1 0x00 else
MPEGAV\AVSEQnn.DAT (pointers to max 98 MPEG-1 Tracks, nn=01..98) (for VCDs)
MPEG2\AVSEQnn.MPG (pointers to max 98 MPEG-2 Tracks, nn=01..98) (for SVCDs)
MPEGAV\AVSEQnn.MPG (pointers to WHATEVER) (as so on some SVCDs or VCD30?)
These filesystem entries contain pointers to the video tracks (that is, outside
of the ISO area on Track 1).
Commercially made SVCDs can reportedly contain 7 folders: Autorun, Data, Ext, Mpegav, Segment, Svcd and Vmp (ie. there's no MPEG2 folder on all SVCDs? though that MPEGAV folder is said to contain a .MPG file instead of .DAT file).
VCD ISO Playback Control PBC Files (PSD, LOT, ITEMnnnn)
Playback Control (PBC) is an optional feature that allows to define menues,
pictures or text pages (whereas all those is internally just consisting of MPEG
compressed bitmaps; rather than of text characters).
Presence of the PBC feature is indicated by PSD.VCD filesize entry (in INFO.VCD) being nonzero. PBC seems to be supported by most VCDs (except older discs from around 1997), however, many VCDs are merely including a single PlayList entry for the movie track, without any further menues/extras.
VCD\PSD.VCD or SVCD\PSD.SVD (00:04:34 and up) (max 256 sectors)
The Descriptors in this file can be considered as being "program code". The
program is usually stuck on "executing" the current descriptor (eg. playing a
movie, or showing a selection menu) without automatically increasing the
program counter. Actual program flow occurs only if the user presses a button
(or upon selection timeouts), causing the program to "goto" to a new PsdOffset.
And, something does probably happen upon end-of-track/item... maybe that does
automatically trigger the Next button handler?
<B> PsdPlayListDescriptor (14+2*N bytes):</B> 00h 1 Type (10h=PlayList) 01h 1 Number of Items (noi) ;for Start-of-Movie and Numeric-Input? 02h 2 ListID for this Descriptor (1..7FFFh) 04h 2 PsdOffset for Prev button (FFFFh=Disable) 06h 2 PsdOffset for Next button (FFFFh=Disable) 08h 2 PsdOffset for Return/back button (FFFFh=Disable) 0Ah 2 Play time in 1/15s (=max 72.8 minutes) (or 0000h=full item) 0Ch 1 Delay time in "1s/10s" units after ;<-- uh, after? after what? 0Dh 1 Auto pause time in "1s/10s" units (used for each item in list if the auto pause flag in a sector is true) [WHAT is that? Trigger bit?] 0Eh 2*N ItemID[N] ;item number (0..599 or 1000..2979) Entry 0 is for "start of movie" (usually 0002h=Track 2) Entry 1..N-1 is for numeric input ? <B> PsdSelectionListDescriptor (20+2*N bytes, or 36+6*N bytes):</B> 00h 1 Type (18h=SELECTION_LIST, or 1Ah=EXT_SELECTION_LIST) 01h 1 Flags (bit0=SelectionArea, bit1=CommandList, bit2-7=Reserved) 02h 1 nos <-- aka Number of Numeric-input selections ? 03h 1 bsn <-- ? 04h 2 ListID for this Descriptor (1..7FFFh) 06h 2 PsdOffset for Prev button 08h 2 PsdOffset for Next button 0Ah 2 PsdOffset for Return/back button 0Ch 2 PsdOffset for Default button (uh, what is that?) 0Eh 2 PsdOffset for Timeout 10h 1 totime <-- aka Timeout Time maybe? in WHAT units? 11h 1 loop <-- aka ? 12h 2 itemid <-- aka Item to be displayed during the selection? 14h 2*N PsdOffset[N] for Numeric-input ? Below only for SVCDs (with Type=18h), or for Extended VCDs (with Type=1Ah): (14h+2*N) 4 Area for Prev (x1,y1,x2,y2) ;\these extra entries exist for (18h+2*N) 4 Area for Next (x1,y1,x2,y2) ; SVCDs with Type=18h, and (1Ch+2*N) 4 Area for Return (x1,y1,x2,y2) ; Extended VCDs with Type=1Ah (20h+2*N) 4 Area for Default (x1,y1,x2,y2) ; (but do NOT exist for (24h+2*N) 4*N Area[N] (x1,y1,x2,y2) ;/older VCDs with Type=18h) <B> PsdEndListDescriptor (8 bytes)</B> 00h 1 Type (1Fh=EndList) 01h 1 Next_disc ;00h to stop PBC or NNh to switch to disc no NN (BCD!?) 02h 2 Item (0 or 1000..2979, should be still image, eg. Change Disc pic) 04h 4 Reserved (0) N/A - This descriptor doesn't have a ListID (unlike as other descriptors) <B> PsdCommandListDescriptor (5+2*N bytes)</B> 00h 1 Type (20h=CommandList) 01h 2 Command_count 03h 2 ListID for this Descriptor (1..7FFFh) 05h 2*N command[EMPTY_ARRAY_SIZE] ;uh, WHAT is a command? <B> PsdAlignmentPadding (after each list entry)</B> 00h 0..7 Padding to next 8-byte PsdOffset boundary (00h-filled)
Delay values in "1s/10s" units (for PlayList[0Ch,0Dh]):
1..60 --> wait "N" seconds 61..254 --> wait "(N-60)*10+60" seconds 255 --> wait infinite
Item numbers (0..599 or 1000..2979) can be:
0..1 - Play nothing 2..99 - Play Track 2..99 (TOC tracks, for AVSEQnn.DAT and AUDIOnn.DAT?) 100..599 - Play Entry 1..500 from table in ENTRIES file up to end of track 600..999 - Reserved 1000..2979 - Play SPI Segment Play Item 1..1980 (ITEMnnnn.DAT file) 2980..65535 - Reserved
PsdOffset values can be:
0..N Offset within PSD.VCD file, in 8-byte units FFFDh PSD_OFS_MULTI_DEF_NO_NUM ;\uh, what is that? FFFEh PSD_OFS_MULTI_DEF ;/ FFFFh PSD_OFS_DISABLED ;-no function assigned to the button
For whatever reason, some PsdOffsets are specified as ListID (lid), these
ListID values must be translated to actual PsdOffset via the ListID Offset
Table (aka LOT.VCD/LOT.SVD file).
VCD\LOT.VCD or SVCD\LOT.SVD (00:04:02..33) (64Kbyte, 32 sectors)
The ListID Offset Table (LOT) allows to translate ListIDs to PsdOffsets. The
file is always 64Kbyte in size (unused entries should be set to FFFFh).
The PSD.VCD file does also assign ListIDs to each descriptor (ie. instead of using the LOT.VCD file, one could also scan all descriptors in PSD.VCD when searching a specific ListID).
0000h 2 Reserved (0) 0002h 2*7FFFh PsdOffset[1..7FFFh] ;for ListID 1..7FFFh
Note: ListID#1 is used as entrypoint to PSD.VCD when inserting a new disc (or
when inserting another disc of the SAME movie, the entrypoint can be ListID#2,
depending on the Next Disc flag in INFO.VCD).
SEGMENT\ITEMnnnn.DAT (Pictures, Menu screens) (nnnn=0001..1980)
These files contain Pictures/Menu screens referenced from PSD.VCD. The files
seem to be stored in FORM2 sectors (not FORM1). Unknown if the files are
located on Track 1.
The content of the files seems to resemble short MPEG video clips (with only one picture frame, or eventually with a few frames for short animations, including audio in some cases). Still images are said to be allowed to use twice the resolution of MPEG videos.
EXT\PSD_X.VCD or EXT\PSD_X.SVD (extended version of PSD.VCD)
EXT\LOT_X.VCD or EXT\LOT_X.SVD (extended version of LOT.VCD)
The "extended" files are often identical to the normal PSD/LOT files. The
difference is that, if disc uses SelectionLists, then PSD should use the normal
descriptor (18h), and PSD_X should use the extended descriptor (1Ah), the
latter one seems to be intended to allow to highlight the current menu
selection (particulary useful when using +/- buttons instead of Numeric Keypad
input). Note: Nethertheless, Muppets from Space uses descriptor 18h in PSD_X.
Unknown if SVCDs do really have "extended" files, too (theoretically the VCD extension should be a default feature for SVCDs).
Playback Control Issues
Although PBC was intended as "nice extra feature", many VCDs are containing
faulty PSD files. In general, VCD players should either leave PBC unsupported
(or provide an option for disabling it).
Red Dragon from 2003 uses extended selection lists, but crops PSD_X.VCD to the same filesize as PSD.VCD.
Muppets from Space from 1999 assigns weird functions to Prev/Next buttons (Next wraps from Last Track to First Track, but Prev doesn't wrap from First to Last; default Non-PBC Prev/Next functions are more user friendly).
Sony's SCPH-5903 console refuses to display the HH:MM:SS playback time when using PBC (instead it does only display a "PBC" logo).
VCD ISO Search Files (SCANDATA, SEARCH, TRACKS, SPICONTX)
Below files can help searching I-frames, and provide some info about the
content of Tracks and Segments.
Essentially, searching I-frames is possible without these files - however, if present, then the files may be useful in two cases: For discs with variable bitrates (which isn't allowed on VCDs though), and, for CDROM firmwares that don't support "inaccurate" seeking (like telling it to start reading anywhere NEAR some MM:SS:FF value, so one could skip sectors till reaching an I-frame) (ie. if the firmware insists on a "accurate" seek position, then it's best to give it a known I-frame address).
Caution: Overlapping Sectors (!?!)
Reportedly the new SVCD files TRACKS.SVD and SEARCH.DAT are on these sectors:
TRACKS_SVD_SECTOR = (PSD_VCD_SECTOR+1) ;aka 2nd sector in PSD.SVD? SEARCH_DAT_SECTOR = (TRACKS_SVD_SECTOR+1) ;aka 3rd..Nth sector in PSD.SVD?
If that's correct, then the files would overlap with PSD.SVD (when PSD.SVD is
bigger than one sector), that would be weird, but possible (ie. the "PsdOffset"
in PSD.SVD would need to "skip" the region used by those two files).
EXT\SCANDATA.DAT (12+3*N bytes for VCD 2.0) (or 16+3*N+2*X+3*Y+3*Z for SVCD)
This file fulfills much the same purpose of the SEARCH.DAT file except that
this file is mandatory only if the System Profile Tag of the INFO.SVD file is
0x01 (HQ-VCD) and also that it contains sector addresses also for each video
Segment Play Items in addition to the regular MPEG tracks.
SCANDATA.DAT Format for VCD 2.0 (12+3*N bytes): 000h 8 ID "SCAN_VCD" 008h 1 Version (02h for VCD 2.0) 009h 1 Reserved (0) 00Ah 2 Number of scan points (in 0.5s units) (max FFFFh = ca. 9.1 hours) 00Ch 3*N Scan Point[0..N-1] ;MM:SS:FF of closest I-frame SCANDATA.DAT Format for SVCD (16+3*N+2*X+3*Y+3*Z bytes): 000h 8 ID "SCAN_VCD" 008h 1 Version (01h for SVCD) 009h 1 Reserved (0) 00Ah 2 scandata_count ;number of 3-byte entries in the table 00Ch 2 track_count ;number of MPEG tracks on disc 00Eh 2 spi_count ;number of consecutively recorded play item segments ; (as opposed to the number of segment play items). 010h 3*N msf_t cum_playtimes[N] ;cumulative playing time up to track N. ; (track time just wraps at 99:59:74) xxxh 2*X spi_indexes[X] ;Indexes into the following scandata table xxxh 2 mpegtrack_start_index ;Index into the following scandata table ; (where the MPEG track scan points start) xxxh 3*Y The scandata table... [Y] ;8bit Track Number and 16bit Index uint8_t track_num; /* Track number as in TOC uint16_t table_offset; /* Index into scandata table xxxh 3*Z msf_t scandata_table[Z] ;MM:SS:FF
SVCD\SEARCH.DAT (13+3*N bytes)
This file defines where the scan points are. It covers all mpeg tracks
together. A scan point at time T is the nearest I-picture in the MPEG stream to
the given time T. Scan points are given at every half-second for the entire
duration of the disc.
000h 8 ID "SEARCHSV" 008h 1 Version (01h) 009h 1 Reserved (0) 00Ah 2 Number of scan points 00Ch 1 Time_interval (in units of 0.5 seconds) (must be 01h) 00Dh 3*N Scan Point[0..N-1] ;MM:SS:FF of closest I-frame
Note: This SVCD file is about same as the old EXT\SCANDATA.DAT file on VCDs
(with one extra entry for Time Interval). Whilst, SVCDs are storing some
different stuff in EXT\SCANDATA.DAT (despite of the identical filename).
SVCD\TRACKS.SVD (11+4*N bytes) (or rarely:11+5*N bytes)
The TRACKS.SVD file contains a series of structures, one for each track, which
indicates the track's playing time (in sectors, not actually real time) and
SVCD\TRACKS.SVD is a mandatory file which describes the numbers and types of MPEG tracks on the disc.
SVCD\TRACKS.SVD Format for SVCD (11+4*N bytes): 000h 8 ID "TRACKSVD" 008h 1 Version (01h) 009h 1 Reserved (0) 00Ah 1 Number of MPEG tracks (N) 00Bh 3*N Track playing_time[N] (MM:SS:FF, in BCD)(in sectors, not real time) 0xxh 1*N TrackContent[N] ;bit0-1=Audio,bit2-4=Video,bit5=Reserved,bit6-7=OGT SVCD\TRACKS.SVD Format for VCD30 (11+5*N bytes) (some sort of SVCD-prototype): 000h 8 ID "TRACKSVD" 008h 1 Version (01h) 009h 1 Reserved (0) 00Ah 1 Number of MPEG tracks (N) 00Bh 5*N Cum_Playing_time and Content (MM:SS:FF in BCD, and OGT, Audio)
SVCD\SPICONTX.SVD (1000h bytes, two sectors)
Unknown if/when/where/why this file exists, possibly only on VCD30?
Note: The same info can be stored in INFO.SVD at offsets [038h..7F3h].
0000h 8 ID "SPICONSV" 0008h 1 Version (01h) 0009h 1 Reserved (0) 000Ah 2*1980 Segment Content[1..1980] (1st byte=OGT, 2nd byte=Audio) 0F82h 126 Reserved (0)
Content Flags for Segments and Tracks
For SVCD\INFO.SVD and SVCD\TRACKS.SVD (on SVCD) these are encoded in 1 byte:
bit0-1 Audio characteristics: 0 = No MPEG audio stream 1 = One MPEG1 or MPEG2 audio stream without extension 2 = Two MPEG1 or MPEG2 audio streams without extension 3 = One MPEG2 multi-channel audio stream with extension bit2-4 Video characteristics: In TRACKS.SVD this must be 0,3,7 (no still pictures) 0 = No MPEG video data 1 = NTSC still picture 2 = NTSC Reserved (NTSC still pic hires?) 3 = NTSC motion picture 4 = Reserved 5 = PAL still picture 6 = PAL Reserved (PAL still pic hires?) 7 = PAL motion picture bit5 Indicates segment is continuation of an item In TRACKS.SVD this must be 0 (reserved) 0 = First or only segment of item 1 = Second or later segment of item bit6-7 Overlay Graphics/Text (OGT): 0 = No OGT substream 1 = Sub-stream 0 available 2 = Sub-stream 0 & 1 available 3 = All OGT sub-substreams available
For SPICONTX.SVD and SVCD\TRACKS.SVD (on VCD30) these are encoded in 2 bytes:
1st byte = Audio characteristics ;\probably same values as 2nd byte = Overlay Graphics/Text (OGT) ;/in above bitfields?
VCD ISO Misc files (CAPTnn, AUDIOnn, KARINFO, PICTURES, CDI)
EXT\CAPTnn.DAT (Closed Caption data, aka subtitles) (SVCD only?)
VCDs with subtitles are usually/always having the subtitles encoded directly in
the picture frames (ie. in the MPEG macroblocks, rather than using the Closed
These CAPTnn.DAT files are intended for Closed Captions (eg. subtitles in different languages and/or for deaf people).
Alternately, the "user_data_cc" flag in INFO.VCD?/INFO.SVD can indicate to store Closed Captions in MPEG User Data (with START_CODE=000001B2h=User Data) instead of in EXT\CAPTnn.DAT. Either way, the format of those Closed Captions is unknown.
Moreover, Content can be flagged to have Overlay Graphics/Text (OGT), whatever that is: it might be related to Closed Captions.
Note: Reportedly CAPTnn.DAT can exist on VCDs and SVCDs (although the same person reported that VCDs do not support subtitles, so that info sounds wrong).
CDDA\AUDIOnn.DAT (pointers to uncompressed CD Audio Tracks)
These filesystem entries contain pointers to uncompressed audio tracks tracks
(that is, outside of the ISO area on Track 1).
Most VCDs don't have audio tracks (though some VCDs do contain empty CDDA folders).
Maybe the feature is occassionally used the other way around: Music discs containing VCD clips as bonus feature?
The KARAOKE folder exists on many VCDs (about 50%), but it's usually/always
empty on all discs.
Reportedly the folder can contain "KARINFO.xxx" files, but the purpose/format of that files is unknown.
Reportedly there are Midi VCDs (MVCDs) for karaoke, maybe those discs have "KARINFO.xxx" files(?)
Unknown purpose. The PICTURES folder has been spotted on one VCD (Wallace and
Gromit), but the folder was just empty.
CDI\*.* (some kind of GUI/driver for Philips CDI Players)
The CDI folder is some relict for Philips CDI Players, it isn't used by normal
VCD players, however, the CDI folder & files are included on most or all
The path/name for the CDI executable is stored at offset 23Eh in the ISO Primary Volume Descriptor (usually "CDI/CDI_APPL.VCD;1" or "CDI/CDI_VCD.APP;1") (or accidentally "CDI_CDI_VCD.APP;1" on homebrew Nero discs).
The files in the CDI folder are usually just some standard files (without any customizations), however, there are some different revisions of these files:
<B> Revision A (spotted on two discs from 1997 and 1999):</B> CDI_APPL.VCD 80702 bytes, 04-Mar-1996, CRC32=AE8FC5D0h ;executable VCD_BACK.DYV 92572 bytes, 18-Jul-1995, CRC32=00693E5Eh ;whatever? VCD_BTN.C8 93719 bytes, 18-Jul-1995, CRC32=FF0A636Ah ;whatever? <B> Revision B (spotted on a disc from 2003):</B> CDI_VCD.APP 20648 bytes, 00-Nul-0000 CRC32=DC885F70h ;executable CDI_FONT.FNT 145388 bytes, 00-Nul-0000 CRC32=FB4D63F4h ;font? CDI_ALL.RTF ? bytes, CRC32=? ;realtimefile? CDI_BUM.RTF ? bytes, CRC32=? ;realtimefile? <B> Revision C (spotted on a disc from 2006, and homebrews from 2001 and 2017):</B> CDI_VCD.APP 102400 bytes, 00-Nul-0000 CRC32=E91E128Dh ;executable CDI_VCD.CFG 193 bytes, 00-Nul-0000 CRC32=D1C6F7ADh ;config/ascii CDI_TEXT.FNT 13616 bytes, 00-Nul-0000 CRC32=BDC55E86h ;font? CDI_IMAG.RTF 1510028 bytes, 00-Nul-0000 CRC32=(RIFF) ;realtimefile?
CDI_VCD.CFG is some ASCII text file (with uncommon 0Dh,0Dh,0Ah line breaks),
the file could be customized to change things like GUI colors, but most or all
discs seem to contain the same file with CRC32=D1C6F7ADh. Note: The CFG file is
missing on the homebrew DemoVCD.
CDI_IMAG.RTF is seen as 1510028 byte file under windows (that is, with a windows RIFF header, and with data area containing the whole 930h bytes from each sector; this includes the MM:SS:FF values from the sector header, so the RTF file may look slightly different depending on which sectors it has been stored on, although the files are usually exactly same apart from those MM:SS:FF values). Note: The RTF file is cropped to 1324220 bytes (instead of 1510028) on the homebrew DemoVCD (apart from that, the file is same as normal).
CDI_ALL.RTF and CDI_BUM.RTF cannot be read/copied under Windows 7 (which is weirdly reporting them to use an "invalid MS-DOS function"; some people also reported having CDI_IMAG.RTF files with similar problems). The reason is unknown, maybe windows doesn't fully support the CD filesystem, or some VCDs are violating the filesystem specs, or whatever... maybe windows is mis-identifying certain RTF files as Rich Text Format files and tries to prevent virus-infections by throwing a faked "MS-DOS" error message.
VCD MPEG-1 Multiplex Stream
Multiplex Stream & Sector Boundaries
The Multiplex stream is some higher level stream, intended to help to
distinguish between Audio- and Video-streams (which are enclosed in the
Multiplex stream). MPEG's are somewhat organized in "sectors", with sector size
varying for normal .mpg files and VCDs:
VCD discs --> Sector Size = 914h bytes (the discs MODE2/FORM2 sector size) .mpg files --> Sector Size = 800h bytes (regardless of physical sector size)
Sectors are always beginning with a Multiplex Packet (and Multiplex Packets are
never crossing sector boundaries). If the amount of video data exceeds the
sector size, then it's split into several Multiplex packets, whereas, that may
happen anywhere in the video stream (ie. there can be Multiplex Headers
occurring even in the middle of Video packet).
MPEG-1 Multiplex Pack (sector header) (12 bytes)
The Pack Header is found at the begin of the stream (on VCDs, it's also found
at the begin of each sector). The SCR values might help on identifying the
current playback position, and, with the bitrate value, this could be also used
to compute the distance to another position (though there are other ways to
determine the position/bitrate, so the Pack is kinda useless).
32bit PACK_START_CODE (000001BAh) ;-4byte 2bit Fixed (00b for MPEG-1) (would be 01b for MPEG-2) ;\ 2bit Fixed (10b) ; 3bit System Clock Reference, bit32-30 ;\ ; 1bit Marker (1) ; System Clock Reference (SCR) ; 15bit System Clock Reference, bit29-15 ; (intended Time, ; 5byte 1bit Marker (1) ; in 90kHz clock cycles) ; 15bit System Clock Reference, bit14-0 ;/ ; 1bit Marker (1) ;/ 1bit Marker (1) ;\ 22bit Multiplex Rate (total bitrate of the stream, in 400bit/s units) ; 3byte 1bit Marker (1) ;/
MPEG-1 Multiplex System Header (12+N*3 bytes)(optionally)(at start of stream)
The System Header is usally found after the first Pack at the begin of the
32bit SYSTEM_HEADER_START_CODE (000001BBh) ;\6byte 16bit Header Length minus 6 (in bytes) (0006h+N*3) ;/ 1bit Marker (1) ;\ 22bit Rate bound (max multiplex rate of all packs in the stream, ; 3byte 1bit Marker (1) in 400bit/s units) ;/ 6bit Audio Bound (max number of audio streams in this ISO stream) ;\ 1bit Fixed Flag (1=Fixed bitrate) ; 1byte 1bit CSPS Flag (1=Constrained) ;/ 1bit System Audio Lock Flag XXX ;\ 1bit System Video Lock Flag XXX ; 1byte 1bit Marker (1) ; 5bit Video Bound (max number of video streams in this ISO stream) ;/ 8bit Reserved (FFh) ;-1byte
Followed by N*3 bytes for the streams (each with first bit=set):
8bit Stream ID (C0h..DFh=Audio, E0h..EFh=Video) ;\ 2bit Fixed (11b) ; 3byte 1bit STD buffer scale (0=Mul128/audio, 1=Mul1024/video) ; 13bit STD buffer size (largest required buffer over all packets) ;/
Terminated by a value with first bit=cleared (eg. next 000001xxh value).
MPEG-1 Multiplex Video/Audio/Special Packets (7..24 bytes, plus data)
These packets are encapsulating the lower-level Video/Audio streams.
32bit START (000001xxh BDh-BFh=Special, C0h-DFh=Audio, E0h-EFh=Video);\6byte 16bit Packet Length minus 6 (in bytes) (1..18, plus data) ;/
If (and while) next two bits are 11b (0..16 padding bytes):
(2bit) Fixed (11b, indicates presence of stuffing) ;\optional 0..16byte (6bit) Fixed (111111b) ;/
If next two bits are 01b (buffer size info):
(2bit) Fixed (01b, indicates presence of buffer size) ;\ (1bit) STD Buffer Scale (0=Mul128/audio, 1=Mul1024/video) ; optional 2byte (13bit) STD Buffer Size (for decoding, in above scale units) ;/
2bit Fixed (00b, indicates no further stuffing/buffer info);\ 1bit PTS Flag (Presentation Time Stamp) ; 0.5 bytes 1bit DTS Flag (Decoding Time Stamp) ;/
If PTS Flag set:
(3bit) Presentation Time Stamp, bit32-30 ;\ (1bit) Marker (1) ; optional 4.5 bytes (15bit) Presentation Time Stamp, bit29-15 ; (time when to output the (1bit) Marker (1) ; the packet to audio/video (15bit) Presentation Time Stamp, bit14-0 ; hardware, in 90kHz cycles) (1bit) Marker (1) ;/
If DTS Flag set (in this case PTS Flag must be also set):
(4bit) Fixed (0001b) ;\ (3bit) Decoding Time Stamp, bit32-30 ; optional 5 bytes (1bit) Marker (1) ; (recommended time when (15bit) Decoding Time Stamp, bit29-15 ; to decode the block, (1bit) Marker (1) ; in 90kHz cycles) (15bit) Decoding Time Stamp, bit14-0 ; (1bit) Marker (1) ;/
If PTS and DTS Flags are both zero:
(4bit) Fixed (1111b) ;-optional 0.5 bytes
... packet data bytes ;-data...(not crossing sector)
Note: The first Multiplex Video Packet would usually start with a Sequence
Header Code (000001B3h), and the first Multiplex Audio Packet should always
start with an Audio Sync Word (FFFh).
However, the size of the Multiplex packets does usually differ from the size of the packets in the audio/video stream, so new Multiplex Packets may occur anywhere in the middle of those streams (eg. in the middle of a video slice, the next Multiplex Video packet would then begin with the remaining slice bytes, rather than with a 000001xxh code; it's also possible that a Multiplex Audio packet gets inserted in the middle of the video slice).
The best (or easiest) way to get continous data for the lower level streams might be to memcopy the data from Multiplex packets to separate Audio & Video buffers.
MPEG-1 Multiplex End Code (4 bytes)
32bit END_CODE (000001B9h) ;-4byte
This should occur at the end of the video. On a VCD it does also occur at the
end of each video track.
VCD MPEG-1 Video Stream
The Video stream is part of the Multiplex stream, meaning that the Video
packets preceeded (and interrupted) by Multiplex headers. Ie. before processing
the Video packets, one must first extract the video snippets from the Multiplex
stream (see previous chapter).
MPEG-1 Video Sequence Header (12, 76, or 140 bytes, ie. 12+N*64)
32bit SEQUENCE_HEADER_CODE (000001B3h) ;-4byte 12bit Width in pixels (1..4095) ;\3byte 12bit Height in pixels (1..2800, for max AFh slices) ;/ 4bit Aspect Ratio (01h..0Eh, see below) ;\1byte 4bit Framerate (01h..08h, see below) ;/ 18bit Bitrate (in 400bit/s units, 3FFFFh=variable rate) ;\ 1bit Marker (1) ; 3byte 10bit VBV (required decoding memory size, in "16 kB" units) ; +6bit 1bit Constrained Parameter Flag ;/ 1bit Load Intra Q Matrix (0=No, use Standard Matrix, 1=Yes, Custom)
Next 64byte only when above bit was set:
(64byte) Intra Quantizer Matrix (64 x 8bit, unsigned) (in zigzag order) 1bit Load Non-Intra Q Matrix (0=No, use Standard Matrix, 1=Yes, Custom)
Next 64byte only when above bit was set:
(64byte) Non-Intra Quantizer Matrix (64 x 8bit, unsigned) (in zigzag order)
Aspect Ratio values:
0 - ;forbidden 1 1.0 ;square pixels 2 0.6735 ;0.6735 3 0.7031 ;16:9, 625 line, PAL 4 0.7615 ;0.7615 5 0.8055 ;0.8055 6 0.8437 ;16:9, 525 line, NTSC 7 0.8935 ;0.8935 8 0.9157 ;4:3, 625 line, PAL, CCIR601 9 0.9815 ;0.9815 10 1.0255 ;1.0255 11 1.0695 ;1.0695 12 1.0950 ;4:3, 525 line, NTSC, CCIR601 13 1.1575 ;1.1575 14 1.2015 ;1.2015 15 - ;reserved
Frame Rate values:
0 - ;forbidden 1 23.976 (24000/1001) ;NTSC encapsulated film rate 2 24.0 ;Standard international cinema film rate 3 25.0 ;PAL video frame rate (625/50) 4 29.97 (30000/1001) ;NTSC video frame rate 5 30.0 ;NTSC video frame rate drop-frame (525/60) 6 50.0 ;PAL double frame rate/progressive 7 59.94 (60000/1001) ;NTSC double frame rate 8 60.0 ;NTSC double frame rate drop-frame 9-15 - ;reserved
MPEG-1 Video Group of Pictures (GOP) (8 bytes) XXX...
32bit GROUP_START_CODE (000001B8h) 1bit Drop Frame (1=drop this frame; for reducing 30 fps to 29.97 fps) 5bit Time Code Hours (0..23) 6bit Time Code Minutes (0..59) 1bit Marker (1) 6bit Time Code Seconds (0..59) 6bit Time Code Picture (0..59) 1bit Closed GOP 1bit Broken Link
MPEG-1 Video Picture Header XXX...
32bit PICTURE_START_CODE (00000100h) ;\ 10bit Temporal Reference (display order, 0..3FFh) ; 61bit 3bit Coding Type (0=Invalid, 1=I, 2=P, 3=B, 4=D, 5-7=Reserved); 16bit VBV Delay (in 90kHz cycles, FFFFh=variable bitrate) ;/
If Coding Type is 2 or 3 (P-Frame or B-Frame):
(1bit) full fel forward vector (0=half pix, 1=full pix) ;\optional 4bit (3bit) forward f code (0=invalid, 1..7=0..6bits) ;/
If Coding Type is 3 (B-Frame):
(1bit) full backward vector ;\optional 4bit (3bit) backward f code ;/
If (and while) next bit is set:
(1bit) Fixed (1, indicates presence of Extra Info) ;\opt. N*9bit (8bit) Extra Information ;/
End of Extra:
1bit Fixed (0, indicates no further Extra Info) ;-1bit 0-7bit Padding to byte boundary (0) ;-0..7bit
Coding Type values:
0 Forbidden 1 I - Intra Coded (full image) 2 P - Predictive Coded (based on prev I or P frame) 3 B - Bidirectionally Predictive Coded (based on prev+next I or P frame) 4 D - DC Intra Coded (don't care, lowres thumbnail) 5 Reserved 6 Reserved 7 Reserved
DISPLAY ORDER: I B B B P B B B P B B B P B B B I B B B P B B B P B B B P B B B ... | |_______|_______| | |_______|_______| | | | | I-Frame P-frames I-Frame P-frames
The B-fames require to know the next P- (or I-) frame in advance, for that
reason, the frames are stored as "PBBB" (although being played as "BBBP"):
STORAGE ORDER: I P B B B P B B B P B B B I B B B P B B B P B B B P B B B ... | |_______|_______| | |_______|_______| | | | | I-Frame P-frames I-Frame P-frames
MPEG-1 Video Slice
Slices are containing the actual 16x16 pixel Macro Blocks. Usually a Slice
contains one horizontal line - although, theoretically, it could be longer or
shorter, ie. a slice could wrap to next line, or a line could be split into
several slices (with the leading "MBA Increment" value greater than 1 to define
the horizontal start offset).
32bit PACK_START_CODE (000001xxh; xx=01h..AFh; vertical index) ;-4byte 5bit Quantizer Scale (1..31) (may be later changed by blocks) ;-5bit
If (and while) next bit is set:
(1bit) Fixed (1, indicates presence of Extra Info) ;\opt. N*9bit (8bit) Extra Information ;/
End of Extra:
1bit Fixed (0, indicates no further Extra Info) ;-1bit
If (and while) next 23bit are nonzero (ie. until next 000001xxh):
... Macroblock (within horizontal line) ;...
0-7bit Padding to byte boundary (0) ;-0..7bit
MPEG-1 Video Group/Sequence Extension Data (reserved)
MPEG-1 Video User Data (optional)
32bit START_CODE (000001B2h=User Data, 000001B5h=Extension Data) ;-4byte ... data (end is signaled by presence of next 000001xxh code) ;-data
User Data can contain Closed Captions (see flag in VCD\INFO.VCD or
User Data contains 11h-byte "Created with Nero" in some homebrew discs.
MPEG-1 Video Sequence End Code (4 bytes)
32bit SEQUENCE_END_CODE (000001B7h) ;-4byte
MPEG-1 Video 4:2:0 Macroblock
N*11bit Macroblock_address_increase escape/stuffing codes (if any) 1..11bit Macroblock_address_increase 1-6bit Macroblock_type 5bit Quantizer_scale ... Motion_vector 3-9bit Coded_block_pattern ... Block(i)
Addr Incr Type Motion Vector QScale CBP Block b0 (Y1) Block b1 (Y2) Block b2 (Y3) Block b3 (Y4) Block b4 (Cb) Block b5 (Cr)
VCD MP2 Audio Stream
VCD video discs and .mpg movie files are having the MP2 Audio Stream enclosed
in the Multiplex stream (whilst .mp2 audio files may contain raw MP2 data
without Multiplex stream).
Each MP2 frame is starting with a FFFh syncword (which is always located on a
byte boundary). Unfortunately, the value FFFh can also occur anywhere in the
audio data (eg. a 16bit sample with value 3FFCh).
So, when starting mid-stream, one will need some guessing when searching a valid syncword. The best method is to compute the frame size (based on the supposed frame header), and then to check if supposed frame begins AND ends with a sync word. Moreover, one could check for invalid sample rate values in the frame header, or invalid "groupings" in the frame's data part.
VCDs are conventionally having three audio frames encoded in one CDROM sector, so the first syncword can be simply found right after the multiplex packet header (though that might differ in some cases: VCD2.0 allows different audio bitrates, and a CDROM sector could be theoretically shared for Audio and Video data).
Overall MP2 Frame Format
Header (32bit) Optional CRC (16bit) (or 0bit if none) Allocation Information Scale Factor Selector Information Scale Factors Data
12bit Syncword (FFFh) ;\ 1bit Revision (0=MPEG-2, 1=MPEG-1) ; 2 bytes 2bit Layer (2=Audio LayerII) ; (3=LayerI, 1=LayerIII, r3=reserved) ; 1bit Protection_bit (1=no crc) ;/ 4bit Bitrate_index (1..14) ;\ (0=free format, 15=reserved) ; 2bit Sampling_frequency ; 1 byte 1bit Padding_bit ; 1bit Private_bit ;/ 2bit Mode ;\ 2bit Mode_extension (aka bound) ; 1bit Copyright ; 1 byte 1bit Original/home ; 2bit Emphasis ;/
MP2 Checksum (optional)
Scale Factor Selector Information
Inflate/Deflate is a common (de-)compression algorithm. In the PSX world, it's
used by the .CDZ cdrom-image format.
Inflate - Core Functions
tinf_init() ;init constants (needed to be done only once) tinf_align_src_to_byte_boundary() repeat bfinal=tinf_getbit() ;read final block flag (1 bit) btype=tinf_read_bits(2) ;read block type (2 bits) if btype=0 then tinf_inflate_uncompressed_block() if btype=1 then tinf_build_fixed_trees(), tinf_inflate_compressed_block() if btype=2 then tinf_decode_dynamic_trees(), tinf_inflate_compressed_block() if btype=3 then ERROR ;reserved until bfinal=1 tinf_align_src_to_byte_boundary() ret
tinf_align_src_to_byte_boundary() len=LittleEndian16bit[src+0] ;get len if LittleEndian16bit[src+2]<>(len XOR FFFFh) then ERROR ;verify inverse len src=src+4 ;skip len values for i=0 to len-1, [dst]=[src], dst=dst+1, src=src+1, next i ;copy block ret
repeat sym1=tinf_decode_symbol(tinf_len_tree) if sym1<256 [dst]=sym1, dst=dst+1 if sym1>256 len = tinf_read_bits(length_bits[sym1-257])+length_base[sym1-257] sym2 = tinf_decode_symbol(tinf_dist_tree) dist = tinf_read_bits(dist_bits[sym2])+dist_base[sym2] for i=0 to len-1, [dst]=[dst-dist], dst=dst+1, next i until sym1=256 ret
sum=0, cur=0, len=0 repeat ;get more bits while code value is above sum cur=cur*2 + tinf_getbit() len=len+1 sum=sum+tree.table[len] cur=cur-tree.table[len] until cur<0 return tree.trans[sum+cur]
tinf_read_bits(num) ;get N bits from source stream
val=0 for i=0 to num-1, val=val+(tinf_getbit() shl i), next i return val
tinf_getbit() ;get one bit from source stream
bit=tag AND 01h, tag=tag/2 if tag=00h then tag=[src], src=src+1, bit=tag AND 01h, tag=tag/2+80h return bit
tag=01h ;empty/end-bit (discard any bits, align src to byte-boundary) ret
Inflate - Initialization & Tree Creation
tinf_build_bits_base(length_bits, length_base, 4, 3) length_bits=0, length_base=258 tinf_build_bits_base(dist_bits, dist_base, 2, 1) ret
for i=0 to 29 bits[i]=min(0,i-delta)/delta base[i]=base_val base_val=base_val+(1 shl bits[i]) ret
for i=0 to 6, tinf_len_tree.table[i]=0, next i ;[0..6]=0 ;len tree... tinf_len_tree.table[7,8,9]=24,152,112 ;[7..9]=24,152,112 for i=0 to 23, tinf_len_tree.trans[i+0] =i+256, next i ;[0..23] =256..279 for i=0 to 143, tinf_len_tree.trans[i+24] =i+0, next i ;[24..167] =0..143 for i=0 to 7, tinf_len_tree.trans[i+168]=i+280, next i ;[168..175]=280..287 for i=0 to 111, tinf_len_tree.trans[i+176]=i+144, next i ;[176..287]=144..255 for i=0 to 4, tinf_dist_tree.table[i]=0, next i ;[0..4]=0,0,0,0,0 ;\dist tinf_dist_tree.table=32 ;=32 ; tree for i=0 to 31, tinf_dist_tree.trans[i]=i, next i ;[0..31]=0..31 ;/ ret
hlit = tinf_read_bits(5)+257 ;get 5 bits HLIT (257-286) hdist = tinf_read_bits(5)+1 ;get 5 bits HDIST (1-32) hclen = tinf_read_bits(4)+4 ;get 4 bits HCLEN (4-19) for i=0 to 18, lengths[i]=0, next i for i=0 to hclen-1 ;read lengths for code length alphabet lengths[clcidx[i]]=tinf_read_bits(3) ;get 3 bits code length (0-7) tinf_build_tree(code_tree, lengths, 19) ;build code length tree for num=0 to hlit+hdist-1 ;decode code lengths for dynamic trees sym = tinf_decode_symbol(code_tree) len=1, val=sym ;default (for sym=0..15) if sym=16 then len=tinf_read_bits(2)+3, val=lengths[num-1] ;3..6 previous if sym=17 then len=tinf_read_bits(3)+3, val=0 ;3..10 zeroes if sym=18 then len=tinf_read_bits(7)+11, val=0 ;11..138 zeroes for i=1 to len, lengths[num]=val, num=num+1, next i tinf_build_tree(tinf_len_tree, 0, hlit) ;\build trees tinf_build_tree(tinf_dist_tree, 0+hlit, hdist) ;/ ret
tinf_build_tree(tree, first, num)
for i=0 to 15, tree.table[i]=0, next i ;clear code length count table ;scan symbol lengths, and sum code length counts... for i=0 to num-1, x=lengths[i+first], tree.table[x]=tree.table[x]+1, next i tree.table=0 sum=0 ;compute offset table for distribution sort for i=0 to 15, offs[i]=sum, sum=sum+tree.table[i], next i for i=0 to num-1 ;create code to symbol xlat table (symbols sorted by code) x=lengths[i+first], if x<>0 then tree.trans[offs[x]]=i, offs[x]=offs[x]+1 next i ret
clcidx[0..18] = 16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15 ;constants
typedef struct TINF_TREE: unsigned short table ;table of code length counts unsigned short trans ;code to symbol translation table
TINF_TREE tinf_len_tree ;length/symbol tree TINF_TREE tinf_dist_tree ;distance tree TINF_TREE code_tree ;temporary tree (for generating the dynamic trees) unsigned char lengths[288+32] ;temporary 288+32 x 8bit ;\for dynamic tree unsigned short offs ;temporary 16 x 16bit ;/creation
unsigned char length_bits unsigned short length_base unsigned char dist_bits unsigned short dist_base
Inflate - Headers and Checksums
tinf_gzip_uncompress(void *dest, *destLen, *source, sourceLen)
src_start=src, dst_start=dst ;memorize start addresses if (src<>1fh or src<>8Bh) then ERROR ;check id bytes if (src<>08h) then ERROR ;check method is deflate flg=src ;get flag byte if (flg AND 0E0h) then ERROR ;verify reserved bits src=src+10 ;skip base header if (flg AND 04h) then src=src+2+LittleEndian16bit[src] ;skip extra data if (flg AND 08h) then repeat, src=src+1, until [src-1]=00h ;skip file name if (flg AND 10h) then repeat, src=src+1, until [src-1]=00h ;skip file comment hcrc=(tinf_crc32(src_start, src-src_start) & 0000ffffh)) ;calc header crc if (flg AND 02h) then x=LittleEndian16bit[src], src=src+2 ;get header crc if (flg AND 02h) then if x<>hcrc then ERROR ;verify header tinf_uncompress(dst, destLen, src, src_start+sourceLen-src-8) ;----> inflate crc32=LittleEndian32bit[src], src=src+4 ;get crc32 of decompressed data dlen=LittleEndian32bit[src], src=src+4 ;get decompressed length if (dlen<>destLen) then ERROR ;verify dest len if (crc32<>tinf_crc32(dst_start,dlen)) then ERROR ;verify crc32 ret
tinf_zlib_uncompress(dst, destLen, src, sourceLen)
src_start=src, dst_start=dst ;memorize start addresses hdr=BigEndian16bit[src], src=src+2 ;get header if (hdr MOD 31)<>0 then ERROR ;check header checksum (modulo) if (hdr AND 20h)>0 then ERROR ;check there is no preset dictionary if (hdr AND 0F00h)<>0800h then ERROR ;check method is deflate if (had AND 0F000h)>7000h then ERROR ;check window size is valid tinf_uncompress(dst, destLen, src, sourceLen-6) ;------> inflate chk=BigEndian32bit[src], src=src+4 ;get data checksum if src-src_start<>sourceLen then ERROR ;verify src len if dst-dst_start<>destLen then ERROR ;verify dst len if a32<>tinf_adler32(dst_start,destLen)) then ERROR ;verify data checksum ret
s1=1, s2=0 while (length>0) k=max(length,5552) for i=0 to k-1, s1=s1+[src], s2=s2+s1, src=src+1, next i s1=s1 mod 65521, s2=s2 mod 65521, length=length-k return (s2*10000h+s1)