36 #include <QTextStream> 42 CacheDisk::CacheDisk(std::string cache_path, std::string format,
float quality,
float scale) :
CacheBase(0) {
46 needs_range_processing =
false;
48 image_format = format;
49 image_quality = quality;
62 needs_range_processing =
false;
64 image_format = format;
65 image_quality = quality;
73 void CacheDisk::InitPath(std::string cache_path) {
76 if (!cache_path.empty()) {
78 qpath = QString(cache_path.c_str());
82 qpath = QDir::tempPath() + QString(
"/preview-cache/");
95 void CacheDisk::CalculateRanges() {
97 if (needs_range_processing) {
103 std::sort(ordered_frame_numbers.begin(), ordered_frame_numbers.end());
106 Json::Value ranges = Json::Value(Json::arrayValue);
111 int64_t starting_frame = *ordered_frame_numbers.begin();
112 int64_t ending_frame = starting_frame;
115 for (
const auto frame_number : ordered_frame_numbers) {
116 if (frame_number - ending_frame > 1) {
122 range[
"start"] = std::to_string(starting_frame);
123 range[
"end"] = std::to_string(ending_frame);
124 ranges.append(range);
127 starting_frame = frame_number;
131 ending_frame = frame_number;
139 range[
"start"] = std::to_string(starting_frame);
140 range[
"end"] = std::to_string(ending_frame);
141 ranges.append(range);
144 json_ranges = ranges.toStyledString();
147 needs_range_processing =
false;
155 frame_numbers.clear();
156 ordered_frame_numbers.clear();
168 int64_t frame_number = frame->number;
171 if (frames.count(frame_number))
178 frames[frame_number] = frame_number;
179 frame_numbers.push_front(frame_number);
180 ordered_frame_numbers.push_back(frame_number);
181 needs_range_processing =
true;
184 QString frame_path(path.path() +
"/" + QString(
"%1.").arg(frame_number) + QString(image_format.c_str()).toLower());
185 frame->Save(frame_path.toStdString(), image_scale, image_format, image_quality);
186 if (frame_size_bytes == 0) {
188 QFile image_file(frame_path);
189 frame_size_bytes = image_file.size();
193 if (frame->has_audio_data) {
194 QString audio_path(path.path() +
"/" + QString(
"%1").arg(frame_number) +
".audio");
195 QFile audio_file(audio_path);
197 if (audio_file.open(QIODevice::WriteOnly)) {
198 QTextStream audio_stream(&audio_file);
199 audio_stream << frame->SampleRate() << Qt::endl;
200 audio_stream << frame->GetAudioChannelsCount() << Qt::endl;
201 audio_stream << frame->GetAudioSamplesCount() << Qt::endl;
202 audio_stream << frame->ChannelsLayout() << Qt::endl;
205 for (
int channel = 0; channel < frame->GetAudioChannelsCount(); channel++)
208 float *samples = frame->GetAudioSamples(channel);
209 for (
int sample = 0; sample < frame->GetAudioSamplesCount(); sample++)
210 audio_stream << samples[sample] << Qt::endl;
229 if (frames.count(frame_number)) {
231 QString frame_path(path.path() +
"/" + QString(
"%1.").arg(frame_number) + QString(image_format.c_str()).toLower());
232 if (path.exists(frame_path)) {
235 auto image = std::make_shared<QImage>();
236 image->load(frame_path);
239 image = std::make_shared<QImage>(image->convertToFormat(QImage::Format_RGBA8888_Premultiplied));
242 auto frame = std::make_shared<Frame>();
243 frame->number = frame_number;
244 frame->AddImage(image);
247 QString audio_path(path.path() +
"/" + QString(
"%1").arg(frame_number) +
".audio");
248 QFile audio_file(audio_path);
249 if (audio_file.exists()) {
251 QTextStream in(&audio_file);
252 if (audio_file.open(QIODevice::ReadOnly)) {
253 int sample_rate = in.readLine().toInt();
254 int channels = in.readLine().toInt();
255 int sample_count = in.readLine().toInt();
256 int channel_layout = in.readLine().toInt();
259 frame->ResizeAudio(channels, sample_count, sample_rate, (
ChannelLayout) channel_layout);
262 int current_channel = 0;
263 int current_sample = 0;
264 float *channel_samples =
new float[sample_count];
265 while (!in.atEnd()) {
267 channel_samples[current_sample] = in.readLine().toFloat();
270 if (current_sample == sample_count) {
272 frame->AddAudio(
true, current_channel, 0, channel_samples, sample_count, 1.0);
289 return std::shared_ptr<Frame>();
297 std::shared_ptr<openshot::Frame> f;
300 std::deque<int64_t>::iterator itr;
301 int64_t smallest_frame = -1;
302 for(itr = frame_numbers.begin(); itr != frame_numbers.end(); ++itr)
304 if (*itr < smallest_frame || smallest_frame == -1)
305 smallest_frame = *itr;
320 int64_t total_bytes = 0;
323 std::deque<int64_t>::reverse_iterator itr;
324 for(itr = frame_numbers.rbegin(); itr != frame_numbers.rend(); ++itr)
325 total_bytes += frame_size_bytes;
333 Remove(frame_number, frame_number);
343 std::deque<int64_t>::iterator itr;
344 for(itr = frame_numbers.begin(); itr != frame_numbers.end();)
347 if (*itr >= start_frame_number && *itr <= end_frame_number)
350 itr = frame_numbers.erase(itr);
356 std::vector<int64_t>::iterator itr_ordered;
357 for(itr_ordered = ordered_frame_numbers.begin(); itr_ordered != ordered_frame_numbers.end();)
359 if (*itr_ordered >= start_frame_number && *itr_ordered <= end_frame_number)
362 frames.erase(*itr_ordered);
365 QString frame_path(path.path() +
"/" + QString(
"%1.").arg(*itr_ordered) + QString(image_format.c_str()).toLower());
366 QFile image_file(frame_path);
367 if (image_file.exists())
371 QString audio_path(path.path() +
"/" + QString(
"%1").arg(*itr_ordered) +
".audio");
372 QFile audio_file(audio_path);
373 if (audio_file.exists())
376 itr_ordered = ordered_frame_numbers.erase(itr_ordered);
382 needs_range_processing =
true;
389 if (frames.count(frame_number))
395 std::deque<int64_t>::iterator itr;
396 for(itr = frame_numbers.begin(); itr != frame_numbers.end(); ++itr)
398 if (*itr == frame_number)
401 frame_numbers.erase(itr);
404 frame_numbers.push_front(frame_number);
419 frame_numbers.clear();
420 ordered_frame_numbers.clear();
421 needs_range_processing =
true;
422 frame_size_bytes = 0;
425 QString current_path = path.path();
426 path.removeRecursively();
429 InitPath(current_path.toStdString());
439 return frames.size();
443 void CacheDisk::CleanUp()
454 int64_t frame_to_remove = frame_numbers.back();
478 root[
"path"] = path.path().toStdString();
481 std::stringstream range_version_str;
482 range_version_str << range_version;
483 root[
"version"] = range_version_str.str();
489 root[
"ranges"] = ranges;
506 catch (
const std::exception& e)
509 throw InvalidJSON(
"JSON is invalid (missing keys or invalid data types)");
522 if (!root[
"type"].isNull())
524 if (!root[
"path"].isNull())
526 InitPath(root[
"path"].asString());
juce::CriticalSection * cacheCriticalSection
Section lock for multiple threads.
void Add(std::shared_ptr< openshot::Frame > frame)
Add a Frame to the cache.
int64_t Count()
Count the frames in the queue.
int64_t GetBytes()
Gets the maximum bytes value.
const Json::Value stringToJson(const std::string value)
std::string Json()
Generate JSON string of this object.
Header file for all Exception classes.
std::shared_ptr< openshot::Frame > GetFrame(int64_t frame_number)
Get a frame from the cache.
void Remove(int64_t frame_number)
Remove a specific frame.
Json::Value JsonValue()
Generate Json::Value for this object.
void MoveToFront(int64_t frame_number)
Move frame to front of queue (so it lasts longer)
void SetJsonValue(const Json::Value root)
Load Json::Value into this object.
All cache managers in libopenshot are based on this CacheBase class.
ChannelLayout
This enumeration determines the audio channel layout (such as stereo, mono, 5 point surround...
virtual Json::Value JsonValue()=0
Generate Json::Value for this object.
void Clear()
Clear the cache of all frames.
Header file for QtUtilities (compatibiity overlay)
std::string cache_type
This is a friendly type name of the derived cache instance.
This namespace is the default namespace for all code in the openshot library.
virtual void SetJsonValue(const Json::Value root)=0
Load Json::Value into this object.
Exception for invalid JSON.
Header file for CacheDisk class.
std::shared_ptr< openshot::Frame > GetSmallestFrame()
Get the smallest frame number.
int64_t max_bytes
This is the max number of bytes to cache (0 = no limit)
void SetJson(const std::string value)
Load JSON string into this object.
CacheDisk(std::string cache_path, std::string format, float quality, float scale)
Default constructor, no max bytes.