const Graphics::Surface *QuickTimeDecoder::VideoTrackHandler::decodeNextFrame() { if (endOfTrack()) return 0; const Graphics::Surface *frame = bufferNextFrame(); if (_holdNextFrameStartTime) { // Don't set the next frame start time here; we just did a seek _holdNextFrameStartTime = false; } else if (_durationOverride >= 0) { // Use our own duration from the edit list calculation _nextFrameStartTime += _durationOverride; _durationOverride = -1; } else { _nextFrameStartTime += getFrameDuration(); } // Update the edit list, if applicable // HACK: We're also accepting the time minus one because edit lists // aren't as accurate as one would hope. if (!endOfTrack() && getRateAdjustedFrameTime() >= getCurEditTimeOffset() + getCurEditTrackDuration() - 1) { _curEdit++; if (!endOfTrack()) enterNewEditList(true); } if (_scaledSurface) { _decoder->scaleSurface(frame, _scaledSurface, _parent->scaleFactorX, _parent->scaleFactorY); return _scaledSurface; } return frame; }
uint32 QuickTimeDecoder::VideoTrackHandler::getNextFrameStartTime() { if (endOfTrack()) return 0; // Convert to milliseconds so the tracks can be compared return getRateAdjustedFrameTime() * 1000 / _parent->timeScale; }
void QuickTimeDecoder::VideoTrackHandler::enterNewEditList(bool bufferFrames) { // Bypass all empty edit lists first while (!endOfTrack() && _parent->editList[_curEdit].mediaTime == -1) _curEdit++; if (endOfTrack()) return; uint32 frameNum = 0; bool done = false; uint32 totalDuration = 0; uint32 prevDuration = 0; // Track down where the mediaTime is in the media for (int32 i = 0; i < _parent->timeToSampleCount && !done; i++) { for (int32 j = 0; j < _parent->timeToSample[i].count; j++) { if (totalDuration == (uint32)_parent->editList[_curEdit].mediaTime) { done = true; prevDuration = totalDuration; break; } else if (totalDuration > (uint32)_parent->editList[_curEdit].mediaTime) { done = true; frameNum--; break; } prevDuration = totalDuration; totalDuration += _parent->timeToSample[i].duration; frameNum++; } } if (bufferFrames) { // Track down the keyframe _curFrame = findKeyFrame(frameNum) - 1; while (_curFrame < (int32)frameNum - 1) bufferNextFrame(); } else { _curFrame = frameNum - 1; } _nextFrameStartTime = getCurEditTimeOffset(); // Set an override for the duration since we came up in-between two frames if (prevDuration != totalDuration) _durationOverride = totalDuration - prevDuration; }
uint32 VideoDecoder::FixedRateVideoTrack::getNextFrameStartTime() const { if (endOfTrack() || getCurFrame() < 0) return 0; Common::Rational time = (getCurFrame() + 1) * 1000; time /= getFrameRate(); return time.toInt(); }
void QuickTimeDecoder::VideoTrackHandler::seekToTime(Audio::Timestamp time) { // First, figure out what edit we're in time = time.convertToFramerate(_parent->timeScale); // Continue until we get to where we need to be for (_curEdit = 0; !endOfTrack(); _curEdit++) if ((uint32)time.totalNumberOfFrames() >= getCurEditTimeOffset() && (uint32)time.totalNumberOfFrames() < getCurEditTimeOffset() + getCurEditTrackDuration()) break; // This track is done if (endOfTrack()) return; enterNewEditList(false); // One extra check for the end of a track if (endOfTrack()) return; // Now we're in the edit and need to figure out what frame we need while (getRateAdjustedFrameTime() < (uint32)time.totalNumberOfFrames()) { _curFrame++; if (_durationOverride >= 0) { _nextFrameStartTime += _durationOverride; _durationOverride = -1; } else { _nextFrameStartTime += getFrameDuration(); } } // All that's left is to figure out what our starting time is going to be // Compare the starting point for the frame to where we need to be _holdNextFrameStartTime = getRateAdjustedFrameTime() != (uint32)time.totalNumberOfFrames(); // If we went past the time, go back a frame if (_holdNextFrameStartTime) _curFrame--; // Handle the keyframe here int32 destinationFrame = _curFrame + 1; assert(destinationFrame < (int32)_parent->frameCount); _curFrame = findKeyFrame(destinationFrame) - 1; while (_curFrame < destinationFrame - 1) bufferNextFrame(); }
bool FlicDecoder::FlicVideoTrack::rewind() { if (endOfTrack() && _fileStream->pos() < _fileStream->size() && _frameCount != 1) _atRingFrame = true; else _fileStream->seek(_offsetFrame1); _curFrame = -1; _nextFrameStartTime = 0; _frameDelay = _startFrameDelay; return true; }
uint32 VideoDecoder::FixedRateVideoTrack::getNextFrameStartTime() const { if (endOfTrack() || getCurFrame() < 0) return 0; return getFrameTime(getCurFrame() + 1).msecs(); }
const Graphics::Surface *QuickTimeDecoder::VideoTrackHandler::decodeNextFrame() { if (endOfTrack()) return 0; if (_reversed) { // Subtract one to place us on the frame before the current displayed frame. _curFrame--; // We have one "dummy" frame at the end to so the last frame is displayed // for the right amount of time. if (_curFrame < 0) return 0; // Decode from the last key frame to the frame before the one we need. // TODO: Probably would be wise to do some caching int targetFrame = _curFrame; _curFrame = findKeyFrame(targetFrame) - 1; while (_curFrame != targetFrame - 1) bufferNextFrame(); } const Graphics::Surface *frame = bufferNextFrame(); if (_reversed) { if (_holdNextFrameStartTime) { // Don't set the next frame start time here; we just did a seek _holdNextFrameStartTime = false; } else { // Just need to subtract the time _nextFrameStartTime -= getFrameDuration(); } } else { if (_holdNextFrameStartTime) { // Don't set the next frame start time here; we just did a seek _holdNextFrameStartTime = false; } else if (_durationOverride >= 0) { // Use our own duration from the edit list calculation _nextFrameStartTime += _durationOverride; _durationOverride = -1; } else { _nextFrameStartTime += getFrameDuration(); } // Update the edit list, if applicable // HACK: We're also accepting the time minus one because edit lists // aren't as accurate as one would hope. if (!atLastEdit() && getRateAdjustedFrameTime() >= getCurEditTimeOffset() + getCurEditTrackDuration() - 1) { _curEdit++; if (!atLastEdit()) enterNewEditList(true); } } if (frame && (_parent->scaleFactorX != 1 || _parent->scaleFactorY != 1)) { if (!_scaledSurface) { _scaledSurface = new Graphics::Surface(); _scaledSurface->create(getScaledWidth().toInt(), getScaledHeight().toInt(), getPixelFormat()); } _decoder->scaleSurface(frame, _scaledSurface, _parent->scaleFactorX, _parent->scaleFactorY); return _scaledSurface; } return frame; }