~mbranton/libopenshot/alpha-channel-fix

« back to all changes in this revision

Viewing changes to src/Timeline.cpp

  • Committer: Jonathan Thomas
  • Date: 2016-09-07 05:40:01 UTC
  • Revision ID: jonathan@openshot.org-20160907054001-v2tbe8uy8a7lk4qw
Added new CacheDisk class, which caches frames to the hard drive, dramatically speeding up preview speeds, at the expense of IO operations. New unittests for caching framework. Fixed a few bugs with Frame constructor, which was causing invalid # width & height. Integrated JSON into the cache framework, to quickly share the state of the cache (including ranges of cached frame numbers). Fixed a bug where some Timeline frames could have no audio samples.

Show diffs side-by-side

added added

removed removed

Lines of Context:
57
57
        info.video_length = info.fps.ToFloat() * info.duration;
58
58
 
59
59
        // Init cache
60
 
        final_cache.SetMaxBytesFromInfo(OPEN_MP_NUM_PROCESSORS * 2, info.width, info.height, info.sample_rate, info.channels);
 
60
        final_cache = new CacheMemory();
 
61
        final_cache->SetMaxBytesFromInfo(OPEN_MP_NUM_PROCESSORS * 2, info.width, info.height, info.sample_rate, info.channels);
61
62
}
62
63
 
63
64
// Add an openshot::Clip to the timeline
125
126
void Timeline::ApplyMapperToClips()
126
127
{
127
128
        // Clear all cached frames
128
 
        final_cache.Clear();
 
129
        final_cache->Clear();
129
130
 
130
131
        // Loop through all clips
131
132
        list<Clip*>::iterator clip_itr;
582
583
        is_open = false;
583
584
 
584
585
        // Clear cache
585
 
        final_cache.Clear();
 
586
        final_cache->Clear();
586
587
}
587
588
 
588
589
// Open the reader (and start consuming resources)
609
610
                requested_frame = 1;
610
611
 
611
612
        // Check cache
612
 
        tr1::shared_ptr<Frame> frame = final_cache.GetFrame(requested_frame);
 
613
        tr1::shared_ptr<Frame> frame = final_cache->GetFrame(requested_frame);
613
614
        if (frame) {
614
615
                // Debug output
615
616
                ZmqLogger::Instance()->AppendDebugMethod("Timeline::GetFrame (Cached frame found)", "requested_frame", requested_frame, "", -1, "", -1, "", -1, "", -1, "", -1);
623
624
                const GenericScopedLock<CriticalSection> lock(getFrameCriticalSection);
624
625
 
625
626
                // Check cache again (due to locking)
626
 
                frame = final_cache.GetFrame(requested_frame);
 
627
                frame = final_cache->GetFrame(requested_frame);
627
628
                if (frame) {
628
629
                        // Debug output
629
630
                        ZmqLogger::Instance()->AppendDebugMethod("Timeline::GetFrame (Cached frame found on 2nd look)", "requested_frame", requested_frame, "", -1, "", -1, "", -1, "", -1, "", -1);
683
684
 
684
685
                                // Create blank frame (which will become the requested frame)
685
686
                                tr1::shared_ptr<Frame> new_frame(tr1::shared_ptr<Frame>(new Frame(frame_number, info.width, info.height, "#000000", samples_in_frame, info.channels)));
 
687
                                new_frame->AddAudioSilence(samples_in_frame);
686
688
                                new_frame->SampleRate(info.sample_rate);
687
689
                                new_frame->ChannelsLayout(info.channel_layout);
688
690
 
748
750
                                ZmqLogger::Instance()->AppendDebugMethod("Timeline::GetFrame (Add frame to cache)", "frame_number", frame_number, "info.width", info.width, "info.height", info.height, "", -1, "", -1, "", -1);
749
751
 
750
752
                                // Add final frame to cache
751
 
                                final_cache.Add(new_frame);
 
753
                                final_cache->Add(new_frame);
752
754
 
753
755
                        } // end frame loop
754
756
                } // end parallel
757
759
                ZmqLogger::Instance()->AppendDebugMethod("Timeline::GetFrame (end parallel region)", "requested_frame", requested_frame, "omp_get_thread_num()", omp_get_thread_num(), "", -1, "", -1, "", -1, "", -1);
758
760
 
759
761
                // Return frame (or blank frame)
760
 
                return final_cache.GetFrame(requested_frame);
 
762
                return final_cache->GetFrame(requested_frame);
761
763
        }
762
764
}
763
765
 
810
812
        return matching_clips;
811
813
}
812
814
 
 
815
// Get the cache object used by this reader
 
816
void Timeline::SetCache(CacheBase* new_cache) {
 
817
        // Set new cache
 
818
        final_cache = new_cache;
 
819
}
 
820
 
813
821
// Generate JSON string of this object
814
822
string Timeline::Json() {
815
823
 
943
951
// Apply a special formatted JSON object, which represents a change to the timeline (insert, update, delete)
944
952
void Timeline::ApplyJsonDiff(string value) throw(InvalidJSON, InvalidJSONKey) {
945
953
 
946
 
        // Clear internal cache (since things are about to change)
947
 
        final_cache.Clear();
948
 
 
949
954
        // Parse JSON string into JSON objects
950
955
        Json::Value root;
951
956
        Json::Reader reader;
982
987
                // Error parsing JSON (or missing keys)
983
988
                throw InvalidJSON("JSON is invalid (missing keys or invalid data types)", "");
984
989
        }
985
 
 
986
 
        // Adjust cache (in case something changed)
987
 
        final_cache.SetMaxBytesFromInfo(OPEN_MP_NUM_PROCESSORS * 2, info.width, info.height, info.sample_rate, info.channels);
988
990
}
989
991
 
990
992
// Apply JSON diff to clips
1053
1055
                }
1054
1056
        }
1055
1057
 
 
1058
        // Calculate start and end frames that this impacts, and remove those frames from the cache
 
1059
        long int new_starting_frame = change["value"]["position"].asDouble() * info.fps.ToDouble();
 
1060
        long int new_ending_frame = (change["value"]["position"].asDouble() + change["value"]["end"].asDouble() - change["value"]["start"].asDouble()) * info.fps.ToDouble();
 
1061
        final_cache->Remove(new_starting_frame - 1, new_ending_frame + 1);
 
1062
 
1056
1063
        // Determine type of change operation
1057
1064
        if (change_type == "insert") {
1058
1065
 
1064
1071
        } else if (change_type == "update") {
1065
1072
 
1066
1073
                // Update existing clip
1067
 
                if (existing_clip)
1068
 
                        existing_clip->SetJsonValue(change["value"]); // Update clip properties from JSON
 
1074
                if (existing_clip) {
 
1075
 
 
1076
                        // Calculate start and end frames that this impacts, and remove those frames from the cache
 
1077
                        long int old_starting_frame = existing_clip->Position() * info.fps.ToDouble();
 
1078
                        long int old_ending_frame = (existing_clip->Position() + existing_clip->End() - existing_clip->Start()) * info.fps.ToDouble();
 
1079
                        final_cache->Remove(old_starting_frame - 1, old_ending_frame + 1);
 
1080
 
 
1081
                        // Update clip properties from JSON
 
1082
                        existing_clip->SetJsonValue(change["value"]);
 
1083
                }
1069
1084
 
1070
1085
        } else if (change_type == "delete") {
1071
1086
 
1072
1087
                // Remove existing clip
1073
 
                if (existing_clip)
1074
 
                        RemoveClip(existing_clip); // Remove clip from timeline
 
1088
                if (existing_clip) {
 
1089
 
 
1090
                        // Calculate start and end frames that this impacts, and remove those frames from the cache
 
1091
                        long int old_starting_frame = existing_clip->Position() * info.fps.ToDouble();
 
1092
                        long int old_ending_frame = (existing_clip->Position() + existing_clip->End() - existing_clip->Start()) * info.fps.ToDouble();
 
1093
                        final_cache->Remove(old_starting_frame - 1, old_ending_frame + 1);
 
1094
 
 
1095
                        // Remove clip from timeline
 
1096
                        RemoveClip(existing_clip);
 
1097
                }
1075
1098
 
1076
1099
        }
1077
1100
 
1124
1147
        // Get key and type of change
1125
1148
        string change_type = change["type"].asString();
1126
1149
 
 
1150
        // Calculate start and end frames that this impacts, and remove those frames from the cache
 
1151
        long int new_starting_frame = change["value"]["position"].asDouble() * info.fps.ToDouble();
 
1152
        long int new_ending_frame = (change["value"]["position"].asDouble() + change["value"]["end"].asDouble() - change["value"]["start"].asDouble()) * info.fps.ToDouble();
 
1153
        final_cache->Remove(new_starting_frame - 1, new_ending_frame + 1);
 
1154
 
1127
1155
        // Determine type of change operation
1128
1156
        if (change_type == "insert") {
1129
1157
 
1145
1173
        } else if (change_type == "update") {
1146
1174
 
1147
1175
                // Update existing effect
1148
 
                if (existing_effect)
1149
 
                        existing_effect->SetJsonValue(change["value"]); // Update effect properties from JSON
 
1176
                if (existing_effect) {
 
1177
 
 
1178
                        // Calculate start and end frames that this impacts, and remove those frames from the cache
 
1179
                        long int old_starting_frame = existing_effect->Position() * info.fps.ToDouble();
 
1180
                        long int old_ending_frame = (existing_effect->Position() + existing_effect->End() - existing_effect->Start()) * info.fps.ToDouble();
 
1181
                        final_cache->Remove(old_starting_frame - 1, old_ending_frame + 1);
 
1182
 
 
1183
                        // Update effect properties from JSON
 
1184
                        existing_effect->SetJsonValue(change["value"]);
 
1185
                }
1150
1186
 
1151
1187
        } else if (change_type == "delete") {
1152
1188
 
1153
1189
                // Remove existing effect
1154
 
                if (existing_effect)
1155
 
                        RemoveEffect(existing_effect); // Remove effect from timeline
 
1190
                if (existing_effect) {
 
1191
 
 
1192
                        // Calculate start and end frames that this impacts, and remove those frames from the cache
 
1193
                        long int old_starting_frame = existing_effect->Position() * info.fps.ToDouble();
 
1194
                        long int old_ending_frame = (existing_effect->Position() + existing_effect->End() - existing_effect->Start()) * info.fps.ToDouble();
 
1195
                        final_cache->Remove(old_starting_frame - 1, old_ending_frame + 1);
 
1196
 
 
1197
                        // Remove effect from timeline
 
1198
                        RemoveEffect(existing_effect);
 
1199
                }
1156
1200
 
1157
1201
        }
1158
1202
}
1167
1211
        if (change["key"].size() >= 2)
1168
1212
                sub_key = change["key"][(uint)1].asString();
1169
1213
 
 
1214
        // Clear entire cache
 
1215
        final_cache->Clear();
 
1216
 
1170
1217
        // Determine type of change operation
1171
1218
        if (change_type == "insert" || change_type == "update") {
1172
1219