예제 #1
0
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;
}
예제 #2
0
void FFMPEGMovie::_consume()
{
    while( !_stopConsuming )
    {
        {
            std::unique_lock<std::mutex> lock( _targetMutex );
            while( !_targetChangedSent )
                _targetChanged.wait( lock );
            _targetChangedSent = false;

            if( _stopConsuming )
                return;

            if( _seekTo( _targetTimestamp ))
                _ptsPosition = UNDEFINED_PTS; // Reset position after seeking
        }

        PicturePtr frame;
        while( !_stopConsuming && _getPtsDelta() >= getFrameDuration() && !isAtEOF( ))
        {
            frame = _queue.dequeue();
            _ptsPosition = _videoStream->getPositionInSec( frame->getTimestamp( ));
        }

        if( !frame )
        {
            auto exception = std::runtime_error( "Frame unavailable error" );
            _promise.set_exception( std::make_exception_ptr( exception ));
            return;
        }

        _promise.set_value( frame );
    }
}
예제 #3
0
void Sprite::removeFrame(FrameNumber newFrame)
{
  FrameNumber newTotal = m_frames.previous();
  for (FrameNumber i=newFrame; i<newTotal; i=i.next())
    setFrameDuration(i, getFrameDuration(i.next()));
  setTotalFrames(newTotal);
}
예제 #4
0
const Graphics::Surface *QuickTimeDecoder::decodeNextFrame() {
	if (_videoStreamIndex < 0 || _curFrame >= (int32)getFrameCount() - 1)
		return 0;

	if (_startTime == 0)
		_startTime = g_system->getMillis();

	_curFrame++;
	_nextFrameStartTime += getFrameDuration();

	// Update the audio while we're at it
	updateAudioBuffer();

	// Get the next packet
	uint32 descId;
	Common::SeekableReadStream *frameData = getNextFramePacket(descId);

	if (!frameData || !descId || descId > _streams[_videoStreamIndex]->stsdEntryCount)
		return 0;

	// Find which video description entry we want
	STSDEntry *entry = &_streams[_videoStreamIndex]->stsdEntries[descId - 1];

	if (!entry->videoCodec)
		return 0;

	const Graphics::Surface *frame = entry->videoCodec->decodeImage(frameData);
	delete frameData;

	// Update the palette
	if (entry->videoCodec->containsPalette()) {
		// The codec itself contains a palette
		if (entry->videoCodec->hasDirtyPalette()) {
			_palette = entry->videoCodec->getPalette();
			_dirtyPalette = true;
		}
	} else {
		// Check if the video description has been updated
		byte *palette = entry->palette;

		if (palette != _palette) {
			_palette = palette;
			_dirtyPalette = true;
		}
	}

	return scaleSurface(frame);
}
예제 #5
0
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();
}
예제 #6
0
void QuickTimeDecoder::processData() {
	if (_curFrame >= (int32)_tracks[_videoTrackIndex]->frameCount - 1) {
		finish();
		return;
	}

	if (getTimeToNextFrame() > 0)
		return;

	_curFrame++;
	_nextFrameStartTime += getFrameDuration();

	// Update the audio while we're at it
	updateAudioBuffer();

	// Get the next packet
	uint32 descId;
	Common::SeekableReadStream *frameData = getNextFramePacket(descId);

	if (!frameData || !descId || descId > _tracks[_videoTrackIndex]->sampleDescs.size()) {
		delete frameData;
		return;
	}

	// Find which video description entry we want
	VideoSampleDesc *entry = (VideoSampleDesc *)_tracks[_videoTrackIndex]->sampleDescs[descId - 1];

	if (entry->_videoCodec) {
		assert(_surface);

		entry->_videoCodec->decodeFrame(*_surface, *frameData);
		_needCopy = true;
	}

	delete frameData;
}
예제 #7
0
bool QuickTimeDecoder::VideoTrackHandler::setReverse(bool reverse) {
	_reversed = reverse;

	if (_reversed) {
		if (_parent->editCount != 1) {
			// TODO: Myst's holo.mov needs this :(
			warning("Can only set reverse without edits");
			return false;
		}

		if (atLastEdit()) {
			// If we're at the end of the video, go to the penultimate edit.
			// The current frame is set to one beyond the last frame here;
			// one "past" the currently displayed frame.
			_curEdit = _parent->editCount - 1;
			_curFrame = _parent->frameCount;
			_nextFrameStartTime = _parent->editList[_curEdit].trackDuration + _parent->editList[_curEdit].timeOffset;
		} else if (_holdNextFrameStartTime) {
			// We just seeked, so "pivot" around the frame that should be displayed
			_curFrame++;
			_nextFrameStartTime -= getFrameDuration();
			_curFrame++;
		} else {
			// We need to put _curFrame to be the one after the one that should be displayed.
			// Since we're on the frame that should be displaying right now, add one.
			_curFrame++;
		}
	} else {
		// 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())
				return true;
		}

		if (_holdNextFrameStartTime) {
			// We just seeked, so "pivot" around the frame that should be displayed
			_curFrame--;
			_nextFrameStartTime += getFrameDuration();
		}

		// We need to put _curFrame to be the one before the one that should be displayed.
		// Since we're on the frame that should be displaying right now, subtract one.
		// (As long as the current frame isn't -1, of course)
		if (_curFrame > 0) {
			// We then need to handle the keyframe situation
			int targetFrame = _curFrame - 1;
			_curFrame = findKeyFrame(targetFrame) - 1;
			while (_curFrame < targetFrame)
				bufferNextFrame();
		} else if (_curFrame == 0) {
			// Make us start at the first frame (no keyframe needed)
			_curFrame--;
		}
	}

	return true;
}
예제 #8
0
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;
}
예제 #9
0
bool QuickTimeDecoder::VideoTrackHandler::seek(const Audio::Timestamp &requestedTime) {
	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)
			break;

	// If we did reach the end of the track, break out
	if (atLastEdit())
		return true;

	// If this track is in an empty edit, position us at the next non-empty
	// edit. There's nothing else to do after this.
	if (_parent->editList[_curEdit].mediaTime == -1) {
		while (!atLastEdit() && _parent->editList[_curEdit].mediaTime == -1)
			_curEdit++;

		if (!atLastEdit())
			enterNewEditList(true);

		return true;
	}

	enterNewEditList(false);

	// One extra check for the end of a track
	if (atLastEdit())
		return true;

	// Now we're in the edit and need to figure out what frame we need
	Audio::Timestamp time = requestedTime.convertToFramerate(_parent->timeScale);
	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. _curFrame before this point is at the frame
	// that should be displayed. This adjustment ensures it is on the frame before the one that
	// should be displayed.
	if (_holdNextFrameStartTime)
		_curFrame--;

	if (_reversed) {
		// Call setReverse again to update
		setReverse(true);
	} else {
		// Handle the keyframe here
		int32 destinationFrame = _curFrame + 1;

		assert(destinationFrame < (int32)_parent->frameCount);
		_curFrame = findKeyFrame(destinationFrame) - 1;
		while (_curFrame < destinationFrame - 1)
			bufferNextFrame();
	}

	return true;
}
예제 #10
0
uint_fast32_t getBitmap(argb *bm, GifInfo *info) {
    drawNextBitmap(bm, info);
    return getFrameDuration(info);
}
예제 #11
0
void Sprite::addFrame(FrameNumber newFrame)
{
  setTotalFrames(m_frames.next());
  for (FrameNumber i=m_frames.previous(); i>=newFrame; i=i.previous())
    setFrameDuration(i, getFrameDuration(i.previous()));
}