mirror of
https://github.com/tangerineturtle1/NX2navi.git
synced 2026-11-15 19:19:58 -04:00
Check the movie decoder under its lock in DecodeAsync, so a sample after Finalize cannot hold the movie frame rate cap.
ov_decode tested v->dav1d without a lock and then queued the sample under v->lock and ran set_live(v, 1). A DecodeAsync on one guest thread racing Finalize on another could pass the test, wait for the lock while finalize closed the decoder and cleared the queues, and then queue the sample and mark the finalized decoder live again: movies_live stayed 1 with no decoder until the destructor or the next Initialize, and frame_rate.c movie_cap_hz kept the movie's frame rate cap meanwhile. ov_decode now reads v->dav1d again under v->lock and returns without queueing when it is gone. finalize takes v->lock after it clears v->dav1d, so the read either sees it set (the sample is queued before finalize's clear_queues, which drops it, and ov_finalize or the destructor then clears live) or sees NULL. Not reproduced before the change: the game's own ordering normally keeps DecodeAsync and Finalize apart, and no unit check exists without dav1d stubs. movie_planes_check passes, and the compile check adds no warnings. The movie play-test's "frame rate: the movie ended" line after each movie confirms it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -782,6 +782,15 @@ static void ov_decode(Cpu *c) {
|
||||
if (skip_ns >= 0) rt_log("movie: movies end after %.1f s (NX2NAVI_MOVIE_SKIP)", skip_ns / 1e9);
|
||||
}
|
||||
plat_mutex_lock(&v->lock);
|
||||
// Finalize on another thread may have closed the decoder since the test above. finalize takes v->lock after it
|
||||
// clears v->dav1d, so read here under v->lock it is either still set (the sample is queued before finalize's
|
||||
// clear_queues, which drops it, and ov_finalize or the destructor then clears live) or already NULL: no sample
|
||||
// makes a finalized decoder live again, which would hold the movie frame rate cap (frame_rate.c movie_cap_hz).
|
||||
if (!v->dav1d) {
|
||||
plat_mutex_unlock(&v->lock);
|
||||
ret_x(c, 0);
|
||||
return;
|
||||
}
|
||||
if (skip_ns >= 0 && v->eos_queued) { // after the early end: what the demuxer still sends is dropped
|
||||
plat_mutex_unlock(&v->lock);
|
||||
ret_x(c, 0);
|
||||
|
||||
Reference in New Issue
Block a user