CNA-BUG-145: VideoDecoder::SetVideoStream switches to another video stream mid-playback without seeking, so decoding resumes at a non-keyframe position
Evidence basis: source-verified at the pinned commit; inferred from the source (the behaviour was not run); 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 genuine SetVideoTrackEXT switch during playback opens a fresh codec context at the demuxer's current position without a seek or flush; CNA's own comment explains that such a context fails on the next non-keyframe.
- Identifier
CNA-BUG-145- Category
- Bug
- Subsystem
- Audio & media
- Status
- Open
- Verified against
- CNA
009d40f5(009d40f5dd085c4e674d3479675fac84b12b3e0a) - Severity
- Low (a triage suggestion, not a project priority)
- Evidence basis
- Inferred (strong): follows from the code, but the behaviour was not run
- Tests touching this area
- Yes: see Current tests
- Affected contract
- VideoPlayer::SetVideoTrackEXT(intcs) and Video::SetVideoTrackEXT(intcs) during playback
Expected behaviour
After a switch to another video stream, GetTexture continues with frames of the new stream at the current play position (decoding from the preceding keyframe), or the method is documented as effective only before Play.
Actual behaviour at TARGET
VideoPlayer::SetVideoTrackEXT (VideoPlayer.cpp) calls VideoDecoder::SetVideoStream during playback and, on a real switch, only recreates the frame texture. OpenVideoStreamByIndex in VideoDecoder.cpp frees the old codec context and opens a new one with no demuxer seek and no flush, so the new stream's decoding starts from whatever packet comes next. The comment in SetVideoStream describes the consequence for the same-stream case it now avoids: a context recreated mid-stream “has no reference frame to decode the very next (non-keyframe) packet against” and the send fails. havePendingVideoPacket_ is not cleared either, so a packet of the old stream retained after an EAGAIN would be sent to the new decoder. The resulting exception surfaces through GetTexture (see the entry on its exceptions). A preference set before Play is applied right after Open, at the start of the file, and is not affected.
Source locations
modules/video-ffmpeg/src/VideoDecoder.cpp— VideoDecoder::SetVideoStream, OpenVideoStreamByIndex, NextFrame (havePendingVideoPacket_)modules/media/src/Xna/Video/VideoPlayer.cpp— VideoPlayer::SetVideoTrackEXT, OpenDecodermodules/media/tests/CNA/Internal/Media/VideoDecoderTests.cpp— SetVideoStreamReselectingTheSameStreamPreservesDimensions
Evidence
Checked by reading at 009d40f5; not executed. That the new context starts mid-stream is mechanical; whether the next packet is rejected or decoded into artefacts depends on the codec and on the keyframe spacing, which is why the confidence is strong rather than verified. No fixture has two video streams.
Focused reproduction
No focused reproduction is known. Nothing has been invented here; the evidence above is what exists.
Current tests
VideoDecoderTests.cpp tests only re-selecting the single video stream of multi_track_audio.mkv, and its comment records that no second-video-stream fixture exists. Audio stream switching is tested.
Regression test
A fixture with two video streams of different sizes and a keyframe interval shorter than the file: play, advance past the first keyframe, switch to stream 1, and require frames of the new size from GetTexture without an exception.
Blast radius
Games that switch video tracks while a multi-video-stream file is playing, with the FFmpeg backend. Track selection before playback and audio track switching are unaffected.
Workaround
Select the video track before Play, or Stop, select, and Play again.
Related pages
The same subject is explained at several altitudes. These are the neighbouring pages at each one.
- User guide
- Video playback: VideoPlayer
- Known issues
- Bug index