From c71a1af6ea198b9f63ef118b3c53572ababc52f3 Mon Sep 17 00:00:00 2001 From: Jonathan Thomas Date: Mon, 28 Feb 2022 15:45:46 -0600 Subject: [PATCH] Allow cache on initial pause, to use the Timeline cache size to initially cache a bunch more frames... and then fully pause. This allows for a balance between not-caching during pause (for Transform and Scrubbing performance), but still caching frames on pause so the user can wait for a smoother playback experience. --- src/Qt/VideoCacheThread.cpp | 40 ++++++++++++++++++++++++++++++++++++- src/QtPlayer.cpp | 5 +++-- 2 files changed, 42 insertions(+), 3 deletions(-) diff --git a/src/Qt/VideoCacheThread.cpp b/src/Qt/VideoCacheThread.cpp index fcaa424a..02e0d40d 100644 --- a/src/Qt/VideoCacheThread.cpp +++ b/src/Qt/VideoCacheThread.cpp @@ -74,6 +74,7 @@ namespace openshot // Types for storing time durations in whole and fractional microseconds using micro_sec = std::chrono::microseconds; using double_micro_sec = std::chrono::duration; + bool should_pause = false; while (!threadShouldExit() && is_playing) { // Calculate on-screen time for a single frame @@ -83,9 +84,46 @@ namespace openshot // Calculate increment (based on speed) // Support caching in both directions int16_t increment = speed; - if (speed == 0) { + if (current_speed == 0 && should_pause) { + // Sleep during pause (after caching additional frames when paused) std::this_thread::sleep_for(frame_duration / 4); continue; + + } else if (current_speed == 0) { + // Allow 'max frames' to increase when pause is detected (based on cache) + // To allow the cache to fill-up only on the initial pause. + should_pause = true; + + // Calculate bytes per frame. If we have a reference openshot::Frame, use that instead (the preview + // window can be smaller, can thus reduce the bytes per frame) + int64_t bytes_per_frame = (reader->info.height * reader->info.width * 4) + + (reader->info.sample_rate * reader->info.channels * 4); + if (last_cached_frame && last_cached_frame->has_image_data && last_cached_frame->has_audio_data) { + bytes_per_frame = last_cached_frame->GetBytes(); + } + + // Calculate # of frames on Timeline cache (when paused) + if (reader->GetCache() && reader->GetCache()->GetMaxBytes() > 0) { + // When paused, use 1/2 the cache size (so our cache will be 50% before the play-head, and 50% after it) + max_frames_ahead = (reader->GetCache()->GetMaxBytes() / bytes_per_frame) / 2; + if (max_frames_ahead > 300) { + // Ignore values that are too large, and default to a safer value + max_frames_ahead = 300; + } + } + + // Overwrite the increment to our cache position + // to fully cache frames while paused (support forward and rewind) + if (last_speed > 0) { + increment = 1; + } else { + increment = -1; + } + + } else { + // Default max frames ahead (normal playback) + max_frames_ahead = 8; + should_pause = false; } // Always cache frames from the current display position to our maximum (based on the cache size). diff --git a/src/QtPlayer.cpp b/src/QtPlayer.cpp index 6a72d458..a1b598c5 100644 --- a/src/QtPlayer.cpp +++ b/src/QtPlayer.cpp @@ -227,8 +227,9 @@ namespace openshot speed = new_speed; p->speed = new_speed; p->videoCache->setSpeed(new_speed); - if (p->reader->info.has_audio) - p->audioPlayback->setSpeed(new_speed); + if (p->reader && p->reader->info.has_audio) { + p->audioPlayback->setSpeed(new_speed); + } } // Get the Volume