Commit Graph
10 Commits
Author SHA1 Message Date
Henrik RydgårdandClaude Opus 5.5 22348ddbff UMD Video: Give a field pair one SEI record per field
Family Guy and The Dark Knight are coded as separate field pictures,
bottom field first. ffmpeg hands each pair back as one frame, and we
described it with the first field's SEI record only.

The UMD Video player (video_main_plugin.prx) shows such a picture a field
per vsync, and takes the field order from comparing the output times of
the picture's two records. With the second left empty it always chose
top first, so every pair ran backwards in time and the picture jittered
between frames. Now the pair carries both fields' timing, the top field's
record first.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-25 16:51:24 +01:00
Henrik RydgårdandClaude Opus 5.5 6c8c71a125 AvcDecoder: Keep the output clock going when a new stream is spliced on
Burnout Legends feeds its intro movies to one decoder back to back, with
no flush in between. Each new stream opens with a buffering period whose
cpb_removal_delay is 0, which put our reconstructed clock 18 frames back,
so every picture after it was held until the clock caught up, and then
20 came out of one decode. sceMpegAvcDecodeYCbCr converts every picture
a decode reports into the caller's buffer list, which only has room for
one, so mpeg.prx went on through stack garbage and crashed as the title
screen came up.

Such a buffering period now continues from the last access unit instead.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-22 21:02:36 +02:00
Henrik RydgårdandClaude Opus 5.5 9f5d074a0e sceVideocodec: Picture records, SEI and sequence timing, for UMD Video
The VSH's UMD Video player reads what the ME writes beside each decoded
picture, which games' mpeg.prx only passes through (pspautotests
video/mpeg/avcdetail, recorded on a PSP):

- Given a 0x540-byte buffer at ctx+0x38, as mpeg_vsh.prx provides in the
  modes the player uses, the ME points each picture descriptor's +0x24
  and +0x28 at two 0xA4-byte records for it. The first is the picture's
  SEI record: cpb_removal_delay at +0x18, dpb_output_delay at +0x1C, the
  pic_struct at +0x20 (which the player picks a duration with), and flags
  of 7 for a keyframe and 2 otherwise. sceVideocodecGetSEI writes the
  record of the last access unit decoded to the buffer at ctx+0x50.
- A descriptor's +0x20 is 1 for a keyframe. The player drops every
  picture after starting or seeking until it sees one.
- The 0x64 bytes at ctx+0x30 carry the VUI timing (num_units_in_tick at
  240000 ticks a second), which the player checks against 5005 for film.

All of it comes from what ffmpeg's H.264 parser reports per access unit,
which AvcDecoder now hands back with each picture.

Each picture also goes into the next of the four frame stores, as the ME
rotates through its own: the player converts a picture in strips spread
over its next few frames, while decoding goes on.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-21 17:32:44 +02:00
Henrik RydgårdandClaude Opus 5.5 8d2fbf7079 sceVideocodec: Hand pictures back when the PSP's decoder does
The PSP's AVC decoder follows the H.264 output process (Annex C),
measured in the new pspautotests video/mp4/avchold on streams that
differ only in their headers, and video/mpeg/decodeend. With HRD
parameters and picture timing SEI, a picture comes out dpb_output_delay
after its access unit; Sony's movies have a one frame delay. Without, it
is bumped out of a buffer three frames deep, whatever the stream
declares. sceMpegAvcDecodeStop hands back what's left, and streams with
more than three reference frames are refused with 0x80628002.

We handed each picture back as soon as it was decoded. MGS Peace
Walker's movie player only checks for the end of a movie while its
clock is short of the movie's length, so its last picture landed right
on that limit and the game hung on a black screen after the cutscene.

ffmpeg still decodes the pixels, in display order; each access unit is
tagged with its index so frames can be matched back, and ffmpeg's H.264
parser supplies the picture timing. A call can now hand back several
pictures, as consecutive 0x2C byte descriptors the way mpeg.prx's
sceMpegAvcDecodeStop reads them, each in a frame buffer slot of its own
(reallocated when a savestate brings a block too small for that).

Not followed: with B-frames and no picture timing, the PSP can complete
several pictures in one call; here they come out one a call. All of
the game movies checked have picture timing.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-18 11:25:55 +02:00
Henrik RydgårdandClaude Opus 5.5 8f70003cce Remove the PaceVideocodecDecode workaround for Ys I & II
The blit cost model now paces its movies at 30 fps without it.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-25 16:44:28 -06:00
Henrik RydgårdandClaude Opus 5 282647803c Add PaceVideocodecDecode compat.ini option
There are a few games that seem to rely on performance problems or
timing quirks to hold the correct pace when playing sceMpeg - have not
been able to nail down any other timing mechanism.

This adds a timing enforcement function.

Coded by Claude.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-21 09:00:48 -06:00
Henrik Rydgård 4d259a6f95 De-claude the comments. 2026-09-20 16:39:35 -06:00
Henrik RydgårdandClaude Opus 5 8a343bec57 AvcDecoder: let ffmpeg say when a frame came out damaged
Nothing on this path ever called InitFFmpeg, so ffmpeg's log callback was never
installed and everything it had to say about the bitstream went nowhere. Our own
return codes only report that a frame arrived, not what it was built from, so a
video could fall apart on screen while the log showed two warnings in two
thousand frames.

Also report decode_error_flags and AV_FRAME_FLAG_CORRUPT per frame, which covers
the other half: a frame that decodes "successfully" out of concealment. Coalesced
into one line per run of damage, since a missing reference makes every frame
damaged until the next keyframe.

Not setting AV_EF_EXPLODE, which would make the decoder fail where it currently
conceals - that is a behaviour change, and this is meant to be a reporting one.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-20 16:39:35 -06:00
Henrik RydgårdandClaude Opus 5 b4b8e2e733 AvcDecoder: Check the pixel format
AvcDecoder handed out frame_->data[0..2] without looking at the pixel format,
and everything downstream indexes them as 8-bit 4:2:0. Check it, and drop the
frame instead of converting whatever else turned up.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-12 12:53:13 -06:00
Henrik RydgårdandClaude Opus 5 3276cdf65f Add AvcDecoder, a plain access-unit-in, frame-out H.264 decoder
sceVideocodec is the interface the Media Engine really exposes: the caller owns
the buffers and hands over one access unit at a time. MediaEngine can't serve
that shape - it is built around sceMpeg's own model, with the PSMF demuxer, the
ringbuffer and its own frame pacing wrapped around the decoder - so this is a
second, separate path rather than a refactor of code every game that plays
video depends on. Merging the two is worth doing once sceVideocodec has earned
its keep.

Nothing calls it yet; sceVideocodec is the next piece.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-12 12:53:13 -06:00