Skip to content

Releases: OxideAV/oxideav-dvd

v0.0.3

15 Jun 05:16
dc1eb58

Choose a tag to compare

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 (ac3 module). Ac3Header::parse
    decodes the syncinfo() (sync word 0x0B77, crc1, fscod
    sampling-rate code, frmsizecod frame-size code) and the
    deterministically-positioned prefix of bsi() (bsid, bsmod
    bitstream mode, acmod audio-coding mode, and the cmixlev /
    surmixlev / dsurmod conditional fields whose presence is a pure
    function of acmod, plus lfeon) off the start of an AC-3
    elementary stream routed from DvdSubstream::Ac3. Accessors:
    sample_rate_hz, nominal_bitrate_kbps and frame_size_words /
    frame_size_bytes (driven by the 38-entry frmsizecod table with
    per-sample-rate columns), total_channel_count (nfchans + lfeon),
    and the Ac3AudioCodingMode channel-layout / conditional-field
    classifiers. Reserved fscod / frmsizecod codes are preserved and
    surface as None from the rate/size accessors. Header-only: fields
    past lfeon (variable-length bsi() 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_md typed decode. HighlightInfo::button_mode()
    now returns a ButtonMode { group_count, group_types: [u8; 3] }
    decoded from the raw btn_md word per the btn_md word sub-table
    of docs/container/dvd/application/mpucoder-pci_pkt.html:
    btngr_ns (number of button groups, u16 bits 13..12) and the three
    3-bit btngrN_ty group-type codes (bits 10..8 / 6..4 / 2..0), with
    the reserved bits (15..14, 11, 7, 3) masked out. ButtonMode
    also provides from_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 opaque u16.

  • PCI NSML_AGLI non-seamless angle jump table. PciPacket now
    decodes the 36-byte NSML_AGLI block at PCI packet offset
    0x3C..0x60 into a typed NsmlAgli { cells: [NsmlAngleCell; 9] }
    per docs/container/dvd/application/mpucoder-pci_pkt.html. Each
    nsml_agl_cN_dsta cell carries the relative sector offset to the
    current ILVU for that angle, with bit 31 as the direction
    (0 = forward, 1 = backward) and the 0x0000_0000 (angle absent) /
    0x7FFF_FFFF (no more video) sentinels. NsmlAngleCell exposes
    is_absent / is_no_more_video / is_backward / offset_sectors;
    NsmlAgli exposes is_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 DSI SmlAgli seamless-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 at 0x0084 is the start byte address of FP_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.html it is the only
    VMGI structure addressed in bytes rather than sectors (same unit as
    the 0x0080 "end byte address of VMGI_MAT" word), and its body is
    an ordinary PGC per mpucoder-pgc.html (the MAT row links straight
    to the PGC page), so Pgc::parse decodes it unchanged. The new
    helper reads the MAT, follows the byte address, and parses the PGC;
    it returns Ok(None) when fp_pgc_addr is 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) / JumpTT actions) 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 byte 0x0400parse_fp_pgc
    commands.preVm::run_listVmAction::JumpTitle { ttn: 1 }),
    plus the zero-pointer None path 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_ADMAP reader helpers on DvdDisc. 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.html documents
    VMGM_C_ADT / VTSM_C_ADT / VTS_C_ADT under one shared #c_adt
    heading (and the three VOBU_ADMAP variants under #vam) because all
    share the wire format, so VtsCAdt::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.VOB cells).
    • 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.VOB cells).
    • DvdDisc::parse_vtsm_vobu_admap(reader, ts_index) — per-title-set
      menu VOBU sector list.
      Each returns Ok(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 malformed end_address length
      field can't pull bytes from an unrelated table — the same
      bounded-read discipline the parse_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-pointer None
      paths. 308 lib tests (was 303) under default features; 318 lib
      tests
      (was 313) under --all-features.
  • VMGM_PGCI_UT + VTSM_PGCI_UT decoders (menu PGCI Unit Table).
    The MAT records the sector pointers vmgm_pgci_ut_sector and
    vtsm_pgci_ut_sector for the menu PGC tables on both the VMG and
    VTS sides, but no body parser existed. This round materialises both
    per docs/container/dvd/application/mpucoder-ifo_vmg.html §VMGM_PGCI_UT
    and mpucoder-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-byte menu_existence flag + 32-bit offset to LU).
      The language_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_menu accessors decode each
      menu-existence flag bit per the table at mpucoder-ifo_vts.html
      (bit 0x80 = root/title, 0x40 = sub-picture, 0x20 = audio,
      0x10 = angle, 0x08 = PTT — the constants live in the public
      menu_existence sub-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 parsed Pgc bodies themselves (via
      Pgc::parse). The PgciLuSrp::is_entry_pgc /
      menu_type / parental_mask accessors decompose the category
      dword per mpucoder-ifo_vts.html (PGC category breakdown).
    • MenuType enum — decodes the low nibble of the PGC category
      byte 0 (2 = title / 3 = root / 4 = sub-picture / 5 =
      audio / 6 = angle / 7 = PTT, plus Unknown(_) 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 return Ok(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...

Read more

v0.0.2

30 May 02:42
0bdd86c

Choose a tag to compare

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 compositorSubPictureUnit::composite(buf, palette)
    turns a parsed sub-picture plus the PGC's 16-entry PaletteEntry
    colour-LUT into a finished SpuBitmap overlay (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 per docs/container/dvd/application/mpucoder-spu.html
    (SET_COLOR/SET_CONTR semantics, 0x0 transparent … 0xF opaque,
    top/bottom field interleave) + stnsoft-color_pick.html (BT.601
    studio-swing luma scale Y = 16 0 % … Y = 235 100 %). 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
      by 1<<16, round-half-up, clamped to 0..=255).
    • SpuBitmap{ x, y, width, height, rgba } overlay: the
      SET_DAREA rectangle 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..=15 palette index) and SET_CONTR
      (→ 0..=15 alpha, expanded to 8-bit by nibble replication);
      a unit lacking those uses well-defined fallbacks (background
      index, fully-opaque). Returns None when SET_DAREA /
      SET_DSPXA are 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_DAREANone).
      126 lib tests (was 121 after the SPU decoder landed).
  • spu module — 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 (SPDSZ total size +
      SP_DCSQTA offset 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, raw LN_CTLI / PX_CTLI
      parameter blob preserved for the caller) / EndOfSequence
      (0xFF, the CMD_END terminator).
    • SpDcSq — one display-control sequence: a 4-byte header
      (90 kHz/1024 start_time + next_offset chain 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_DCSQTA offset until a
        terminal block (whose next_offset points back at itself).
        Convenience accessors pixel_data_offsets() / display_dimensions()
        pull the PXDtf/PXDbf offsets and rectangle width/height out of
        the command stream.
    • 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-entry PaletteEntry
      table.
    • spdcsq_stm_to_ms — converts an SP_DCSQ_STM 90 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 PGC PaletteEntry
    table (already exposed by crate::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_COLCON raw
    round-trip / DCSQTA-out-of-range rejection / runaway-DCSQ
    rejection / opcode table). 132 tests total (was 119).

  • nav module — typed VM instruction decoder (Phase 3c precursor).
    The previous NavCommand surface exposed only an 8-byte raw word
    plus the 3-bit command_type classifier; the new NavCommand::decode() -> NavInstruction returns a typed-enum disassembly tree clean-room
    per docs/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 (only 0x00..=0x0F and 0x80..=0x97 are 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 the Type-1 0x20 0x01 Link 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 / CallSS rows in mpucoder-vmi.html. CallSSTarget
      additionally carries the rsm_cell resume-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 (with af/sf/nf flag
      bits and per-channel register-or-immediate source), SetNvtmr,
      SetGprmMd (with counter mode bit), SetAmxMd, SetHlBtnn,
      Set { op, dst, src }. Compound Type 4..6 forms surface their
      classifier SetOp + CmpOp sub-ops via SetCLnk (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 return Invalid.
    • 42 new unit tests covering the Register GPRM / SPRM /
      invalid-hole classifier, the full SetOp / CmpOp /
      LinkSubset named-code tables, the spec's named-but-invalid
      sub-codes (SetSystem sub=5, Set sub=0/C/F, Type 0 cmd
      nibble 4..F, Link cmd nibble 2), the round-trip from a
      NavCommand::default() (all zero) decoding to Nop, and one
      decoded form per NavInstruction variant including the
      JumpSS four-way target selector and the CallSS rsm_cell field.
  • NAV-pack DSI typed sub-section decode (Data Search Information):
    the DsiPacket decoder 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 BCD c_eltm cell-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-bit ilvu flag word with
      preu() / is_ilvu() / ...
Read more

v0.0.1

21 May 16:45

Choose a tag to compare

chore: Release package oxideav-dvd version 0.0.1