Releases: OxideAV/oxideav-dvd
v0.0.3
Other
- AC-3 sync-frame header decoder (syncinfo + bsi prefix)
- decode HLI_GI btn_md into typed ButtonMode (PCI highlight button groups)
- PCI NSML_AGLI non-seamless angle jump table
- add First-Play PGC reader (DvdDisc::parse_fp_pgc)
- menu C_ADT + VOBU_ADMAP reader helpers on DvdDisc
- decode VMGM_PGCI_UT + VTSM_PGCI_UT (menu PGCI Unit Table)
- decode VMG_VTS_ATRT + VMG_PTL_MAIT on the VMG side
- typed accessors for the remaining language / sentinel SPRMs
- drop release-plz.toml — use release-plz defaults across the workspace
- typed-instruction iterators on PgcCommandTable + decode_instruction bridge
- typed HighlightStatus enum on PCI_GI hli_ss
- typed cell-elapsed-time accessor on DsiGi + PgcTime::to_nanoseconds
- VTSI_MAT / VMGI_MAT stream-attribute extension decoders
- VOBU_ADMAP + VTS_TMAPTI typed decoders for time-based seek
- typed UOP-prohibition decoder + three-level OR-merge
- decode DVD-Video LPCM private_stream_1 audio-pack header
- SPRM bitfield accessors + named SPRM indices (Phase 3c next-item)
- execute Type 4..6 compound CMP/SET/LNK families (Phase 3c completion)
- Phase 3c interpreter — SPRM/GPRM register file + Link/Jump/Call execution
Added
-
AC-3 sync-frame header decode (
ac3module).Ac3Header::parse
decodes thesyncinfo()(sync word0x0B77,crc1,fscod
sampling-rate code,frmsizecodframe-size code) and the
deterministically-positioned prefix ofbsi()(bsid,bsmod
bitstream mode,acmodaudio-coding mode, and thecmixlev/
surmixlev/dsurmodconditional fields whose presence is a pure
function ofacmod, pluslfeon) off the start of an AC-3
elementary stream routed fromDvdSubstream::Ac3. Accessors:
sample_rate_hz,nominal_bitrate_kbpsandframe_size_words/
frame_size_bytes(driven by the 38-entryfrmsizecodtable with
per-sample-rate columns),total_channel_count(nfchans + lfeon),
and theAc3AudioCodingModechannel-layout / conditional-field
classifiers. Reservedfscod/frmsizecodcodes are preserved and
surface asNonefrom the rate/size accessors. Header-only: fields
pastlfeon(variable-lengthbsi()tail) and the audio blocks stay
with a downstream AC-3 decoder. Clean-room per
docs/container/dvd/application/stnsoft-ac3hdr.html+
mpucoder-dvdmpeg.html. -
HLI_GI
btn_mdtyped decode.HighlightInfo::button_mode()
now returns aButtonMode { group_count, group_types: [u8; 3] }
decoded from the rawbtn_mdword per thebtn_md wordsub-table
ofdocs/container/dvd/application/mpucoder-pci_pkt.html:
btngr_ns(number of button groups, u16 bits 13..12) and the three
3-bitbtngrN_tygroup-type codes (bits 10..8 / 6..4 / 2..0), with
the reserved bits (15..14, 11, 7, 3) masked out.ButtonMode
also providesfrom_btn_md/to_btn_md(reserved-bit-dropping
round-trip). The reference labels the type codes "normal / lb /
p/s" (normal / letterbox / pan-scan) but gives no numeric
value-to-name mapping, so the codes are surfaced raw rather than as
a named enum; the field had previously been kept as an opaqueu16. -
PCI NSML_AGLI non-seamless angle jump table.
PciPacketnow
decodes the 36-byte NSML_AGLI block at PCI packet offset
0x3C..0x60into a typedNsmlAgli { cells: [NsmlAngleCell; 9] }
perdocs/container/dvd/application/mpucoder-pci_pkt.html. Each
nsml_agl_cN_dstacell carries the relative sector offset to the
current ILVU for that angle, with bit 31 as the direction
(0 = forward, 1 = backward) and the0x0000_0000(angle absent) /
0x7FFF_FFFF(no more video) sentinels.NsmlAngleCellexposes
is_absent/is_no_more_video/is_backward/offset_sectors;
NsmlAgliexposesis_empty,active_angle_count, and a 1-based
angle(n)accessor that pairs with SPRM 3 (current angle). This is
the PCI counterpart to the existing DSISmlAgliseamless-angle
table, completing the multi-angle navigation surface a player needs
to switch angles on a non-seamless interleaved block. -
First-Play PGC reader —
DvdDisc::parse_fp_pgc. The VMGI_MAT
word at0x0084is the start byte address ofFP_PGC, the
program chain a player enters at disc insertion before any title or
menu domain is active — per
docs/container/dvd/application/mpucoder-ifo.htmlit is the only
VMGI structure addressed in bytes rather than sectors (same unit as
the0x0080"end byte address of VMGI_MAT" word), and its body is
an ordinary PGC permpucoder-pgc.html(the MAT row links straight
to the PGC page), soPgc::parsedecodes it unchanged. The new
helper reads the MAT, follows the byte address, and parses the PGC;
it returnsOk(None)whenfp_pgc_addris zero (no First-Play PGC
authored). The read is bounded at the first non-zero sector-aligned
VMG table so a malformed address can't pull bytes from an unrelated
table — an address at/past that boundary is rejected with an error
rather than mis-parsed. This closes the navigation bootstrap gap:
the Phase 3c VM could already execute startup routing
(JumpSs(FirstPlay)/JumpTTactions) but nothing could fetch
the FP_PGC those commands live in. Three new tests: the populated
path drives the disc-insertion sequence end-to-end (synthetic
cell-less FP_PGC at byte0x0400→parse_fp_pgc→
commands.pre→Vm::run_list→VmAction::JumpTitle { ttn: 1 }),
plus the zero-pointerNonepath and the past-first-table
rejection. 311 lib tests (was 308) under default features;
321 lib tests (was 318) under--all-features. -
Menu
C_ADT+VOBU_ADMAPreader helpers onDvdDisc. The
VMGI / VTSI MATs carry sector pointers to the menu-side cell-address
tables (vmgm_c_adt_sector/vtsm_c_adt_sector) and menu VOBU
address maps (vmgm_vobu_admap_sector/vtsm_vobu_admap_sector),
but no high-level reader followed them. The body decoders already
existed —docs/container/dvd/application/mpucoder-ifo.htmldocuments
VMGM_C_ADT/VTSM_C_ADT/VTS_C_ADTunder one shared#c_adt
heading (and the three VOBU_ADMAP variants under#vam) because all
share the wire format, soVtsCAdt::parse/VobuAdmap::parse
decode the menu copies unchanged. This round wires the four
high-level reader helpers that read the appropriate MAT, follow the
sector pointer, and parse the body:DvdDisc::parse_vmgm_c_adt(reader)— VMG menu cell-address table
(VIDEO_TS.VOBcells).DvdDisc::parse_vmgm_vobu_admap(reader)— VMG menu VOBU sector
list.DvdDisc::parse_vtsm_c_adt(reader, ts_index)— per-title-set menu
cell-address table (VTS_xx_0.VOBcells).DvdDisc::parse_vtsm_vobu_admap(reader, ts_index)— per-title-set
menu VOBU sector list.
Each returnsOk(None)when the corresponding MAT sector pointer is
zero (no menu VOB authored). The reads are bounded at the next
non-zero table sector in the MAT so a malformedend_addresslength
field can't pull bytes from an unrelated table — the same
bounded-read discipline theparse_vmgm_pgci_ut/parse_vtsm_pgci_ut
helpers use. Five new in-module tests cover the populated happy path
for all four helpers (synthetic VMGI/VTSI disc image → cell lookup +
VOBU sector-count/start round-trip) and the four zero-pointerNone
paths. 308 lib tests (was 303) under default features; 318 lib
tests (was 313) under--all-features.
-
VMGM_PGCI_UT+VTSM_PGCI_UTdecoders (menu PGCI Unit Table).
The MAT records the sector pointersvmgm_pgci_ut_sectorand
vtsm_pgci_ut_sectorfor the menu PGC tables on both the VMG and
VTS sides, but no body parser existed. This round materialises both
perdocs/container/dvd/application/mpucoder-ifo_vmg.html§VMGM_PGCI_UT
andmpucoder-ifo_vts.html§VTSM_PGCI_UT — the wire format is
identical between the two sides:PgciUt— the outer search-pointer list keyed by ISO 639 language
code (each entry: 16-bit language code + 1-byte language-code
extension + 1-bytemenu_existenceflag + 32-bit offset to LU).
Thelanguage_unit(lang_code)lookup round-trips a packed
b"en"-style code to its parsed Language Unit; the per-entry
has_root_menu/has_subpicture_menu/has_audio_menu/
has_angle_menu/has_ptt_menuaccessors decode each
menu-existence flag bit per the table atmpucoder-ifo_vts.html
(bit0x80= root/title,0x40= sub-picture,0x20= audio,
0x10= angle,0x08= PTT — the constants live in the public
menu_existencesub-module).PgciLu— one Language Unit body: a per-PGC search-pointer list
(PgciLuSrp: 32-bit PGC category dword + 32-bit offset to the
PGC body) plus the parsedPgcbodies themselves (via
Pgc::parse). ThePgciLuSrp::is_entry_pgc/
menu_type/parental_maskaccessors decompose the category
dword permpucoder-ifo_vts.html(PGC category breakdown).MenuTypeenum — decodes the low nibble of the PGC category
byte 0 (2= title /3= root /4= sub-picture /5=
audio /6= angle /7= PTT, plusUnknown(_)for the
reserved nibble values).DvdDisc::parse_vmgm_pgci_ut(reader)/
parse_vtsm_pgci_ut(reader, ts_index)— high-level reader helpers
that read the appropriate MAT, follow the sector pointer, and
parse the body. Both returnOk(None)when the corresponding
MAT sector pointer is zero (table absent on this disc / title
set). The reads are bounded at the next non-zero table sector
so a malformed length field can't pull bytes from an unrelated
table.
Nine new unit tests cover the happy path (two-language walkthrough
with entry-PGC + menu-type round-trip), the boundary cases (zero
language units, parental-mask extraction from the category dword),
and the four malformed-input rejection paths (short header /
SRP list past buffer / LU offset zero / L...
v0.0.2
Other
- composite SPU into RGBA overlay (palette + contrast + BT.601)
- add DVD Sub-Picture Unit decoder
- scrub enumerated-denial / decorative-attribution prose (r131 disclaimer-hygiene sweep follow-up)
- add Phase-3c-precursor NavInstruction disassembler
- decode NAV-pack DSI typed sub-sections (SML_PBI / SML_AGLI / SYNCI)
- decode NAV-pack PCI highlight (HLI_GI + SL_COLI + BTN_IT)
- re-export PaletteEntry / NavCommand / PgcCommandTable at crate root
- decode PGC palette colour-LUT + pre/post/cell command table
- Phase 3b: VOB → MKV mux glue + convert_dvd_to_mkv pipeline
- Phase 3a: VOB demuxer — MPEG-PS pack + nav-pack + DVD substream router
- Phase 2: IFO body parser — VMGI/VTSI MAT + TT_SRPT + VTS_PTT_SRPT + VTS_PGCI + VTS_C_ADT
Added
-
SPU RGBA compositor —
SubPictureUnit::composite(buf, palette)
turns a parsed sub-picture plus the PGC's 16-entryPaletteEntry
colour-LUT into a finishedSpuBitmapoverlay (row-major
[R, G, B, A]pixels + on-screen rectangle), completing the
"final framebuffer left to the caller" gap entirely inside the
crate. Clean-room perdocs/container/dvd/application/mpucoder-spu.html
(SET_COLOR/SET_CONTR semantics,0x0transparent …0xFopaque,
top/bottom field interleave) +stnsoft-color_pick.html(BT.601
studio-swing luma scaleY = 160 % …Y = 235100 %). No
libdvdread / libdvdnav / libdvdcss / FFmpeg / VLC / mpv / xine
source consulted; no web search.ycbcr_to_rgb— standalone BT.601 studio-swing
(Y, Cb, Cr) -> (R, G, B)inverse-matrix conversion in fixed
point (1.164 / 1.596 / 0.391 / 0.813 / 2.018 coefficients scaled
by1<<16, round-half-up, clamped to0..=255).SpuBitmap—{ x, y, width, height, rgba }overlay: the
SET_DAREArectangle plus the composited pixels, ready to blend
onto the decoded MPEG-2 frame by the player.- The four 2-bit pixel codes are resolved through the unit's own
SET_COLOR(→0..=15palette index) andSET_CONTR
(→0..=15alpha, expanded to 8-bit by nibble replication);
a unit lacking those uses well-defined fallbacks (background
index, fully-opaque). ReturnsNonewhenSET_DAREA/
SET_DSPXAare absent (a malformed unit per the spec). - +5 unit tests (BT.601 known-point conversion incl. clamp +
red/blue dominance, contrast-nibble expansion, full solid-rect
composite round-trip, missing-SET_DAREA→None).
126 lib tests (was 121 after the SPU decoder landed).
-
spumodule — DVD Sub-Picture Unit decoder, the overlay
graphics stream that carries subtitles, menu button highlights,
and karaoke captions. Pure-bytes decoder clean-room per
docs/container/dvd/application/mpucoder-spu.html(sole 160-line
source; no libdvdread / libdvdnav / libdvdcss / FFmpeg / VLC / mpv
/ xine / HandBrake source consulted; no web search).SpuHeader— the 4-byte SPUH (SPDSZtotal size +
SP_DCSQTAoffset to the Sub-Picture Display Control Sequence
Table).SpuCommand— typed enum for the eight SP_DCSQ command
codes:ForcedStartDisplay(0x00) /StartDisplay(0x01)
/StopDisplay(0x02) /SetColor(0x03, four 4-bit
palette indices) /SetContrast(0x04, four 4-bit alpha
values) /SetDisplayArea(0x05, four 12-bit coordinates)
/SetPixelDataAddresses(0x06, top/bottom field offsets) /
ChangeColorContrast(0x07, rawLN_CTLI/PX_CTLI
parameter blob preserved for the caller) /EndOfSequence
(0xFF, theCMD_ENDterminator).SpDcSq— one display-control sequence: a 4-byte header
(90 kHz/1024start_time+next_offsetchain pointer) plus
the decoded command list. Chain-walk validates per-block
forward progress and rejects loops.SubPictureUnit::parse— top-level entry that walks SPUH- every chained DCSQ from the
SP_DCSQTAoffset until a
terminal block (whosenext_offsetpoints back at itself).
Convenience accessorspixel_data_offsets()/display_dimensions()
pull the PXDtf/PXDbf offsets and rectangle width/height out of
the command stream.
- every chained DCSQ from the
decode_rle_field— the 2-bit / four-form PXD run-length
decoder. Implements the nested-prefix encoding (n n c c/
0 0 n n n n c c/0 0 0 0 n n n n n n c c/
0 0 0 0 0 0 n n n n n n n n c c) and the 16-bit
"count=0 = until end of line" terminator, with byte alignment
at every row boundary per mpucoder-spu.html §PXDtf.render_field— flattens the run vector into a row-major
Vec<u8>of palette indices (0..=3), one byte per pixel,
ready for blending against the PGC's 16-entryPaletteEntry
table.spdcsq_stm_to_ms— converts anSP_DCSQ_STM90 kHz/1024
delay to integer milliseconds via the inverse of the
mpucoder-spu.html conversion table.
Producing a final framebuffer (YCrCb + alpha) is intentionally
left to the caller — that step needs the PGCPaletteEntry
table (already exposed bycrate::ifo) plus the renderer's
preferred pixel format, both outside the SPU bitstream itself.+13 unit tests (header parse / delay conversion / one-run RLE
for all four forms / end-of-line marker / EOL row padding /
full-unit round-trip with six commands /CHG_COLCONraw
round-trip / DCSQTA-out-of-range rejection / runaway-DCSQ
rejection / opcode table). 132 tests total (was 119). -
navmodule — typed VM instruction decoder (Phase 3c precursor).
The previousNavCommandsurface exposed only an 8-byte raw word
plus the 3-bitcommand_typeclassifier; the newNavCommand::decode() -> NavInstructionreturns a typed-enum disassembly tree clean-room
perdocs/container/dvd/application/mpucoder-vmi.html+
mpucoder-vmi-sum.html+mpucoder-vmi-jmp.html+
mpucoder-sprm.html(no libdvdread / libdvdnav / libdvdcss /
FFmpeg / VLC / mpv / xine / HandBrake source consulted; no web
search). No execution — an interpreter that owns
SPRMs / GPRMs / PC / RSM stack is the bulk of Phase 3c proper;
decoding the stream is the prerequisite step shared by a future
executor, an analyser, and a disc debugger.Register— 8-bit operand classifier:Gprm(0..=15)/
Sprm(0..=23)/Invalid(raw)per the asterisk note on the VMI
spec page (only0x00..=0x0Fand0x80..=0x97are valid).SetOp+CmpOp— the SET (12 named codes:mov,
swp,add,sub,mul,div,mod,rnd,and,or,
xor) and CMP (7 named codes:BC,EQ,NE,GE,GT,
LE,LT) sub-op tables from the same page.LinkSubset— the 13-entry inner table for theType-1 0x20 0x01Link command:LinkTopCell/LinkNextCell/
LinkPrevCell/LinkTopPG/LinkNextPG/LinkPrevPG/
LinkTopPGC/LinkNextPGC/LinkPrevPGC/LinkGoupPGC/
LinkTailPGC/Rsm+Nop, with the spec's invalid bag
(0x04, 0x08, 0x0E, 0x0F, 0x11..0x1F) preserved via
Invalid(raw).JumpSSTarget+CallSSTarget— the four-way
destination selector (FirstPlay/VmgmMenu { menu }/
VtsmMenu { vts, ttn, menu }/VmgmPgcn { pgcn }) from the
JumpSS/CallSSrows inmpucoder-vmi.html.CallSSTarget
additionally carries thersm_cellresume-cell byte shared by
all four CallSS variants.NavInstruction— top-level decode enum. Variants for the
well-defined opcodes:Nop,Goto { line },Break,
SetTmpPml { level, line },LinkSub { subset, hl_bn },
LinkPgcn { pgcn },LinkPttn { pttn, hl_bn },
LinkPgn { pgn, hl_bn },LinkCn { cn, hl_bn },Exit,
JumpTT { ttn },JumpVtsTt { ttn },
JumpVtsPtt { ttn, pttn },JumpSs(JumpSSTarget),
CallSs(CallSSTarget),SetStn(withaf/sf/nfflag
bits and per-channel register-or-immediate source),SetNvtmr,
SetGprmMd(withcountermode bit),SetAmxMd,SetHlBtnn,
Set { op, dst, src }. Compound Type 4..6 forms surface their
classifierSetOp+CmpOpsub-ops viaSetCLnk(Type 4),
CSetCLnk(Type 5),CmpSetLnk(Type 6); the per-operand
sub-decode is deferred to the executor. Type 7 returns
Unknown(the VMI page documents the family has never been
observed in real-world streams); structurally-impossible
encodings returnInvalid.- 42 new unit tests covering the
RegisterGPRM / SPRM /
invalid-hole classifier, the fullSetOp/CmpOp/
LinkSubsetnamed-code tables, the spec's named-but-invalid
sub-codes (SetSystemsub=5,Setsub=0/C/F, Type 0 cmd
nibble 4..F, Link cmd nibble 2), the round-trip from a
NavCommand::default()(all zero) decoding toNop, and one
decoded form perNavInstructionvariant including the
JumpSS four-way target selector and the CallSS rsm_cell field.
-
NAV-pack DSI typed sub-section decode (Data Search Information):
theDsiPacketdecoder previously surfaced only the DSI_GI preamble
and a flat 43-entry VOBU_SRI array; it now returns a typed
DsiPacket { general_info, sml_pbi, sml_agli, vobu_sri, synci }
with every spec-listed field exposed by name, clean-room per
mpucoder-dsi_pkt.html(no libdvdread / libdvdnav / FFmpeg / VLC /
mpv / xine source consulted).DsiGi— DSI_GI general information (packet 0x00..0x20):
nv_pck_scr,nv_pck_lbn,vobu_ea, the 1st/2nd/3rd reference-
frame end-address triplet, the(vobu_vob_idn, vobu_c_idn)
identifier pair, and the BCDc_eltmcell-elapsed-time + frame-
rate bits field. Convenience getters
(DsiPacket::nv_pck_scr()etc.) mirror the pre-refactor flat-field
accessors so the bump stays source-compatible for call-sites that
only read DSI_GI.SmlPbi+SmlAudioGap— SML_PBI seamless-playback info
(packet 0x20..0xB4, 148 bytes): the 16-bitilvuflag word with
preu()/is_ilvu()/ ...
v0.0.1
chore: Release package oxideav-dvd version 0.0.1