From 8fcdbc9d030ea85af2842c33db4e1e4da2ecf4ab Mon Sep 17 00:00:00 2001 From: Jonathan Thomas Date: Tue, 11 Oct 2022 23:01:26 -0500 Subject: [PATCH] Timeline now checks cache 2nd time, after mutex - incase previous call generated the same frame --- src/Timeline.cpp | 215 +++++++++++++++++++++++++---------------------- 1 file changed, 113 insertions(+), 102 deletions(-) diff --git a/src/Timeline.cpp b/src/Timeline.cpp index 61bf5905..6b3b015e 100644 --- a/src/Timeline.cpp +++ b/src/Timeline.cpp @@ -874,128 +874,139 @@ std::shared_ptr Timeline::GetFrame(int64_t requested_frame) // Prevent async calls to the following code const std::lock_guard lock(getFrameMutex); - // Get a list of clips that intersect with the requested section of timeline - // This also opens the readers for intersecting clips, and marks non-intersecting clips as 'needs closing' - std::vector nearby_clips; - nearby_clips = find_intersecting_clips(requested_frame, 1, true); + // Check cache 2nd time + std::shared_ptr frame; + frame = final_cache->GetFrame(requested_frame); + if (frame) { + // Debug output + ZmqLogger::Instance()->AppendDebugMethod( + "Timeline::GetFrame (Cached frame found on 2nd check)", + "requested_frame", requested_frame); - // Debug output - ZmqLogger::Instance()->AppendDebugMethod( - "Timeline::GetFrame (processing frame)", - "requested_frame", requested_frame, - "omp_get_thread_num()", omp_get_thread_num()); - - // Init some basic properties about this frame - int samples_in_frame = Frame::GetSamplesPerFrame(requested_frame, info.fps, info.sample_rate, info.channels); - - // Create blank frame (which will become the requested frame) - std::shared_ptr new_frame(std::make_shared(requested_frame, preview_width, preview_height, "#000000", samples_in_frame, info.channels)); - new_frame->AddAudioSilence(samples_in_frame); - new_frame->SampleRate(info.sample_rate); - new_frame->ChannelsLayout(info.channel_layout); - - // Debug output - ZmqLogger::Instance()->AppendDebugMethod( - "Timeline::GetFrame (Adding solid color)", - "requested_frame", requested_frame, - "info.width", info.width, - "info.height", info.height); - - // Add Background Color to 1st layer (if animated or not black) - if ((color.red.GetCount() > 1 || color.green.GetCount() > 1 || color.blue.GetCount() > 1) || - (color.red.GetValue(requested_frame) != 0.0 || color.green.GetValue(requested_frame) != 0.0 || color.blue.GetValue(requested_frame) != 0.0)) - new_frame->AddColor(preview_width, preview_height, color.GetColorHex(requested_frame)); - - // Debug output - ZmqLogger::Instance()->AppendDebugMethod( - "Timeline::GetFrame (Loop through clips)", - "requested_frame", requested_frame, - "clips.size()", clips.size(), - "nearby_clips.size()", nearby_clips.size()); - - // Find Clips near this time - for (auto clip : nearby_clips) - { - long clip_start_position = round(clip->Position() * info.fps.ToDouble()) + 1; - long clip_end_position = round((clip->Position() + clip->Duration()) * info.fps.ToDouble()); - bool does_clip_intersect = (clip_start_position <= requested_frame && clip_end_position >= requested_frame); + // Return cached frame + return frame; + } else { + // Get a list of clips that intersect with the requested section of timeline + // This also opens the readers for intersecting clips, and marks non-intersecting clips as 'needs closing' + std::vector nearby_clips; + nearby_clips = find_intersecting_clips(requested_frame, 1, true); // Debug output ZmqLogger::Instance()->AppendDebugMethod( - "Timeline::GetFrame (Does clip intersect)", - "requested_frame", requested_frame, - "clip->Position()", clip->Position(), - "clip->Duration()", clip->Duration(), - "does_clip_intersect", does_clip_intersect); + "Timeline::GetFrame (processing frame)", + "requested_frame", requested_frame, + "omp_get_thread_num()", omp_get_thread_num()); - // Clip is visible - if (does_clip_intersect) - { - // Determine if clip is "top" clip on this layer (only happens when multiple clips are overlapping) - bool is_top_clip = true; - float max_volume = 0.0; - for (auto nearby_clip : nearby_clips) - { - long nearby_clip_start_position = round(nearby_clip->Position() * info.fps.ToDouble()) + 1; - long nearby_clip_end_position = round((nearby_clip->Position() + nearby_clip->Duration()) * info.fps.ToDouble()) + 1; - long nearby_clip_start_frame = (nearby_clip->Start() * info.fps.ToDouble()) + 1; - long nearby_clip_frame_number = requested_frame - nearby_clip_start_position + nearby_clip_start_frame; + // Init some basic properties about this frame + int samples_in_frame = Frame::GetSamplesPerFrame(requested_frame, info.fps, info.sample_rate, info.channels); - // Determine if top clip - if (clip->Id() != nearby_clip->Id() && clip->Layer() == nearby_clip->Layer() && + // Create blank frame (which will become the requested frame) + std::shared_ptr new_frame(std::make_shared(requested_frame, preview_width, preview_height, "#000000", samples_in_frame, info.channels)); + new_frame->AddAudioSilence(samples_in_frame); + new_frame->SampleRate(info.sample_rate); + new_frame->ChannelsLayout(info.channel_layout); + + // Debug output + ZmqLogger::Instance()->AppendDebugMethod( + "Timeline::GetFrame (Adding solid color)", + "requested_frame", requested_frame, + "info.width", info.width, + "info.height", info.height); + + // Add Background Color to 1st layer (if animated or not black) + if ((color.red.GetCount() > 1 || color.green.GetCount() > 1 || color.blue.GetCount() > 1) || + (color.red.GetValue(requested_frame) != 0.0 || color.green.GetValue(requested_frame) != 0.0 || + color.blue.GetValue(requested_frame) != 0.0)) + new_frame->AddColor(preview_width, preview_height, color.GetColorHex(requested_frame)); + + // Debug output + ZmqLogger::Instance()->AppendDebugMethod( + "Timeline::GetFrame (Loop through clips)", + "requested_frame", requested_frame, + "clips.size()", clips.size(), + "nearby_clips.size()", nearby_clips.size()); + + // Find Clips near this time + for (auto clip : nearby_clips) { + long clip_start_position = round(clip->Position() * info.fps.ToDouble()) + 1; + long clip_end_position = round((clip->Position() + clip->Duration()) * info.fps.ToDouble()); + bool does_clip_intersect = (clip_start_position <= requested_frame && clip_end_position >= requested_frame); + + // Debug output + ZmqLogger::Instance()->AppendDebugMethod( + "Timeline::GetFrame (Does clip intersect)", + "requested_frame", requested_frame, + "clip->Position()", clip->Position(), + "clip->Duration()", clip->Duration(), + "does_clip_intersect", does_clip_intersect); + + // Clip is visible + if (does_clip_intersect) { + // Determine if clip is "top" clip on this layer (only happens when multiple clips are overlapping) + bool is_top_clip = true; + float max_volume = 0.0; + for (auto nearby_clip : nearby_clips) { + long nearby_clip_start_position = round(nearby_clip->Position() * info.fps.ToDouble()) + 1; + long nearby_clip_end_position = round((nearby_clip->Position() + nearby_clip->Duration()) * info.fps.ToDouble()) + 1; + long nearby_clip_start_frame = (nearby_clip->Start() * info.fps.ToDouble()) + 1; + long nearby_clip_frame_number = requested_frame - nearby_clip_start_position + nearby_clip_start_frame; + + // Determine if top clip + if (clip->Id() != nearby_clip->Id() && clip->Layer() == nearby_clip->Layer() && nearby_clip_start_position <= requested_frame && nearby_clip_end_position >= requested_frame && nearby_clip_start_position > clip_start_position && is_top_clip == true) { - is_top_clip = false; - } + is_top_clip = false; + } - // Determine max volume of overlapping clips - if (nearby_clip->Reader() && nearby_clip->Reader()->info.has_audio && + // Determine max volume of overlapping clips + if (nearby_clip->Reader() && nearby_clip->Reader()->info.has_audio && nearby_clip->has_audio.GetInt(nearby_clip_frame_number) != 0 && nearby_clip_start_position <= requested_frame && nearby_clip_end_position >= requested_frame) { max_volume += nearby_clip->volume.GetValue(nearby_clip_frame_number); + } } + + // Determine the frame needed for this clip (based on the position on the timeline) + long clip_start_frame = (clip->Start() * info.fps.ToDouble()) + 1; + long clip_frame_number = requested_frame - clip_start_position + clip_start_frame; + + // Debug output + ZmqLogger::Instance()->AppendDebugMethod( + "Timeline::GetFrame (Calculate clip's frame #)", + "clip->Position()", clip->Position(), + "clip->Start()", clip->Start(), + "info.fps.ToFloat()", info.fps.ToFloat(), + "clip_frame_number", clip_frame_number); + + // Add clip's frame as layer + add_layer(new_frame, clip, clip_frame_number, is_top_clip, max_volume); + + } else { + // Debug output + ZmqLogger::Instance()->AppendDebugMethod( + "Timeline::GetFrame (clip does not intersect)", + "requested_frame", requested_frame, + "does_clip_intersect", does_clip_intersect); } - // Determine the frame needed for this clip (based on the position on the timeline) - long clip_start_frame = (clip->Start() * info.fps.ToDouble()) + 1; - long clip_frame_number = requested_frame - clip_start_position + clip_start_frame; + } // end clip loop - // Debug output - ZmqLogger::Instance()->AppendDebugMethod( - "Timeline::GetFrame (Calculate clip's frame #)", - "clip->Position()", clip->Position(), - "clip->Start()", clip->Start(), - "info.fps.ToFloat()", info.fps.ToFloat(), - "clip_frame_number", clip_frame_number); - - // Add clip's frame as layer - add_layer(new_frame, clip, clip_frame_number, is_top_clip, max_volume); - - } else { - // Debug output - ZmqLogger::Instance()->AppendDebugMethod( - "Timeline::GetFrame (clip does not intersect)", + // Debug output + ZmqLogger::Instance()->AppendDebugMethod( + "Timeline::GetFrame (Add frame to cache)", "requested_frame", requested_frame, - "does_clip_intersect", does_clip_intersect); - } + "info.width", info.width, + "info.height", info.height); - } // end clip loop + // Set frame # on mapped frame + new_frame->SetFrameNumber(requested_frame); - // Debug output - ZmqLogger::Instance()->AppendDebugMethod( - "Timeline::GetFrame (Add frame to cache)", - "requested_frame", requested_frame, - "info.width", info.width, - "info.height", info.height); + // Add final frame to cache + final_cache->Add(new_frame); - // Set frame # on mapped frame - new_frame->SetFrameNumber(requested_frame); - - // Add final frame to cache - final_cache->Add(new_frame); - - // Return frame (or blank frame) - return new_frame; + // Return frame (or blank frame) + return new_frame; + } } }