Skip to content

Commit

Permalink
VIDEO: Fix QuickTime regression with mediaTime and dithering
Browse files Browse the repository at this point in the history
Fixes an error when playing a QuickTime video that has a mediaTime set
on its first edit. This was caused by mediaTime changes in:
ef184a6

Those changes buffered frames during initialization so that the keyframe
and other frames don't play instead of the intended start frame that
mediaTime specifies. My mistake was that decoding isn't allowed during
VideoDecoder::loadStream(); VideoDecoder::setDitheringPalette() requires
that no frames have been decoded yet, and Director calls that.

Now the initial mediaTime buffering is delayed until the first decode.

Fixes bug #13479 where certain Myst videos error.
Fixes the opening movie in the Director game Chop Suey.
  • Loading branch information
sluicebox committed Aug 4, 2022
1 parent 61eae10 commit a6eed66
Show file tree
Hide file tree
Showing 2 changed files with 28 additions and 5 deletions.
30 changes: 26 additions & 4 deletions video/qt_decoder.cpp
Expand Up @@ -299,7 +299,8 @@ QuickTimeDecoder::VideoTrackHandler::VideoTrackHandler(QuickTimeDecoder *decoder

_curEdit = 0;
_curFrame = -1;
enterNewEditListEntry(true); // might set _curFrame
_delayedFrameToBufferTo = -1;
enterNewEditListEntry(true, true); // might set _curFrame

_durationOverride = -1;
_scaledSurface = 0;
Expand Down Expand Up @@ -369,6 +370,8 @@ bool QuickTimeDecoder::VideoTrackHandler::endOfTrack() const {
}

bool QuickTimeDecoder::VideoTrackHandler::seek(const Audio::Timestamp &requestedTime) {
_delayedFrameToBufferTo = -1; // abort any delayed buffering

uint32 convertedFrames = requestedTime.convertToFramerate(_decoder->_timeScale).totalNumberOfFrames();
for (_curEdit = 0; !atLastEdit(); _curEdit++)
if (convertedFrames >= _parent->editList[_curEdit].timeOffset && convertedFrames < _parent->editList[_curEdit].timeOffset + _parent->editList[_curEdit].trackDuration)
Expand Down Expand Up @@ -580,6 +583,8 @@ const byte *QuickTimeDecoder::VideoTrackHandler::getPalette() const {
}

bool QuickTimeDecoder::VideoTrackHandler::setReverse(bool reverse) {
_delayedFrameToBufferTo = -1; // abort any delayed buffering

_reversed = reverse;

if (_reversed) {
Expand Down Expand Up @@ -721,7 +726,7 @@ bool QuickTimeDecoder::VideoTrackHandler::isEmptyEdit() const {
return (_parent->editList[_curEdit].mediaTime == -1);
}

void QuickTimeDecoder::VideoTrackHandler::enterNewEditListEntry(bool bufferFrames) {
void QuickTimeDecoder::VideoTrackHandler::enterNewEditListEntry(bool bufferFrames, bool initializingTrack) {
if (atLastEdit())
return;

Expand Down Expand Up @@ -765,8 +770,15 @@ void QuickTimeDecoder::VideoTrackHandler::enterNewEditListEntry(bool bufferFrame
// Track down the keyframe
// Then decode until the frame before target
_curFrame = findKeyFrame(frameNum) - 1;
while (_curFrame < (int32)frameNum - 1)
bufferNextFrame();
if (initializingTrack) {
// We can't decode frames during track initialization,
// so delay buffering until the first decode.
_delayedFrameToBufferTo = (int32)frameNum - 1;
} else {
while (_curFrame < (int32)frameNum - 1) {
bufferNextFrame();
}
}
} else {
// Since frameNum is the frame that needs to be displayed
// we'll set _curFrame to be the "last frame displayed"
Expand All @@ -777,6 +789,16 @@ void QuickTimeDecoder::VideoTrackHandler::enterNewEditListEntry(bool bufferFrame
}

const Graphics::Surface *QuickTimeDecoder::VideoTrackHandler::bufferNextFrame() {
// Buffer any frames that were identified during track initialization
// and delayed until decoding.
if (_delayedFrameToBufferTo != -1) {
int32 frameNum = _delayedFrameToBufferTo;
_delayedFrameToBufferTo = -1;
while (_curFrame < frameNum) {
bufferNextFrame();
}
}

_curFrame++;

// Get the next packet
Expand Down
3 changes: 2 additions & 1 deletion video/qt_decoder.h
Expand Up @@ -155,6 +155,7 @@ class QuickTimeDecoder : public VideoDecoder, public Audio::QuickTimeAudioDecode
Common::QuickTimeParser::Track *_parent;
uint32 _curEdit;
int32 _curFrame;
int32 _delayedFrameToBufferTo;
uint32 _nextFrameStartTime; // media time
Graphics::Surface *_scaledSurface;
int32 _durationOverride; // media time
Expand All @@ -172,7 +173,7 @@ class QuickTimeDecoder : public VideoDecoder, public Audio::QuickTimeAudioDecode
uint32 getCurFrameDuration(); // media time
uint32 findKeyFrame(uint32 frame) const;
bool isEmptyEdit() const;
void enterNewEditListEntry(bool bufferFrames);
void enterNewEditListEntry(bool bufferFrames, bool intializingTrack = false);
const Graphics::Surface *bufferNextFrame();
uint32 getRateAdjustedFrameTime() const; // media time
uint32 getCurEditTimeOffset() const; // media time
Expand Down

0 comments on commit a6eed66

Please sign in to comment.