31 #include "../include/CacheDisk.h" 37 CacheDisk::CacheDisk(std::string cache_path, std::string format,
float quality,
float scale) :
CacheBase(0) {
41 needs_range_processing =
false;
43 image_format = format;
44 image_quality = quality;
57 needs_range_processing =
false;
59 image_format = format;
60 image_quality = quality;
68 void CacheDisk::InitPath(std::string cache_path) {
71 if (!cache_path.empty()) {
73 qpath = QString(cache_path.c_str());
77 qpath = QDir::tempPath() + QString(
"/preview-cache/");
90 void CacheDisk::CalculateRanges() {
92 if (needs_range_processing) {
98 std::sort(ordered_frame_numbers.begin(), ordered_frame_numbers.end());
101 Json::Value ranges = Json::Value(Json::arrayValue);
106 int64_t starting_frame = *ordered_frame_numbers.begin();
107 int64_t ending_frame = starting_frame;
110 for (
const auto frame_number : ordered_frame_numbers) {
111 if (frame_number - ending_frame > 1) {
117 std::stringstream start_str;
118 start_str << starting_frame;
119 std::stringstream end_str;
120 end_str << ending_frame;
121 range[
"start"] = start_str.str();
122 range[
"end"] = end_str.str();
123 ranges.append(range);
126 starting_frame = frame_number;
130 ending_frame = frame_number;
138 std::stringstream start_str;
139 start_str << starting_frame;
140 std::stringstream end_str;
141 end_str << ending_frame;
142 range[
"start"] = start_str.str();
143 range[
"end"] = end_str.str();
144 ranges.append(range);
147 json_ranges = ranges.toStyledString();
150 needs_range_processing =
false;
158 frame_numbers.clear();
159 ordered_frame_numbers.clear();
171 int64_t frame_number = frame->number;
174 if (frames.count(frame_number))
181 frames[frame_number] = frame_number;
182 frame_numbers.push_front(frame_number);
183 ordered_frame_numbers.push_back(frame_number);
184 needs_range_processing =
true;
187 QString frame_path(path.path() +
"/" + QString(
"%1.").arg(frame_number) + QString(image_format.c_str()).toLower());
188 frame->Save(frame_path.toStdString(), image_scale, image_format, image_quality);
189 if (frame_size_bytes == 0) {
191 QFile image_file(frame_path);
192 frame_size_bytes = image_file.size();
196 if (frame->has_audio_data) {
197 QString audio_path(path.path() +
"/" + QString(
"%1").arg(frame_number) +
".audio");
198 QFile audio_file(audio_path);
200 if (audio_file.open(QIODevice::WriteOnly)) {
201 QTextStream audio_stream(&audio_file);
202 audio_stream << frame->SampleRate() << endl;
203 audio_stream << frame->GetAudioChannelsCount() << endl;
204 audio_stream << frame->GetAudioSamplesCount() << endl;
205 audio_stream << frame->ChannelsLayout() << endl;
208 for (
int channel = 0; channel < frame->GetAudioChannelsCount(); channel++)
211 float *samples = frame->GetAudioSamples(channel);
212 for (
int sample = 0; sample < frame->GetAudioSamplesCount(); sample++)
213 audio_stream << samples[sample] << endl;
232 if (frames.count(frame_number)) {
234 QString frame_path(path.path() +
"/" + QString(
"%1.").arg(frame_number) + QString(image_format.c_str()).toLower());
235 if (path.exists(frame_path)) {
238 std::shared_ptr<QImage> image = std::shared_ptr<QImage>(
new QImage());
239 bool success = image->load(QString::fromStdString(frame_path.toStdString()));
242 image = std::shared_ptr<QImage>(
new QImage(image->convertToFormat(QImage::Format_RGBA8888)));
245 std::shared_ptr<Frame> frame(
new Frame());
246 frame->number = frame_number;
247 frame->AddImage(image);
250 QString audio_path(path.path() +
"/" + QString(
"%1").arg(frame_number) +
".audio");
251 QFile audio_file(audio_path);
252 if (audio_file.exists()) {
254 QTextStream in(&audio_file);
255 if (audio_file.open(QIODevice::ReadOnly)) {
256 int sample_rate = in.readLine().toInt();
257 int channels = in.readLine().toInt();
258 int sample_count = in.readLine().toInt();
259 int channel_layout = in.readLine().toInt();
262 frame->ResizeAudio(channels, sample_count, sample_rate, (
ChannelLayout) channel_layout);
265 int current_channel = 0;
266 int current_sample = 0;
267 float *channel_samples =
new float[sample_count];
268 while (!in.atEnd()) {
270 channel_samples[current_sample] = in.readLine().toFloat();
273 if (current_sample == sample_count) {
275 frame->AddAudio(
true, current_channel, 0, channel_samples, sample_count, 1.0);
292 return std::shared_ptr<Frame>();
300 std::shared_ptr<openshot::Frame> f;
303 std::deque<int64_t>::iterator itr;
304 int64_t smallest_frame = -1;
305 for(itr = frame_numbers.begin(); itr != frame_numbers.end(); ++itr)
307 if (*itr < smallest_frame || smallest_frame == -1)
308 smallest_frame = *itr;
323 int64_t total_bytes = 0;
326 std::deque<int64_t>::reverse_iterator itr;
327 for(itr = frame_numbers.rbegin(); itr != frame_numbers.rend(); ++itr)
328 total_bytes += frame_size_bytes;
336 Remove(frame_number, frame_number);
346 std::deque<int64_t>::iterator itr;
347 for(itr = frame_numbers.begin(); itr != frame_numbers.end();)
350 if (*itr >= start_frame_number && *itr <= end_frame_number)
353 itr = frame_numbers.erase(itr);
359 std::vector<int64_t>::iterator itr_ordered;
360 for(itr_ordered = ordered_frame_numbers.begin(); itr_ordered != ordered_frame_numbers.end();)
362 if (*itr_ordered >= start_frame_number && *itr_ordered <= end_frame_number)
365 frames.erase(*itr_ordered);
368 QString frame_path(path.path() +
"/" + QString(
"%1.").arg(*itr_ordered) + QString(image_format.c_str()).toLower());
369 QFile image_file(frame_path);
370 if (image_file.exists())
374 QString audio_path(path.path() +
"/" + QString(
"%1").arg(*itr_ordered) +
".audio");
375 QFile audio_file(audio_path);
376 if (audio_file.exists())
379 itr_ordered = ordered_frame_numbers.erase(itr_ordered);
385 needs_range_processing =
true;
392 if (frames.count(frame_number))
398 std::deque<int64_t>::iterator itr;
399 for(itr = frame_numbers.begin(); itr != frame_numbers.end(); ++itr)
401 if (*itr == frame_number)
404 frame_numbers.erase(itr);
407 frame_numbers.push_front(frame_number);
422 frame_numbers.clear();
423 ordered_frame_numbers.clear();
424 needs_range_processing =
true;
425 frame_size_bytes = 0;
428 QString current_path = path.path();
429 path.removeRecursively();
432 InitPath(current_path.toStdString());
442 return frames.size();
446 void CacheDisk::CleanUp()
457 int64_t frame_to_remove = frame_numbers.back();
481 root[
"path"] = path.path().toStdString();
484 std::stringstream range_version_str;
485 range_version_str << range_version;
486 root[
"version"] = range_version_str.str();
490 Json::CharReaderBuilder rbuilder;
491 Json::CharReader* reader(rbuilder.newCharReader());
494 bool success = reader->parse( json_ranges.c_str(),
495 json_ranges.c_str() + json_ranges.size(), &ranges, &errors );
499 root[
"ranges"] = ranges;
510 Json::CharReaderBuilder rbuilder;
511 Json::CharReader* reader(rbuilder.newCharReader());
514 bool success = reader->parse( value.c_str(),
515 value.c_str() + value.size(), &root, &errors );
520 throw InvalidJSON(
"JSON could not be parsed (or is invalid)");
527 catch (
const std::exception& e)
530 throw InvalidJSON(
"JSON is invalid (missing keys or invalid data types)");
543 if (!root[
"type"].isNull())
545 if (!root[
"path"].isNull())
547 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.
This class represents a single frame of video (i.e. image & audio data)
int64_t GetBytes()
Gets the maximum bytes value.
void SetJsonValue(Json::Value root)
Load Json::JsonValue into this object.
std::string Json()
Get and Set JSON methods.
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::JsonValue for this object.
void MoveToFront(int64_t frame_number)
Move frame to front of queue (so it lasts longer)
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::JsonValue for this object.
void SetJson(std::string value)
Load JSON string into this object.
void Clear()
Clear the cache of all frames.
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.
Exception for invalid JSON.
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)
virtual void SetJsonValue(Json::Value root)=0
Load Json::JsonValue into this object.
CacheDisk(std::string cache_path, std::string format, float quality, float scale)
Default constructor, no max bytes.