bool ThumbFinder::seekBackward() { int inc; int64_t newFrame; int64_t currentFrame = (m_currentPTS - m_startPTS) / m_frameTime; inc = SeekAmounts[m_currentSeek].amount; if (inc == -1) inc = -1; else if (inc == -2) { // seek to previous cut point frm_dir_map_t::const_iterator it; int pos = 0; for (it = m_deleteMap.begin(); it != m_deleteMap.end(); ++it) { if (it.key() >= (uint64_t)currentFrame) break; pos = it.key(); } // seek to next cutpoint m_offset = 0; seekToFrame(pos, false); return true; } else inc = (int) (-inc * ceil(m_fps)); newFrame = currentFrame + inc - m_offset; seekToFrame(newFrame); return true; }
bool VQAPlayer::setBeginAndEndFrame(int begin, int end, int repeatsCount, int loopSetMode, void (*callback)(void *, int, int), void *callbackData) { #if BLADERUNNER_DEBUG_CONSOLE debug("VQAPlayer::setBeginAndEndFrame(%i, %i, %i, %i), streamLoaded = %i", begin, end, repeatsCount, loopSetMode, _s != nullptr); #endif if (repeatsCount < 0) { repeatsCount = -1; } if (_repeatsCount == 0 && loopSetMode == kLoopSetModeEnqueue) { loopSetMode = kLoopSetModeImmediate; } //TODO: there is code in original game which deals with changing loop at start of loop, is it nescesarry? loc_46EA04 _frameBegin = begin; if (loopSetMode == kLoopSetModeJustStart) { _repeatsCount = repeatsCount; } else if (loopSetMode == kLoopSetModeEnqueue) { _repeatsCountQueued = repeatsCount; _frameEndQueued = end; } else if (loopSetMode == kLoopSetModeImmediate) { _repeatsCount = repeatsCount; _frameEnd = end; seekToFrame(begin); } _callbackLoopEnded = callback; _callbackData = callbackData; return true; }
bool AVISurface::startAtFrame(int frameNumber) { if (isPlaying()) // If it's already playing, then don't allow it return false; if (frameNumber == -1) // Default to starting frame of first movie range frameNumber = _movieRangeInfo.front()->_startFrame; if (_isReversed && frameNumber == (int)_decoder->getFrameCount()) --frameNumber; // Start the playback _decoder->start(); // Seek to the starting frame seekToFrame(frameNumber); // If we're in reverse playback, set the decoder to play in reverse if (_isReversed) _decoder->setRate(Common::Rational(-1)); renderFrame(); return true; }
void RobotDecoder::doRobot() { if (_status != kRobotStatusPlaying) { return; } if (!_syncFrame) { if (_cueForceShowFrame != -1) { _currentFrameNo = _cueForceShowFrame; _cueForceShowFrame = -1; } else { const int nextFrameNo = calculateNextFrameNo(_delayTime.predictedTicks()); if (nextFrameNo < _currentFrameNo) { return; } _currentFrameNo = nextFrameNo; } } if (_currentFrameNo >= _numFramesTotal) { const int finalFrameNo = _numFramesTotal - 1; if (_previousFrameNo == finalFrameNo) { _status = kRobotStatusEnd; if (_hasAudio) { _audioList.stopAudio(); _frameRate = _normalFrameRate; _hasAudio = false; } return; } else { _currentFrameNo = finalFrameNo; } } if (_currentFrameNo == _previousFrameNo) { _audioList.submitDriverMax(); return; } if (_hasAudio) { for (int candidateFrameNo = _previousFrameNo + _maxSkippablePackets + 1; candidateFrameNo < _currentFrameNo; candidateFrameNo += _maxSkippablePackets + 1) { _audioList.submitDriverMax(); int audioPosition, audioSize; if (readAudioDataFromRecord(candidateFrameNo, _audioBuffer, audioPosition, audioSize)) { _audioList.addBlock(audioPosition, audioSize, _audioBuffer); } } _audioList.submitDriverMax(); } _delayTime.startTiming(); seekToFrame(_currentFrameNo); doVersion5(); if (_hasAudio) { _audioList.submitDriverMax(); } }
void ThumbFinder::gridItemChanged(MythUIButtonListItem *item) { (void) item; int itemNo = m_imageGrid->GetCurrentPos(); ThumbImage *thumb = m_thumbList.at(itemNo); if (thumb) seekToFrame(thumb->frame); }
void AVISurface::setFrame(int frameNumber) { // If playback was in process, stop it if (isPlaying()) stop(); // Ensure the frame number is valid if (frameNumber >= (int)_decoder->getFrameCount()) frameNumber = _decoder->getFrameCount() - 1; seekToFrame(frameNumber); renderFrame(); }
const Graphics::Surface *RlfAnimation::getFrameData(uint frameNumber) { assert(!_stream); assert(frameNumber < _frameCount); // Since this method is so expensive, first check to see if we can use // getNextFrame() it's cheap. if ((int)frameNumber == _currentFrame) { return &_currentFrameBuffer; } else if (_currentFrame + 1 == (int)frameNumber) { return getNextFrame(); } seekToFrame(frameNumber); return &_currentFrameBuffer; }
bool AVISurface::handleEvents(CMovieEventList &events) { if (!isPlaying()) return true; CMovieRangeInfo *info = _movieRangeInfo.front(); _priorFrame = _currentFrame; _currentFrame += _isReversed ? -1 : 1; int newFrame = _currentFrame; if ((info->_isReversed && newFrame < info->_endFrame) || (!info->_isReversed && newFrame > info->_endFrame)) { if (info->_isRepeat) { newFrame = info->_startFrame; } else { info->getMovieEnd(events); _movieRangeInfo.remove(info); delete info; if (_movieRangeInfo.empty()) { // No more ranges, so stop playback stop(); } else { // Not empty, so move onto new first one info = _movieRangeInfo.front(); newFrame = info->_startFrame; setReversed(info->_isReversed); } } } if (isPlaying()) { if (newFrame != getFrame()) { // The frame has been changed, so move to new position seekToFrame(newFrame); renderFrame(); } // Get any events for the given position info->getMovieFrame(events, newFrame); return renderFrame(); } else { return false; } }
bool AVISurface::startAtFrame(int frameNumber) { if (isPlaying()) // If it's already playing, then don't allow it return false; if (frameNumber == -1) // Default to starting frame of first movie range frameNumber = _movieRangeInfo.front()->_startFrame; // Get the initial frame seekToFrame(frameNumber); renderFrame(); // Start the playback _decoders[0]->start(); if (_decoders[1]) _decoders[1]->start(); return true; }
void LadybugWidget::keyPressEvent(QKeyEvent* e) { if (e->key() >= Qt::Key_1 && e->key() <= Qt::Key_5) { int i = e->key()-Qt::Key_1; // invert camera on/off setting setCameraState(i, !cameraState(i)); if (mPaused) updateVideo(getSingleFrame(mCurrentFrame)); } switch (e->key()) { case Qt::Key_Space: pause(); break; case Qt::Key_Left: seekToFrame(mCurrentFrame-1); break; case Qt::Key_Right: seekToFrame(mCurrentFrame+1); break; case Qt::Key_Home: seekToFrame(0); break; case Qt::Key_End: seekToFrame(mStream.framesCount()-1); break; case Qt::Key_PageUp: seekToFrame(mCurrentFrame-25); break; case Qt::Key_PageDown: seekToFrame(mCurrentFrame+25); break; // %%% seek to random position (for testing) case Qt::Key_S: { uint msecs = rand() % (mStream.framesCount() / 15 * 1000); printf("RANDOM TIME SEEK! %d ms\n", msecs); seekToTime(msecs); break; } } }
void QuickTimeDecoder::seekToTime(Audio::Timestamp time) { // TODO: Audio-only seeking (or really, have QuickTime sounds) if (_videoStreamIndex < 0) error("Audio-only seeking not supported"); // Try to find the last frame that should have been decoded uint32 frame = 0; Audio::Timestamp totalDuration(0, _streams[_videoStreamIndex]->time_scale); bool done = false; for (int32 i = 0; i < _streams[_videoStreamIndex]->stts_count && !done; i++) { for (int32 j = 0; j < _streams[_videoStreamIndex]->stts_data[i].count; j++) { totalDuration = totalDuration.addFrames(_streams[_videoStreamIndex]->stts_data[i].duration); if (totalDuration > time) { done = true; break; } frame++; } } seekToFrame(frame); }
void QuickTimeDecoder::seekToTime(Audio::Timestamp time) { // Use makeQuickTimeStream() instead if (_videoTrackIndex < 0) error("Audio-only seeking not supported"); // Try to find the last frame that should have been decoded uint32 frame = 0; Audio::Timestamp totalDuration(0, _tracks[_videoTrackIndex]->timeScale); bool done = false; for (int32 i = 0; i < _tracks[_videoTrackIndex]->timeToSampleCount && !done; i++) { for (int32 j = 0; j < _tracks[_videoTrackIndex]->timeToSample[i].count; j++) { totalDuration = totalDuration.addFrames(_tracks[_videoTrackIndex]->timeToSample[i].duration); if (totalDuration > time) { done = true; break; } frame++; } } seekToFrame(frame); }
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()); }
bool ThumbFinder::getThumbImages() { if (!getFileDetails(m_archiveItem)) { LOG(VB_GENERAL, LOG_ERR, QString("ThumbFinder:: Failed to get file details for %1") .arg(m_archiveItem->filename)); return false; } if (!initAVCodec(m_archiveItem->filename)) return false; if (m_archiveItem->type == "Recording") loadCutList(); // calculate the file duration taking the cut list into account m_finalDuration = calcFinalDuration(); QString origFrameFile = m_frameFile; m_updateFrame = true; getFrameImage(); int chapterLen; if (m_thumbCount) chapterLen = m_finalDuration / m_thumbCount; else chapterLen = m_finalDuration; QString thumbList = ""; m_updateFrame = false; // add title thumb m_frameFile = m_thumbDir + "/title.jpg"; ThumbImage *thumb = nullptr; if (m_thumbList.size() > 0) { // use the thumb details in the thumbList if already available thumb = m_thumbList.at(0); } if (!thumb) { // no thumb available create a new one thumb = new ThumbImage; thumb->filename = m_frameFile; thumb->frame = (int64_t) 0; thumb->caption = "Title"; m_thumbList.append(thumb); } else m_frameFile = thumb->filename; seekToFrame(thumb->frame); getFrameImage(); new MythUIButtonListItem(m_imageGrid, thumb->caption, thumb->filename); qApp->processEvents(); for (int x = 1; x <= m_thumbCount; x++) { m_frameFile = m_thumbDir + QString("/chapter-%1.jpg").arg(x); thumb = nullptr; if (m_archiveItem->thumbList.size() > x) { // use the thumb details in the archiveItem if already available thumb = m_archiveItem->thumbList.at(x); } if (!thumb) { QString time; int chapter, hour, min, sec; chapter = chapterLen * (x - 1); hour = chapter / 3600; min = (chapter % 3600) / 60; sec = chapter % 60; time = time.sprintf("%02d:%02d:%02d", hour, min, sec); int64_t frame = (int64_t) (chapter * ceil(m_fps)); // no thumb available create a new one thumb = new ThumbImage; thumb->filename = m_frameFile; thumb->frame = frame; thumb->caption = time; m_thumbList.append(thumb); } else m_frameFile = thumb->filename; seekToFrame(thumb->frame); qApp->processEvents(); getFrameImage(); qApp->processEvents(); new MythUIButtonListItem(m_imageGrid, thumb->caption, thumb->filename); qApp->processEvents(); } m_frameFile = origFrameFile; seekToFrame(0); m_updateFrame = true; m_imageGrid->SetRedraw(); SetFocusWidget(m_imageGrid); return true; }
void RobotDecoder::showFrame(const uint16 frameNo, const uint16 newX, const uint16 newY, const uint16 newPriority) { debugC(kDebugLevelVideo, "Show frame %d (%d %d %d)", frameNo, newX, newY, newPriority); if (newX != kUnspecified) { _position.x = newX; } if (newY != kUnspecified) { _position.y = newY; } if (newPriority != kUnspecified) { _priority = newPriority; } _currentFrameNo = frameNo; pause(); if (frameNo != _previousFrameNo) { seekToFrame(frameNo); doVersion5(false); } else { for (RobotScreenItemList::size_type i = 0; i < _screenItemList.size(); ++i) { if (_isHiRes) { SciBitmap &bitmap = *_segMan->lookupBitmap(_celHandles[i].bitmapId); const int16 scriptWidth = g_sci->_gfxFrameout->getCurrentBuffer().scriptWidth; const int16 scriptHeight = g_sci->_gfxFrameout->getCurrentBuffer().scriptHeight; const int16 screenWidth = g_sci->_gfxFrameout->getCurrentBuffer().screenWidth; const int16 screenHeight = g_sci->_gfxFrameout->getCurrentBuffer().screenHeight; if (scriptWidth == kLowResX && scriptHeight == kLowResY) { const Ratio lowResToScreenX(screenWidth, kLowResX); const Ratio lowResToScreenY(screenHeight, kLowResY); const Ratio screenToLowResX(kLowResX, screenWidth); const Ratio screenToLowResY(kLowResY, screenHeight); const int16 scaledX = _originalScreenItemX[i] + (_position.x * lowResToScreenX).toInt(); const int16 scaledY1 = _originalScreenItemY[i] + (_position.y * lowResToScreenY).toInt(); const int16 scaledY2 = scaledY1 + bitmap.getHeight() - 1; const int16 lowResX = (scaledX * screenToLowResX).toInt(); const int16 lowResY = (scaledY2 * screenToLowResY).toInt(); bitmap.setOrigin(Common::Point( (scaledX - (lowResX * lowResToScreenX).toInt()) * -1, (lowResY * lowResToScreenY).toInt() - scaledY1 )); _screenItemX[i] = lowResX; _screenItemY[i] = lowResY; } else { const int16 scaledX = _originalScreenItemX[i] + _position.x; const int16 scaledY = _originalScreenItemY[i] + _position.y + bitmap.getHeight() - 1; bitmap.setOrigin(Common::Point(0, bitmap.getHeight() - 1)); _screenItemX[i] = scaledX; _screenItemY[i] = scaledY; } } else { _screenItemX[i] = _originalScreenItemX[i] + _position.x; _screenItemY[i] = _originalScreenItemY[i] + _position.y; } if (_screenItemList[i] == nullptr) { CelInfo32 celInfo; celInfo.type = kCelTypeMem; celInfo.bitmap = _celHandles[i].bitmapId; ScreenItem *screenItem = new ScreenItem(_plane->_object, celInfo); _screenItemList[i] = screenItem; screenItem->_position = Common::Point(_screenItemX[i], _screenItemY[i]); if (_priority == -1) { screenItem->_fixedPriority = false; } else { screenItem->_priority = _priority; screenItem->_fixedPriority = true; } g_sci->_gfxFrameout->addScreenItem(*screenItem); } else { ScreenItem *screenItem = _screenItemList[i]; screenItem->_celInfo.bitmap = _celHandles[i].bitmapId; screenItem->_position = Common::Point(_screenItemX[i], _screenItemY[i]); if (_priority == -1) { screenItem->_fixedPriority = false; } else { screenItem->_priority = _priority; screenItem->_fixedPriority = true; } g_sci->_gfxFrameout->updateScreenItem(*screenItem); } } } _previousFrameNo = frameNo; }
bool ThumbFinder::keyPressEvent(QKeyEvent *event) { if (GetFocusWidget()->keyPressEvent(event)) return true; QStringList actions; bool handled = GetMythMainWindow()->TranslateKeyPress("Archive", event, actions); for (int i = 0; i < actions.size() && !handled; i++) { QString action = actions[i]; handled = true; if (action == "MENU") { NextPrevWidgetFocus(true); return true; } if (action == "ESCAPE") { ShowMenu(); return true; } if (action == "0" || action == "1" || action == "2" || action == "3" || action == "4" || action == "5" || action == "6" || action == "7" || action == "8" || action == "9") { m_imageGrid->SetItemCurrent(action.toInt()); int itemNo = m_imageGrid->GetCurrentPos(); ThumbImage *thumb = m_thumbList.at(itemNo); if (thumb) seekToFrame(thumb->frame); return true; } if (GetFocusWidget() == m_frameButton) { if (action == "UP") { changeSeekAmount(true); } else if (action == "DOWN") { changeSeekAmount(false); } else if (action == "LEFT") { seekBackward(); } else if (action == "RIGHT") { seekForward(); } else if (action == "SELECT") { updateThumb(); } else handled = false; } else handled = false; } if (!handled && MythScreenType::keyPressEvent(event)) handled = true; return handled; }
bool VideoPlayer::seekToRatio(double ratio) { assert(ratio >= 0.0 && ratio <= 1.0); const size_t frameIdx = static_cast<size_t>(std::floor(ratio * numFrames())); return seekToFrame(frameIdx); }