From 2ccc9597a3eb370e4fe31f249704f9ff8675f7a1 Mon Sep 17 00:00:00 2001 From: Radek Dutkiewicz Date: Sat, 22 Dec 2018 01:46:19 +0000 Subject: [PATCH] Fixed high CPU on video playback and video freezing after resuming from sleep (#520) Some snap videos ( ie. Proggetto Snaps ) consumed excessive amount of CPU. This was caused by max_sleep being dependent on the time base instead of the frame rate. Fixed video freezing after resuming from sleep, which was caused by only showing key frames. Videos now restart when computer wakes up. --- src/media.cpp | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/src/media.cpp b/src/media.cpp index c851b9ba6..ba906e665 100644 --- a/src/media.cpp +++ b/src/media.cpp @@ -143,6 +143,7 @@ class FeBaseStream virtual ~FeBaseStream(); bool at_end; // set when at the end of our input + bool far_behind; AVCodecContext *codec_ctx; AVCodec *codec; int stream_id; @@ -199,6 +200,7 @@ class FeVideoImp : public FeBaseStream public: bool run_video_thread; sf::Time time_base; + sf::Time max_sleep; sf::Clock video_timer; sf::Texture *display_texture; SwsContext *sws_ctx; @@ -259,6 +261,7 @@ void FeMediaImp::close() FeBaseStream::FeBaseStream() : at_end( false ), + far_behind( false ), codec_ctx( NULL ), codec( NULL ), stream_id( -1 ) @@ -277,6 +280,7 @@ FeBaseStream::~FeBaseStream() codec = NULL; at_end = false; + far_behind = false; stream_id = -1; } @@ -284,6 +288,7 @@ void FeBaseStream::stop() { clear_packet_queue(); at_end=false; + far_behind = false; } AVPacket *FeBaseStream::pop_packet() @@ -588,8 +593,6 @@ void FeVideoImp::preload() void FeVideoImp::video_thread() { - sf::Time max_sleep = time_base / (sf::Int64)2; - const int QMAX = 16; const int QMIN = 0; int qscore( 10 ); // quality scoring @@ -601,6 +604,8 @@ void FeVideoImp::video_thread() int64_t prev_pts = 0; int64_t prev_duration = 0; + sf::Time wait_time; + if ((!sws_ctx) || (!rgba_buffer[0])) { FeLog() << "Error initializing video thread" << std::endl; @@ -610,12 +615,26 @@ void FeVideoImp::video_thread() while ( run_video_thread ) { bool do_process = true; + + // + // If we are falling behind for more than 2 seconds + // it can only mean that we are in suspend/hibernation state, + // so we flag the video to be restarted on the next tick. + // This prevents displaying only keyframes for several seconds on wake. + // + if ( wait_time < sf::seconds( -2.0f ) ) + { + wait_time = sf::seconds( 0 ); + far_behind = true; + run_video_thread = false; + } + // // First, display queued frame // if ( detached_frame ) { - sf::Time wait_time = (sf::Int64)detached_frame->pts * time_base + wait_time = (sf::Int64)detached_frame->pts * time_base - m_parent->get_video_time(); if ( wait_time < max_sleep ) @@ -863,6 +882,9 @@ void FeMedia::close() bool FeMedia::is_playing() { + if ((m_video) && (m_video->far_behind)) + return false; + if ((m_video) && (!m_video->at_end)) return (m_video->run_video_thread); @@ -1066,6 +1088,8 @@ bool FeMedia::open( const std::string &archive, m_video->time_base = sf::seconds( av_q2d(m_imp->m_format_ctx->streams[stream_id]->time_base) ); + m_video->max_sleep = sf::seconds( 0.5 / av_q2d(m_imp->m_format_ctx->streams[stream_id]->r_frame_rate)); + float aspect_ratio = 1.0; if ( codec_ctx->sample_aspect_ratio.num != 0 ) aspect_ratio = av_q2d( codec_ctx->sample_aspect_ratio );