32#include <QPainterPath>
45 struct CompositeChoice {
const char* name;
CompositeType value; };
46 const CompositeChoice composite_choices[] = {
69 const int composite_choices_count =
sizeof(composite_choices)/
sizeof(CompositeChoice);
89 reader_orientation_mode = ReaderOrientationMode::Reader;
111 wave_color =
Color((
unsigned char)0, (
unsigned char)123, (
unsigned char)255, (
unsigned char)255);
136 parentTrackedObject =
nullptr;
137 parentClipObject = NULL;
167 const auto rotate_meta = reader->
info.
metadata.find(
"rotate");
174 float rotate_angle = 0.0f;
176 rotate_angle = strtof(rotate_meta->second.c_str(),
nullptr);
177 }
catch (
const std::exception& e) {
184 auto has_default_scale = [](
const Keyframe& kf) {
185 return kf.GetCount() == 1 && fabs(kf.GetPoint(0).co.Y - 1.0) < 0.00001;
191 if (fabs(rotate_angle) < 0.0001f)
194 float w =
static_cast<float>(reader->
info.
width);
195 float h =
static_cast<float>(reader->
info.
height);
196 if (w <= 0.0f || h <= 0.0f)
199 float rad = rotate_angle *
static_cast<float>(M_PI) / 180.0f;
201 float new_width = fabs(w * cos(rad)) + fabs(h * sin(rad));
202 float new_height = fabs(w * sin(rad)) + fabs(h * cos(rad));
203 if (new_width <= 0.0f || new_height <= 0.0f)
206 float uniform_scale = std::min(w / new_width, h / new_height);
213Clip::Clip() : resampler(NULL), reader(NULL), allocated_reader(NULL), is_open(false)
220Clip::Clip(
ReaderBase* new_reader) : resampler(NULL), reader(new_reader), allocated_reader(NULL), is_open(false)
239Clip::Clip(std::string
path) : resampler(NULL), reader(NULL), allocated_reader(NULL), is_open(false)
249 allocated_reader = reader;
258 std::string ext = get_file_extension(
path);
259 std::transform(ext.begin(), ext.end(), ext.begin(), ::tolower);
262 if (ext==
"avi" || ext==
"flac" || ext==
"mov" || ext==
"mkv" || ext==
"mpg" || ext==
"mpeg" || ext==
"mp3" || ext==
"mp4" || ext==
"mts" ||
263 ext==
"ogg" || ext==
"wav" || ext==
"wmv" || ext==
"webm" || ext==
"vob" || ext==
"gif" ||
path.find(
"%") != std::string::npos)
296 if (allocated_reader) {
297 delete allocated_reader;
298 allocated_reader = NULL;
318 if (parentTimeline) {
320 std::shared_ptr<openshot::TrackedObjectBase> trackedObject = parentTimeline->
GetTrackedObject(object_id);
321 Clip* clipObject = parentTimeline->
GetClip(object_id);
326 parentClipObject = NULL;
328 else if (clipObject) {
330 parentTrackedObject =
nullptr;
337 parentTrackedObject = trackedObject;
342 parentClipObject = clipObject;
350 bool is_same_reader =
false;
351 if (new_reader && allocated_reader) {
352 if (new_reader->
Name() ==
"FrameMapper") {
355 if (allocated_reader == clip_mapped_reader->
Reader()) {
356 is_same_reader =
true;
361 if (allocated_reader && !is_same_reader) {
363 allocated_reader->
Close();
364 delete allocated_reader;
366 allocated_reader = NULL;
389 throw ReaderClosed(
"No Reader has been initialized for this Clip. Call Reader(*reader) before calling this method.");
410 throw ReaderClosed(
"No Reader has been initialized for this Clip. Call Reader(*reader) before calling this method.");
416 if (is_open && reader) {
441 throw ReaderClosed(
"No Reader has been initialized for this Clip. Call Reader(*reader) before calling this method.");
467 return GetFrame(NULL, clip_frame_number, NULL);
472std::shared_ptr<Frame>
Clip::GetFrame(std::shared_ptr<openshot::Frame> background_frame, int64_t clip_frame_number)
475 return GetFrame(background_frame, clip_frame_number, NULL);
483 throw ReaderClosed(
"The Clip is closed. Call Open() before calling this method.");
488 std::shared_ptr<Frame> frame = NULL;
491 frame = GetOrCreateFrame(clip_frame_number);
494 int64_t timeline_frame_number = clip_frame_number;
495 QSize timeline_size(frame->GetWidth(), frame->GetHeight());
496 if (background_frame) {
498 timeline_frame_number = background_frame->number;
499 timeline_size.setWidth(background_frame->GetWidth());
500 timeline_size.setHeight(background_frame->GetHeight());
504 apply_timemapping(frame);
507 apply_waveform(frame, timeline_size);
510 apply_effects(frame, timeline_frame_number, options,
true);
513 apply_keyframes(frame, timeline_size);
516 apply_effects(frame, timeline_frame_number, options,
false);
521 if (!background_frame) {
522 background_frame = std::make_shared<Frame>(frame->number, frame->GetWidth(), frame->GetHeight(),
523 "#00000000", frame->GetAudioSamplesCount(),
524 frame->GetAudioChannelsCount());
526 apply_background(frame, background_frame,
false);
531 if (!background_frame) {
536 auto output = std::make_shared<Frame>(*frame.get());
537 apply_background(output, background_frame,
true);
542 throw ReaderClosed(
"No Reader has been initialized for this Clip. Call Reader(*reader) before calling this method.");
549 for (
const auto& effect : effects) {
550 if (effect->Id() ==
id) {
559 if (!parentObjectId.empty() && (!parentClipObject && !parentTrackedObject)) {
563 return parentClipObject;
568 if (!parentObjectId.empty() && (!parentClipObject && !parentTrackedObject)) {
572 return parentTrackedObject;
576std::string Clip::get_file_extension(std::string
path)
579 const auto dot_pos =
path.find_last_of(
'.');
580 if (dot_pos == std::string::npos || dot_pos + 1 >=
path.size()) {
581 return std::string();
584 return path.substr(dot_pos + 1);
588void Clip::apply_timemapping(std::shared_ptr<Frame> frame)
593 throw ReaderClosed(
"No Reader has been initialized for this Clip. Call Reader(*reader) before calling this method.");
598 const std::lock_guard<std::recursive_mutex> lock(
getFrameMutex);
600 int64_t clip_frame_number = frame->number;
601 int64_t new_frame_number = adjust_frame_number_minimum(
time.
GetLong(clip_frame_number));
618 int source_sample_count = round(target_sample_count * fabs(delta));
624 location.
frame = new_frame_number;
639 init_samples.clear();
640 resampler->
SetBuffer(&init_samples, 1.0);
648 if (source_sample_count <= 0) {
650 frame->AddAudioSilence(target_sample_count);
656 source_samples->clear();
659 int remaining_samples = source_sample_count;
661 while (remaining_samples > 0) {
662 std::shared_ptr<Frame> source_frame = GetOrCreateFrame(location.
frame,
false);
663 int frame_sample_count = source_frame->GetAudioSamplesCount() - location.
sample_start;
666 if (
auto *fm =
dynamic_cast<FrameMapper*
>(reader)) {
667 fm->SetDirectionHint(is_increasing);
669 source_frame->SetAudioDirection(is_increasing);
671 if (frame_sample_count == 0) {
681 if (remaining_samples - frame_sample_count >= 0) {
683 for (
int channel = 0; channel < source_frame->GetAudioChannelsCount(); channel++) {
684 source_samples->addFrom(channel, source_pos, source_frame->GetAudioSamples(channel) + location.
sample_start, frame_sample_count, 1.0f);
692 remaining_samples -= frame_sample_count;
693 source_pos += frame_sample_count;
697 for (
int channel = 0; channel < source_frame->GetAudioChannelsCount(); channel++) {
698 source_samples->addFrom(channel, source_pos, source_frame->GetAudioSamples(channel) + location.
sample_start, remaining_samples, 1.0f);
701 remaining_samples = 0;
702 source_pos += remaining_samples;
709 frame->AddAudioSilence(target_sample_count);
711 if (source_sample_count != target_sample_count) {
713 double resample_ratio = double(source_sample_count) / double(target_sample_count);
714 resampler->
SetBuffer(source_samples, resample_ratio);
722 frame->AddAudio(
true, channel, 0, resampled_buffer->getReadPointer(channel, 0), std::min(resampled_buffer->getNumSamples(), target_sample_count), 1.0f);
728 frame->AddAudio(
true, channel, 0, source_samples->getReadPointer(channel, 0), target_sample_count, 1.0f);
733 delete source_samples;
741int64_t Clip::adjust_frame_number_minimum(int64_t frame_number)
744 if (frame_number < 1)
752std::shared_ptr<Frame> Clip::GetOrCreateFrame(int64_t number,
bool enable_time)
756 int64_t clip_frame_number = adjust_frame_number_minimum(number);
757 bool is_increasing =
true;
762 const int64_t time_frame_number = adjust_frame_number_minimum(
time.
GetLong(clip_frame_number));
763 if (
auto *fm =
dynamic_cast<FrameMapper*
>(reader)) {
765 fm->SetDirectionHint(is_increasing);
767 clip_frame_number = time_frame_number;
772 "Clip::GetOrCreateFrame (from reader)",
773 "number", number,
"clip_frame_number", clip_frame_number);
776 auto reader_frame = reader->
GetFrame(clip_frame_number);
779 reader_frame->number = number;
780 reader_frame->SetAudioDirection(is_increasing);
786 auto reader_copy = std::make_shared<Frame>(*reader_frame.get());
789 reader_copy->AddColor(QColor(Qt::transparent));
793 reader_copy->AddAudioSilence(reader_copy->GetAudioSamplesCount());
809 "Clip::GetOrCreateFrame (create blank)",
811 "estimated_samples_in_frame", estimated_samples_in_frame);
814 auto new_frame = std::make_shared<Frame>(
816 "#000000", estimated_samples_in_frame, reader->
info.
channels);
819 new_frame->AddAudioSilence(estimated_samples_in_frame);
835 root[
"id"] =
add_property_json(
"ID", 0.0,
"string",
Id(), NULL, -1, -1,
true, requested_frame);
836 root[
"position"] =
add_property_json(
"Position",
Position(),
"float",
"", NULL, 0, 30 * 60 * 60 * 48,
false, requested_frame);
838 root[
"start"] =
add_property_json(
"Start",
Start(),
"float",
"", NULL, 0, 30 * 60 * 60 * 48,
false, requested_frame);
839 root[
"end"] =
add_property_json(
"End",
End(),
"float",
"", NULL, 0, 30 * 60 * 60 * 48,
false, requested_frame);
840 root[
"duration"] =
add_property_json(
"Duration",
Duration(),
"float",
"", NULL, 0, 30 * 60 * 60 * 48,
true, requested_frame);
845 root[
"composite"] =
add_property_json(
"Composite",
composite,
"int",
"", NULL, 0, composite_choices_count - 1,
false, requested_frame);
846 root[
"waveform"] =
add_property_json(
"Waveform", waveform,
"int",
"", NULL, 0, 1,
false, requested_frame);
848 root[
"parentObjectId"] =
add_property_json(
"Parent", 0.0,
"string", parentObjectId, NULL, -1, -1,
false, requested_frame);
879 for (
int i = 0; i < composite_choices_count; ++i)
898 if (parentClipObject)
903 double timeline_frame_number = requested_frame + clip_start_position - clip_start_frame;
906 float parentObject_location_x = parentClipObject->
location_x.
GetValue(timeline_frame_number);
907 float parentObject_location_y = parentClipObject->
location_y.
GetValue(timeline_frame_number);
908 float parentObject_scale_x = parentClipObject->
scale_x.
GetValue(timeline_frame_number);
909 float parentObject_scale_y = parentClipObject->
scale_y.
GetValue(timeline_frame_number);
910 float parentObject_shear_x = parentClipObject->
shear_x.
GetValue(timeline_frame_number);
911 float parentObject_shear_y = parentClipObject->
shear_y.
GetValue(timeline_frame_number);
912 float parentObject_rotation = parentClipObject->
rotation.
GetValue(timeline_frame_number);
915 root[
"location_x"] =
add_property_json(
"Location X", parentObject_location_x,
"float",
"", &
location_x, -1.0, 1.0,
false, requested_frame);
916 root[
"location_y"] =
add_property_json(
"Location Y", parentObject_location_y,
"float",
"", &
location_y, -1.0, 1.0,
false, requested_frame);
917 root[
"scale_x"] =
add_property_json(
"Scale X", parentObject_scale_x,
"float",
"", &
scale_x, 0.0, 1.0,
false, requested_frame);
918 root[
"scale_y"] =
add_property_json(
"Scale Y", parentObject_scale_y,
"float",
"", &
scale_y, 0.0, 1.0,
false, requested_frame);
919 root[
"rotation"] =
add_property_json(
"Rotation", parentObject_rotation,
"float",
"", &
rotation, -360, 360,
false, requested_frame);
920 root[
"shear_x"] =
add_property_json(
"Shear X", parentObject_shear_x,
"float",
"", &
shear_x, -1.0, 1.0,
false, requested_frame);
921 root[
"shear_y"] =
add_property_json(
"Shear Y", parentObject_shear_y,
"float",
"", &
shear_y, -1.0, 1.0,
false, requested_frame);
963 return root.toStyledString();
971 root[
"parentObjectId"] = parentObjectId;
973 root[
"scale"] =
scale;
979 root[
"waveform"] = waveform;
980 root[
"waveform_mode"] = waveform_mode;
981 switch (reader_orientation_mode) {
982 case ReaderOrientationMode::LegacyClipTransform:
983 root[
"reader_orientation_mode"] =
"legacy_clip_transform";
985 case ReaderOrientationMode::Reader:
987 root[
"reader_orientation_mode"] =
"reader";
1019 root[
"effects"] = Json::Value(Json::arrayValue);
1022 for (
auto existing_effect : effects)
1024 root[
"effects"].append(existing_effect->JsonValue());
1030 root[
"reader"] = Json::Value(Json::objectValue);
1046 catch (
const std::exception& e)
1049 throw InvalidJSON(
"JSON is invalid (missing keys or invalid data types)");
1055 auto ensure_default_keyframe = [](
Keyframe& kf,
double default_value) {
1066 if (root[
"reader_orientation_mode"].isNull()) {
1067 reader_orientation_mode = ReaderOrientationMode::LegacyClipTransform;
1069 const std::string mode = root[
"reader_orientation_mode"].asString();
1070 if (mode ==
"legacy_clip_transform") {
1071 reader_orientation_mode = ReaderOrientationMode::LegacyClipTransform;
1073 reader_orientation_mode = ReaderOrientationMode::Reader;
1078 if (!root[
"parentObjectId"].isNull()){
1079 parentObjectId = root[
"parentObjectId"].asString();
1080 if (parentObjectId.size() > 0 && parentObjectId !=
""){
1083 parentTrackedObject =
nullptr;
1084 parentClipObject = NULL;
1087 if (!root[
"gravity"].isNull())
1089 if (!root[
"scale"].isNull())
1091 if (!root[
"location_coordinate_system"].isNull()) {
1092 const auto& coordinates = root[
"location_coordinate_system"];
1097 if (!root[
"anchor"].isNull())
1099 if (!root[
"display"].isNull())
1101 if (!root[
"mixing"].isNull())
1103 if (!root[
"composite"].isNull())
1105 if (!root[
"waveform"].isNull())
1106 waveform = root[
"waveform"].asBool();
1107 if (!root[
"waveform_mode"].isNull())
1108 waveform_mode = root[
"waveform_mode"].asInt();
1109 if (!root[
"scale_x"].isNull())
1111 if (!root[
"scale_y"].isNull())
1113 if (!root[
"location_x"].isNull())
1115 if (!root[
"location_y"].isNull())
1117 if (!root[
"alpha"].isNull())
1119 if (!root[
"corner_radius"].isNull())
1121 if (!root[
"margin"].isNull())
1123 if (!root[
"rotation"].isNull())
1125 if (!root[
"time"].isNull())
1127 if (!root[
"volume"].isNull())
1129 if (!root[
"wave_color"].isNull())
1131 if (!root[
"shear_x"].isNull())
1133 if (!root[
"shear_y"].isNull())
1135 if (!root[
"origin_x"].isNull())
1137 if (!root[
"origin_y"].isNull())
1139 if (!root[
"channel_filter"].isNull())
1141 if (!root[
"channel_mapping"].isNull())
1143 if (!root[
"has_audio"].isNull())
1145 if (!root[
"has_video"].isNull())
1147 if (!root[
"perspective_c1_x"].isNull())
1149 if (!root[
"perspective_c1_y"].isNull())
1151 if (!root[
"perspective_c2_x"].isNull())
1153 if (!root[
"perspective_c2_y"].isNull())
1155 if (!root[
"perspective_c3_x"].isNull())
1157 if (!root[
"perspective_c3_y"].isNull())
1159 if (!root[
"perspective_c4_x"].isNull())
1161 if (!root[
"perspective_c4_y"].isNull())
1166 ensure_default_keyframe(
scale_x, 1.0);
1167 ensure_default_keyframe(
scale_y, 1.0);
1170 ensure_default_keyframe(
origin_x, 0.5);
1171 ensure_default_keyframe(
origin_y, 0.5);
1172 ensure_default_keyframe(
rotation, 0.0);
1174 ensure_default_keyframe(
margin, 0.0);
1175 if (!root[
"effects"].isNull()) {
1181 for (
const auto existing_effect : root[
"effects"]) {
1183 if (existing_effect.isNull()) {
1189 if (!existing_effect[
"type"].isNull()) {
1192 if ( (e =
EffectInfo().CreateEffect(existing_effect[
"type"].asString()))) {
1203 if (!root[
"reader"].isNull())
1205 if (!root[
"reader"][
"type"].isNull())
1208 bool already_open =
false;
1212 already_open = reader->
IsOpen();
1219 std::string type = root[
"reader"][
"type"].asString();
1221 if (type ==
"FFmpegReader") {
1227 }
else if (type ==
"QtTextReader") {
1231 }
else if (type ==
"QtImageReader") {
1237#ifdef USE_IMAGEMAGICK
1238 }
else if (type ==
"ImageReader") {
1241 reader =
new ImageReader(root[
"reader"][
"path"].asString(),
false);
1244 }
else if (type ==
"TextReader") {
1251 }
else if (type ==
"ChunkReader") {
1257 }
else if (type ==
"DummyReader") {
1263 }
else if (type ==
"Timeline") {
1274 allocated_reader = reader;
1285 final_cache.
Clear();
1289void Clip::sort_effects()
1302 effects.push_back(effect);
1318 if (parentTimeline){
1326 std::shared_ptr<TrackedObjectBBox> trackedObjectBBox = std::static_pointer_cast<TrackedObjectBBox>(trackedObject.second);
1329 trackedObjectBBox->ParentClip(
this);
1339 final_cache.
Clear();
1345 effects.remove(effect);
1348 final_cache.
Clear();
1352void Clip::apply_background(std::shared_ptr<openshot::Frame> frame,
1353 std::shared_ptr<openshot::Frame> background_frame,
1354 bool update_frame_image) {
1356 std::shared_ptr<QImage> background_canvas = background_frame->GetImage();
1357 QPainter painter(background_canvas.get());
1360 painter.setCompositionMode(
static_cast<QPainter::CompositionMode
>(
composite));
1361 painter.drawImage(0, 0, *frame->GetImage());
1366 if (update_frame_image)
1367 frame->AddImage(background_canvas);
1371void Clip::apply_effects(std::shared_ptr<Frame> frame, int64_t timeline_frame_number,
TimelineInfoStruct* options,
bool before_keyframes)
1373 for (
auto effect : effects)
1376 if (effect->info.apply_before_clip && before_keyframes) {
1377 effect->ProcessFrame(frame, frame->number);
1378 }
else if (!effect->info.apply_before_clip && !before_keyframes) {
1379 effect->ProcessFrame(frame, frame->number);
1383 if (
timeline != NULL && options != NULL) {
1392bool Clip::isNear(
double a,
double b)
1394 return fabs(a - b) < 0.000001;
1398void Clip::apply_keyframes(std::shared_ptr<Frame> frame, QSize timeline_size) {
1400 if (!frame->has_image_data) {
1406 std::shared_ptr<QImage> source_image = frame->GetImage();
1407 std::shared_ptr<QImage> background_canvas = std::make_shared<QImage>(timeline_size.width(),
1408 timeline_size.height(),
1409 QImage::Format_RGBA8888_Premultiplied);
1410 background_canvas->fill(QColor(Qt::transparent));
1413 QTransform transform = get_transform(frame, background_canvas->width(), background_canvas->height());
1416 QPainter painter(background_canvas.get());
1417 painter.setRenderHint(QPainter::TextAntialiasing,
true);
1418 if (!transform.isIdentity()) {
1419 painter.setRenderHint(QPainter::SmoothPixmapTransform,
true);
1422 painter.setTransform(transform);
1425 painter.setCompositionMode(
static_cast<QPainter::CompositionMode
>(
composite));
1429 const double corner_radius_value = std::max(0.0, std::min(0.5,
corner_radius.
GetValue(frame->number)));
1430 if (corner_radius_value > 0.0f) {
1431 painter.setRenderHint(QPainter::Antialiasing,
true);
1432 const double radius_pixels = corner_radius_value
1433 * std::min(source_image->width(), source_image->height());
1434 QPainterPath clip_path;
1435 clip_path.addRoundedRect(
1436 QRectF(0, 0, source_image->width(), source_image->height()),
1439 painter.setClipPath(clip_path);
1441 if (alpha_value != 1.0f) {
1442 painter.setOpacity(alpha_value);
1443 painter.drawImage(0, 0, *source_image);
1445 painter.setOpacity(1.0);
1447 painter.drawImage(0, 0, *source_image);
1455 std::stringstream frame_number_str;
1462 frame_number_str << frame->number;
1475 painter.setPen(QColor(
"#ffffff"));
1476 painter.drawText(20, 20, QString(frame_number_str.str().c_str()));
1482 frame->AddImage(background_canvas);
1486void Clip::apply_waveform(std::shared_ptr<Frame> frame, QSize timeline_size) {
1495 "frame->number", frame->number,
1497 "width", timeline_size.width(),
1498 "height", timeline_size.height());
1508 auto visual_frame = std::make_shared<Frame>(*frame.get());
1509 visual_frame->AddImage(std::make_shared<QImage>(
1510 timeline_size.width(), timeline_size.height(), QImage::Format_RGBA8888_Premultiplied));
1511 visual_frame->GetImage()->fill(Qt::transparent);
1517 static_cast<unsigned char>(red),
1518 static_cast<unsigned char>(green),
1519 static_cast<unsigned char>(blue),
1520 static_cast<unsigned char>(
alpha));
1531 visualization.
GetFrame(visual_frame, frame->number);
1533 frame->AddImage(visual_frame->GetImage());
1537QSize Clip::scale_size(QSize source_size,
ScaleType source_scale,
int target_width,
int target_height) {
1538 switch (source_scale)
1541 source_size.scale(target_width, target_height, Qt::KeepAspectRatio);
1545 source_size.scale(target_width, target_height, Qt::IgnoreAspectRatio);
1549 source_size.scale(target_width, target_height, Qt::KeepAspectRatioByExpanding);;
1558QTransform Clip::get_transform(std::shared_ptr<Frame> frame,
int width,
int height)
1561 std::shared_ptr<QImage> source_image = frame->GetImage();
1563 const double margin_value = std::max(0.0, std::min(0.5,
margin.
GetValue(frame->number)));
1564 const double margin_pixels = margin_value * std::min(width, height);
1565 const double layout_x = margin_pixels;
1566 const double layout_y = margin_pixels;
1567 const double layout_width = std::max(1.0, width - (margin_pixels * 2.0));
1568 const double layout_height = std::max(1.0, height - (margin_pixels * 2.0));
1571 QSize source_size = scale_size(source_image->size(),
scale, layout_width, layout_height);
1576 if (
auto* mapper =
dynamic_cast<FrameMapper*
>(source))
1577 source = mapper->Reader();
1578 if (
auto* text =
dynamic_cast<QtTextReader*
>(source)) {
1579 const double detail = text->DetailScale();
1580 source_size = QSize(std::max(1,
int(std::round(source_size.width() / detail))),
1581 std::max(1,
int(std::round(source_size.height() / detail))));
1586 float parentObject_location_x = 0.0;
1587 float parentObject_location_y = 0.0;
1588 float parentObject_scale_x = 1.0;
1589 float parentObject_scale_y = 1.0;
1590 float parentObject_shear_x = 0.0;
1591 float parentObject_shear_y = 0.0;
1592 float parentObject_rotation = 0.0;
1598 long parent_frame_number = frame->number + parent_start_offset;
1601 parentObject_location_x = parentClipObject->
location_x.
GetValue(parent_frame_number);
1602 parentObject_location_y = parentClipObject->
location_y.
GetValue(parent_frame_number);
1603 parentObject_scale_x = parentClipObject->
scale_x.
GetValue(parent_frame_number);
1604 parentObject_scale_y = parentClipObject->
scale_y.
GetValue(parent_frame_number);
1605 parentObject_shear_x = parentClipObject->
shear_x.
GetValue(parent_frame_number);
1606 parentObject_shear_y = parentClipObject->
shear_y.
GetValue(parent_frame_number);
1607 parentObject_rotation = parentClipObject->
rotation.
GetValue(parent_frame_number);
1613 Clip* parentClip = (
Clip*) parentTrackedObject->ParentClip();
1618 long parent_frame_number = frame->number + parent_start_offset;
1621 std::map<std::string, float> trackedObjectProperties = parentTrackedObject->GetBoxValues(parent_frame_number);
1625 parentClip->
scale, width, height);
1628 int trackedWidth = trackedObjectProperties[
"w"] * trackedObjectProperties[
"sx"] * parent_size.width() *
1630 int trackedHeight = trackedObjectProperties[
"h"] * trackedObjectProperties[
"sy"] * parent_size.height() *
1634 source_size = scale_size(source_size,
scale, trackedWidth, trackedHeight);
1637 parentObject_location_x = parentClip->
location_x.
GetValue(parent_frame_number) + ((trackedObjectProperties[
"cx"] - 0.5) * parentClip->
scale_x.
GetValue(parent_frame_number));
1638 parentObject_location_y = parentClip->
location_y.
GetValue(parent_frame_number) + ((trackedObjectProperties[
"cy"] - 0.5) * parentClip->
scale_y.
GetValue(parent_frame_number));
1639 parentObject_rotation = trackedObjectProperties[
"r"] + parentClip->
rotation.
GetValue(parent_frame_number);
1652 if(parentObject_scale_x != 0.0 && parentObject_scale_y != 0.0){
1653 sx*= parentObject_scale_x;
1654 sy*= parentObject_scale_y;
1657 float scaled_source_width = source_size.width() * sx;
1658 float scaled_source_height = source_size.height() * sy;
1668 x = layout_x + ((layout_width - scaled_source_width) / 2.0);
1672 x = layout_x + layout_width - scaled_source_width;
1677 y = layout_y + ((layout_height - scaled_source_height) / 2.0);
1680 x = layout_x + ((layout_width - scaled_source_width) / 2.0);
1681 y = layout_y + ((layout_height - scaled_source_height) / 2.0);
1684 x = layout_x + layout_width - scaled_source_width;
1685 y = layout_y + ((layout_height - scaled_source_height) / 2.0);
1689 y = layout_y + (layout_height - scaled_source_height);
1692 x = layout_x + ((layout_width - scaled_source_width) / 2.0);
1693 y = layout_y + (layout_height - scaled_source_height);
1696 x = layout_x + layout_width - scaled_source_width;
1697 y = layout_y + (layout_height - scaled_source_height);
1703 "Clip::get_transform (Gravity)",
1704 "frame->number", frame->number,
1705 "source_clip->gravity",
gravity,
1706 "scaled_source_width", scaled_source_width,
1707 "scaled_source_height", scaled_source_height);
1709 QTransform transform;
1713 float location_x_value =
location_x.
GetValue(frame->number) + parentObject_location_x;
1714 float location_y_value =
location_y.
GetValue(frame->number) + parentObject_location_y;
1715 auto location_offset = [](
float location,
float anchored_position,
float canvas_size,
float clip_size) {
1716 if (location < 0.0f) {
1717 return location * (anchored_position + clip_size);
1719 return location * (canvas_size - anchored_position);
1725 x += location_offset(location_x_value, x - layout_x, layout_width, scaled_source_width);
1726 y += location_offset(location_y_value, y - layout_y, layout_height, scaled_source_height);
1731 x += width * location_x_value;
1732 y += height * location_y_value;
1734 float shear_x_value =
shear_x.
GetValue(frame->number) + parentObject_shear_x;
1735 float shear_y_value =
shear_y.
GetValue(frame->number) + parentObject_shear_y;
1741 "Clip::get_transform (Build QTransform - if needed)",
1742 "frame->number", frame->number,
1745 "sx", sx,
"sy", sy);
1747 if (!isNear(x, 0) || !isNear(y, 0)) {
1749 transform.translate(x, y);
1751 if (!isNear(r, 0) || !isNear(shear_x_value, 0) || !isNear(shear_y_value, 0)) {
1753 float origin_x_offset = (scaled_source_width * origin_x_value);
1754 float origin_y_offset = (scaled_source_height * origin_y_value);
1755 transform.translate(origin_x_offset, origin_y_offset);
1756 transform.rotate(r);
1757 transform.shear(shear_x_value, shear_y_value);
1758 transform.translate(-origin_x_offset,-origin_y_offset);
1761 float source_width_scale = (float(source_size.width()) / float(source_image->width())) * sx;
1762 float source_height_scale = (float(source_size.height()) / float(source_image->height())) * sy;
1763 if (!isNear(source_width_scale, 1.0) || !isNear(source_height_scale, 1.0)) {
1764 transform.scale(source_width_scale, source_height_scale);
1771int64_t Clip::adjust_timeline_framenumber(int64_t clip_frame_number) {
1788 int64_t frame_number = clip_frame_number + clip_start_position - clip_start_frame;
1790 return frame_number;
Header file for AudioResampler class.
Header file for AudioVisualization effect class.
Header file for ChunkReader class.
Header file for Clip class.
Header file for DummyReader class.
Header file for all Exception classes.
Header file for FFmpegReader class.
Header file for the FrameMapper class.
Header file for ImageReader class.
Header file for MagickUtilities (IM6/IM7 compatibility overlay)
Header file for QtImageReader class.
Header file for QtTextReader class.
Header file for TextReader class.
Header file for Timeline class.
This class is used to resample audio data for many sequential frames.
void SetBuffer(juce::AudioBuffer< float > *new_buffer, double sample_rate, double new_sample_rate)
Sets the audio buffer and key settings.
juce::AudioBuffer< float > * GetResampledBuffer()
Get the resampled audio buffer.
std::shared_ptr< openshot::Frame > GetFrame(int64_t frame_number) override
This method is required for all derived classes of ClipBase, and returns a new openshot::Frame object...
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.
void Clear()
Clear the cache of all frames.
This class reads a special chunk-formatted file, which can be easily shared in a distributed environm...
void SetBaseJsonValue(const Json::Value &root)
Load common clip fields without copying derived animation data.
float Start() const
Get start position (in seconds) of clip (trim start of video)
float start
The position in seconds to start playing (used to trim the beginning of a clip)
float Duration() const
Get the length of this clip (in seconds)
virtual float End() const
Get end position (in seconds) of clip (trim end of video)
std::string Id() const
Get the Id of this clip object.
virtual Json::Value JsonValue() const =0
Generate Json::Value for this object.
Json::Value add_property_choice_json(std::string name, int value, int selected_value) const
Generate JSON choice for a property (dropdown properties)
int Layer() const
Get layer of clip on timeline (lower number is covered by higher numbers)
openshot::TimelineBase * timeline
Pointer to the parent timeline instance (if any)
float Position() const
Get position on timeline (in seconds)
virtual openshot::TimelineBase * ParentTimeline()
Get the associated Timeline pointer (if any)
std::string id
ID Property for all derived Clip and Effect classes.
float position
The position on the timeline where this clip should start playing.
float end
The position in seconds to end playing (used to trim the ending of a clip)
std::string previous_properties
This string contains the previous JSON properties.
Json::Value add_property_json(std::string name, float value, std::string type, std::string memo, const Keyframe *keyframe, float min_value, float max_value, bool readonly, int64_t requested_frame) const
Generate JSON for a property.
This class represents a clip (used to arrange readers on the timeline)
void SetAttachedObject(std::shared_ptr< openshot::TrackedObjectBase > trackedObject)
Set the pointer to the trackedObject this clip is attached to.
openshot::Keyframe scale_x
Curve representing the horizontal scaling in percent (0 to 1)
openshot::Keyframe location_y
Curve representing the relative Y position in percent based on the gravity (-1 to 1)
openshot::Keyframe shear_x
Curve representing X shear angle in degrees (-45.0=left, 45.0=right)
openshot::Keyframe perspective_c4_x
Curves representing X for coordinate 4.
openshot::AnchorType anchor
The anchor determines what parent a clip should snap to.
openshot::VolumeMixType mixing
What strategy should be followed when mixing audio with other clips.
void Open() override
Open the internal reader.
openshot::Keyframe rotation
Curve representing the rotation (0 to 360)
openshot::Keyframe channel_filter
A number representing an audio channel to filter (clears all other channels)
openshot::FrameDisplayType display
The format to display the frame number (if any)
void init_reader_rotation()
Update default rotation from reader.
Clip()
Default Constructor.
openshot::Keyframe perspective_c1_x
Curves representing X for coordinate 1.
void AttachToObject(std::string object_id)
Attach clip to Tracked Object or to another Clip.
std::string Json() const override
Generate JSON string of this object.
openshot::EffectBase * GetEffect(const std::string &id)
Look up an effect by ID.
void SetJsonValue(const Json::Value root) override
Load Json::Value into this object.
openshot::Keyframe alpha
Curve representing the alpha (1 to 0)
openshot::Keyframe has_audio
An optional override to determine if this clip has audio (-1=undefined, 0=no, 1=yes)
openshot::Keyframe perspective_c3_x
Curves representing X for coordinate 3.
void init_reader_settings()
Init reader info details.
openshot::Keyframe perspective_c1_y
Curves representing Y for coordinate 1.
Json::Value JsonValue() const override
Generate Json::Value for this object.
void SetAttachedClip(Clip *clipObject)
Set the pointer to the clip this clip is attached to.
openshot::TimelineBase * ParentTimeline() override
Get the associated Timeline pointer (if any)
openshot::Keyframe perspective_c4_y
Curves representing Y for coordinate 4.
openshot::Keyframe time
Curve representing the frames over time to play (used for speed and direction of video)
openshot::Clip * GetParentClip()
Return the associated ParentClip (if any)
bool Waveform()
Get the waveform property of this clip.
openshot::CompositeType composite
How this clip is composited onto lower layers.
openshot::GravityType gravity
The gravity of a clip determines where it snaps to its parent.
AudioLocation previous_location
Previous time-mapped audio location.
openshot::Keyframe perspective_c3_y
Curves representing Y for coordinate 3.
std::shared_ptr< openshot::TrackedObjectBase > GetParentTrackedObject()
Return the associated Parent Tracked Object (if any)
void AddEffect(openshot::EffectBase *effect)
Add an effect to the clip.
void Close() override
Close the internal reader.
virtual ~Clip()
Destructor.
openshot::Keyframe perspective_c2_y
Curves representing Y for coordinate 2.
std::string location_coordinate_system
openshot::Keyframe volume
Curve representing the volume (0 to 1)
openshot::Keyframe shear_y
Curve representing Y shear angle in degrees (-45.0=down, 45.0=up)
openshot::Keyframe scale_y
Curve representing the vertical scaling in percent (0 to 1)
float End() const override
Get end position (in seconds) of clip (trim end of video), which can be affected by the time curve.
std::shared_ptr< openshot::Frame > GetFrame(int64_t clip_frame_number) override
Get an openshot::Frame object for a specific frame number of this clip. The image size and number of ...
openshot::ReaderBase * Reader()
Get the current reader.
void RemoveEffect(openshot::EffectBase *effect)
Remove an effect from the clip.
openshot::Keyframe channel_mapping
A number representing an audio channel to output (only works when filtering a channel)
openshot::Keyframe has_video
An optional override to determine if this clip has video (-1=undefined, 0=no, 1=yes)
openshot::Keyframe corner_radius
Curve representing corner radius as a percent of the clip's shortest side.
std::string PropertiesJSON(int64_t requested_frame) const override
openshot::Color wave_color
Curve representing the color of the audio wave form.
void init_settings()
Init default settings for a clip.
openshot::Keyframe perspective_c2_x
Curves representing X for coordinate 2.
static openshot::ReaderBase * CreateReader(std::string path, bool inspect_reader=true)
openshot::Keyframe margin
Curve representing edge margin as a percent of the canvas' shortest side.
openshot::ScaleType scale
openshot::Keyframe location_x
Curve representing the relative X position in percent based on the gravity (-1 to 1)
openshot::Keyframe origin_x
Curve representing X origin point (0.0=0% (left), 1.0=100% (right))
std::recursive_mutex getFrameMutex
Mutex for multiple threads.
void SetJson(const std::string value) override
Load JSON string into this object.
openshot::Keyframe origin_y
Curve representing Y origin point (0.0=0% (top), 1.0=100% (bottom))
This class represents a color (used on the timeline and clips)
openshot::Keyframe blue
Curve representing the red value (0 - 255)
openshot::Keyframe red
Curve representing the red value (0 - 255)
openshot::Keyframe green
Curve representing the green value (0 - 255)
void SetJsonValue(const Json::Value root)
Load Json::Value into this object.
openshot::Keyframe alpha
Curve representing the alpha value (0 - 255)
Json::Value JsonValue() const
Generate Json::Value for this object.
This class is used as a simple, dummy reader, which can be very useful when writing unit tests....
This abstract class is the base class, used by all effects in libopenshot.
openshot::ClipBase * ParentClip()
Parent clip object of this effect (which can be unparented and NULL)
virtual void SetJsonValue(const Json::Value root)
Load Json::Value into this object.
EffectInfoStruct info
Information about the current effect.
std::map< int, std::shared_ptr< openshot::TrackedObjectBase > > trackedObjects
Map of Tracked Object's by their indices (used by Effects that track objects on clips)
This class returns a listing of all effects supported by libopenshot.
This class uses the FFmpeg libraries, to open video files and audio files, and return openshot::Frame...
float ToFloat()
Return this fraction as a float (i.e. 1/2 = 0.5)
double ToDouble() const
Return this fraction as a double (i.e. 1/2 = 0.5)
This class creates a mapping between 2 different frame rates, applying a specific pull-down technique...
ReaderBase * Reader()
Get the current reader.
int GetSamplesPerFrame(openshot::Fraction fps, int sample_rate, int channels)
Calculate the # of samples per video frame (for the current frame number)
This class uses the ImageMagick++ libraries, to open image files, and return openshot::Frame objects ...
Exception for invalid JSON.
A Keyframe is a collection of Point instances, which is used to vary a number or property over time.
int GetInt(int64_t index) const
Get the rounded INT value at a specific index.
void SetJsonValue(const Json::Value root)
Load Json::Value into this object.
double GetDelta(int64_t index) const
Get the change in Y value (from the previous Y value)
int64_t GetLength() const
int64_t GetLong(int64_t index) const
Get the rounded LONG value at a specific index.
double GetValue(int64_t index) const
Get the value at a specific index.
Json::Value JsonValue() const
Generate Json::Value for this object.
bool IsIncreasing(int index) const
Get the direction of the curve at a specific index (increasing or decreasing)
int64_t GetCount() const
Get the number of points (i.e. # of points)
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)
static Logger * Instance()
Exception for frames that are out of bounds.
This class uses the Qt library, to open image files, and return openshot::Frame objects containing th...
This class uses Qt libraries, to create frames with "Text", and return openshot::Frame objects.
This abstract class is the base class, used by all readers in libopenshot.
virtual bool IsOpen()=0
Determine if reader is open or closed.
virtual std::string Name()=0
Return the type name of the class.
openshot::ReaderInfo info
Information about the current media file.
virtual void SetJsonValue(const Json::Value root)=0
Load Json::Value into this object.
virtual Json::Value JsonValue() const =0
Generate Json::Value for this object.
void ApplyOrientationMetadata(bool value)
Set whether readers should apply source orientation metadata to returned frames.
virtual void Open()=0
Open the reader (and start consuming resources, such as images or video files)
virtual std::shared_ptr< openshot::Frame > GetFrame(int64_t number)=0
openshot::ClipBase * ParentClip()
Parent clip object of this reader (which can be unparented and NULL)
virtual void Close()=0
Close the reader (and any resources it was consuming)
Exception when a reader is closed, and a frame is requested.
This class uses the ImageMagick++ libraries, to create frames with "Text", and return openshot::Frame...
This class represents a timeline (used for building generic timeline implementations)
This class represents a timeline.
void AddTrackedObject(std::shared_ptr< openshot::TrackedObjectBase > trackedObject)
Add to the tracked_objects map a pointer to a tracked object (TrackedObjectBBox)
std::shared_ptr< openshot::TrackedObjectBase > GetTrackedObject(std::string id) const
Return tracked object pointer by it's id.
openshot::Clip * GetClip(const std::string &id)
Look up a single clip by ID.
std::shared_ptr< openshot::Frame > apply_effects(std::shared_ptr< openshot::Frame > frame, int64_t timeline_frame_number, int layer, TimelineInfoStruct *options)
Apply global/timeline effects to the source frame (if any)
This namespace is the default namespace for all code in the openshot library.
@ AUDIO_VISUALIZATION_CHANNEL_AUTO
AnchorType
This enumeration determines what parent a clip should be aligned to.
@ ANCHOR_CANVAS
Anchor the clip to the canvas.
ChunkVersion
This enumeration allows the user to choose which version of the chunk they would like (low,...
GravityType
This enumeration determines how clips are aligned to their parent container.
@ GRAVITY_TOP_LEFT
Align clip to the top left of its parent.
@ GRAVITY_LEFT
Align clip to the left of its parent (middle aligned)
@ GRAVITY_TOP_RIGHT
Align clip to the top right of its parent.
@ GRAVITY_RIGHT
Align clip to the right of its parent (middle aligned)
@ GRAVITY_BOTTOM_LEFT
Align clip to the bottom left of its parent.
@ GRAVITY_BOTTOM
Align clip to the bottom center of its parent.
@ GRAVITY_TOP
Align clip to the top center of its parent.
@ GRAVITY_BOTTOM_RIGHT
Align clip to the bottom right of its parent.
@ GRAVITY_CENTER
Align clip to the center of its parent (middle aligned)
ScaleType
This enumeration determines how clips are scaled to fit their parent container.
@ SCALE_FIT
Scale the clip until either height or width fills the canvas (with no cropping)
@ SCALE_STRETCH
Scale the clip until both height and width fill the canvas (distort to fit)
@ SCALE_CROP
Scale the clip until both height and width fill the canvas (cropping the overlap)
@ SCALE_NONE
Do not scale the clip.
@ AUDIO_VISUALIZATION_BACKGROUND_TRANSPARENT
VolumeMixType
This enumeration determines the strategy when mixing audio with other clips.
@ VOLUME_MIX_AVERAGE
Evenly divide the overlapping clips volume keyframes, so that the sum does not exceed 100%.
@ VOLUME_MIX_NONE
Do not apply any volume mixing adjustments. Just add the samples together.
@ VOLUME_MIX_REDUCE
Reduce volume by about %25, and then mix (louder, but could cause pops if the sum exceeds 100%)
@ AUDIO_VISUALIZATION_COLOR_SEED
@ AUDIO_VISUALIZATION_VU_METER
@ AUDIO_VISUALIZATION_BARS
@ AUDIO_VISUALIZATION_SPECTRUM
@ AUDIO_VISUALIZATION_WAVEFORM
@ AUDIO_VISUALIZATION_PHASE_SCOPE
@ AUDIO_VISUALIZATION_RADIAL_BARS
@ AUDIO_VISUALIZATION_PARTICLES
@ AUDIO_VISUALIZATION_FILLED_WAVEFORM
@ AUDIO_VISUALIZATION_RADIAL
FrameDisplayType
This enumeration determines the display format of the clip's frame number (if any)....
@ FRAME_DISPLAY_CLIP
Display the clip's internal frame number.
@ FRAME_DISPLAY_TIMELINE
Display the timeline's frame number.
@ FRAME_DISPLAY_BOTH
Display both the clip's and timeline's frame number.
@ FRAME_DISPLAY_NONE
Do not display the frame number.
const Json::Value stringToJson(const std::string value)
CompositeType
This enumeration determines how clips are composited onto lower layers.
@ AUDIO_VISUALIZATION_STYLE_MINIMAL
This struct holds the associated video frame and starting sample # for an audio packet.
bool has_tracked_object
Determines if this effect track objects through the clip.
float duration
Length of time (in seconds)
int width
The width of the video (in pixesl)
int channels
The number of audio channels used in the audio stream.
openshot::Fraction fps
Frames per second, as a fraction (i.e. 24/1 = 24 fps)
int height
The height of the video (in pixels)
int64_t video_length
The number of frames in the video stream.
std::map< std::string, std::string > metadata
An optional map/dictionary of metadata for this reader.
openshot::ChannelLayout channel_layout
The channel layout (mono, stereo, 5 point surround, etc...)
int sample_rate
The number of audio samples per second (44100 is a common sample rate)
This struct contains info about the current Timeline clip instance.
bool is_before_clip_keyframes
Is this before clip keyframes are applied.