diff --git a/src/Qt/VideoCacheThread.cpp b/src/Qt/VideoCacheThread.cpp
index f817c93f3..e1e53f5d4 100644
--- a/src/Qt/VideoCacheThread.cpp
+++ b/src/Qt/VideoCacheThread.cpp
@@ -94,8 +94,10 @@ namespace openshot
while (!threadShouldExit() && is_playing) {
// Cache frames before the other threads need them
- // Cache frames up to the max frames
- while (speed == 1 && (position - current_display_frame) < max_frames)
+ // Cache frames up to the max frames. Reset to current position
+ // if cache gets too far away from display frame. Cache frames
+ // even when player is paused (i.e. speed 0).
+ while ((position - current_display_frame) < max_frames)
{
// Only cache up till the max_frames amount... then sleep
try
@@ -104,6 +106,14 @@ namespace openshot
ZmqLogger::Instance()->AppendDebugMethod("VideoCacheThread::run (cache frame)", "position", position, "current_display_frame", current_display_frame, "max_frames", max_frames, "needed_frames", (position - current_display_frame));
// Force the frame to be generated
+ if (reader->GetCache()->GetSmallestFrame()) {
+ int64_t smallest_cached_frame = reader->GetCache()->GetSmallestFrame()->number;
+ if (smallest_cached_frame > current_display_frame) {
+ // Cache position has gotten too far away from current display frame.
+ // Reset the position to the current display frame.
+ position = current_display_frame;
+ }
+ }
reader->GetFrame(position);
}
@@ -113,14 +123,8 @@ namespace openshot
// Ignore out of bounds frame exceptions
}
- // Is cache position behind current display frame?
- if (position < current_display_frame) {
- // Jump ahead
- position = current_display_frame;
- }
-
// Increment frame number
- position++;
+ position++;
}
// Sleep for 1 frame length
diff --git a/src/Qt/VideoCacheThread.h b/src/Qt/VideoCacheThread.h
index 6fbf6d58f..f9551bdb8 100644
--- a/src/Qt/VideoCacheThread.h
+++ b/src/Qt/VideoCacheThread.h
@@ -45,10 +45,13 @@ namespace openshot
*/
class VideoCacheThread : Thread
{
+ private:
+ std::atomic_int position;
+
+ protected:
std::shared_ptr frame;
int speed;
bool is_playing;
- int64_t position;
int64_t current_display_frame;
ReaderBase *reader;
int max_frames;
diff --git a/src/Timeline.cpp b/src/Timeline.cpp
index 2c5a9a279..abc02b6f8 100644
--- a/src/Timeline.cpp
+++ b/src/Timeline.cpp
@@ -695,6 +695,7 @@ std::shared_ptr Timeline::GetFrame(int64_t requested_frame)
// Check cache
std::shared_ptr frame;
+ std::lock_guard guard(get_frame_mutex);
#pragma omp critical (T_GetFrame)
frame = final_cache->GetFrame(requested_frame);
if (frame) {
@@ -724,6 +725,15 @@ std::shared_ptr Timeline::GetFrame(int64_t requested_frame)
return frame;
}
+ // Check if previous frame was cached? (if not, assume we are seeking somewhere else on the Timeline, and need
+ // to clear all cache (for continuity sake). For example, jumping back to a previous spot can cause issues with audio
+ // data where the new jump location doesn't match up with the previously cached audio data.
+ std::shared_ptr previous_frame = final_cache->GetFrame(requested_frame - 1);
+ if (!previous_frame) {
+ // Seeking to new place on timeline (destroy cache)
+ ClearAllCache();
+ }
+
// Minimum number of frames to process (for performance reasons)
int minimum_frames = OPEN_MP_NUM_PROCESSORS;
diff --git a/src/Timeline.h b/src/Timeline.h
index 227183428..1d156153b 100644
--- a/src/Timeline.h
+++ b/src/Timeline.h
@@ -33,6 +33,7 @@
#include
#include
+#include
#include
#include
#include
@@ -175,6 +176,7 @@ namespace openshot {
std::set allocated_frame_mappers; ///< all the frame mappers we allocated and must free
bool managed_cache; ///< Does this timeline instance manage the cache object
std::string path; ///< Optional path of loaded UTF-8 OpenShot JSON project file
+ std::mutex get_frame_mutex; ///< Mutex to protect GetFrame method from different threads calling it
/// Process a new layer of video or audio
void add_layer(std::shared_ptr new_frame, openshot::Clip* source_clip, int64_t clip_frame_number, int64_t timeline_frame_number, bool is_top_clip, float max_volume);