29 is_open(false), auto_map_clips(true), managed_cache(true),
path(
""),
75 info.width, info.height, info.fps, info.sample_rate,
76 info.channels, info.channel_layout) {}
80 is_open(false), auto_map_clips(true), managed_cache(true), path(projectPath),
100 QFileInfo filePath(QString::fromStdString(path));
101 if (!filePath.exists()) {
102 throw InvalidFile(
"File could not be opened.", path);
108 if (!openshotPath.exists()) {
111 QDir openshotTransPath(openshotPath.filePath(
"transitions"));
112 if (!openshotTransPath.exists()) {
113 throw InvalidFile(
"PATH_OPENSHOT_INSTALL/transitions could not be found.", openshotTransPath.path().toStdString());
117 QString asset_name = filePath.baseName().left(30) +
"_assets";
118 QDir asset_folder(filePath.dir().filePath(asset_name));
119 if (!asset_folder.exists()) {
121 asset_folder.mkpath(
".");
125 QFile projectFile(QString::fromStdString(path));
126 projectFile.open(QFile::ReadOnly);
127 QString projectContents = QString::fromUtf8(projectFile.readAll());
130 if (convert_absolute_paths) {
134 QRegularExpression allPathsRegex(QStringLiteral(
"\"(image|path)\":.*?\"(.*?)\""));
135 std::vector<QRegularExpressionMatch> matchedPositions;
136 QRegularExpressionMatchIterator i = allPathsRegex.globalMatch(projectContents);
137 while (i.hasNext()) {
138 QRegularExpressionMatch match = i.next();
139 if (match.hasMatch()) {
141 matchedPositions.push_back(match);
146 std::vector<QRegularExpressionMatch>::reverse_iterator itr;
147 for (itr = matchedPositions.rbegin(); itr != matchedPositions.rend(); itr++) {
148 QRegularExpressionMatch match = *itr;
149 QString relativeKey = match.captured(1);
150 QString relativePath = match.captured(2);
151 QString absolutePath =
"";
154 if (relativePath.startsWith(
"@assets")) {
155 absolutePath = QFileInfo(asset_folder.absoluteFilePath(relativePath.replace(
"@assets",
"."))).canonicalFilePath();
156 }
else if (relativePath.startsWith(
"@transitions")) {
157 absolutePath = QFileInfo(openshotTransPath.absoluteFilePath(relativePath.replace(
"@transitions",
"."))).canonicalFilePath();
159 absolutePath = QFileInfo(filePath.absoluteDir().absoluteFilePath(relativePath)).canonicalFilePath();
163 if (!absolutePath.isEmpty()) {
164 projectContents.replace(match.capturedStart(0), match.capturedLength(0),
"\"" + relativeKey +
"\": \"" + absolutePath +
"\"");
168 matchedPositions.clear();
172 SetJson(projectContents.toStdString());
176 float calculated_duration = 0.0;
177 for (
auto clip : clips)
180 if (clip_last_frame > calculated_duration)
181 calculated_duration = clip_last_frame;
182 if (
clip->Reader() &&
clip->Reader()->info.has_audio)
184 if (
clip->Reader() &&
clip->Reader()->info.has_video)
216 if (managed_cache && final_cache) {
226 auto iterator = tracked_objects.find(trackedObject->Id());
228 if (iterator != tracked_objects.end()){
230 iterator->second = trackedObject;
234 tracked_objects[trackedObject->Id()] = trackedObject;
244 auto iterator = tracked_objects.find(
id);
246 if (iterator != tracked_objects.end()){
248 std::shared_ptr<openshot::TrackedObjectBase> trackedObject = iterator->second;
249 return trackedObject;
261 std::list<std::string> trackedObjects_ids;
264 for (
auto const& it: tracked_objects){
266 trackedObjects_ids.push_back(it.first);
269 return trackedObjects_ids;
277 Json::Value trackedObjectJson;
280 auto iterator = tracked_objects.find(
id);
282 if (iterator != tracked_objects.end())
285 std::shared_ptr<TrackedObjectBBox> trackedObject = std::static_pointer_cast<
TrackedObjectBBox>(iterator->second);
288 if (trackedObject->ExactlyContains(frame_number)){
289 BBox box = trackedObject->GetBox(frame_number);
290 float x1 = box.
cx - (box.
width/2);
292 float x2 = box.
cx + (box.
width/2);
294 float rotation = box.
angle;
296 trackedObjectJson[
"x1"] = x1;
297 trackedObjectJson[
"y1"] = y1;
298 trackedObjectJson[
"x2"] = x2;
299 trackedObjectJson[
"y2"] = y2;
300 trackedObjectJson[
"rotation"] = rotation;
303 BBox box = trackedObject->BoxVec.begin()->second;
304 float x1 = box.
cx - (box.
width/2);
306 float x2 = box.
cx + (box.
width/2);
308 float rotation = box.
angle;
310 trackedObjectJson[
"x1"] = x1;
311 trackedObjectJson[
"y1"] = y1;
312 trackedObjectJson[
"x2"] = x2;
313 trackedObjectJson[
"y2"] = y2;
314 trackedObjectJson[
"rotation"] = rotation;
320 trackedObjectJson[
"x1"] = 0;
321 trackedObjectJson[
"y1"] = 0;
322 trackedObjectJson[
"x2"] = 0;
323 trackedObjectJson[
"y2"] = 0;
324 trackedObjectJson[
"rotation"] = 0;
327 return trackedObjectJson.toStyledString();
335 const std::lock_guard<std::recursive_mutex> guard(
getFrameMutex);
342 clip->
Reader()->GetCache()->Clear();
345 if (auto_map_clips) {
347 apply_mapper_to_clip(clip);
351 clips.push_back(clip);
364 effects.push_back(effect);
373 effects.remove(effect);
376 bool allocated = allocated_effects.count(effect);
380 allocated_effects.erase(effect);
391 const std::lock_guard<std::recursive_mutex> guard(
getFrameMutex);
396 bool allocated = allocated_clips.count(clip);
400 allocated_clips.erase(clip);
411 for (
const auto&
clip : clips) {
423 for (
const auto& effect : effects) {
424 if (effect->Id() == id) {
434 for (
const auto&
clip : clips) {
435 const auto e =
clip->GetEffect(
id);
447 std::list<EffectBase*> timelineEffectsList;
450 for (
const auto&
clip : clips) {
453 std::list<EffectBase*> clipEffectsList =
clip->Effects();
456 timelineEffectsList.insert(timelineEffectsList.end(), clipEffectsList.begin(), clipEffectsList.end());
459 return timelineEffectsList;
472 return std::round(max_time * fps) + 1;
476 void Timeline::apply_mapper_to_clip(
Clip*
clip)
480 if (clip->
Reader()->Name() ==
"FrameMapper")
493 allocated_frame_mappers.insert(mapper);
498 clip->
Reader(clip_reader);
508 for (
auto clip : clips)
511 apply_mapper_to_clip(clip);
516 double Timeline::calculate_time(int64_t number,
Fraction rate)
519 double raw_fps = rate.
ToFloat();
522 return double(number - 1) / raw_fps;
530 "Timeline::apply_effects",
531 "frame->number", frame->number,
532 "timeline_frame_number", timeline_frame_number,
536 for (
auto effect : effects)
539 long effect_start_position = round(effect->Position() *
info.
fps.
ToDouble()) + 1;
540 long effect_end_position = round((effect->Position() + (effect->Duration())) *
info.
fps.
ToDouble());
542 bool does_effect_intersect = (effect_start_position <= timeline_frame_number && effect_end_position >= timeline_frame_number && effect->Layer() == layer);
546 "Timeline::apply_effects (Does effect intersect)",
547 "effect->Position()", effect->Position(),
548 "does_effect_intersect", does_effect_intersect,
549 "timeline_frame_number", timeline_frame_number,
553 if (does_effect_intersect)
557 long effect_frame_number = timeline_frame_number - effect_start_position + effect_start_frame;
561 "Timeline::apply_effects (Process Effect)",
562 "effect_frame_number", effect_frame_number,
563 "does_effect_intersect", does_effect_intersect);
566 frame = effect->GetFrame(frame, effect_frame_number);
576 std::shared_ptr<Frame> Timeline::GetOrCreateFrame(std::shared_ptr<Frame> background_frame,
Clip* clip, int64_t number,
openshot::TimelineInfoStruct* options)
578 std::shared_ptr<Frame> new_frame;
586 "Timeline::GetOrCreateFrame (from reader)",
588 "samples_in_frame", samples_in_frame);
591 new_frame = std::shared_ptr<Frame>(clip->
GetFrame(background_frame, number, options));
604 "Timeline::GetOrCreateFrame (create blank)",
606 "samples_in_frame", samples_in_frame);
613 void Timeline::add_layer(std::shared_ptr<Frame> new_frame,
Clip* source_clip, int64_t clip_frame_number,
bool is_top_clip,
float max_volume)
620 std::shared_ptr<Frame> source_frame;
621 source_frame = GetOrCreateFrame(new_frame, source_clip, clip_frame_number, options);
630 "Timeline::add_layer",
631 "new_frame->number", new_frame->number,
632 "clip_frame_number", clip_frame_number);
635 if (source_clip->
Reader()->info.has_audio) {
638 "Timeline::add_layer (Copy Audio)",
639 "source_clip->Reader()->info.has_audio", source_clip->
Reader()->info.has_audio,
640 "source_frame->GetAudioChannelsCount()", source_frame->GetAudioChannelsCount(),
642 "clip_frame_number", clip_frame_number);
645 for (
int channel = 0; channel < source_frame->GetAudioChannelsCount(); channel++)
648 float previous_volume = source_clip->
volume.
GetValue(clip_frame_number - 1);
656 previous_volume = previous_volume / max_volume;
657 volume = volume / max_volume;
661 previous_volume = previous_volume * 0.77;
662 volume = volume * 0.77;
666 if (channel_filter != -1 && channel_filter != channel)
670 if (previous_volume == 0.0 && volume == 0.0)
674 if (channel_mapping == -1)
675 channel_mapping = channel;
678 if (!isEqual(previous_volume, 1.0) || !isEqual(volume, 1.0))
679 source_frame->ApplyGainRamp(channel_mapping, 0, source_frame->GetAudioSamplesCount(), previous_volume, volume);
685 if (new_frame->GetAudioSamplesCount() != source_frame->GetAudioSamplesCount()){
691 new_frame->AddAudio(
false, channel_mapping, 0, source_frame->GetAudioSamples(channel), source_frame->GetAudioSamplesCount(), 1.0);
696 "Timeline::add_layer (No Audio Copied - Wrong # of Channels)",
697 "source_clip->Reader()->info.has_audio",
698 source_clip->
Reader()->info.has_audio,
699 "source_frame->GetAudioChannelsCount()",
700 source_frame->GetAudioChannelsCount(),
702 "clip_frame_number", clip_frame_number);
707 "Timeline::add_layer (Transform: Composite Image Layer: Completed)",
708 "source_frame->number", source_frame->number,
709 "new_frame->GetImage()->width()", new_frame->GetImage()->width(),
710 "new_frame->GetImage()->height()", new_frame->GetImage()->height());
714 void Timeline::update_open_clips(
Clip *clip,
bool does_clip_intersect)
717 const std::lock_guard<std::recursive_mutex> guard(
getFrameMutex);
720 "Timeline::update_open_clips (before)",
721 "does_clip_intersect", does_clip_intersect,
722 "closing_clips.size()", closing_clips.size(),
723 "open_clips.size()", open_clips.size());
726 bool clip_found = open_clips.count(clip);
728 if (clip_found && !does_clip_intersect)
731 open_clips.erase(clip);
736 else if (!clip_found && does_clip_intersect)
752 "Timeline::update_open_clips (after)",
753 "does_clip_intersect", does_clip_intersect,
754 "clip_found", clip_found,
755 "closing_clips.size()", closing_clips.size(),
756 "open_clips.size()", open_clips.size());
760 void Timeline::calculate_max_duration() {
761 double last_clip = 0.0;
762 double last_effect = 0.0;
764 if (!clips.empty()) {
765 const auto max_clip = std::max_element(
767 last_clip = (*max_clip)->Position() + (*max_clip)->Duration();
769 if (!effects.empty()) {
770 const auto max_effect = std::max_element(
772 last_effect = (*max_effect)->Position() + (*max_effect)->Duration();
774 max_time = std::max(last_clip, last_effect);
778 void Timeline::sort_clips()
781 const std::lock_guard<std::recursive_mutex> guard(
getFrameMutex);
785 "Timeline::SortClips",
786 "clips.size()", clips.size());
792 calculate_max_duration();
796 void Timeline::sort_effects()
799 const std::lock_guard<std::recursive_mutex> guard(
getFrameMutex);
805 calculate_max_duration();
814 const std::lock_guard<std::recursive_mutex> guard(
getFrameMutex);
817 for (
auto clip : clips)
819 update_open_clips(clip,
false);
822 bool allocated = allocated_clips.count(clip);
829 allocated_clips.clear();
832 for (
auto effect : effects)
835 bool allocated = allocated_effects.count(effect);
842 allocated_effects.clear();
845 for (
auto mapper : allocated_frame_mappers)
847 mapper->Reader(NULL);
851 allocated_frame_mappers.clear();
860 const std::lock_guard<std::recursive_mutex> guard(
getFrameMutex);
863 for (
auto clip : clips)
866 update_open_clips(clip,
false);
883 bool Timeline::isEqual(
double a,
double b)
885 return fabs(a - b) < 0.000001;
892 if (requested_frame < 1)
896 std::shared_ptr<Frame> frame;
897 frame = final_cache->
GetFrame(requested_frame);
901 "Timeline::GetFrame (Cached frame found)",
902 "requested_frame", requested_frame);
910 const std::lock_guard<std::recursive_mutex> lock(
getFrameMutex);
913 std::shared_ptr<Frame> frame;
914 frame = final_cache->
GetFrame(requested_frame);
918 "Timeline::GetFrame (Cached frame found on 2nd check)",
919 "requested_frame", requested_frame);
926 std::vector<Clip *> nearby_clips;
927 nearby_clips = find_intersecting_clips(requested_frame, 1,
true);
931 "Timeline::GetFrame (processing frame)",
932 "requested_frame", requested_frame,
933 "omp_get_thread_num()", omp_get_thread_num());
940 new_frame->AddAudioSilence(samples_in_frame);
946 "Timeline::GetFrame (Adding solid color)",
947 "requested_frame", requested_frame,
959 "Timeline::GetFrame (Loop through clips)",
960 "requested_frame", requested_frame,
961 "clips.size()", clips.size(),
962 "nearby_clips.size()", nearby_clips.size());
965 for (
auto clip : nearby_clips) {
968 bool does_clip_intersect = (clip_start_position <= requested_frame && clip_end_position >= requested_frame);
972 "Timeline::GetFrame (Does clip intersect)",
973 "requested_frame", requested_frame,
974 "clip->Position()", clip->
Position(),
975 "clip->Duration()", clip->
Duration(),
976 "does_clip_intersect", does_clip_intersect);
979 if (does_clip_intersect) {
981 bool is_top_clip =
true;
982 float max_volume = 0.0;
983 for (
auto nearby_clip : nearby_clips) {
984 long nearby_clip_start_position = round(nearby_clip->Position() *
info.
fps.
ToDouble()) + 1;
985 long nearby_clip_end_position = round((nearby_clip->Position() + nearby_clip->Duration()) *
info.
fps.
ToDouble()) + 1;
986 long nearby_clip_start_frame = (nearby_clip->Start() *
info.
fps.
ToDouble()) + 1;
987 long nearby_clip_frame_number = requested_frame - nearby_clip_start_position + nearby_clip_start_frame;
990 if (clip->
Id() != nearby_clip->Id() && clip->
Layer() == nearby_clip->Layer() &&
991 nearby_clip_start_position <= requested_frame && nearby_clip_end_position >= requested_frame &&
992 nearby_clip_start_position > clip_start_position && is_top_clip ==
true) {
997 if (nearby_clip->Reader() && nearby_clip->Reader()->info.has_audio &&
998 nearby_clip->has_audio.GetInt(nearby_clip_frame_number) != 0 &&
999 nearby_clip_start_position <= requested_frame && nearby_clip_end_position >= requested_frame) {
1000 max_volume += nearby_clip->volume.GetValue(nearby_clip_frame_number);
1006 long clip_frame_number = requested_frame - clip_start_position + clip_start_frame;
1010 "Timeline::GetFrame (Calculate clip's frame #)",
1011 "clip->Position()", clip->
Position(),
1012 "clip->Start()", clip->
Start(),
1014 "clip_frame_number", clip_frame_number);
1017 add_layer(new_frame, clip, clip_frame_number, is_top_clip, max_volume);
1022 "Timeline::GetFrame (clip does not intersect)",
1023 "requested_frame", requested_frame,
1024 "does_clip_intersect", does_clip_intersect);
1031 "Timeline::GetFrame (Add frame to cache)",
1032 "requested_frame", requested_frame,
1037 new_frame->SetFrameNumber(requested_frame);
1040 final_cache->
Add(new_frame);
1050 std::vector<Clip*> Timeline::find_intersecting_clips(int64_t requested_frame,
int number_of_frames,
bool include)
1053 std::vector<Clip*> matching_clips;
1056 float min_requested_frame = requested_frame;
1057 float max_requested_frame = requested_frame + (number_of_frames - 1);
1060 for (
auto clip : clips)
1066 bool does_clip_intersect =
1067 (clip_start_position <= min_requested_frame || clip_start_position <= max_requested_frame) &&
1068 (clip_end_position >= min_requested_frame || clip_end_position >= max_requested_frame);
1072 "Timeline::find_intersecting_clips (Is clip near or intersecting)",
1073 "requested_frame", requested_frame,
1074 "min_requested_frame", min_requested_frame,
1075 "max_requested_frame", max_requested_frame,
1076 "clip->Position()", clip->
Position(),
1077 "does_clip_intersect", does_clip_intersect);
1080 update_open_clips(clip, does_clip_intersect);
1083 if (does_clip_intersect && include)
1085 matching_clips.push_back(clip);
1087 else if (!does_clip_intersect && !include)
1089 matching_clips.push_back(clip);
1094 return matching_clips;
1100 if (managed_cache && final_cache) {
1103 managed_cache =
false;
1107 final_cache = new_cache;
1122 root[
"type"] =
"Timeline";
1127 root[
"path"] = path;
1130 root[
"clips"] = Json::Value(Json::arrayValue);
1133 for (
const auto existing_clip : clips)
1135 root[
"clips"].append(existing_clip->JsonValue());
1139 root[
"effects"] = Json::Value(Json::arrayValue);
1142 for (
const auto existing_effect: effects)
1144 root[
"effects"].append(existing_effect->JsonValue());
1155 const std::lock_guard<std::recursive_mutex> lock(
getFrameMutex);
1164 catch (
const std::exception& e)
1167 throw InvalidJSON(
"JSON is invalid (missing keys or invalid data types)");
1175 const std::lock_guard<std::recursive_mutex> lock(
getFrameMutex);
1178 bool was_open = is_open;
1185 if (!root[
"path"].isNull())
1186 path = root[
"path"].asString();
1188 if (!root[
"clips"].isNull()) {
1193 for (
const Json::Value existing_clip : root[
"clips"]) {
1198 allocated_clips.insert(c);
1215 if (!root[
"effects"].isNull()) {
1220 for (
const Json::Value existing_effect :root[
"effects"]) {
1224 if (!existing_effect[
"type"].isNull()) {
1226 if ( (e =
EffectInfo().CreateEffect(existing_effect[
"type"].asString())) ) {
1229 allocated_effects.insert(e);
1241 if (!root[
"duration"].isNull()) {
1260 const std::lock_guard<std::recursive_mutex> lock(
getFrameMutex);
1267 for (
const Json::Value change : root) {
1268 std::string change_key = change[
"key"][(uint)0].asString();
1271 if (change_key ==
"clips")
1273 apply_json_to_clips(change);
1275 else if (change_key ==
"effects")
1277 apply_json_to_effects(change);
1281 apply_json_to_timeline(change);
1285 catch (
const std::exception& e)
1288 throw InvalidJSON(
"JSON is invalid (missing keys or invalid data types)");
1293 void Timeline::apply_json_to_clips(Json::Value change) {
1296 std::string change_type = change[
"type"].asString();
1297 std::string clip_id =
"";
1298 Clip *existing_clip = NULL;
1301 for (
auto key_part : change[
"key"]) {
1303 if (key_part.isObject()) {
1305 if (!key_part[
"id"].isNull()) {
1307 clip_id = key_part[
"id"].asString();
1310 for (
auto c : clips)
1312 if (c->Id() == clip_id) {
1324 if (existing_clip && change[
"key"].size() == 4 && change[
"key"][2] ==
"effects")
1327 Json::Value key_part = change[
"key"][3];
1329 if (key_part.isObject()) {
1331 if (!key_part[
"id"].isNull())
1334 std::string effect_id = key_part[
"id"].asString();
1337 std::list<EffectBase*> effect_list = existing_clip->
Effects();
1338 for (
auto e : effect_list)
1340 if (e->Id() == effect_id) {
1342 apply_json_to_effects(change, e);
1347 final_cache->
Remove(new_starting_frame - 8, new_ending_frame + 8);
1357 if (!change[
"value"].isArray() && !change[
"value"][
"position"].isNull()) {
1358 int64_t new_starting_frame = (change[
"value"][
"position"].asDouble() *
info.
fps.
ToDouble()) + 1;
1359 int64_t new_ending_frame = ((change[
"value"][
"position"].asDouble() + change[
"value"][
"end"].asDouble() - change[
"value"][
"start"].asDouble()) *
info.
fps.
ToDouble()) + 1;
1360 final_cache->
Remove(new_starting_frame - 8, new_ending_frame + 8);
1364 if (change_type ==
"insert") {
1370 allocated_clips.insert(clip);
1378 }
else if (change_type ==
"update") {
1381 if (existing_clip) {
1386 final_cache->
Remove(old_starting_frame - 8, old_ending_frame + 8);
1389 if (existing_clip->
Reader() && existing_clip->
Reader()->GetCache())
1390 existing_clip->
Reader()->GetCache()->Remove(old_starting_frame - 8, old_ending_frame + 8);
1396 if (auto_map_clips) {
1397 apply_mapper_to_clip(existing_clip);
1401 }
else if (change_type ==
"delete") {
1404 if (existing_clip) {
1409 final_cache->
Remove(old_starting_frame - 8, old_ending_frame + 8);
1422 void Timeline::apply_json_to_effects(Json::Value change) {
1425 std::string change_type = change[
"type"].asString();
1429 for (
auto key_part : change[
"key"]) {
1431 if (key_part.isObject()) {
1433 if (!key_part[
"id"].isNull())
1436 std::string effect_id = key_part[
"id"].asString();
1439 for (
auto e : effects)
1441 if (e->Id() == effect_id) {
1442 existing_effect = e;
1452 if (existing_effect || change_type ==
"insert") {
1454 apply_json_to_effects(change, existing_effect);
1459 void Timeline::apply_json_to_effects(Json::Value change,
EffectBase* existing_effect) {
1462 std::string change_type = change[
"type"].asString();
1465 if (!change[
"value"].isArray() && !change[
"value"][
"position"].isNull()) {
1466 int64_t new_starting_frame = (change[
"value"][
"position"].asDouble() *
info.
fps.
ToDouble()) + 1;
1467 int64_t new_ending_frame = ((change[
"value"][
"position"].asDouble() + change[
"value"][
"end"].asDouble() - change[
"value"][
"start"].asDouble()) *
info.
fps.
ToDouble()) + 1;
1468 final_cache->
Remove(new_starting_frame - 8, new_ending_frame + 8);
1472 if (change_type ==
"insert") {
1475 std::string effect_type = change[
"value"][
"type"].asString();
1481 if ( (e =
EffectInfo().CreateEffect(effect_type)) ) {
1484 allocated_effects.insert(e);
1493 }
else if (change_type ==
"update") {
1496 if (existing_effect) {
1501 final_cache->
Remove(old_starting_frame - 8, old_ending_frame + 8);
1507 }
else if (change_type ==
"delete") {
1510 if (existing_effect) {
1515 final_cache->
Remove(old_starting_frame - 8, old_ending_frame + 8);
1528 void Timeline::apply_json_to_timeline(Json::Value change) {
1529 bool cache_dirty =
true;
1532 std::string change_type = change[
"type"].asString();
1533 std::string root_key = change[
"key"][(uint)0].asString();
1534 std::string sub_key =
"";
1535 if (change[
"key"].size() >= 2)
1536 sub_key = change[
"key"][(uint)1].asString();
1539 if (change_type ==
"insert" || change_type ==
"update") {
1543 if (root_key ==
"color")
1546 else if (root_key ==
"viewport_scale")
1549 else if (root_key ==
"viewport_x")
1552 else if (root_key ==
"viewport_y")
1555 else if (root_key ==
"duration") {
1561 cache_dirty =
false;
1563 else if (root_key ==
"width") {
1568 else if (root_key ==
"height") {
1573 else if (root_key ==
"fps" && sub_key ==
"" && change[
"value"].isObject()) {
1575 if (!change[
"value"][
"num"].isNull())
1576 info.
fps.
num = change[
"value"][
"num"].asInt();
1577 if (!change[
"value"][
"den"].isNull())
1578 info.
fps.
den = change[
"value"][
"den"].asInt();
1580 else if (root_key ==
"fps" && sub_key ==
"num")
1583 else if (root_key ==
"fps" && sub_key ==
"den")
1586 else if (root_key ==
"display_ratio" && sub_key ==
"" && change[
"value"].isObject()) {
1588 if (!change[
"value"][
"num"].isNull())
1590 if (!change[
"value"][
"den"].isNull())
1593 else if (root_key ==
"display_ratio" && sub_key ==
"num")
1596 else if (root_key ==
"display_ratio" && sub_key ==
"den")
1599 else if (root_key ==
"pixel_ratio" && sub_key ==
"" && change[
"value"].isObject()) {
1601 if (!change[
"value"][
"num"].isNull())
1603 if (!change[
"value"][
"den"].isNull())
1606 else if (root_key ==
"pixel_ratio" && sub_key ==
"num")
1609 else if (root_key ==
"pixel_ratio" && sub_key ==
"den")
1613 else if (root_key ==
"sample_rate")
1616 else if (root_key ==
"channels")
1619 else if (root_key ==
"channel_layout")
1624 throw InvalidJSONKey(
"JSON change key is invalid", change.toStyledString());
1627 }
else if (change[
"type"].asString() ==
"delete") {
1631 if (root_key ==
"color") {
1637 else if (root_key ==
"viewport_scale")
1639 else if (root_key ==
"viewport_x")
1641 else if (root_key ==
"viewport_y")
1645 throw InvalidJSONKey(
"JSON change key is invalid", change.toStyledString());
1660 final_cache->
Clear();
1665 for (
const auto clip : clips) {
1667 clip->
Reader()->GetCache()->Clear();
1670 if (deep && clip->
Reader()->Name() ==
"FrameMapper") {
1689 display_ratio_size.scale(proposed_size, Qt::KeepAspectRatio);
void ApplyJsonDiff(std::string value)
Apply a special formatted JSON object, which represents a change to the timeline (add, update, delete) This is primarily designed to keep the timeline (and its child objects... such as clips and effects) in sync with another application... such as OpenShot Video Editor (http://www.openshot.org).
void SetJsonValue(const Json::Value root)
Load Json::Value into this object.
openshot::Color color
Background color of timeline canvas.
This class is contains settings used by libopenshot (and can be safely toggled at any point) ...
void SetJsonValue(const Json::Value root) override
Load Json::Value into this object.
int num
Numerator for the fraction.
ReaderBase * Reader()
Get the current reader.
This abstract class is the base class, used by all effects in libopenshot.
bool is_top_clip
Is clip on top (if overlapping another clip)
std::shared_ptr< openshot::Frame > GetFrame(int64_t requested_frame) override
std::string Id() const
Get the Id of this clip object.
float Start() const
Get start position (in seconds) of clip (trim start of video)
virtual void SetJsonValue(const Json::Value root)
Load Json::Value into this object.
int width
The width of the video (in pixesl)
float cy
y-coordinate of the bounding box center
void ClearAllCache(bool deep=false)
int preview_width
Optional preview width of timeline image. If your preview window is smaller than the timeline...
float ToFloat()
Return this fraction as a float (i.e. 1/2 = 0.5)
float duration
Length of time (in seconds)
float height
bounding box height
void Close() override
Close the internal reader.
double ToDouble() const
Return this fraction as a double (i.e. 1/2 = 0.5)
void Reduce()
Reduce this fraction (i.e. 640/480 = 4/3)
This struct contains info about the current Timeline clip instance.
void SetMaxBytesFromInfo(int64_t number_of_frames, int width, int height, int sample_rate, int channels)
Set maximum bytes to a different amount based on a ReaderInfo struct.
Evenly divide the overlapping clips volume keyframes, so that the sum does not exceed 100%...
openshot::Clip * GetClip(const std::string &id)
Look up a single clip by ID.
void SetJsonValue(const Json::Value root) override
Load Json::Value into this object.
const Json::Value stringToJson(const std::string value)
This abstract class is the base class, used by all readers in libopenshot.
#define OPEN_MP_NUM_PROCESSORS
openshot::Keyframe volume
Curve representing the volume (0 to 1)
Exception when a reader is closed, and a frame is requested.
bool has_video
Determines if this file has a video stream.
void Open() override
Open the internal reader.
float angle
bounding box rotation angle [degrees]
Header file for CacheMemory class.
void Close() override
Close the timeline reader (and any resources it was consuming)
Header file for Timeline class.
std::list< openshot::EffectBase * > Effects()
Return the list of effects on the timeline.
int GetInt(int64_t index) const
Get the rounded INT value at a specific index.
void AppendDebugMethod(std::string method_name, std::string arg1_name="", float arg1_value=-1.0, std::string arg2_name="", float arg2_value=-1.0, std::string arg3_name="", float arg3_value=-1.0, std::string arg4_name="", float arg4_value=-1.0, std::string arg5_name="", float arg5_value=-1.0, std::string arg6_name="", float arg6_value=-1.0)
Append debug information.
openshot::Keyframe blue
Curve representing the red value (0 - 255)
void SetCache(openshot::CacheBase *new_cache)
Exception for missing JSON Change key.
std::list< std::string > GetTrackedObjectsIds() const
Return the ID's of the tracked objects as a list of strings.
Header file for CacheBase class.
int GetSamplesPerFrame(openshot::Fraction fps, int sample_rate, int channels)
Calculate the # of samples per video frame (for the current frame number)
Header file for all Exception classes.
double GetMaxTime()
Look up the end time of the latest timeline element.
void SetJson(const std::string value) override
Load JSON string into this object.
virtual openshot::CacheBase * GetCache()=0
Get the cache object used by this reader (note: not all readers use cache)
bool has_audio
Determines if this file has an audio stream.
virtual Json::Value JsonValue() const =0
Generate Json::Value for this object.
This class represents a clip (used to arrange readers on the timeline)
void ChangeMapping(Fraction target_fps, PulldownType pulldown, int target_sample_rate, int target_channels, ChannelLayout target_channel_layout)
Change frame rate or audio mapping details.
int64_t video_length
The number of frames in the video stream.
openshot::Keyframe channel_filter
A number representing an audio channel to filter (clears all other channels)
openshot::Keyframe green
Curve representing the green value (0 - 255)
int height
The height of the video (in pixels)
virtual void Remove(int64_t frame_number)=0
Remove a specific frame.
void SetMaxSize(int width, int height)
openshot::Fraction video_timebase
The video timebase determines how long each frame stays on the screen.
Exception for files that can not be found or opened.
std::recursive_mutex getFrameMutex
Mutex for multiple threads.
openshot::EffectBase * GetClipEffect(const std::string &id)
Look up a clip effect by ID.
static CrashHandler * Instance()
Json::Value JsonValue() const override
Generate Json::Value for this object.
void AddClip(openshot::Clip *clip)
Add an openshot::Clip to the timeline.
void ApplyMapperToClips()
Apply the timeline's framerate and samplerate to all clips.
float width
bounding box width
std::list< openshot::EffectBase * > ClipEffects() const
Return the list of effects on all clips.
This class represents a fraction.
Header file for the FrameMapper class.
std::string GetColorHex(int64_t frame_number)
Get the HEX value of a color at a specific frame.
openshot::Keyframe has_audio
An optional override to determine if this clip has audio (-1=undefined, 0=no, 1=yes) ...
virtual std::shared_ptr< openshot::Frame > GetFrame(int64_t frame_number)=0
Get a frame from the cache.
This struct contains info about a media file, such as height, width, frames per second, etc...
openshot::ChannelLayout channel_layout
The channel layout (mono, stereo, 5 point surround, etc...)
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...
std::string GetTrackedObjectValues(std::string id, int64_t frame_number) const
Return the trackedObject's properties as a JSON string.
Fraction Reciprocal() const
Return the reciprocal as a Fraction.
openshot::Keyframe channel_mapping
A number representing an audio channel to output (only works when filtering a channel) ...
openshot::Keyframe viewport_y
Curve representing the y coordinate for the viewport.
This struct holds the information of a bounding-box.
virtual void SetJsonValue(const Json::Value root)=0
Load Json::Value into this object.
openshot::EffectBase * GetEffect(const std::string &id)
Look up a timeline effect by ID.
openshot::Keyframe viewport_x
Curve representing the x coordinate for the viewport.
openshot::ReaderInfo info
Information about the current media file.
std::string Json() const override
Generate JSON string of this object.
Exception for frames that are out of bounds.
This class creates a mapping between 2 different frame rates, applying a specific pull-down technique...
This class represents a color (used on the timeline and clips)
static ZmqLogger * Instance()
Create or get an instance of this logger singleton (invoke the class with this method) ...
Reduce volume by about %25, and then mix (louder, but could cause pops if the sum exceeds 100%) ...
std::shared_ptr< openshot::TrackedObjectBase > GetTrackedObject(std::string id) const
Return tracked object pointer by it's id.
float Duration() const
Get the length of this clip (in seconds)
std::string vcodec
The name of the video codec used to encode / decode the video stream.
void SetJsonValue(const Json::Value root)
Load Json::Value into this object.
void AddTrackedObject(std::shared_ptr< openshot::TrackedObjectBase > trackedObject)
Add to the tracked_objects map a pointer to a tracked object (TrackedObjectBBox)
openshot::ClipBase * clip
Pointer to the parent clip instance (if any)
std::string PATH_OPENSHOT_INSTALL
This namespace is the default namespace for all code in the openshot library.
float cx
x-coordinate of the bounding box center
Do not apply pull-down techniques, just repeat or skip entire frames.
Json::Value JsonValue() const
Generate Json::Value for this object.
virtual void Clear()=0
Clear the cache of all frames.
void Open() override
Open the reader (and start consuming resources)
int64_t GetMaxFrame()
Look up the end frame number of the latest element on the timeline.
openshot::Keyframe viewport_scale
Curve representing the scale of the viewport (0 to 100)
Exception for invalid JSON.
int64_t GetCount() const
Get the number of points (i.e. # of points)
double GetValue(int64_t index) const
Get the value at a specific index.
openshot::Fraction display_ratio
The ratio of width to height of the video stream (i.e. 640x480 has a ratio of 4/3) ...
void Reader(openshot::ReaderBase *new_reader)
Set the current reader.
std::shared_ptr< openshot::Frame > apply_effects(std::shared_ptr< openshot::Frame > frame, int64_t timeline_frame_number, int layer)
Apply global/timeline effects to the source frame (if any)
openshot::Keyframe red
Curve representing the red value (0 - 255)
openshot::TimelineBase * ParentTimeline()
Get the associated Timeline pointer (if any)
Timeline(int width, int height, openshot::Fraction fps, int sample_rate, int channels, openshot::ChannelLayout channel_layout)
Constructor for the timeline (which configures the default frame properties)
static Settings * Instance()
Create or get an instance of this logger singleton (invoke the class with this method) ...
Header file for CacheDisk class.
Header file for CrashHandler class.
virtual void Add(std::shared_ptr< openshot::Frame > frame)=0
Add a Frame to the cache.
openshot::Fraction pixel_ratio
The pixel ratio of the video stream as a fraction (i.e. some pixels are not square) ...
Like CompareClipEndFrames, but for effects.
std::shared_ptr< openshot::Frame > GetFrame(int64_t frame_number) override
Get an openshot::Frame object for a specific frame number of this clip. The image size and number of ...
int preview_height
Optional preview width of timeline image. If your preview window is smaller than the timeline...
float Position() const
Get position on timeline (in seconds)
void AddEffect(openshot::EffectBase *effect)
Add an effect to the timeline.
void Clear()
Clear all clips, effects, and frame mappers from timeline (and free memory)
void RemoveEffect(openshot::EffectBase *effect)
Remove an effect from the timeline.
This class returns a listing of all effects supported by libopenshot.
int den
Denominator for the fraction.
int channels
The number of audio channels used in the audio stream.
A Keyframe is a collection of Point instances, which is used to vary a number or property over time...
openshot::VolumeMixType mixing
What strategy should be followed when mixing audio with other clips.
This class contains the properties of a tracked object and functions to manipulate it...
This class is a memory-based cache manager for Frame objects.
openshot::Fraction fps
Frames per second, as a fraction (i.e. 24/1 = 24 fps)
void RemoveClip(openshot::Clip *clip)
Remove an openshot::Clip from the timeline.
std::string acodec
The name of the audio codec used to encode / decode the video stream.
int Layer() const
Get layer of clip on timeline (lower number is covered by higher numbers)
int sample_rate
The number of audio samples per second (44100 is a common sample rate)
Json::Value JsonValue() const
Generate Json::Value for this object.
This class represents a timeline.