void OMXPlayerVideo::Output(double pts, bool bDropPacket) { if (!g_renderManager.IsStarted()) { CLog::Log(LOGERROR, "%s - renderer not started", __FUNCTION__); return; } if (CThread::m_bStop) return; // we aim to submit subtitles 100ms early const double preroll = DVD_MSEC_TO_TIME(100); double media_pts = m_av_clock->OMXMediaTime(); if (m_nextOverlay != DVD_NOPTS_VALUE && media_pts + preroll <= m_nextOverlay) return; int buffer = g_renderManager.WaitForBuffer(CThread::m_bStop); if (buffer < 0) return; double subtitle_pts = m_nextOverlay; double time = subtitle_pts != DVD_NOPTS_VALUE ? subtitle_pts - media_pts : 0.0; if (m_nextOverlay != DVD_NOPTS_VALUE) media_pts = m_nextOverlay; m_nextOverlay = NextOverlay(media_pts); ProcessOverlays(media_pts); time += m_av_clock->GetAbsoluteClock(); g_renderManager.FlipPage(CThread::m_bStop, time/DVD_TIME_BASE); }
void OMXPlayerVideo::Output(int iGroupId, double pts, bool bDropPacket) { if (!g_renderManager.IsStarted()) { CLog::Log(LOGERROR, "%s - renderer not started", __FUNCTION__); return; } // calculate the time we need to delay this picture before displaying double iSleepTime, iClockSleep, iFrameSleep, iPlayingClock, iCurrentClock, iFrameDuration; iPlayingClock = m_av_clock->GetClock(iCurrentClock, false); // snapshot current clock iClockSleep = pts - iPlayingClock; //sleep calculated by pts to clock comparison iFrameSleep = m_FlipTimeStamp - iCurrentClock; // sleep calculated by duration of frame iFrameDuration = (double)DVD_TIME_BASE / m_fFrameRate; //pPacket->duration; // correct sleep times based on speed if(m_speed) { iClockSleep = iClockSleep * DVD_PLAYSPEED_NORMAL / m_speed; iFrameSleep = iFrameSleep * DVD_PLAYSPEED_NORMAL / abs(m_speed); iFrameDuration = iFrameDuration * DVD_PLAYSPEED_NORMAL / abs(m_speed); } else { iClockSleep = 0; iFrameSleep = 0; } // dropping to a very low framerate is not correct (it should not happen at all) iClockSleep = min(iClockSleep, DVD_MSEC_TO_TIME(500)); iFrameSleep = min(iFrameSleep, DVD_MSEC_TO_TIME(500)); if( m_stalled ) iSleepTime = iFrameSleep; else iSleepTime = iFrameSleep + (iClockSleep - iFrameSleep) / m_autosync; // present the current pts of this frame to user, and include the actual // presentation delay, to allow him to adjust for it if( m_stalled ) m_iCurrentPts = DVD_NOPTS_VALUE; else m_iCurrentPts = pts - max(0.0, iSleepTime); // timestamp when we think next picture should be displayed based on current duration m_FlipTimeStamp = iCurrentClock; m_FlipTimeStamp += max(0.0, iSleepTime); m_FlipTimeStamp += iFrameDuration; if( m_speed < 0 ) { if( iClockSleep < -DVD_MSEC_TO_TIME(200)) return; } if(bDropPacket) return; #if 0 if( m_speed != DVD_PLAYSPEED_NORMAL) { // calculate frame dropping pattern to render at this speed // we do that by deciding if this or next frame is closest // to the flip timestamp double current = fabs(m_dropbase - m_droptime); double next = fabs(m_dropbase - (m_droptime + iFrameDuration)); double frametime = (double)DVD_TIME_BASE / m_fFrameRate; m_droptime += iFrameDuration; #ifndef PROFILE if( next < current /*&& !(pPicture->iFlags & DVP_FLAG_NOSKIP) */) return /*result | EOS_DROPPED*/; #endif while(!m_bStop && m_dropbase < m_droptime) m_dropbase += frametime; while(!m_bStop && m_dropbase - frametime > m_droptime) m_dropbase -= frametime; } else { m_droptime = 0.0f; m_dropbase = 0.0f; } #else m_droptime = 0.0f; m_dropbase = 0.0f; #endif // DVDPlayer sleeps until m_iSleepEndTime here before calling FlipPage. // Video playback in asynchronous in OMXPlayer, so we don't want to do that here, as it prevents the video fifo from being kept full. // So, we keep track of when FlipPage would have been called on DVDPlayer and return early if it is not time. // m_iSleepEndTime == DVD_NOPTS_VALUE means we are not waiting to call FlipPage, otherwise it is the time we want to call FlipPage if (m_iSleepEndTime == DVD_NOPTS_VALUE) { m_iSleepEndTime = iCurrentClock + iSleepTime; } if (!CThread::m_bStop && m_av_clock->GetAbsoluteClock(false) < m_iSleepEndTime + DVD_MSEC_TO_TIME(500)) return; double pts_media = m_av_clock->OMXMediaTime(false, false); ProcessOverlays(iGroupId, pts_media); g_renderManager.FlipPage(CThread::m_bStop, m_iSleepEndTime / DVD_TIME_BASE, -1, FS_NONE); m_iSleepEndTime = DVD_NOPTS_VALUE; //m_av_clock->WaitAbsoluteClock((iCurrentClock + iSleepTime)); }
void OMXPlayerVideo::Output(int iGroupId, double pts, bool bDropPacket) { if (!g_renderManager.IsStarted()) { CLog::Log(LOGERROR, "%s - renderer not started", __FUNCTION__); return; } // calculate the time we need to delay this picture before displaying double iSleepTime, iClockSleep, iFrameSleep, iPlayingClock, iCurrentClock, iFrameDuration; iPlayingClock = m_av_clock->GetClock(iCurrentClock, false); // snapshot current clock iClockSleep = pts - iPlayingClock; //sleep calculated by pts to clock comparison iFrameSleep = m_FlipTimeStamp - iCurrentClock; // sleep calculated by duration of frame iFrameDuration = (double)DVD_TIME_BASE / m_fFrameRate; //pPacket->duration; // correct sleep times based on speed if(m_speed) { iClockSleep = iClockSleep * DVD_PLAYSPEED_NORMAL / m_speed; iFrameSleep = iFrameSleep * DVD_PLAYSPEED_NORMAL / abs(m_speed); iFrameDuration = iFrameDuration * DVD_PLAYSPEED_NORMAL / abs(m_speed); } else { iClockSleep = 0; iFrameSleep = 0; } // dropping to a very low framerate is not correct (it should not happen at all) iClockSleep = min(iClockSleep, DVD_MSEC_TO_TIME(500)); iFrameSleep = min(iFrameSleep, DVD_MSEC_TO_TIME(500)); if( m_stalled ) iSleepTime = iFrameSleep; else iSleepTime = iFrameSleep + (iClockSleep - iFrameSleep) / m_autosync; // present the current pts of this frame to user, and include the actual // presentation delay, to allow him to adjust for it if( m_stalled ) m_iCurrentPts = DVD_NOPTS_VALUE; else m_iCurrentPts = pts - max(0.0, iSleepTime); // timestamp when we think next picture should be displayed based on current duration m_FlipTimeStamp = iCurrentClock; m_FlipTimeStamp += max(0.0, iSleepTime); m_FlipTimeStamp += iFrameDuration; if( m_speed < 0 ) { if( iClockSleep < -DVD_MSEC_TO_TIME(200)) return; } if(bDropPacket) return; #if 0 if( m_speed != DVD_PLAYSPEED_NORMAL) { // calculate frame dropping pattern to render at this speed // we do that by deciding if this or next frame is closest // to the flip timestamp double current = fabs(m_dropbase - m_droptime); double next = fabs(m_dropbase - (m_droptime + iFrameDuration)); double frametime = (double)DVD_TIME_BASE / m_fFrameRate; m_droptime += iFrameDuration; #ifndef PROFILE if( next < current /*&& !(pPicture->iFlags & DVP_FLAG_NOSKIP) */) return /*result | EOS_DROPPED*/; #endif while(!m_bStop && m_dropbase < m_droptime) m_dropbase += frametime; while(!m_bStop && m_dropbase - frametime > m_droptime) m_dropbase -= frametime; } else { m_droptime = 0.0f; m_dropbase = 0.0f; } #else m_droptime = 0.0f; m_dropbase = 0.0f; #endif int buffer = g_renderManager.WaitForBuffer(m_bStop, 0); if (buffer < 0) return; double pts_overlay = m_av_clock->OMXMediaTime(false, false) + 2* (double)DVD_TIME_BASE / g_graphicsContext.GetFPS(); ProcessOverlays(iGroupId, pts_overlay); double timestamp = CDVDClock::GetAbsoluteClock(false) + 2 / g_graphicsContext.GetFPS(); g_renderManager.FlipPage(CThread::m_bStop, timestamp, -1, FS_NONE); }
void OMXPlayerVideo::Output(int iGroupId, double pts, bool bDropPacket) { if (!g_renderManager.IsConfigured() || m_video_width != m_width || m_video_height != m_height || m_fps != m_fFrameRate) { m_width = m_video_width; m_height = m_video_height; m_fps = m_fFrameRate; unsigned flags = 0; ERenderFormat format = RENDER_FMT_BYPASS; if(m_bAllowFullscreen) { flags |= CONF_FLAGS_FULLSCREEN; m_bAllowFullscreen = false; // only allow on first configure } if(m_flags & CONF_FLAGS_FORMAT_SBS) { if(g_Windowing.Support3D(m_video_width, m_video_height, D3DPRESENTFLAG_MODE3DSBS)) { CLog::Log(LOGNOTICE, "3DSBS movie found"); flags |= CONF_FLAGS_FORMAT_SBS; } } CLog::Log(LOGDEBUG,"%s - change configuration. %dx%d. framerate: %4.2f. format: BYPASS", __FUNCTION__, m_width, m_height, m_fps); if(!g_renderManager.Configure(m_video_width, m_video_height, m_video_width, m_video_height, m_fps, flags, format, 0, m_hints.orientation)) { CLog::Log(LOGERROR, "%s - failed to configure renderer", __FUNCTION__); return; } } if (!g_renderManager.IsStarted()) { CLog::Log(LOGERROR, "%s - renderer not started", __FUNCTION__); return; } // calculate the time we need to delay this picture before displaying double iSleepTime, iClockSleep, iFrameSleep, iPlayingClock, iCurrentClock, iFrameDuration; iPlayingClock = m_av_clock->GetClock(iCurrentClock, false); // snapshot current clock iClockSleep = pts - iPlayingClock; //sleep calculated by pts to clock comparison iFrameSleep = m_FlipTimeStamp - iCurrentClock; // sleep calculated by duration of frame iFrameDuration = (double)DVD_TIME_BASE / m_fFrameRate; //pPacket->duration; // correct sleep times based on speed if(m_speed) { iClockSleep = iClockSleep * DVD_PLAYSPEED_NORMAL / m_speed; iFrameSleep = iFrameSleep * DVD_PLAYSPEED_NORMAL / abs(m_speed); iFrameDuration = iFrameDuration * DVD_PLAYSPEED_NORMAL / abs(m_speed); } else { iClockSleep = 0; iFrameSleep = 0; } // dropping to a very low framerate is not correct (it should not happen at all) iClockSleep = min(iClockSleep, DVD_MSEC_TO_TIME(500)); iFrameSleep = min(iFrameSleep, DVD_MSEC_TO_TIME(500)); if( m_stalled ) iSleepTime = iFrameSleep; else iSleepTime = iFrameSleep + (iClockSleep - iFrameSleep) / m_autosync; // present the current pts of this frame to user, and include the actual // presentation delay, to allow him to adjust for it if( m_stalled ) m_iCurrentPts = DVD_NOPTS_VALUE; else m_iCurrentPts = pts - max(0.0, iSleepTime); // timestamp when we think next picture should be displayed based on current duration m_FlipTimeStamp = iCurrentClock; m_FlipTimeStamp += max(0.0, iSleepTime); m_FlipTimeStamp += iFrameDuration; if( m_speed < 0 ) { if( iClockSleep < -DVD_MSEC_TO_TIME(200)) return; } if(bDropPacket) return; #if 0 if( m_speed != DVD_PLAYSPEED_NORMAL) { // calculate frame dropping pattern to render at this speed // we do that by deciding if this or next frame is closest // to the flip timestamp double current = fabs(m_dropbase - m_droptime); double next = fabs(m_dropbase - (m_droptime + iFrameDuration)); double frametime = (double)DVD_TIME_BASE / m_fFrameRate; m_droptime += iFrameDuration; #ifndef PROFILE if( next < current /*&& !(pPicture->iFlags & DVP_FLAG_NOSKIP) */) return /*result | EOS_DROPPED*/; #endif while(!m_bStop && m_dropbase < m_droptime) m_dropbase += frametime; while(!m_bStop && m_dropbase - frametime > m_droptime) m_dropbase -= frametime; } else { m_droptime = 0.0f; m_dropbase = 0.0f; } #else m_droptime = 0.0f; m_dropbase = 0.0f; #endif double pts_media = m_av_clock->OMXMediaTime(); ProcessOverlays(iGroupId, pts_media); while(!CThread::m_bStop && m_av_clock->GetAbsoluteClock(false) < (iCurrentClock + iSleepTime + DVD_MSEC_TO_TIME(500)) ) Sleep(1); g_renderManager.FlipPage(CThread::m_bStop, (iCurrentClock + iSleepTime) / DVD_TIME_BASE, -1, FS_NONE); //m_av_clock->WaitAbsoluteClock((iCurrentClock + iSleepTime)); }
CVideoPlayerVideo::EOutputState CVideoPlayerVideo::OutputPicture(const VideoPicture* pPicture) { m_bAbortOutput = false; if (m_processInfo.GetVideoStereoMode() != pPicture->stereoMode) { m_processInfo.SetVideoStereoMode(pPicture->stereoMode); // signal about changes in video parameters m_messageParent.Put(new CDVDMsg(CDVDMsg::PLAYER_AVCHANGE)); } double config_framerate = m_bFpsInvalid ? 0.0 : m_fFrameRate; if (m_processInfo.GetVideoInterlaced()) { if (MathUtils::FloatEquals(config_framerate, 25.0, 0.02)) config_framerate = 50.0; else if (MathUtils::FloatEquals(config_framerate, 29.97, 0.02)) config_framerate = 59.94; } int sorient = m_processInfo.GetVideoSettings().m_Orientation; int orientation = sorient != 0 ? (sorient + m_hints.orientation) % 360 : m_hints.orientation; if (!m_renderManager.Configure(*pPicture, static_cast<float>(config_framerate), orientation, m_pVideoCodec->GetAllowedReferences())) { CLog::Log(LOGERROR, "%s - failed to configure renderer", __FUNCTION__); return OUTPUT_ABORT; } //try to calculate the framerate m_ptsTracker.Add(pPicture->pts); if (!m_stalled) CalcFrameRate(); // signal to clock what our framerate is, it may want to adjust it's // speed to better match with our video renderer's output speed m_pClock->UpdateFramerate(m_fFrameRate); // calculate the time we need to delay this picture before displaying double iPlayingClock, iCurrentClock; iPlayingClock = m_pClock->GetClock(iCurrentClock, false); // snapshot current clock if (m_speed < 0) { double renderPts; int queued, discard; int lateframes; double inputPts = m_droppingStats.m_lastPts; m_renderManager.GetStats(lateframes, renderPts, queued, discard); if (pPicture->pts > renderPts || queued > 0) { if (inputPts >= renderPts) { m_rewindStalled = true; Sleep(50); } return OUTPUT_DROPPED; } else if (pPicture->pts < iPlayingClock) { return OUTPUT_DROPPED; } } if ((pPicture->iFlags & DVP_FLAG_DROPPED)) { m_droppingStats.AddOutputDropGain(pPicture->pts, 1); CLog::Log(LOGDEBUG,"%s - dropped in output", __FUNCTION__); return OUTPUT_DROPPED; } int timeToDisplay = DVD_TIME_TO_MSEC(pPicture->pts - iPlayingClock); // make sure waiting time is not negative int maxWaitTime = std::min(std::max(timeToDisplay + 500, 50), 500); // don't wait when going ff if (m_speed > DVD_PLAYSPEED_NORMAL) maxWaitTime = std::max(timeToDisplay, 0); int buffer = m_renderManager.WaitForBuffer(m_bAbortOutput, maxWaitTime); if (buffer < 0) { return OUTPUT_AGAIN; } ProcessOverlays(pPicture, pPicture->pts); EINTERLACEMETHOD deintMethod = EINTERLACEMETHOD::VS_INTERLACEMETHOD_NONE; deintMethod = m_processInfo.GetVideoSettings().m_InterlaceMethod; if (!m_processInfo.Supports(deintMethod)) deintMethod = m_processInfo.GetDeinterlacingMethodDefault(); if (!m_renderManager.AddVideoPicture(*pPicture, m_bAbortOutput, deintMethod, (m_syncState == ESyncState::SYNC_STARTING))) { m_droppingStats.AddOutputDropGain(pPicture->pts, 1); return OUTPUT_DROPPED; } return OUTPUT_NORMAL; }