Skip to content

Video Decode (Cobra: .CB8 + .VDO)

The Cobra full-motion-video framework — EA's in-house movie player, not licensed middleware. A per-frame vector-quantization scheme: 2×2 codebooks rendered to 8/15/16/24 bpp with optional 2× pixel doubling. 0x456300–0x45CDA0.

Attribution corrected (#95): Cobra is first and foremost the CB8 playerInitCobra (0x46ae10) validates the DRBC container (rejecting the older ARBC/BRBC/CRBC generations), streams it through the engine's own LIB layer, and the 8-bit paletted path (DecodeFrame submode 5 → DecodeSVGA8Frame/DecodeDSVGA8Frame, ExpandDB/EDB, CopySB8/CopyDB8) is exactly the CB8 keyframe codec, with a 768-byte palette embedded per frame. The 15/16/24-bit submode-6 paths are the hi-color generalization. Note the shipped .VDO corpus does not run through this DecodeFrame dispatcher — those 320×200 8bpp movies decode via a separate, much smaller cluster (GetVDOFrameUnRLEDecompressVideo, 0x4C8Axx), documented in VDO.md (#138). DecodeFrame here is the CB8 player. The compiled-in engine structs, the LIB-layer I/O, and the private generation lineage mark the whole framework as homegrown (confirmed); the CB8 side is validated by fx_lib's pixel-exact codec (tests/test_cb8.cpp) and the on-disk layout is specified in CB8.md.

Provenance: Ghidra static analysis of the game executable with FA.SMS symbols applied; recorded in the symbol database and applied to the Ghidra project. Progress: reconstruction matrix. Markers follow spec-authoring.md: confirmed · inferred · unknown. Coordinates with the VDO format spec (epic #55).

Vector-quantized YUV, four output depths

Each frame carries a codebook of 256 entries, each 4 luma + 2 chroma decoded to four RGB pixels (a 2×2 block). DecodeDBook builds the book at 15/16-bit (5:5:5 or 5:6:5 chosen per frame), Decode24Book at 24-bit; the YUV→RGB conversion uses the per-movie scale/offset constants and saturates each channel through ClampU8 (the one recovered leaf in the range — the color clamp called from every book decoder). The 8-bit path (DecodeSVGA8Frame / DecodeDSVGA8Frame) renders paletted output with an interpolated 2×2 dither built by EDB (expand-book), optionally 2× doubled.

Frames are key (intra) or delta (inter) — the dispatch keys on the frame header, and the inter decoders are gated on the keyframe latch. .VDO audio is a separate .11K track, not interleaved in this cluster.

Cobra decode: per-frame codebook (DBook/24Book/EDB) decoded to RGB via ClampU8, rendered at 8/15/16/24 bpp with optional 2x doubling.

VDO container & Cobra lifecycle

Around the frame decoders sit two support layers the game already names. The Cobra lifecycle brings the movie framework up and down against the GlobalData block — InitVideo/SetupCobra on entry, CleanVideo/CleanCobra/CleanupCobra on teardown — and StartCobraSound/StopCobraSound gate its audio. The .VDO container layer is the 320×200 8bpp path (the shipped .VDO corpus, distinct from the DecodeFrame CB8 dispatcher): a VDOLinkedList of nodes read from disk, then decoded frame by frame.

VA Symbol Role
0x46B120 InitVideo bring the video/Cobra framework up (GlobalData)
0x46B4E0 SetupCobra configure the Cobra player
0x46B0F0 CleanCobra release Cobra decode state
0x46B4B0 CleanVideo tear the video framework down
0x46B530 CleanupCobra final Cobra teardown
0x4219D0 StartCobraSound start the movie's audio track
0x4219B0 StopCobraSound stop the movie's audio track
0x442360 InitMovieContext zero/size a MovieContext
0x4AEE80 BuildVDOList build the VDOLinkedList for a .VDO file
0x4AF100 NewVDOLinkNode append a node to the list
0x4AF1B0 FreeVDOLinkNode free one list node
0x4AF1E0 OpenVDOFile open the .VDO file
0x4AF200 ReadVDOHeader read the VDOHEADER
0x4AF230 ReadFrameSizesFile read the per-frame size table
0x4AF2D0 ReadVDOPalette read the movie palette into T_RGB[]
0x4AF3A0 AllocVDO allocate the VDO playback buffers
0x4AF4B0 DeallocVDO free them
0x4AF070 StartVDOAudio start the .11K audio track
0x4C8CD8 DecompressVideoImage decompress one .VDO image (the 8bpp path)

Functions

Full record: db/symbols/video.csv.

VA Symbol Role
0x457230 DecodeDBook decode the 15/16-bit YUV codebook
0x456300 DecodeDSVGA8Frame key frame → 8bpp paletted, 2× doubled
0x456EC0 DecodeSVGA8Frame key frame → 8bpp paletted
0x456AD0 EDB expand-book: interpolated 2×2 dither pattern
0x4575E0 ClampU8 saturate a channel to [0,255] (YUV→RGB leaf)
0x4054B0 ZeroFrame clear a VDO frame buffer (follows VDOInit)
0x46ADC0 WritePalette write a palette range to the display
0x46ADF0 SetVESABank select the active VESA bank
0x46AE00 SetVESATop set the VESA display start
0x4C8BEC BuildSelfModifyCode self-modifying blit codegen (video-decompress unit)
0x4C8C60 DoNibble nibble-stream helper for the decompressors
0x4CCD14 CopySB15 15-bit single-buffer copy (pairs CopySB8)
0x4CCD70 CopyDB15 15-bit double-buffer copy
0x4CCDF8 CopyDSB15 15-bit double-to-single copy
0x4CCE7C CopyDDB15 15-bit double-to-double copy
0x4CCF88 ExpandSB expand a single-buffer frame
0x4CCFE1 clampit_ YUV clamp helper (precedes DecodeYUV15)
0x4AE350 CenterPrint centered-text helper (VDO subtitle print)
0x4AF030 FileExists VDO unit's file probe
0x4AF050 FileSize VDO unit's file-size query
0x4127B0 ScreenDump screenshot writer (mhwa/nh header + palette + framebuffer)

Vendored libjpeg

Five IJG libjpeg support leaves (jdiv_round_up/jround_up/jcopy_sample_rows/ jcopy_block_row/jzero_far, 0x4760600x476100) are statically linked into the executable — the game's still-image JPEG path, not the Cobra/VDO codec. As vendored third-party code they are carried in the DB as waivers (source=waiver): they clear the #482 unclaimed ratchet without being counted as first-party reconstruction. (Their FA.SMS neighbours are the jdpostct block that carries the misapplied PilotSetField label — see shell-ui.md § Open Questions.)

Open Questions

1. VDO.md corrections — resolved

The three VDO.md inaccuracies are now reconciled (#259): the DecodeFrame dispatch keys are documented on the FrameHeader (+8 kind, +9 submode), not the movie context; the frame-kind polarity is corrected (0 = key/intra, 1 = inter/delta); and the 0xC14E canvas pointer is attributed to GlobalData. The Cobra per-frame codec itself (the ~45 leaf decoders) remains the long pole, tracked under epic #55.

Status: resolved — re-static (#259; the codec long-pole stays under #55).