CNA-BUG-144: VideoPlayer::GetTexture lets the decoder's std::runtime_error escape, undocumented, and leaves the player Playing
Evidence basis: source-verified at the pinned commit; tests exist (not executed for this page). Claims on this page were checked by reading the CNA source at commit 009d40f5; unless a sentence says otherwise, nothing here was built or executed. Nothing on this page was executed unless the Evidence section says so.
A decode, packet, resample or I/O error mid-stream is thrown by VideoDecoder::NextFrame as std::runtime_error through GetTexture, whose header documents only ObjectDisposedException, and the player stays Playing so the next call tries again.
- Identifier
CNA-BUG-144- Category
- Bug
- Subsystem
- Audio & media
- Status
- Open
- Verified against
- CNA
009d40f5(009d40f5dd085c4e674d3479675fac84b12b3e0a) - Severity
- Low (a triage suggestion, not a project priority)
- Evidence basis
- Source-verified: read at TARGET, not executed
- Tests touching this area
- Yes: see Current tests
- Affected contract
- VideoPlayer::GetTexture() exceptions and the player state after a mid-stream decode failure
Expected behaviour
VideoPlayer.hpp documents GetTexture as throwing ObjectDisposedException only. Play treats a decoder failure transactionally: OpenDecoder catches, closes the decoder, resets the state to Stopped and rethrows. The frame path should either be documented as throwing, with a defined state afterwards, or report the failure through the state.
Actual behaviour at TARGET
GetTexture in VideoPlayer.cpp loops over decoder_->NextFrame and DrainAndFlushAudioBuffer with no try. NextFrame and ProcessAudioPacket in VideoDecoder.cpp throw std::runtime_error for a video decode error, a rejected or failed packet send, a failed flush, a demux I/O error and audio decode or resample failures (a deliberate change so that corruption is no longer mistaken for end of stream). The exception reaches the caller, usually inside Draw. It is not a System::Exception, so a handler written for that type misses it. The player stays Playing with the decoder open, and every later GetTexture re-enters the decoder.
Source locations
modules/media/src/Xna/Video/VideoPlayer.cpp— VideoPlayer::GetTexture (no try) versus OpenDecoder (catch, CloseDecoder, rethrow)modules/video-ffmpeg/src/VideoDecoder.cpp— VideoDecoder::NextFrame and ProcessAudioPacket throw sitesmodules/media/include/Microsoft/Xna/Framework/Media/Video/VideoPlayer.hpp— GetTexture documentationmodules/media/tests/CNA/Internal/Media/VideoDecoderTests.cpp— CorruptedMidStreamDataThrowsRatherThanSilentlyEndingCleanly
Evidence
Checked by reading at 009d40f5; not executed. The decoder-level throw is pinned by VideoDecoderTest.CorruptedMidStreamDataThrowsRatherThanSilentlyEndingCleanly; what the player does with it follows from GetTexture's code.
Focused reproduction
No focused reproduction is known. Nothing has been invented here; the evidence above is what exists.
Current tests
VideoDecoderTests.cpp pins the throw at decoder level with corrupt_test_h264.mp4. VideoPlayerTests.cpp has no case that plays a corrupt file through GetTexture.
Regression test
Play corrupt_test_h264.mp4 through a VideoPlayer and call GetTexture until the corruption is reached; require the documented outcome (for example an exception of a documented type followed by Stopped) and no second throw from the next call.
Blast radius
Builds with the FFmpeg backend playing corrupt or truncated-in-the-middle files. Clean files and trailing truncation of Matroska files (reported as end of stream) are unaffected.
Workaround
Catch std::exception around GetTexture and call Stop() on failure.
Related pages
The same subject is explained at several altitudes. These are the neighbouring pages at each one.
- User guide
- Video playback: the rendering pattern
- Known issues
- Bug index