bool VideoDecoder::seek(const Audio::Timestamp &time) { if (!isSeekable()) return false; // Stop all tracks so they can be seeked if (isPlaying()) stopAudio(); // Do the actual seeking if (!seekIntern(time)) return false; // Seek any external track too for (TrackListIterator it = _externalTracks.begin(); it != _externalTracks.end(); it++) if (!(*it)->seek(time)) return false; _lastTimeChange = time; // Now that we've seeked, start all tracks again // Also reset our start time if (isPlaying()) { startAudio(); _startTime = g_system->getMillis() - (time.msecs() / _playbackRate).toInt(); } resetPauseStartTime(); findNextVideoTrack(); _needsUpdate = true; return true; }
bool VideoDecoder::seek(const Audio::Timestamp &time) { if (!isSeekable()) return false; // Stop all tracks so they can be seeked if (isPlaying()) stopAudio(); for (TrackList::iterator it = _tracks.begin(); it != _tracks.end(); it++) if (!(*it)->seek(time)) return false; _lastTimeChange = time; // Now that we've seeked, start all tracks again // Also reset our start time if (isPlaying()) { startAudio(); _startTime = g_system->getMillis() - time.msecs(); } resetPauseStartTime(); _needsUpdate = true; return true; }
void QuickTimeDecoder::seekToTime(const Audio::Timestamp &time) { stopAudio(); _audioStartOffset = time; // Sets all tracks to this time for (uint32 i = 0; i < _handlers.size(); i++) _handlers[i]->seekToTime(time); startAudio(); // Reset our start time _startTime = g_system->getMillis() - time.msecs(); _setStartTime = true; resetPauseStartTime(); // Reset the next video track too _nextVideoTrack = findNextVideoTrack(); _needUpdate = _nextVideoTrack != 0; }
void VideoDecoder::setEndTime(const Audio::Timestamp &endTime) { Audio::Timestamp startTime = 0; if (isPlaying()) { startTime = getTime(); stopAudio(); } _endTime = endTime; _endTimeSet = true; if (startTime > endTime) return; if (isPlaying()) { // We'll assume the audio track is going to start up at the same time it just was // and therefore not do any seeking. // Might want to set it anyway if we're seekable. startAudioLimit(_endTime.msecs() - startTime.msecs()); _lastTimeChange = startTime; } }
void QuickTimeDecoder::seekToFrame(uint32 frame) { assert(_videoTrackIndex >= 0); assert(frame < _tracks[_videoTrackIndex]->frameCount); // Stop all audio (for now) stopAudio(); // Track down the keyframe _curFrame = findKeyFrame(frame) - 1; while (_curFrame < (int32)frame - 1) decodeNextFrame(); // Map out the starting point _nextFrameStartTime = 0; uint32 curFrame = 0; for (int32 i = 0; i < _tracks[_videoTrackIndex]->timeToSampleCount && curFrame < frame; i++) { for (int32 j = 0; j < _tracks[_videoTrackIndex]->timeToSample[i].count && curFrame < frame; j++) { curFrame++; _nextFrameStartTime += _tracks[_videoTrackIndex]->timeToSample[i].duration; } } // Adjust the video starting point const Audio::Timestamp curVideoTime(0, _nextFrameStartTime, _tracks[_videoTrackIndex]->timeScale); _startTime = g_system->getMillis() - curVideoTime.msecs(); resetPauseStartTime(); // Adjust the audio starting point if (_audioTrackIndex >= 0) { _audioStartOffset = curVideoTime; // Seek to the new audio location setAudioStreamPos(_audioStartOffset); // Restart the audio startAudio(); } }
void QuickTimeDecoder::seekToFrame(uint32 frame) { assert(_videoStreamIndex >= 0); assert(frame < _streams[_videoStreamIndex]->nb_frames); // Stop all audio (for now) stopAudio(); // Track down the keyframe _curFrame = findKeyFrame(frame) - 1; while (_curFrame < (int32)frame - 1) decodeNextFrame(); // Map out the starting point _nextFrameStartTime = 0; uint32 curFrame = 0; for (int32 i = 0; i < _streams[_videoStreamIndex]->stts_count && curFrame < frame; i++) { for (int32 j = 0; j < _streams[_videoStreamIndex]->stts_data[i].count && curFrame < frame; j++) { curFrame++; _nextFrameStartTime += _streams[_videoStreamIndex]->stts_data[i].duration; } } // Adjust the video starting point const Audio::Timestamp curVideoTime(0, _nextFrameStartTime, _streams[_videoStreamIndex]->time_scale); _startTime = g_system->getMillis() - curVideoTime.msecs(); resetPauseStartTime(); // Adjust the audio starting point if (_audioStreamIndex >= 0) { _audioStartOffset = curVideoTime; // Re-create the audio stream STSDEntry *entry = &_streams[_audioStreamIndex]->stsdEntries[0]; _audStream = Audio::makeQueuingAudioStream(entry->sampleRate, entry->channels == 2); // First, we need to track down what audio sample we need Audio::Timestamp curAudioTime(0, _streams[_audioStreamIndex]->time_scale); uint sample = 0; bool done = false; for (int32 i = 0; i < _streams[_audioStreamIndex]->stts_count && !done; i++) { for (int32 j = 0; j < _streams[_audioStreamIndex]->stts_data[i].count; j++) { curAudioTime = curAudioTime.addFrames(_streams[_audioStreamIndex]->stts_data[i].duration); if (curAudioTime > curVideoTime) { done = true; break; } sample++; } } // Now to track down what chunk it's in _curAudioChunk = 0; uint32 totalSamples = 0; for (uint32 i = 0; i < _streams[_audioStreamIndex]->chunk_count; i++, _curAudioChunk++) { int sampleToChunkIndex = -1; for (uint32 j = 0; j < _streams[_audioStreamIndex]->sample_to_chunk_sz; j++) if (i >= _streams[_audioStreamIndex]->sample_to_chunk[j].first) sampleToChunkIndex = j; assert(sampleToChunkIndex >= 0); totalSamples += _streams[_audioStreamIndex]->sample_to_chunk[sampleToChunkIndex].count; if (sample < totalSamples) { totalSamples -= _streams[_audioStreamIndex]->sample_to_chunk[sampleToChunkIndex].count; break; } } // Reposition the audio stream readNextAudioChunk(); if (sample != totalSamples) { // HACK: Skip a certain amount of samples from the stream // (There's got to be a better way to do this!) int16 *tempBuffer = new int16[sample - totalSamples]; _audStream->readBuffer(tempBuffer, sample - totalSamples); delete[] tempBuffer; debug(3, "Skipping %d audio samples", sample - totalSamples); } // Restart the audio startAudio(); } }
void SeekableBinkDecoder::seekToTime(Audio::Timestamp time) { // Try to find the last frame that should have been decoded Common::Rational frame = time.msecs() * getFrameRate() / 1000; seekToFrame(frame.toInt()); }