Files
psxrecomp/runtime/include/mdec.h
T
Matthew Stanley 46a653aa63 feat(fmv): auto-skip FMVs via the game's own skip + launcher toggle
Adds an opt-in "skip full-motion videos" feature ([video] auto_skip_fmv,
default off). A streaming FMV is detected as active MDEC decode
(mdec_get_decode_count climbing per vblank) + cdrom_xa_stream_active();
while detected, the frontend injects START into pad slot 0 so the game's
OWN FMV player aborts the movie and jumps cleanly to the next screen —
instant, invisible, and desync-free, with all guest state correct.

Mechanism notes (why this and not the alternatives):
- Flooding XA sectors ('instant' CD during streaming) desyncs the player
  and hangs the movie on a white screen — rejected.
- Uncapped-pacing fast-forward is safe but slow and choppy (plays the
  whole stream) — rejected.
- Triggering the game's native skip is instant and correct. Injection is
  gated on raw xa_stream_active so START stops the moment the FMV ends and
  never bleeds into the next screen (verified: title stays interactive).
Present/pacing are suppressed + audio muted as a safety net for the 1-2
frames before the game's abort takes effect.

Plumbed end-to-end: config_loader [video] auto_skip_fmv + UserSettings
(settings.toml load/save), main.cpp detector/injection + settings layering
+ launcher seed/apply, and a "Skip FMVs" toggle in the launcher Settings
(launcher.cpp + launcher.rml), mirroring the existing SPU/AA toggles.
Runtime-only; no emitter/regen impact.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-14 15:29:01 -07:00

78 lines
2.1 KiB
C

#ifndef PSXRECOMP_MDEC_H
#define PSXRECOMP_MDEC_H
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
void mdec_init(void);
uint32_t mdec_read(uint32_t addr);
void mdec_write(uint32_t addr, uint32_t value);
void mdec_dma_write_word(uint32_t value);
uint32_t mdec_dma_read_word(void);
int mdec_dma_write_ready(void);
int mdec_dma_read_ready(void);
typedef struct MDECDebugState {
uint32_t command;
uint32_t expected_halfwords;
uint32_t input_count;
uint32_t output_size;
uint32_t output_pos;
uint32_t output_depth;
uint32_t output_signed;
uint32_t output_bit15;
uint32_t busy;
uint32_t input_full;
uint32_t enable_dma_in;
uint32_t enable_dma_out;
uint32_t last_status;
uint32_t decode_macroblocks;
uint32_t decode_blocks;
uint32_t decode_stop_reason;
uint32_t decode_input_pos;
uint32_t decode_input_end;
uint32_t dma_in_words;
uint32_t dma_out_words;
uint32_t dma_read_underflows;
} MDECDebugState;
typedef struct MDECDebugEvent {
uint64_t seq;
uint32_t frame;
uint32_t kind;
uint32_t value;
uint32_t command;
uint32_t input_count;
uint32_t expected_halfwords;
uint32_t output_size;
uint32_t output_pos;
uint32_t macroblocks;
uint32_t blocks;
uint32_t stop_reason;
uint32_t underruns;
} MDECDebugEvent;
/* Monotonic decode-invocation counter — frontend FMV detector samples this
* per display-frame to detect active MDEC video (FMV) vs idle. */
uint32_t mdec_get_decode_count(void);
void mdec_debug_get_state(MDECDebugState *out);
uint64_t mdec_debug_get_event_total(void);
uint32_t mdec_debug_copy_events(uint64_t seq_lo, uint64_t seq_hi,
MDECDebugEvent *out, uint32_t max_count);
void mdec_debug_clear(void);
void mdec_debug_dma_in_start(uint32_t addr, uint32_t words);
void mdec_debug_dma_in_end(uint32_t addr, uint32_t words);
void mdec_debug_dma_out_start(uint32_t addr, uint32_t words);
void mdec_debug_dma_out_end(uint32_t addr, uint32_t words);
#ifdef __cplusplus
}
#endif
#endif /* PSXRECOMP_MDEC_H */