Alcohol 120% MDS/MDF disc image format
Alcohol 120% (Alcohol Soft, early 2000s) stores a disc as two files:
.mdf("media data file"): the sector data, optionally with subchannel data appended to each sector;.mds("media descriptor"): a small binary file describing the disc. It holds the medium type, sessions, the full TOC, track layout and file offsets, and for DVDs the physical format structures and BCA. It can also carry a DPM table measured from the original disc.
The format was never published. Everything here comes from reverse engineering:
- Our own sample analysis (Quake, a Mixed Mode CD; Deus Ex, a data CD; Empire Earth III, a dual-layer DVD; and a single-layer DVD). Facts that come only from these samples are marked (samples).
- libmirage, the CDEmu image library:
lib/cdemu/libmirage/images/image-mds/. - Aaru, which reads and writes the format:
lib/Aaru/Aaru.Images/Alcohol120/. - psx-spx / no$psx documentation by Martin Korth: https://problemkaputt.de/psxspx-cdrom-disk-images-mds-mdf-alcohol-120.htm.
Where these sources disagree, both views are given.
The same MEDIA DESCRIPTOR container, at version 1.x, is also used by GameJack (.xmd). DAEMON Tools' later MDS v2 / MDX format (version 2.x) is different: its descriptor is compressed and encrypted (see the appendix).
Conventions. All multi-byte integers are little-endian. Track, point, session and index numbers and MSF values are binary, not BCD. Offsets are in bytes from the start of the .mds file unless stated otherwise. Fields shown as "zero" were zero in all samples and in files written by Aaru. Their meaning is unknown.
File.MDF
The MDF holds the sector data: each sector is stored at 2048 to 2352 bytes, optionally followed by 96 bytes of subchannel data. The sector size is a per-track field in the MDS (data block 10h). It already includes the 96 subchannel bytes when subchannel is present.
Sector sizes seen:
| Size | Meaning |
|---|---|
800h (2048) |
DVD sectors (user data only), or cooked CD data |
930h (2352) |
raw CD sectors (audio or data), no subchannel |
990h (2448) |
raw CD sectors + 96 bytes subchannel |
920h, 914h, … |
cooked Mode 2 variants (not observed; from psx-spx) |
What is stored #
DVD: sectors start at LBA 0 and run to the end of the data area. On a dual-layer disc, layer 1 follows layer 0 directly.
CD: the image starts at LBA 0 (MSF
00:02:00). The first 150 sectors (LBA −150..−1, track 1's pregap) are not stored.CD pregaps of later tracks (samples): the 150-sector pregap (index 0) of the first audio track after a data track was also not stored. In a Mixed Mode disc every track after track 1 therefore sits 150 sectors earlier in the MDF than its PLBA suggests:
Track 1 start offset = 0 Track N (N>1) start offset = (PLBA − 150) × sector size (Quake)The total MDF size on a CD equalled the sum of all tracks' index-1 lengths × sector size. For Quake that is 319,611 sectors × 2448 = 782,407,728 bytes, which matched the file size exactly.
How the readers handle pregaps. The libraries disagree, so a converter should use each track's explicit start offset (data block 28h) and index-1 length rather than assume a layout:
- libmirage assumes pregaps are never stored. It inserts an empty ("NULL") fragment of
pregapsectors before each track and reads index 1 fromstart_offset. This matches the samples. - Aaru assumes the pregap sectors are stored immediately before
start_offset: it reads a pregap sector atstart_offset − pregap × sector_size. Its writer lays files out that way, except for track 1, whose pregap it never writes. On an image like Quake this would read the end of track 1 as track 2's pregap. Aaru also has a special case for "faulty UltraISO" MDS files, which set track 1's pregap wrongly.
Split MDF files. A track's data can be spread over several files (data block 30h, "number of filenames", > 1). libmirage treats this as consecutive fragments, assumes splits fall on sector boundaries, and works out each fragment's length from its file size. The start offset applies only to the first file. (not observed)
Subchannel data #
When present (data block 01h = 8, sector size 990h), the 96 subchannel bytes follow each 2352-byte sector in interleaved ("raw P–W") order: each byte holds one bit from each of the eight subchannels.
Bit7..0 = Subchannel P..W (in that order, e.g. Bit6 = Subchannel Q)
1st..8th bit of each subchannel = Bit7..Bit0 of bytes 0..7 (MSB first)
9th..16th bit = bytes 8..15
...
This is the opposite of CloneCD's .sub, which is linear (12 bytes of P, then 12 of Q, …). Conversion code is on the Subchannels page.
File.MDS: layout
An MDS file consists of these parts, normally in this order and without gaps:
Header (58h bytes documented; first structure at 58h or 60h)
Disc structures (DVD only; one 1004h-byte slot per layer)
BCA data (DVD only, optional; position given in the header)
Session block(s) (24 bytes each)
Data blocks (80 bytes each; per session: lead-in entries, then tracks)
Index blocks (CD only; 8 bytes per data block)
Filename block(s) (16 bytes each; usually one, shared by all tracks)
Filename string(s) (usually one: "*.mdf")
Disc metadata blocks (optional: DPM, read-error list)
Every part is located through an offset in an earlier part, so readers should follow offsets and not assume positions.
Typical offsets (samples):
| Item | CD | DVD, single layer | DVD, dual layer |
|---|---|---|---|
| Disc structures | – | 60h |
60h |
| Session block | 58h or 60h |
1064h |
2068h |
| First data block | 70h or 78h |
107Ch |
2080h |
(psx-spx gives 58h/70h for CDs; our samples had 60h/78h. Both are valid, since the header gives the session block's offset.)
Header #
| Offset | Size | Field |
|---|---|---|
00h |
16 | File ID "MEDIA DESCRIPTOR" |
10h |
1 | Format major version: 1 for Alcohol (libmirage and Aaru reject > 1; 2 = DAEMON Tools MDS v2/MDX) |
11h |
1 | Format minor version (5 in samples and in Aaru's writer) |
12h |
2 | Medium type: 00h CD-ROM, 01h CD-R, 02h CD-RW, 10h DVD-ROM, 12h DVD-R |
14h |
2 | Number of sessions |
16h |
2 | Unknown, always 2. Aaru: "Alcohol sets this always, Daemon Tools expects this" |
18h |
2 | Unknown (zero) |
1Ah |
2 | DVD: length of BCA data in bytes, otherwise zero |
1Ch |
8 | Zero |
24h |
4 | DVD: offset to BCA data, otherwise zero |
28h |
24 | Zero ("probably more offsets": libmirage) |
40h |
4 | DVD: offset to disc structures (60h), otherwise zero |
44h |
12 | Zero |
50h |
4 | Offset to the first session block |
54h |
4 | Offset to disc metadata blocks (DPM etc.); zero if none |
58h |
8 | Zero (present in some files only, before the first structure) |
Notes:
- Aaru maps all CD-like media (CD-DA, CD-ROM XA, PlayStation, …) to
00h, all writable DVD types (±R, ±RW, DL) to12h, and everything else to10h. libmirage accepts only the five values in the table. - Aaru treats DVD-R as a DVD regardless of the PFI's own disc category.
No sample contained a BCA.
Session blocks (24 bytes) #
| Offset | Size | Field |
|---|---|---|
00h |
4 | Session start sector (signed LBA). First session: FFFFFF6Ah (−150) on CD, 0 on DVD |
04h |
4 | Session end sector. CD: LBA of this session's lead-out (the A2 MSF as an LBA). DVD: total number of sectors |
08h |
2 | Session number (from 1) |
0Ah |
1 | Number of data blocks in this session (all of them) |
0Bh |
1 | Number of data blocks with Point ≥ A0h ("non-track" or lead-in blocks) |
0Ch |
2 | First track number in the session |
0Eh |
2 | Last track number in the session |
10h |
4 | Zero |
14h |
4 | Offset to the session's first data block |
Lead-in block count (0Bh). On a single-session CD this is 3 (A0, A1, A2). On a multisession CD it also counts the ADR 5 entries (B0, C0) in that session. (samples) It was 3 even on DVDs, which have only one data block and no A0–A2 blocks. This looks like an Alcohol quirk and is safe to ignore.
Gaps between sessions. libmirage computes the length of the lead-out/lead-in/pregap gap after session n as start(session n+1) − end(session n). This uses only the session blocks; the MDF doesn't store the gap.
Data blocks (80 bytes) #
One data block per TOC entry.
- CD: each session has one block per lead-in entry (Points A0h, A1h, A2h, and on multisession/recordable discs B0h, C0h, …), followed by one block per track in track order. In samples, A0–A2 came first.
- DVD: a single block for "Point 1", with no A0h–A2h blocks.
Bytes 02h–0Bh are a direct copy of an MMC READ TOC Full TOC descriptor (bytes 1–10: ADR/Control, TNO, POINT, Min, Sec, Frame, Zero, PMIN, PSEC, PFRAME; see Subchannels §5.3). The rest is Alcohol's own track description.
| Offset | Size | Field |
|---|---|---|
00h |
1 | Track mode (see below) |
01h |
1 | Subchannel mode: 00h none, 08h 96-byte interleaved P–W appended to each sector |
02h |
1 | ADR/Control, MMC order: high nibble = ADR, low nibble = Control (14h = ADR 1, data; 10h = ADR 1, audio). The raw Q channel has them the other way round |
03h |
1 | TNO (always 00h: these are lead-in entries) |
04h |
1 | Point (01h–63h = track number, A0h+ = lead-in info) |
05h |
1 | Min: lead-in time at which the entry was read (zero in samples) |
06h |
1 | Sec |
07h |
1 | Frame |
08h |
1 | Zero. Aaru: old Aaru versions wrongly stored an hour value here for DDCD support, and Aaru's reader folds it into PMIN |
09h |
1 | PMIN |
0Ah |
1 | PSEC |
0Bh |
1 | PFRAME |
0Ch |
4 | CD: offset to this track's index block ("extra" block). DVD: length of the track in sectors (there is no index block) |
10h |
2 | Sector size in the MDF (800h, 930h, 990h, …), including subchannel |
12h |
1 | Unknown: 02h for CD tracks, 00h for DVD. Aaru: "Alcohol seems to set that for all CD tracks; Daemon Tools expect it to be like this" |
13h |
17 | Zero |
24h |
4 | Track start sector, "PLBA": LBA of index 1 (0 = 00:02:00) |
28h |
8 | Track start offset: byte offset of index 1 in the (first) MDF file |
30h |
4 | Number of filenames for this track (usually 1; > 1 = split MDF) |
34h |
4 | Offset to the filename block(s) for this track |
38h |
24 | Zero |
For Point ≥ A0h, bytes 0Ch–4Fh are zero, and the track mode is 00h. Aaru does give lead-in blocks an index-block offset; libmirage ignores it.
Meaning of the MSF fields #
| Point | PMIN / PSEC / PFRAME |
|---|---|
01h..63h |
Absolute start time of the track (= PLBA + 150) |
A0h |
PMIN = first track number, PSEC = disc type (00h CD-DA / CD-ROM, 10h CD-i, 20h CD-ROM XA), PFRAME = 0 |
A1h |
PMIN = last track number |
A2h |
Start of the lead-out |
B0h (ADR 5) |
Min/Sec/Frame = start of next possible program area; Zero = number of ADR 5 pointers; PMIN/PSEC/PFRAME = last possible lead-out start |
C0h (ADR 5) |
Min = recording power; PMIN/PSEC/PFRAME = start of the first lead-in (ATIP) |
| DVD (Point 1) | all zero |
Aaru's writer, when it has no real TOC, synthesises B0h as ADR/Control 50h with the next session's address, and C0h as 50h with Min = 128 and PMIN:PSEC = 97:25 (a placeholder ATIP manufacturer code).
ADR/Control on lead-in blocks (samples): 14h on a data CD (Deus Ex), but 10h on a Mixed Mode CD (Quake) whose track 1 is 14h. Aaru writes A0h and A2h with the first track's control, and A1h with the last track's control. On Quake the last track is audio, so A1h is 10h. The 10h on Quake's A0h/A2h suggests Alcohol copies the drive's raw TOC, whatever it reports.
Track mode #
libmirage's author hex-edited this byte and fed it to Alcohol. Only the low nibble had any effect:
| Low nibble | Mode |
|---|---|
0, 3, 7, 8, B, F |
Mode 2 |
1, 9 |
Audio |
2, A |
Mode 1 |
4, C |
Mode 2 Form 1 |
5, D |
Mode 2 Form 2 |
6, E |
unknown |
The values actually seen in files:
| Value | Meaning | Sector sizes | Source |
|---|---|---|---|
00h |
None (Point ≥ A0h) | – | all |
02h |
DVD data | 800h |
samples, Aaru |
A9h |
Audio | 930h / 990h |
samples, all |
E9h |
Audio ("alternative") | – | Aaru |
AAh |
Mode 1 | 930h / 990h raw; 800h user data (bytes 010h..80Fh) |
samples, all |
EAh |
Mode 1 ("alternative") | – | Aaru |
ABh |
Mode 2 (formless / mixed) | 920h (bytes 010h..92Fh), 930h, 990h |
libmirage, Aaru, psx-spx |
ACh |
Mode 2 Form 1 | 800h (bytes 018h..817h) |
libmirage, psx-spx; Aaru calls it the "old" value |
ADh |
Mode 2 Form 2 | 914h (bytes 018h..92Bh) |
libmirage, psx-spx; Aaru calls it the "old" value |
ECh |
Mode 2 Form 1 (Aaru) / Mode 2 with subchannel, 990h (psx-spx) |
disputed | |
EDh |
Mode 2 Form 2 | Aaru |
The high nibble is thus either A or E. Bit 6 (40h) has no effect in Alcohol according to libmirage. psx-spx associates ECh with subchannel-carrying Mode 2 tracks, but the subchannel mode byte (01h) already says that. Aaru writes ECh/EDh for Form 1/Form 2 and flags images containing ACh as written by an older, incorrect writer. Readers should decode the low nibble only, as libmirage does. Writers aiming for maximum compatibility should probably use ABh for raw Mode 2 tracks.
For A9h and AAh, the sector size field (930h vs 990h) and the subchannel byte agree on whether subchannel is stored.
Index blocks (CD only, 8 bytes) #
| Offset | Size | Field |
|---|---|---|
00h |
4 | Number of sectors with index 0 (pregap length) |
04h |
4 | Number of sectors with index 1 (length of the track's main area) |
libmirage calls this the "track extra block". There is one index block for every data block, including dummy all-zero blocks for A0h–A2h, which come first; the track index blocks follow in track order. Each data block's 0Ch field points to its own.
Rules seen in the samples:
- Index 0 is 150 for track 1 and for the first audio track following a data track, and 0 for other tracks. Only the track 1 and data→audio cases were observed.
- Index 1 of track 1 is the length of its stored data: from PLBA 0 to the start of the next track, minus the next track's pregap.
- For consecutive tracks:
PLBA(N) + index1(N) = PLBA(N+1) − index0(N+1). In other words the "length" field excludes the following pregap, which is why the MDF has no room for it.
Aaru's writer follows the same rules: the first track gets pregap 150, a track whose mode differs from the previous track gets pregap 150 (taken off the previous track's length), and other tracks get 0.
Alcohol stores only index 0 and index 1. Indexes 2+ are lost unless the subchannel is stored.
DVD images have no index blocks. Their data block 0Ch holds the length instead.
Filename blocks (16 bytes) #
| Offset | Size | Field |
|---|---|---|
00h |
4 | Offset to the filename string |
04h |
1 | Filename format: 0 = 8-bit characters, 1 = 16-bit (UTF-16LE). libmirage reads this as a 4-byte field; the upper bytes are zero |
05h |
11 | Zero |
All tracks normally share the same filename block (their 34h fields point to the same place). A track with n filenames has n consecutive filename blocks.
Filename strings #
"*.mdf",00h (8-bit: 6 bytes)
"*.mdf",00h,00h (16-bit: 12 bytes, UTF-16LE)
This is the name of the sector-data file. *.mdf is a wildcard meaning "same base name as this .mds, with the extension .mdf". libmirage implements it as a regex (\*\.(\w+) → replace the .mds file's extension with the captured one). A literal filename is resolved relative to the .mds file. Aaru always writes *.mdf in UTF-16 ("Yup, Alcohol stores no filename but a wildcard").
DVD-specific structures
Disc structures #
The region starting at the offset in header field 40h holds copies of the DVD's lead-in control structures, as read with MMC READ DISC STRUCTURE. It is made up of 1004h-byte (4,100-byte) slots: one for a single-layer disc, two for a dual-layer disc.
Within each slot, per libmirage:
| Offset | Size | Contents | READ DISC STRUCTURE format |
|---|---|---|---|
000h |
4 | Copyright information: copy protection system type (e.g. 01h = CSS/CPPM), region management info, 2 reserved | 01h |
004h |
2048 | Disc Manufacturing Information (DMI) | 04h |
804h |
2048 | Physical Format Information (PFI): only the first ~17 bytes are meaningful on DVD-ROM | 00h |
Aaru reads the same slot slightly differently. It treats bytes 000h–003h as the 4-byte READ DISC STRUCTURE response header of the DMI (its writer emits 08 02 00 00, i.e. length 0802h), then the DMI, then the PFI at 804h. Both agree on where DMI and PFI are. For the first 4 bytes, libmirage's "copyright info" reading fits the 4100-byte slot size (4 + 2048 + 2048) best. Aaru notes "TODO: CMI" and does not use them.
(samples) The first 804h bytes were all zero in every sample (pressed discs commonly have an empty DMI and no copy protection). On the dual-layer disc, the two PFI copies were identical.
libmirage decides whether a second slot exists from the PFI's layer-count bits. Aaru reads only the first slot ("TODO: Second layer").
PFI (Physical Format Information) #
| Byte | Bits | Field | Samples |
|---|---|---|---|
00h |
7–4 | Disk category (book type): 0 DVD-ROM, 1 DVD-RAM, 2 DVD-R, 3 DVD-RW, 9 DVD+RW, 10 DVD+R, … | 0 |
| 3–0 | Part version | 1 | |
01h |
7–4 | Disc size: 0 = 120 mm, 1 = 80 mm | 0 |
| 3–0 | Maximum transfer rate: 0 = 2.52, 1 = 5.04, 2 = 10.08 Mbit/s, F = not specified | 2 | |
02h |
7 | reserved | |
| 6–5 | Number of layers − 1 (0 = single, 1 = dual) | ||
| 4 | Track path: 0 = parallel (PTP), 1 = opposite (OTP) | ||
| 3–0 | Layer type: bit 0 embossed (read-only), bit 1 recordable, bit 2 rewritable | 1 | |
03h |
7–4 | Linear density: 0 = 0.267 µm/bit, 1 = 0.293 µm/bit, 2 = 0.409–0.435 µm/bit, 4 = 0.280–0.291, 8 = 0.353 | |
| 3–0 | Track density: 0 = 0.74 µm/track, 1 = 0.80, 2 = 0.615 | 0 | |
04h |
zero | ||
05h–07h |
24 bits | Start PSN of the data area (big-endian) | 030000h |
08h |
zero | ||
09h–0Bh |
24 bits | End PSN of the data area (big-endian) | |
0Ch |
zero | ||
0Dh–0Fh |
24 bits | End PSN of layer 0 (dual-layer OTP; zero otherwise) | |
10h |
7 | BCA flag: 1 = a BCA is present | |
11h–7FFh |
reserved / media-specific (recordables put manufacturer and write-strategy data here) |
The multi-byte PSN fields are big-endian (MMC/ECMA convention), unlike the rest of the MDS.
Aaru warns that Alcohol has been seen changing the disk category and part version in the stored PFI (for example, recording a DVD-R as DVD-ROM), "so much for archival value". So don't trust the PFI's category byte to tell you what the original medium was. The header's medium type is no more reliable.
Geometry #
- Layer 0 contains
end(layer 0) − 030000h + 1sectors. - Total sectors = session end sector = the data block's length field (
0Ch). - MDF sector 0 corresponds to physical sector
030000h. - On an opposite-track-path disc, layer 1 starts at physical sector
FFFFFFh − end(layer 0). The layer break is at an LBA equal to the layer 0 sector count. Worked conversions are on the LBA page.
Empire Earth III (dual layer) (samples):
| Field | Value |
|---|---|
| PFI bytes 0..3 | 01 02 31 10 (DVD-ROM v1; 120 mm, 10.08 Mbit/s; dual layer, OTP, embossed; 0.293 µm/bit, 0.74 µm) |
| Data area start | 030000h |
| End of layer 0 | 151CDFh, so layer 0 = 1,187,040 sectors |
| End of data area | FCFFEFh |
| Layer 1 start | EAE320h, so layer 1 = 1,187,024 sectors |
| Total / session end / length field | 2,374,064 |
The layer sizes differ by one 16-sector ECC block.
The single-layer sample used 01 02 01 00: single layer, embossed, 0.267 µm/bit, data area 030000h..17C1DFh, 1,360,352 sectors in total.
BCA #
If header field 1Ah (BCA length) is non-zero, the raw BCA data (up to 188 bytes on DVD) is stored at the offset in header field 24h. libmirage exposes it as disc structure 03h. Aaru's writer places it between the disc structures and the session blocks. (not observed)
Disc metadata blocks (DPM and others)
Header field 54h points to a small directory of optional blocks:
At the offset in header field 54h:
00h 4 Number of blocks (N)
04h 4*N Offset of each block (from start of the .mds)
Each block starts with a 4-byte block type. Aaru: "This value indicates what kind of block it is. DPM is 01. Other, non-DPM block types have been observed, but their purpose is currently unknown." libmirage loads only the first block. Aaru loads it only if its type is 1.
DPM data #
DPM (Data Position Measurement) is a physical fingerprint of the original disc. It records the angular position of sectors as the disc turns, sampled every resolution sectors. Because of CLV (Physical layout §3), a revolution holds more sectors at the edge than at the centre, so the curve flattens toward the outside. Its exact shape depends on the pressing. Copy protections such as SecuROM and StarForce measure it to tell an original from a copy, and emulators (DAEMON Tools, Alcohol, CDEmu) use the stored table to fake the right timing. Alcohol measures it when imaging with the right options; not all images contain it.
Structure (block type 1) #
00h 4 Block type (1 = DPM)
04h 4 Start sector (0)
08h 4 Resolution (sectors per entry)
0Ch 4 Number of entries (E)
10h 4*E Entries (32-bit unsigned)
(samples) The DPM data was the last thing in the file, and the main block ended exactly at end of file.
Entries #
(samples, with Aaru's interpretation)
- The resolution is 50 sectors for CD and 256 for DVD. Aaru's comment: going lower than 50, Alcohol's minimum, "you start losing precision since cumulative hex angles are only stored as uint32".
- The entry count × resolution just covers the disc (for example Deus Ex: 6,544 × 50 = 327,200 for a 327,274-sector disc).
- Entries increase monotonically. They are cumulative angles: the total rotation from the start sector up to each sample point.
- The first entry is about one interval's worth of rotation, so entry k probably describes sector (k+1) × resolution. (unconfirmed)
- The difference between successive entries shrinks as the radius grows. For CD it falls from about 1,316 to 582; for the single-layer DVD from about 2,252 to about 1,159.
- A rough check suggests the counter ticks about 256 times per revolution. (unconfirmed)
- On a dual-layer disc the table is a single block over both layers. The per-entry increments form a V shape: they shrink through layer 0, jump slightly at the layer break (1274 to 1279 in Empire Earth III, at sector 1,187,040 / 256 = 4,636.9), and then grow again across layer 1 as it spirals back toward the centre.
Second block: probably a read-error list #
One CD sample (Deus Ex) had a second block with header 2, 4, 1, 1 followed by a single value, 327,270 (= session end − 4).
psx-spx describes a "read errors" structure at the header-54h offset with fields "unknown (1), offset, unknown (2), unknown (7), unknown (1), number of read errors (E), E × LBA". That reads as a block directory followed by a type 2 block listing the LBAs of sectors Alcohol could not read. On that reading, Deus Ex's block (type 2, then 4, 1, count 1) lists one unreadable sector at LBA 327,270, near the very end of the disc where TAO run-out or a damaged edge would cause read errors. The meaning of the middle fields (4 vs. psx-spx's 7, and 1) is unknown. psx-spx also mentions that "additional data may include hundreds of kilobytes of text strings or zero-filled blocks" in some files.
Converting MDS/MDF
A recipe for turning an MDS/MDF into a disc model (or into CUE/BIN or CCD):
- Check the signature, and that the major version is 1.
- Read the header, then each session block in order from
50h. - For each session, read
num_all_blocksdata blocks from14h. Separate track blocks (Point 1–99) from lead-in blocks (≥ A0h). The lead-in blocks give A0 (disc type), A1, A2 and any B0/C0, which is enough to rebuild a Full TOC (for CCD[Entry]sections). - For each track block:
- mode ← low nibble of
00h; control ← low nibble of02h; ADR ← high nibble; - sector size ←
10h; if01h= 8, the last 96 bytes of each sector are interleaved subchannel; - CD: pregap, length ← index block at
0Ch. DVD: length ←0Ch; - index 1 at LBA
24h, at byte28hin the MDF; pregap sectors are not in the MDF (samples, libmirage); - filename ← filename block at
34h(handle*.extwildcards and UTF-16).
- mode ← low nibble of
- Session gaps:
start(next session) − end(this session). - DVD: read the PFI at structure slot +
804hfor layer info. Keep DMI, copyright info and BCA if the output can hold them (only MDS can). - DPM: copy it if the output is MDS; otherwise it is lost.
Appendix A: MDS v2 / MDX (DAEMON Tools)
DAEMON Tools 4.x and later write descriptors that start with the same MEDIA DESCRIPTOR string, but with major version 2. libmirage handles them in a separate parser (lib/cdemu/libmirage/images/image-mdx/):
00h 16 "MEDIA DESCRIPTOR"
10h 1 Major version: 2
11h 1 Minor version: 0 or 1
12h 26 Copyright string: "(C) 2000-2010 DT Soft Ltd." (minor 0) / "(C) 2000-2015 Disc Soft Ltd." (minor 1)
2Ch 4 Offset to encryption header (MDS v2), or FFFFFFFFh (MDX: descriptor embedded in the data file)
The descriptor that follows is zlib-compressed and encrypted (AES-based, XTS mode, in a TrueCrypt-style 512-byte header with a PKCS#5 salt and a TRUE magic value). The data file may itself be encrypted or compressed. Once decrypted, the descriptor resembles a v1 MDS. It is out of scope here; the libmirage source is the best reference.
Appendix B: Missing / unknown data
- CD-TEXT: no known storage. The lead-in isn't stored, so it is probably lost. Aaru's capability flags claim CD-TEXT/MCN/ISRC support, but its Alcohol code never reads or writes them.
- MCN / ISRC: no dedicated fields. They survive only inside stored subchannel data (Q ADR 2/3 frames).
- The meaning of header
16h(= 2) and data block12h(= 2 on CD). Both are required by DAEMON Tools according to Aaru, but their meaning is unknown. - The meaning of bit 6 in the track mode byte (
AxvsEx). - Whether other disc structures (BCA, or non-zero copyright info and DMI) appear in images of protected or recordable DVDs.
- The ADR/Control byte of A0h..A2h blocks (copied from the drive's TOC, or computed?).
- Whether pregaps other than track 1's and the data→audio one are ever stored in the MDF, and how an emulator should synthesise the missing pregaps (silence for audio; zero-data sectors in the track's mode for data).
- The exact DPM units, and the middle fields of the type 2 (read error) block.
- Media types other than the five listed, and track modes marked not observed.
Sources #
- Our own sample analysis (Quake, Deus Ex, Empire Earth III, one single-layer DVD).
- libmirage
lib/cdemu/libmirage/images/image-mds/image-mds.handparser.c(structures, track mode experiment, disc structures, BCA, DPM, filename wildcard);image-mdx/image-mdx.h(MDS v2/MDX). - Aaru
lib/Aaru/Aaru.Images/Alcohol120/Structs.cs,Enums.cs,Read.cs,Write.cs,Helpers.cs(field names, alternative track modes, DAEMON Tools compatibility values, DPM, PFI/DMI layout, B0/C0 synthesis). - psx-spx, "CDROM Disk Images MDS/MDF (Alcohol 120%)": https://problemkaputt.de/psxspx-cdrom-disk-images-mds-mdf-alcohol-120.htm
- Wikipedia, "Media Descriptor File": https://en.wikipedia.org/wiki/Media_Descriptor_File
- T10 MMC-6 draft (READ TOC Full TOC descriptor; READ DISC STRUCTURE formats 00h/01h/03h/04h). https://www.t10.org/drafts.htm
- ECMA-267 §3.3 / Annex (Physical format information field definitions). https://ecma-international.org/publications-and-standards/standards/ecma-267/