Adding new Clear() method to Timeline, to delete all allocated clips, effects, and frame mapeprs (freeing memory). Also, keep track of allocated clips and effects on timeline (when using SetJson to create them), so we can clean them up correctly on Clear() or RemoveClip()/RemoveEffect(). Added new test case for Clear().

This commit is contained in:
Jonathan Thomas
2022-10-06 15:07:31 -05:00
parent 8ac1589b2d
commit 934ca786ed
3 changed files with 134 additions and 23 deletions

View File

@@ -208,23 +208,14 @@ Timeline::~Timeline() {
// Auto Close if not already
Close();
// Free all allocated frame mappers
std::set<FrameMapper *>::iterator it;
for (it = allocated_frame_mappers.begin(); it != allocated_frame_mappers.end(); ) {
// Dereference and clean up FrameMapper object
FrameMapper *mapper = (*it);
mapper->Reader(NULL);
mapper->Close();
delete mapper;
// Remove reference and proceed to next element
it = allocated_frame_mappers.erase(it);
}
// Remove all clips, effects, and frame mappers
Clear();
// Destroy previous cache (if managed by timeline)
if (managed_cache && final_cache) {
delete final_cache;
final_cache = NULL;
}
// Destroy previous cache (if managed by timeline)
if (managed_cache && final_cache) {
delete final_cache;
final_cache = NULL;
}
}
// Add to the tracked_objects map a pointer to a tracked object (TrackedObjectBBox)
@@ -375,12 +366,26 @@ void Timeline::AddEffect(EffectBase* effect)
void Timeline::RemoveEffect(EffectBase* effect)
{
effects.remove(effect);
// Delete effect object (if timeline allocated it)
bool allocated = allocated_effects.count(effect);
if (allocated) {
delete effect;
effect = NULL;
}
}
// Remove an openshot::Clip to the timeline
void Timeline::RemoveClip(Clip* clip)
{
clips.remove(clip);
// Delete clip object (if timeline allocated it)
bool allocated = allocated_clips.count(clip);
if (allocated) {
delete clip;
clip = NULL;
}
}
// Look up a clip
@@ -473,6 +478,10 @@ void Timeline::apply_mapper_to_clip(Clip* clip)
// Get the existing reader
clip_reader = (ReaderBase*) clip->Reader();
// Update the mapping
FrameMapper* clip_mapped_reader = (FrameMapper*) clip_reader;
clip_mapped_reader->ChangeMapping(info.fps, PULLDOWN_NONE, info.sample_rate, info.channels, info.channel_layout);
} else {
// Create a new FrameMapper to wrap the current reader
@@ -481,10 +490,6 @@ void Timeline::apply_mapper_to_clip(Clip* clip)
clip_reader = (ReaderBase*) mapper;
}
// Update the mapping
FrameMapper* clip_mapped_reader = (FrameMapper*) clip_reader;
clip_mapped_reader->ChangeMapping(info.fps, PULLDOWN_NONE, info.sample_rate, info.channels, info.channel_layout);
// Update clip reader
clip->Reader(clip_reader);
}
@@ -763,6 +768,49 @@ void Timeline::sort_effects()
effects.sort(CompareEffects());
}
// Clear all clips from timeline
void Timeline::Clear()
{
ZmqLogger::Instance()->AppendDebugMethod("Timeline::Clear");
// Close all open clips
for (auto clip : clips)
{
update_open_clips(clip, false);
// Delete clip object (if timeline allocated it)
bool allocated = allocated_clips.count(clip);
if (allocated) {
delete clip;
clip = NULL;
}
}
// Clear all clips
clips.clear();
// Close all effects
for (auto effect : effects)
{
// Delete effect object (if timeline allocated it)
bool allocated = allocated_effects.count(effect);
if (allocated) {
delete effect;
effect = NULL;
}
}
// Clear all effects
effects.clear();
// Delete all FrameMappers
for (auto mapper : allocated_frame_mappers)
{
mapper->Reader(NULL);
mapper->Close();
delete mapper;
}
allocated_frame_mappers.clear();
}
// Close the reader (and any resources it was consuming)
void Timeline::Close()
{
@@ -1072,7 +1120,7 @@ void Timeline::SetJson(const std::string value) {
// Load Json::Value into this object
void Timeline::SetJsonValue(const Json::Value root) {
// Close timeline before we do anything (this also removes all open and closing clips)
// Close timeline before we do anything (this closes all clips)
bool was_open = is_open;
Close();
@@ -1092,6 +1140,9 @@ void Timeline::SetJsonValue(const Json::Value root) {
// Create Clip
Clip *c = new Clip();
// Keep track of allocated clip objects
allocated_clips.insert(c);
// When a clip is attached to an object, it searches for the object
// on it's parent timeline. Setting the parent timeline of the clip here
// allows attaching it to an object when exporting the project (because)
@@ -1120,6 +1171,9 @@ void Timeline::SetJsonValue(const Json::Value root) {
// Create instance of effect
if ( (e = EffectInfo().CreateEffect(existing_effect["type"].asString())) ) {
// Keep track of allocated effect objects
allocated_effects.insert(e);
// Load Json into Effect
e->SetJsonValue(existing_effect);
@@ -1255,9 +1309,14 @@ void Timeline::apply_json_to_clips(Json::Value change) {
// Determine type of change operation
if (change_type == "insert") {
// Create new clip
// Create clip
Clip *clip = new Clip();
clip->SetJsonValue(change["value"]); // Set properties of new clip from JSON
// Keep track of allocated clip objects
allocated_clips.insert(clip);
// Set properties of clip from JSON
clip->SetJsonValue(change["value"]);
AddClip(clip); // Add clip to timeline
// Apply framemapper (or update existing framemapper)
@@ -1363,6 +1422,9 @@ void Timeline::apply_json_to_effects(Json::Value change, EffectBase* existing_ef
// Init the matching effect object
if ( (e = EffectInfo().CreateEffect(effect_type)) ) {
// Keep track of allocated effect objects
allocated_effects.insert(e);
// Load Json into Effect
e->SetJsonValue(change["value"]);

View File

@@ -154,7 +154,9 @@ namespace openshot {
std::list<openshot::Clip*> clips; ///<List of clips on this timeline
std::list<openshot::Clip*> closing_clips; ///<List of clips that need to be closed
std::map<openshot::Clip*, openshot::Clip*> open_clips; ///<List of 'opened' clips on this timeline
std::set<openshot::Clip*> allocated_clips; ///<List of clips that were allocated by this timeline
std::list<openshot::EffectBase*> effects; ///<List of clips on this timeline
std::set<openshot::EffectBase*> allocated_effects; ///<List of effects that were allocated by this timeline
openshot::CacheBase *final_cache; ///<Final cache of timeline frames
std::set<openshot::FrameMapper*> allocated_frame_mappers; ///< all the frame mappers we allocated and must free
bool managed_cache; ///< Does this timeline instance manage the cache object
@@ -258,6 +260,9 @@ namespace openshot {
/// @brief Automatically map all clips to the timeline's framerate and samplerate
void AutoMapClips(bool auto_map) { auto_map_clips = auto_map; };
/// Clear all clips, effects, and frame mappers from timeline (and free memory)
void Clear();
/// Clear all cache for this timeline instance, including all clips' cache
/// @param deep If True, clear all FrameMappers and nested Readers (QtImageReader, FFmpegReader, etc...)
void ClearAllCache(bool deep=false);

File diff suppressed because one or more lines are too long