uint VideoDecoder::FixedRateVideoTrack::getFrameAtTime(const Audio::Timestamp &time) const { Common::Rational frameRate = getFrameRate(); // Easy conversion if (frameRate == time.framerate()) return time.totalNumberOfFrames(); // Default case return (time.totalNumberOfFrames() * frameRate / time.framerate()).toInt(); }
uint VideoDecoder::FixedRateVideoTrack::getFrameAtTime(const Audio::Timestamp &time) const { Common::Rational frameRate = getFrameRate(); // Easy conversion if (frameRate == time.framerate()) return time.totalNumberOfFrames(); // Create the rational based on the time first to hopefully cancel out // *something* when multiplying by the frameRate (which can be large in // some AVI videos). return (Common::Rational(time.totalNumberOfFrames(), time.framerate()) * frameRate).toInt(); }
void AVIDecoder::AVIAudioTrack::skipAudio(const Audio::Timestamp &time, const Audio::Timestamp &frameTime) { Audio::Timestamp timeDiff = time.convertToFramerate(_wvInfo.samplesPerSec) - frameTime.convertToFramerate(_wvInfo.samplesPerSec); int skipFrames = timeDiff.totalNumberOfFrames(); if (skipFrames <= 0) return; if (_audStream->isStereo()) skipFrames *= 2; int16 *tempBuffer = new int16[skipFrames]; _audStream->readBuffer(tempBuffer, skipFrames); delete[] tempBuffer; }
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::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(); }
int16 ScriptFunctions::sfGetSoundEnergy(int16 argc, int16 *argv) { // This is called while in-game voices are played to animate // mouths when NPCs are talking int result = 0; if (_vm->_mixer->isSoundHandleActive(_audioStreamHandle) && _vm->_soundEnergyArray) { while (_vm->_soundEnergyIndex < _vm->_soundEnergyArray->size()) { SoundEnergyItem *soundEnergyItem = &(*_vm->_soundEnergyArray)[_vm->_soundEnergyIndex]; const Audio::Timestamp ts = _vm->_mixer->getElapsedTime(_audioStreamHandle); if (ts.convertToFramerate(_vm->_soundRate).totalNumberOfFrames() < (int)soundEnergyItem->position) { result = soundEnergyItem->energy; break; } _vm->_soundEnergyIndex++; } if (_vm->_soundEnergyIndex >= _vm->_soundEnergyArray->size()) result = 0; } return result; }
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::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; }
uint32 SoundManager::getVOCFrame() { Audio::Timestamp timestamp = _mixer->getElapsedTime(_soundHandle); return timestamp.secs(); }
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(); } }
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; }
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()); }