You've already forked libopenshot
mirror of
https://github.com/OpenShot/libopenshot.git
synced 2026-03-02 08:53:52 -08:00
Timeline now checks cache 2nd time, after mutex - incase previous call generated the same frame
This commit is contained in:
215
src/Timeline.cpp
215
src/Timeline.cpp
@@ -874,128 +874,139 @@ std::shared_ptr<Frame> Timeline::GetFrame(int64_t requested_frame)
|
||||
// Prevent async calls to the following code
|
||||
const std::lock_guard<std::recursive_mutex> 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<Clip*> nearby_clips;
|
||||
nearby_clips = find_intersecting_clips(requested_frame, 1, true);
|
||||
// Check cache 2nd time
|
||||
std::shared_ptr<Frame> 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<Frame> new_frame(std::make_shared<Frame>(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<Clip *> 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<Frame> new_frame(std::make_shared<Frame>(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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user