Loading...
Searching...
No Matches
Clip.cpp
Go to the documentation of this file.
// Copyright (c) 2008-2019 OpenShot Studios, LLC
//
// SPDX-License-Identifier: LGPL-3.0-or-later
#include "Clip.h"
#include "AudioResampler.h"
#include "Exceptions.h"
#include "FFmpegReader.h"
#include "FrameMapper.h"
#include "QtImageReader.h"
#include "ChunkReader.h"
#include "DummyReader.h"
#include "Timeline.h"
#include "ZmqLogger.h"
#ifdef USE_IMAGEMAGICK
#include "MagickUtilities.h"
#include "ImageReader.h"
#include "TextReader.h"
#endif
#include <Qt>
using namespace openshot;
// Init default settings for a clip
void Clip::init_settings()
{
// Init clip settings
Position(0.0);
Layer(0);
Start(0.0);
ClipBase::End(0.0);
gravity = GRAVITY_CENTER;
scale = SCALE_FIT;
anchor = ANCHOR_CANVAS;
display = FRAME_DISPLAY_NONE;
mixing = VOLUME_MIX_NONE;
waveform = false;
previous_properties = "";
parentObjectId = "";
// Init scale curves
scale_x = Keyframe(1.0);
scale_y = Keyframe(1.0);
// Init location curves
location_x = Keyframe(0.0);
location_y = Keyframe(0.0);
// Init alpha
alpha = Keyframe(1.0);
// Init time & volume
time = Keyframe(1.0);
volume = Keyframe(1.0);
// Init audio waveform color
wave_color = Color((unsigned char)0, (unsigned char)123, (unsigned char)255, (unsigned char)255);
// Init shear and perspective curves
shear_x = Keyframe(0.0);
shear_y = Keyframe(0.0);
origin_x = Keyframe(0.5);
origin_y = Keyframe(0.5);
perspective_c1_x = Keyframe(-1.0);
perspective_c1_y = Keyframe(-1.0);
perspective_c2_x = Keyframe(-1.0);
perspective_c2_y = Keyframe(-1.0);
perspective_c3_x = Keyframe(-1.0);
perspective_c3_y = Keyframe(-1.0);
perspective_c4_x = Keyframe(-1.0);
perspective_c4_y = Keyframe(-1.0);
// Init audio channel filter and mappings
channel_filter = Keyframe(-1.0);
channel_mapping = Keyframe(-1.0);
// Init audio and video overrides
has_audio = Keyframe(-1.0);
has_video = Keyframe(-1.0);
// Initialize the attached object and attached clip as null pointers
parentTrackedObject = nullptr;
parentClipObject = NULL;
// Init reader info struct
init_reader_settings();
}
// Init reader info details
void Clip::init_reader_settings() {
if (reader) {
// Init rotation (if any)
init_reader_rotation();
// Initialize info struct
info = reader->info;
// Init cache
final_cache.SetMaxBytesFromInfo(8, info.width, info.height, info.sample_rate, info.channels);
}
}
// Init reader's rotation (if any)
void Clip::init_reader_rotation() {
// Dont init rotation if clip has keyframes
if (rotation.GetCount() > 0)
return;
// Init rotation
if (reader && reader->info.metadata.count("rotate") > 0) {
// Use reader metadata rotation (if any)
// This is typical with cell phone videos filmed in different orientations
try {
float rotate_metadata = strtof(reader->info.metadata["rotate"].c_str(), 0);
rotation = Keyframe(rotate_metadata);
} catch (const std::exception& e) {}
}
else
// Default no rotation
rotation = Keyframe(0.0);
}
// Default Constructor for a clip
Clip::Clip() : resampler(NULL), reader(NULL), allocated_reader(NULL), is_open(false)
{
// Init all default settings
init_settings();
}
// Constructor with reader
Clip::Clip(ReaderBase* new_reader) : resampler(NULL), reader(new_reader), allocated_reader(NULL), is_open(false)
{
// Init all default settings
init_settings();
// Open and Close the reader (to set the duration of the clip)
Open();
Close();
// Update duration and set parent
if (reader) {
ClipBase::End(reader->info.duration);
reader->ParentClip(this);
// Init reader info struct
init_reader_settings();
}
}
// Constructor with filepath
Clip::Clip(std::string path) : resampler(NULL), reader(NULL), allocated_reader(NULL), is_open(false)
{
// Init all default settings
init_settings();
// Get file extension (and convert to lower case)
std::string ext = get_file_extension(path);
std::transform(ext.begin(), ext.end(), ext.begin(), ::tolower);
// Determine if common video formats (or image sequences)
if (ext=="avi" || ext=="mov" || ext=="mkv" || ext=="mpg" || ext=="mpeg" || ext=="mp3" || ext=="mp4" || ext=="mts" ||
ext=="ogg" || ext=="wav" || ext=="wmv" || ext=="webm" || ext=="vob" || path.find("%") != std::string::npos)
{
try
{
// Open common video format
reader = new openshot::FFmpegReader(path);
} catch(...) { }
}
if (ext=="osp")
{
try
{
// Open common video format
reader = new openshot::Timeline(path, true);
} catch(...) { }
}
// If no video found, try each reader
if (!reader)
{
try
{
// Try an image reader
reader = new openshot::QtImageReader(path);
} catch(...) {
try
{
// Try a video reader
reader = new openshot::FFmpegReader(path);
} catch(...) { }
}
}
// Update duration and set parent
if (reader) {
ClipBase::End(reader->info.duration);
reader->ParentClip(this);
allocated_reader = reader;
// Init reader info struct
init_reader_settings();
}
}
// Destructor
Clip::~Clip()
{
// Delete the reader if clip created it
if (allocated_reader) {
delete allocated_reader;
allocated_reader = NULL;
reader = NULL;
}
// Close the resampler
if (resampler) {
delete resampler;
resampler = NULL;
}
// Close clip
Close();
}
// Attach clip to bounding box
void Clip::AttachToObject(std::string object_id)
{
// Search for the tracked object on the timeline
Timeline* parentTimeline = static_cast<Timeline *>(ParentTimeline());
if (parentTimeline) {
// Create a smart pointer to the tracked object from the timeline
std::shared_ptr<openshot::TrackedObjectBase> trackedObject = parentTimeline->GetTrackedObject(object_id);
Clip* clipObject = parentTimeline->GetClip(object_id);
// Check for valid tracked object
if (trackedObject){
SetAttachedObject(trackedObject);
}
else if (clipObject) {
SetAttachedClip(clipObject);
}
}
}
// Set the pointer to the trackedObject this clip is attached to
void Clip::SetAttachedObject(std::shared_ptr<openshot::TrackedObjectBase> trackedObject){
parentTrackedObject = trackedObject;
}
// Set the pointer to the clip this clip is attached to
void Clip::SetAttachedClip(Clip* clipObject){
parentClipObject = clipObject;
}
void Clip::Reader(ReaderBase* new_reader)
{
// Delete previously allocated reader (if not related to new reader)
// FrameMappers that point to the same allocated reader are ignored
bool is_same_reader = false;
if (new_reader && allocated_reader) {
if (new_reader->Name() == "FrameMapper") {
// Determine if FrameMapper is pointing at the same allocated ready
FrameMapper* clip_mapped_reader = static_cast<FrameMapper*>(new_reader);
if (allocated_reader == clip_mapped_reader->Reader()) {
is_same_reader = true;
}
}
}
// Clear existing allocated reader (if different)
if (allocated_reader && !is_same_reader) {
reader->Close();
allocated_reader->Close();
delete allocated_reader;
reader = NULL;
allocated_reader = NULL;
}
// set reader pointer
reader = new_reader;
// set parent
if (reader) {
reader->ParentClip(this);
// Init reader info struct
init_reader_settings();
}
}
ReaderBase* Clip::Reader()
{
if (reader)
return reader;
else
// Throw error if reader not initialized
throw ReaderClosed("No Reader has been initialized for this Clip. Call Reader(*reader) before calling this method.");
}
// Open the internal reader
void Clip::Open()
{
if (reader)
{
// Open the reader
reader->Open();
is_open = true;
// Copy Reader info to Clip
info = reader->info;
// Set some clip properties from the file reader
if (end == 0.0)
ClipBase::End(reader->info.duration);
}
else
// Throw error if reader not initialized
throw ReaderClosed("No Reader has been initialized for this Clip. Call Reader(*reader) before calling this method.");
}
// Close the internal reader
void Clip::Close()
{
if (is_open && reader) {
ZmqLogger::Instance()->AppendDebugMethod("Clip::Close");
// Close the reader
reader->Close();
}
// Clear cache
final_cache.Clear();
is_open = false;
}
// Get end position of clip (trim end of video), which can be affected by the time curve.
float Clip::End() const
{
// if a time curve is present, use its length
if (time.GetCount() > 1)
{
// Determine the FPS fo this clip
float fps = 24.0;
if (reader)
// file reader
fps = reader->info.fps.ToFloat();
else
// Throw error if reader not initialized
throw ReaderClosed("No Reader has been initialized for this Clip. Call Reader(*reader) before calling this method.");
return float(time.GetLength()) / fps;
}
else
// just use the duration (as detected by the reader)
return end;
}
// Override End() position
void Clip::End(float value) {
ClipBase::End(value);
}
// Set associated Timeline pointer
void Clip::ParentTimeline(openshot::TimelineBase* new_timeline) {
timeline = new_timeline;
// Clear cache (it might have changed)
final_cache.Clear();
}
// Create an openshot::Frame object for a specific frame number of this reader.
std::shared_ptr<Frame> Clip::GetFrame(int64_t clip_frame_number)
{
// Call override of GetFrame
return GetFrame(NULL, clip_frame_number, NULL);
}
// Create an openshot::Frame object for a specific frame number of this reader.
// NOTE: background_frame is ignored in this method (this method is only used by Effect classes)
std::shared_ptr<Frame> Clip::GetFrame(std::shared_ptr<openshot::Frame> background_frame, int64_t clip_frame_number)
{
// Call override of GetFrame
return GetFrame(background_frame, clip_frame_number, NULL);
}
// Use an existing openshot::Frame object and draw this Clip's frame onto it
std::shared_ptr<Frame> Clip::GetFrame(std::shared_ptr<openshot::Frame> background_frame, int64_t clip_frame_number, openshot::TimelineInfoStruct* options)
{
// Check for open reader (or throw exception)
if (!is_open)
throw ReaderClosed("The Clip is closed. Call Open() before calling this method.");
if (reader)
{
// Get frame object
std::shared_ptr<Frame> frame = NULL;
// Check cache
frame = final_cache.GetFrame(clip_frame_number);
if (frame) {
// Debug output
ZmqLogger::Instance()->AppendDebugMethod(
"Clip::GetFrame (Cached frame found)",
"requested_frame", clip_frame_number);
// Return cached frame
return frame;
}
// Generate clip frame
frame = GetOrCreateFrame(clip_frame_number);
if (!background_frame) {
// Create missing background_frame w/ transparent color (if needed)
background_frame = std::make_shared<Frame>(clip_frame_number, frame->GetWidth(), frame->GetHeight(),
"#00000000", frame->GetAudioSamplesCount(),
frame->GetAudioChannelsCount());
}
// Get time mapped frame object (used to increase speed, change direction, etc...)
apply_timemapping(frame);
// Apply waveform image (if any)
apply_waveform(frame, background_frame);
// Apply local effects to the frame (if any)
apply_effects(frame);
// Apply global timeline effects (i.e. transitions & masks... if any)
if (timeline != NULL && options != NULL) {
if (options->is_top_clip) {
// Apply global timeline effects (only to top clip... if overlapping, pass in timeline frame number)
Timeline* timeline_instance = static_cast<Timeline*>(timeline);
frame = timeline_instance->apply_effects(frame, background_frame->number, Layer());
}
}
// Apply keyframe / transforms
apply_keyframes(frame, background_frame);
// Add final frame to cache
final_cache.Add(frame);
// Return processed 'frame'
return frame;
}
else
// Throw error if reader not initialized
throw ReaderClosed("No Reader has been initialized for this Clip. Call Reader(*reader) before calling this method.");
}
// Look up an effect by ID
openshot::EffectBase* Clip::GetEffect(const std::string& id)
{
// Find the matching effect (if any)
for (const auto& effect : effects) {
if (effect->Id() == id) {
return effect;
}
}
return nullptr;
}
// Get file extension
std::string Clip::get_file_extension(std::string path)
{
// return last part of path
return path.substr(path.find_last_of(".") + 1);
}
// Reverse an audio buffer
void Clip::reverse_buffer(juce::AudioBuffer<float>* buffer)
{
int number_of_samples = buffer->getNumSamples();
int channels = buffer->getNumChannels();
// Reverse array (create new buffer to hold the reversed version)
auto *reversed = new juce::AudioBuffer<float>(channels, number_of_samples);
reversed->clear();
for (int channel = 0; channel < channels; channel++)
{
int n=0;
for (int s = number_of_samples - 1; s >= 0; s--, n++)
reversed->getWritePointer(channel)[n] = buffer->getWritePointer(channel)[s];
}
// Copy the samples back to the original array
buffer->clear();
// Loop through channels, and get audio samples
for (int channel = 0; channel < channels; channel++)
// Get the audio samples for this channel
buffer->addFrom(channel, 0, reversed->getReadPointer(channel), number_of_samples, 1.0f);
delete reversed;
}
// Adjust the audio and image of a time mapped frame
void Clip::apply_timemapping(std::shared_ptr<Frame> frame)
{
// Check for valid reader
if (!reader)
// Throw error if reader not initialized
throw ReaderClosed("No Reader has been initialized for this Clip. Call Reader(*reader) before calling this method.");
// Check for a valid time map curve
if (time.GetLength() > 1)
{
const std::lock_guard<std::recursive_mutex> lock(getFrameMutex);
int64_t clip_frame_number = frame->number;
int64_t new_frame_number = adjust_frame_number_minimum(time.GetLong(clip_frame_number));
// create buffer
juce::AudioBuffer<float> *source_samples = nullptr;
// Get delta (difference from this frame to the next time mapped frame: Y value)
double delta = time.GetDelta(clip_frame_number + 1);
bool is_increasing = time.IsIncreasing(clip_frame_number + 1);
// Determine length of source audio (in samples)
// A delta of 1.0 == normal expected samples
// A delta of 0.5 == 50% of normal expected samples
// A delta of 2.0 == 200% of normal expected samples
int target_sample_count = Frame::GetSamplesPerFrame(adjust_timeline_framenumber(clip_frame_number), Reader()->info.fps,
Reader()->info.sample_rate,
Reader()->info.channels);
int source_sample_count = round(target_sample_count * fabs(delta));
// Determine starting audio location
AudioLocation location;
if (previous_location.frame == 0 || abs(new_frame_number - previous_location.frame) > 2) {
// No previous location OR gap detected
location.frame = new_frame_number;
location.sample_start = 0;
// Create / Reset resampler
// We don't want to interpolate between unrelated audio data
if (resampler) {
delete resampler;
}
// Init resampler with # channels from Reader (should match the timeline)
resampler = new AudioResampler(Reader()->info.channels);
// Allocate buffer of silence to initialize some data inside the resampler
// To prevent it from becoming input limited
juce::AudioBuffer<float> init_samples(Reader()->info.channels, 64);
init_samples.clear();
resampler->SetBuffer(&init_samples, 1.0);
resampler->GetResampledBuffer();
} else {
// Use previous location
location = previous_location;
}
if (source_sample_count <= 0) {
// Add silence and bail (we don't need any samples)
frame->AddAudioSilence(target_sample_count);
return;
}
// Allocate a new sample buffer for these delta frames
source_samples = new juce::AudioBuffer<float>(Reader()->info.channels, source_sample_count);
source_samples->clear();
// Determine ending audio location
int remaining_samples = source_sample_count;
int source_pos = 0;
while (remaining_samples > 0) {
std::shared_ptr<Frame> source_frame = GetOrCreateFrame(location.frame, false);
int frame_sample_count = source_frame->GetAudioSamplesCount() - location.sample_start;
if (frame_sample_count == 0) {
// No samples found in source frame (fill with silence)
if (is_increasing) {
location.frame++;
} else {
location.frame--;
}
location.sample_start = 0;
break;
}
if (remaining_samples - frame_sample_count >= 0) {
// Use all frame samples & increment location
for (int channel = 0; channel < source_frame->GetAudioChannelsCount(); channel++) {
source_samples->addFrom(channel, source_pos, source_frame->GetAudioSamples(channel) + location.sample_start, frame_sample_count, 1.0f);
}
if (is_increasing) {
location.frame++;
} else {
location.frame--;
}
location.sample_start = 0;
remaining_samples -= frame_sample_count;
source_pos += frame_sample_count;
} else {
// Use just what is needed (and reverse samples)
for (int channel = 0; channel < source_frame->GetAudioChannelsCount(); channel++) {
source_samples->addFrom(channel, source_pos, source_frame->GetAudioSamples(channel) + location.sample_start, remaining_samples, 1.0f);
}
location.sample_start += remaining_samples;
remaining_samples = 0;
source_pos += remaining_samples;
}
}
// Resize audio for current frame object + fill with silence
// We are fixing to clobber this with actual audio data (possibly resampled)
frame->AddAudioSilence(target_sample_count);
if (source_sample_count != target_sample_count) {
// Resample audio (if needed)
double resample_ratio = double(source_sample_count) / double(target_sample_count);
resampler->SetBuffer(source_samples, resample_ratio);
// Resample the data
juce::AudioBuffer<float> *resampled_buffer = resampler->GetResampledBuffer();
// Fill the frame with resampled data
for (int channel = 0; channel < Reader()->info.channels; channel++) {
// Add new (slower) samples, to the frame object
frame->AddAudio(true, channel, 0, resampled_buffer->getReadPointer(channel, 0), std::min(resampled_buffer->getNumSamples(), target_sample_count), 1.0f);
}
} else {
// Fill the frame
for (int channel = 0; channel < Reader()->info.channels; channel++) {
// Add new (slower) samples, to the frame object
frame->AddAudio(true, channel, 0, source_samples->getReadPointer(channel, 0), target_sample_count, 1.0f);
}
}
// Clean up
delete source_samples;
// Set previous location
previous_location = location;
}
}
// Adjust frame number minimum value
int64_t Clip::adjust_frame_number_minimum(int64_t frame_number)
{
// Never return a frame number 0 or below
if (frame_number < 1)
return 1;
else
return frame_number;
}
// Get or generate a blank frame
std::shared_ptr<Frame> Clip::GetOrCreateFrame(int64_t number, bool enable_time)
{
try {
// Init to requested frame
int64_t clip_frame_number = adjust_frame_number_minimum(number);
// Adjust for time-mapping (if any)
if (enable_time && time.GetLength() > 1) {
clip_frame_number = adjust_frame_number_minimum(time.GetLong(clip_frame_number));
}
// Debug output
ZmqLogger::Instance()->AppendDebugMethod(
"Clip::GetOrCreateFrame (from reader)",
"number", number, "clip_frame_number", clip_frame_number);
// Attempt to get a frame (but this could fail if a reader has just been closed)
auto reader_frame = reader->GetFrame(clip_frame_number);
reader_frame->number = number; // Override frame # (due to time-mapping might change it)
// Return real frame
if (reader_frame) {
// Create a new copy of reader frame
// This allows a clip to modify the pixels and audio of this frame without
// changing the underlying reader's frame data
auto reader_copy = std::make_shared<Frame>(*reader_frame.get());
if (has_video.GetInt(number) == 0) {
// No video, so add transparent pixels
reader_copy->AddColor(QColor(Qt::transparent));
}
if (has_audio.GetInt(number) == 0 || number > reader->info.video_length) {
// No audio, so include silence (also, mute audio if past end of reader)
reader_copy->AddAudioSilence(reader_copy->GetAudioSamplesCount());
}
return reader_copy;
}
} catch (const ReaderClosed & e) {
// ...
} catch (const OutOfBoundsFrame & e) {
// ...
}
// Estimate # of samples needed for this frame
int estimated_samples_in_frame = Frame::GetSamplesPerFrame(number, reader->info.fps, reader->info.sample_rate, reader->info.channels);
// Debug output
ZmqLogger::Instance()->AppendDebugMethod(
"Clip::GetOrCreateFrame (create blank)",
"number", number,
"estimated_samples_in_frame", estimated_samples_in_frame);
// Create blank frame
auto new_frame = std::make_shared<Frame>(
number, reader->info.width, reader->info.height,
"#000000", estimated_samples_in_frame, reader->info.channels);
new_frame->SampleRate(reader->info.sample_rate);
new_frame->ChannelsLayout(reader->info.channel_layout);
new_frame->AddAudioSilence(estimated_samples_in_frame);
return new_frame;
}
// Generate JSON string of this object
std::string Clip::Json() const {
// Return formatted string
return JsonValue().toStyledString();
}
// Get all properties for a specific frame
std::string Clip::PropertiesJSON(int64_t requested_frame) const {
// Generate JSON properties list
Json::Value root;
root["id"] = add_property_json("ID", 0.0, "string", Id(), NULL, -1, -1, true, requested_frame);
root["position"] = add_property_json("Position", Position(), "float", "", NULL, 0, 30 * 60 * 60 * 48, false, requested_frame);
root["layer"] = add_property_json("Track", Layer(), "int", "", NULL, 0, 20, false, requested_frame);
root["start"] = add_property_json("Start", Start(), "float", "", NULL, 0, 30 * 60 * 60 * 48, false, requested_frame);
root["end"] = add_property_json("End", End(), "float", "", NULL, 0, 30 * 60 * 60 * 48, false, requested_frame);
root["duration"] = add_property_json("Duration", Duration(), "float", "", NULL, 0, 30 * 60 * 60 * 48, true, requested_frame);
root["gravity"] = add_property_json("Gravity", gravity, "int", "", NULL, 0, 8, false, requested_frame);
root["scale"] = add_property_json("Scale", scale, "int", "", NULL, 0, 3, false, requested_frame);
root["display"] = add_property_json("Frame Number", display, "int", "", NULL, 0, 3, false, requested_frame);
root["mixing"] = add_property_json("Volume Mixing", mixing, "int", "", NULL, 0, 2, false, requested_frame);
root["waveform"] = add_property_json("Waveform", waveform, "int", "", NULL, 0, 1, false, requested_frame);
root["parentObjectId"] = add_property_json("Parent", 0.0, "string", parentObjectId, NULL, -1, -1, false, requested_frame);
// Add gravity choices (dropdown style)
root["gravity"]["choices"].append(add_property_choice_json("Top Left", GRAVITY_TOP_LEFT, gravity));
root["gravity"]["choices"].append(add_property_choice_json("Top Center", GRAVITY_TOP, gravity));
root["gravity"]["choices"].append(add_property_choice_json("Top Right", GRAVITY_TOP_RIGHT, gravity));
root["gravity"]["choices"].append(add_property_choice_json("Left", GRAVITY_LEFT, gravity));
root["gravity"]["choices"].append(add_property_choice_json("Center", GRAVITY_CENTER, gravity));
root["gravity"]["choices"].append(add_property_choice_json("Right", GRAVITY_RIGHT, gravity));
root["gravity"]["choices"].append(add_property_choice_json("Bottom Left", GRAVITY_BOTTOM_LEFT, gravity));
root["gravity"]["choices"].append(add_property_choice_json("Bottom Center", GRAVITY_BOTTOM, gravity));
root["gravity"]["choices"].append(add_property_choice_json("Bottom Right", GRAVITY_BOTTOM_RIGHT, gravity));
// Add scale choices (dropdown style)
root["scale"]["choices"].append(add_property_choice_json("Crop", SCALE_CROP, scale));
root["scale"]["choices"].append(add_property_choice_json("Best Fit", SCALE_FIT, scale));
root["scale"]["choices"].append(add_property_choice_json("Stretch", SCALE_STRETCH, scale));
root["scale"]["choices"].append(add_property_choice_json("None", SCALE_NONE, scale));
// Add frame number display choices (dropdown style)
root["display"]["choices"].append(add_property_choice_json("None", FRAME_DISPLAY_NONE, display));
root["display"]["choices"].append(add_property_choice_json("Clip", FRAME_DISPLAY_CLIP, display));
root["display"]["choices"].append(add_property_choice_json("Timeline", FRAME_DISPLAY_TIMELINE, display));
root["display"]["choices"].append(add_property_choice_json("Both", FRAME_DISPLAY_BOTH, display));
// Add volume mixing choices (dropdown style)
root["mixing"]["choices"].append(add_property_choice_json("None", VOLUME_MIX_NONE, mixing));
root["mixing"]["choices"].append(add_property_choice_json("Average", VOLUME_MIX_AVERAGE, mixing));
root["mixing"]["choices"].append(add_property_choice_json("Reduce", VOLUME_MIX_REDUCE, mixing));
// Add waveform choices (dropdown style)
root["waveform"]["choices"].append(add_property_choice_json("Yes", true, waveform));
root["waveform"]["choices"].append(add_property_choice_json("No", false, waveform));
// Add the parentTrackedObject's properties
if (parentTrackedObject && parentClipObject)
{
// Convert Clip's frame position to Timeline's frame position
long clip_start_position = round(Position() * info.fps.ToDouble()) + 1;
long clip_start_frame = (Start() * info.fps.ToDouble()) + 1;
double timeline_frame_number = requested_frame + clip_start_position - clip_start_frame;
// Get attached object's parent clip properties
std::map< std::string, float > trackedObjectParentClipProperties = parentTrackedObject->GetParentClipProperties(timeline_frame_number);
double parentObject_frame_number = trackedObjectParentClipProperties["frame_number"];
// Get attached object properties
std::map< std::string, float > trackedObjectProperties = parentTrackedObject->GetBoxValues(parentObject_frame_number);
// Correct the parent Tracked Object properties by the clip's reference system
float parentObject_location_x = trackedObjectProperties["cx"] - 0.5 + trackedObjectParentClipProperties["cx"];
float parentObject_location_y = trackedObjectProperties["cy"] - 0.5 + trackedObjectParentClipProperties["cy"];
float parentObject_scale_x = trackedObjectProperties["w"]*trackedObjectProperties["sx"];
float parentObject_scale_y = trackedObjectProperties["h"]*trackedObjectProperties["sy"];
float parentObject_rotation = trackedObjectProperties["r"] + trackedObjectParentClipProperties["r"];
// Add the parent Tracked Object properties to JSON
root["location_x"] = add_property_json("Location X", parentObject_location_x, "float", "", &location_x, -1.0, 1.0, false, requested_frame);
root["location_y"] = add_property_json("Location Y", parentObject_location_y, "float", "", &location_y, -1.0, 1.0, false, requested_frame);
root["scale_x"] = add_property_json("Scale X", parentObject_scale_x, "float", "", &scale_x, 0.0, 1.0, false, requested_frame);
root["scale_y"] = add_property_json("Scale Y", parentObject_scale_y, "float", "", &scale_y, 0.0, 1.0, false, requested_frame);
root["rotation"] = add_property_json("Rotation", parentObject_rotation, "float", "", &rotation, -360, 360, false, requested_frame);
root["shear_x"] = add_property_json("Shear X", shear_x.GetValue(requested_frame), "float", "", &shear_x, -1.0, 1.0, false, requested_frame);
root["shear_y"] = add_property_json("Shear Y", shear_y.GetValue(requested_frame), "float", "", &shear_y, -1.0, 1.0, false, requested_frame);
}
// Add the parentClipObject's properties
else if (parentClipObject)
{
// Convert Clip's frame position to Timeline's frame position
long clip_start_position = round(Position() * info.fps.ToDouble()) + 1;
long clip_start_frame = (Start() * info.fps.ToDouble()) + 1;
double timeline_frame_number = requested_frame + clip_start_position - clip_start_frame;
// Correct the parent Clip Object properties by the clip's reference system
float parentObject_location_x = parentClipObject->location_x.GetValue(timeline_frame_number);
float parentObject_location_y = parentClipObject->location_y.GetValue(timeline_frame_number);
float parentObject_scale_x = parentClipObject->scale_x.GetValue(timeline_frame_number);
float parentObject_scale_y = parentClipObject->scale_y.GetValue(timeline_frame_number);
float parentObject_shear_x = parentClipObject->shear_x.GetValue(timeline_frame_number);
float parentObject_shear_y = parentClipObject->shear_y.GetValue(timeline_frame_number);
float parentObject_rotation = parentClipObject->rotation.GetValue(timeline_frame_number);
// Add the parent Clip Object properties to JSON
root["location_x"] = add_property_json("Location X", parentObject_location_x, "float", "", &location_x, -1.0, 1.0, false, requested_frame);
root["location_y"] = add_property_json("Location Y", parentObject_location_y, "float", "", &location_y, -1.0, 1.0, false, requested_frame);
root["scale_x"] = add_property_json("Scale X", parentObject_scale_x, "float", "", &scale_x, 0.0, 1.0, false, requested_frame);
root["scale_y"] = add_property_json("Scale Y", parentObject_scale_y, "float", "", &scale_y, 0.0, 1.0, false, requested_frame);
root["rotation"] = add_property_json("Rotation", parentObject_rotation, "float", "", &rotation, -360, 360, false, requested_frame);
root["shear_x"] = add_property_json("Shear X", parentObject_shear_x, "float", "", &shear_x, -1.0, 1.0, false, requested_frame);
root["shear_y"] = add_property_json("Shear Y", parentObject_shear_y, "float", "", &shear_y, -1.0, 1.0, false, requested_frame);
}
else
{
// Add this own clip's properties to JSON
root["location_x"] = add_property_json("Location X", location_x.GetValue(requested_frame), "float", "", &location_x, -1.0, 1.0, false, requested_frame);
root["location_y"] = add_property_json("Location Y", location_y.GetValue(requested_frame), "float", "", &location_y, -1.0, 1.0, false, requested_frame);
root["scale_x"] = add_property_json("Scale X", scale_x.GetValue(requested_frame), "float", "", &scale_x, 0.0, 1.0, false, requested_frame);
root["scale_y"] = add_property_json("Scale Y", scale_y.GetValue(requested_frame), "float", "", &scale_y, 0.0, 1.0, false, requested_frame);
root["rotation"] = add_property_json("Rotation", rotation.GetValue(requested_frame), "float", "", &rotation, -360, 360, false, requested_frame);
root["shear_x"] = add_property_json("Shear X", shear_x.GetValue(requested_frame), "float", "", &shear_x, -1.0, 1.0, false, requested_frame);
root["shear_y"] = add_property_json("Shear Y", shear_y.GetValue(requested_frame), "float", "", &shear_y, -1.0, 1.0, false, requested_frame);
}
// Keyframes
root["alpha"] = add_property_json("Alpha", alpha.GetValue(requested_frame), "float", "", &alpha, 0.0, 1.0, false, requested_frame);
root["origin_x"] = add_property_json("Origin X", origin_x.GetValue(requested_frame), "float", "", &origin_x, 0.0, 1.0, false, requested_frame);
root["origin_y"] = add_property_json("Origin Y", origin_y.GetValue(requested_frame), "float", "", &origin_y, 0.0, 1.0, false, requested_frame);
root["volume"] = add_property_json("Volume", volume.GetValue(requested_frame), "float", "", &volume, 0.0, 1.0, false, requested_frame);
root["time"] = add_property_json("Time", time.GetValue(requested_frame), "float", "", &time, 0.0, 30 * 60 * 60 * 48, false, requested_frame);
root["channel_filter"] = add_property_json("Channel Filter", channel_filter.GetValue(requested_frame), "int", "", &channel_filter, -1, 10, false, requested_frame);
root["channel_mapping"] = add_property_json("Channel Mapping", channel_mapping.GetValue(requested_frame), "int", "", &channel_mapping, -1, 10, false, requested_frame);
root["has_audio"] = add_property_json("Enable Audio", has_audio.GetValue(requested_frame), "int", "", &has_audio, -1, 1.0, false, requested_frame);
root["has_video"] = add_property_json("Enable Video", has_video.GetValue(requested_frame), "int", "", &has_video, -1, 1.0, false, requested_frame);
// Add enable audio/video choices (dropdown style)
root["has_audio"]["choices"].append(add_property_choice_json("Auto", -1, has_audio.GetValue(requested_frame)));
root["has_audio"]["choices"].append(add_property_choice_json("Off", 0, has_audio.GetValue(requested_frame)));
root["has_audio"]["choices"].append(add_property_choice_json("On", 1, has_audio.GetValue(requested_frame)));
root["has_video"]["choices"].append(add_property_choice_json("Auto", -1, has_video.GetValue(requested_frame)));
root["has_video"]["choices"].append(add_property_choice_json("Off", 0, has_video.GetValue(requested_frame)));
root["has_video"]["choices"].append(add_property_choice_json("On", 1, has_video.GetValue(requested_frame)));
root["wave_color"] = add_property_json("Wave Color", 0.0, "color", "", &wave_color.red, 0, 255, false, requested_frame);
root["wave_color"]["red"] = add_property_json("Red", wave_color.red.GetValue(requested_frame), "float", "", &wave_color.red, 0, 255, false, requested_frame);
root["wave_color"]["blue"] = add_property_json("Blue", wave_color.blue.GetValue(requested_frame), "float", "", &wave_color.blue, 0, 255, false, requested_frame);
root["wave_color"]["green"] = add_property_json("Green", wave_color.green.GetValue(requested_frame), "float", "", &wave_color.green, 0, 255, false, requested_frame);
// Return formatted string
return root.toStyledString();
}
// Generate Json::Value for this object
Json::Value Clip::JsonValue() const {
// Create root json object
Json::Value root = ClipBase::JsonValue(); // get parent properties
root["parentObjectId"] = parentObjectId;
root["gravity"] = gravity;
root["scale"] = scale;
root["anchor"] = anchor;
root["display"] = display;
root["mixing"] = mixing;
root["waveform"] = waveform;
root["scale_x"] = scale_x.JsonValue();
root["scale_y"] = scale_y.JsonValue();
root["location_x"] = location_x.JsonValue();
root["location_y"] = location_y.JsonValue();
root["alpha"] = alpha.JsonValue();
root["rotation"] = rotation.JsonValue();
root["time"] = time.JsonValue();
root["volume"] = volume.JsonValue();
root["wave_color"] = wave_color.JsonValue();
root["shear_x"] = shear_x.JsonValue();
root["shear_y"] = shear_y.JsonValue();
root["origin_x"] = origin_x.JsonValue();
root["origin_y"] = origin_y.JsonValue();
root["channel_filter"] = channel_filter.JsonValue();
root["channel_mapping"] = channel_mapping.JsonValue();
root["has_audio"] = has_audio.JsonValue();
root["has_video"] = has_video.JsonValue();
root["perspective_c1_x"] = perspective_c1_x.JsonValue();
root["perspective_c1_y"] = perspective_c1_y.JsonValue();
root["perspective_c2_x"] = perspective_c2_x.JsonValue();
root["perspective_c2_y"] = perspective_c2_y.JsonValue();
root["perspective_c3_x"] = perspective_c3_x.JsonValue();
root["perspective_c3_y"] = perspective_c3_y.JsonValue();
root["perspective_c4_x"] = perspective_c4_x.JsonValue();
root["perspective_c4_y"] = perspective_c4_y.JsonValue();
// Add array of effects
root["effects"] = Json::Value(Json::arrayValue);
// loop through effects
for (auto existing_effect : effects)
{
root["effects"].append(existing_effect->JsonValue());
}
if (reader)
root["reader"] = reader->JsonValue();
else
root["reader"] = Json::Value(Json::objectValue);
// return JsonValue
return root;
}
// Load JSON string into this object
void Clip::SetJson(const std::string value) {
// Parse JSON string into JSON objects
try
{
const Json::Value root = openshot::stringToJson(value);
// Set all values that match
SetJsonValue(root);
}
catch (const std::exception& e)
{
// Error parsing JSON (or missing keys)
throw InvalidJSON("JSON is invalid (missing keys or invalid data types)");
}
}
// Load Json::Value into this object
void Clip::SetJsonValue(const Json::Value root) {
// Set parent data
ClipBase::SetJsonValue(root);
// Set data from Json (if key is found)
if (!root["parentObjectId"].isNull()){
parentObjectId = root["parentObjectId"].asString();
if (parentObjectId.size() > 0 && parentObjectId != ""){
AttachToObject(parentObjectId);
} else{
parentTrackedObject = nullptr;
parentClipObject = NULL;
}
}
if (!root["gravity"].isNull())
gravity = (GravityType) root["gravity"].asInt();
if (!root["scale"].isNull())
scale = (ScaleType) root["scale"].asInt();
if (!root["anchor"].isNull())
anchor = (AnchorType) root["anchor"].asInt();
if (!root["display"].isNull())
display = (FrameDisplayType) root["display"].asInt();
if (!root["mixing"].isNull())
mixing = (VolumeMixType) root["mixing"].asInt();
if (!root["waveform"].isNull())
waveform = root["waveform"].asBool();
if (!root["scale_x"].isNull())
scale_x.SetJsonValue(root["scale_x"]);
if (!root["scale_y"].isNull())
scale_y.SetJsonValue(root["scale_y"]);
if (!root["location_x"].isNull())
location_x.SetJsonValue(root["location_x"]);
if (!root["location_y"].isNull())
location_y.SetJsonValue(root["location_y"]);
if (!root["alpha"].isNull())
alpha.SetJsonValue(root["alpha"]);
if (!root["rotation"].isNull())
rotation.SetJsonValue(root["rotation"]);
if (!root["time"].isNull())
time.SetJsonValue(root["time"]);
if (!root["volume"].isNull())
volume.SetJsonValue(root["volume"]);
if (!root["wave_color"].isNull())
wave_color.SetJsonValue(root["wave_color"]);
if (!root["shear_x"].isNull())
shear_x.SetJsonValue(root["shear_x"]);
if (!root["shear_y"].isNull())
shear_y.SetJsonValue(root["shear_y"]);
if (!root["origin_x"].isNull())
origin_x.SetJsonValue(root["origin_x"]);
if (!root["origin_y"].isNull())
origin_y.SetJsonValue(root["origin_y"]);
if (!root["channel_filter"].isNull())
channel_filter.SetJsonValue(root["channel_filter"]);
if (!root["channel_mapping"].isNull())
channel_mapping.SetJsonValue(root["channel_mapping"]);
if (!root["has_audio"].isNull())
has_audio.SetJsonValue(root["has_audio"]);
if (!root["has_video"].isNull())
has_video.SetJsonValue(root["has_video"]);
if (!root["perspective_c1_x"].isNull())
perspective_c1_x.SetJsonValue(root["perspective_c1_x"]);
if (!root["perspective_c1_y"].isNull())
perspective_c1_y.SetJsonValue(root["perspective_c1_y"]);
if (!root["perspective_c2_x"].isNull())
perspective_c2_x.SetJsonValue(root["perspective_c2_x"]);
if (!root["perspective_c2_y"].isNull())
perspective_c2_y.SetJsonValue(root["perspective_c2_y"]);
if (!root["perspective_c3_x"].isNull())
perspective_c3_x.SetJsonValue(root["perspective_c3_x"]);
if (!root["perspective_c3_y"].isNull())
perspective_c3_y.SetJsonValue(root["perspective_c3_y"]);
if (!root["perspective_c4_x"].isNull())
perspective_c4_x.SetJsonValue(root["perspective_c4_x"]);
if (!root["perspective_c4_y"].isNull())
perspective_c4_y.SetJsonValue(root["perspective_c4_y"]);
if (!root["effects"].isNull()) {
// Clear existing effects
effects.clear();
// loop through effects
for (const auto existing_effect : root["effects"]) {
// Create Effect
EffectBase *e = NULL;
if (!existing_effect["type"].isNull()) {
// Create instance of effect
if ( (e = EffectInfo().CreateEffect(existing_effect["type"].asString()))) {
// Load Json into Effect
e->SetJsonValue(existing_effect);
// Add Effect to Timeline
AddEffect(e);
}
}
}
}
if (!root["reader"].isNull()) // does Json contain a reader?
{
if (!root["reader"]["type"].isNull()) // does the reader Json contain a 'type'?
{
// Close previous reader (if any)
bool already_open = false;
if (reader)
{
// Track if reader was open
already_open = reader->IsOpen();
// Close and delete existing allocated reader (if any)
Reader(NULL);
}
// Create new reader (and load properties)
std::string type = root["reader"]["type"].asString();
if (type == "FFmpegReader") {
// Create new reader
reader = new openshot::FFmpegReader(root["reader"]["path"].asString(), false);
reader->SetJsonValue(root["reader"]);
} else if (type == "QtImageReader") {
// Create new reader
reader = new openshot::QtImageReader(root["reader"]["path"].asString(), false);
reader->SetJsonValue(root["reader"]);
#ifdef USE_IMAGEMAGICK
} else if (type == "ImageReader") {
// Create new reader
reader = new ImageReader(root["reader"]["path"].asString(), false);
reader->SetJsonValue(root["reader"]);
} else if (type == "TextReader") {
// Create new reader
reader = new TextReader();
reader->SetJsonValue(root["reader"]);
#endif
} else if (type == "ChunkReader") {
// Create new reader
reader = new openshot::ChunkReader(root["reader"]["path"].asString(), (ChunkVersion) root["reader"]["chunk_version"].asInt());
reader->SetJsonValue(root["reader"]);
} else if (type == "DummyReader") {
// Create new reader
reader = new openshot::DummyReader();
reader->SetJsonValue(root["reader"]);
} else if (type == "Timeline") {
// Create new reader (always load from file again)
// This prevents FrameMappers from being loaded on accident
reader = new openshot::Timeline(root["reader"]["path"].asString(), true);
}
// mark as managed reader and set parent
if (reader) {
reader->ParentClip(this);
allocated_reader = reader;
}
// Re-Open reader (if needed)
if (already_open) {
reader->Open();
}
}
}
// Clear cache (it might have changed)
final_cache.Clear();
}
// Sort effects by order
void Clip::sort_effects()
{
// sort clips
effects.sort(CompareClipEffects());
}
// Add an effect to the clip
void Clip::AddEffect(EffectBase* effect)
{
// Set parent clip pointer
effect->ParentClip(this);
// Add effect to list
effects.push_back(effect);
// Sort effects
sort_effects();
// Get the parent timeline of this clip
Timeline* parentTimeline = static_cast<Timeline *>(ParentTimeline());
if (parentTimeline)
effect->ParentTimeline(parentTimeline);
#ifdef USE_OPENCV
// Add Tracked Object to Timeline
if (effect->info.has_tracked_object){
// Check if this clip has a parent timeline
if (parentTimeline){
effect->ParentTimeline(parentTimeline);
// Iterate through effect's vector of Tracked Objects
for (auto const& trackedObject : effect->trackedObjects){
// Cast the Tracked Object as TrackedObjectBBox
std::shared_ptr<TrackedObjectBBox> trackedObjectBBox = std::static_pointer_cast<TrackedObjectBBox>(trackedObject.second);
// Set the Tracked Object's parent clip to this
trackedObjectBBox->ParentClip(this);
// Add the Tracked Object to the timeline
parentTimeline->AddTrackedObject(trackedObjectBBox);
}
}
}
#endif
// Clear cache (it might have changed)
final_cache.Clear();
}
// Remove an effect from the clip
void Clip::RemoveEffect(EffectBase* effect)
{
effects.remove(effect);
// Clear cache (it might have changed)
final_cache.Clear();
}
// Apply effects to the source frame (if any)
void Clip::apply_effects(std::shared_ptr<Frame> frame)
{
// Find Effects at this position and layer
for (auto effect : effects)
{
// Apply the effect to this frame
frame = effect->GetFrame(frame, frame->number);
} // end effect loop
}
// Compare 2 floating point numbers for equality
bool Clip::isEqual(double a, double b)
{
return fabs(a - b) < 0.000001;
}
// Apply keyframes to the source frame (if any)
void Clip::apply_keyframes(std::shared_ptr<Frame> frame, std::shared_ptr<Frame> background_frame) {
// Skip out if video was disabled or only an audio frame (no visualisation in use)
if (!frame->has_image_data) {
// Skip the rest of the image processing for performance reasons
return;
}
// Get image from clip
std::shared_ptr<QImage> source_image = frame->GetImage();
std::shared_ptr<QImage> background_canvas = background_frame->GetImage();
// Get transform from clip's keyframes
QTransform transform = get_transform(frame, background_canvas->width(), background_canvas->height());
// Debug output
ZmqLogger::Instance()->AppendDebugMethod(
"Clip::ApplyKeyframes (Transform: Composite Image Layer: Prepare)",
"frame->number", frame->number,
"background_canvas->width()", background_canvas->width(),
"background_canvas->height()", background_canvas->height());
// Load timeline's new frame image into a QPainter
QPainter painter(background_canvas.get());
painter.setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform | QPainter::TextAntialiasing, true);
// Apply transform (translate, rotate, scale)
painter.setTransform(transform);
// Composite a new layer onto the image
painter.setCompositionMode(QPainter::CompositionMode_SourceOver);
painter.drawImage(0, 0, *source_image);
if (timeline) {
Timeline *t = static_cast<Timeline *>(timeline);
// Draw frame #'s on top of image (if needed)
if (display != FRAME_DISPLAY_NONE) {
std::stringstream frame_number_str;
switch (display) {
case (FRAME_DISPLAY_NONE):
// This is only here to prevent unused-enum warnings
break;
case (FRAME_DISPLAY_CLIP):
frame_number_str << frame->number;
break;
case (FRAME_DISPLAY_TIMELINE):
frame_number_str << round((Position() - Start()) * t->info.fps.ToFloat()) + frame->number;
break;
case (FRAME_DISPLAY_BOTH):
frame_number_str << round((Position() - Start()) * t->info.fps.ToFloat()) + frame->number << " (" << frame->number << ")";
break;
}
// Draw frame number on top of image
painter.setPen(QColor("#ffffff"));
painter.drawText(20, 20, QString(frame_number_str.str().c_str()));
}
}
painter.end();
// Add new QImage to frame
frame->AddImage(background_canvas);
}
// Apply apply_waveform image to the source frame (if any)
void Clip::apply_waveform(std::shared_ptr<Frame> frame, std::shared_ptr<Frame> background_frame) {
if (!Waveform()) {
// Exit if no waveform is needed
return;
}
// Get image from clip
std::shared_ptr<QImage> source_image = frame->GetImage();
std::shared_ptr<QImage> background_canvas = background_frame->GetImage();
// Debug output
ZmqLogger::Instance()->AppendDebugMethod(
"Clip::apply_waveform (Generate Waveform Image)",
"frame->number", frame->number,
"Waveform()", Waveform(),
"background_canvas->width()", background_canvas->width(),
"background_canvas->height()", background_canvas->height());
// Get the color of the waveform
int red = wave_color.red.GetInt(frame->number);
int green = wave_color.green.GetInt(frame->number);
int blue = wave_color.blue.GetInt(frame->number);
int alpha = wave_color.alpha.GetInt(frame->number);
// Generate Waveform Dynamically (the size of the timeline)
source_image = frame->GetWaveform(background_canvas->width(), background_canvas->height(), red, green, blue, alpha);
frame->AddImage(source_image);
}
// Apply keyframes to the source frame (if any)
QTransform Clip::get_transform(std::shared_ptr<Frame> frame, int width, int height)
{
// Get image from clip
std::shared_ptr<QImage> source_image = frame->GetImage();
/* ALPHA & OPACITY */
if (alpha.GetValue(frame->number) != 1.0)
{
float alpha_value = alpha.GetValue(frame->number);
// Get source image's pixels
unsigned char *pixels = source_image->bits();
// Loop through pixels
for (int pixel = 0, byte_index=0; pixel < source_image->width() * source_image->height(); pixel++, byte_index+=4)
{
// Apply alpha to pixel values (since we use a premultiplied value, we must
// multiply the alpha with all colors).
pixels[byte_index + 0] *= alpha_value;
pixels[byte_index + 1] *= alpha_value;
pixels[byte_index + 2] *= alpha_value;
pixels[byte_index + 3] *= alpha_value;
}
// Debug output
ZmqLogger::Instance()->AppendDebugMethod(
"Clip::get_transform (Set Alpha & Opacity)",
"alpha_value", alpha_value,
"frame->number", frame->number);
}
/* RESIZE SOURCE IMAGE - based on scale type */
QSize source_size = source_image->size();
// Apply stretch scale to correctly fit the bounding-box
if (parentTrackedObject){
scale = SCALE_STRETCH;
}
switch (scale)
{
case (SCALE_FIT): {
source_size.scale(width, height, Qt::KeepAspectRatio);
// Debug output
ZmqLogger::Instance()->AppendDebugMethod(
"Clip::get_transform (Scale: SCALE_FIT)",
"frame->number", frame->number,
"source_width", source_size.width(),
"source_height", source_size.height());
break;
}
case (SCALE_STRETCH): {
source_size.scale(width, height, Qt::IgnoreAspectRatio);
// Debug output
ZmqLogger::Instance()->AppendDebugMethod(
"Clip::get_transform (Scale: SCALE_STRETCH)",
"frame->number", frame->number,
"source_width", source_size.width(),
"source_height", source_size.height());
break;
}
case (SCALE_CROP): {
source_size.scale(width, height, Qt::KeepAspectRatioByExpanding);
// Debug output
ZmqLogger::Instance()->AppendDebugMethod(
"Clip::get_transform (Scale: SCALE_CROP)",
"frame->number", frame->number,
"source_width", source_size.width(),
"source_height", source_size.height());
break;
}
case (SCALE_NONE): {
// Image is already the original size (i.e. no scaling mode) relative
// to the preview window size (i.e. timeline / preview ratio). No further
// scaling is needed here.
// Debug output
ZmqLogger::Instance()->AppendDebugMethod(
"Clip::get_transform (Scale: SCALE_NONE)",
"frame->number", frame->number,
"source_width", source_size.width(),
"source_height", source_size.height());
break;
}
}
// Initialize parent object's properties (Clip or Tracked Object)
float parentObject_location_x = 0.0;
float parentObject_location_y = 0.0;
float parentObject_scale_x = 1.0;
float parentObject_scale_y = 1.0;
float parentObject_shear_x = 0.0;
float parentObject_shear_y = 0.0;
float parentObject_rotation = 0.0;
// Get the parentClipObject properties
if (parentClipObject){
// Convert Clip's frame position to Timeline's frame position
long clip_start_position = round(Position() * info.fps.ToDouble()) + 1;
long clip_start_frame = (Start() * info.fps.ToDouble()) + 1;
double timeline_frame_number = frame->number + clip_start_position - clip_start_frame;
// Get parent object's properties (Clip)
parentObject_location_x = parentClipObject->location_x.GetValue(timeline_frame_number);
parentObject_location_y = parentClipObject->location_y.GetValue(timeline_frame_number);
parentObject_scale_x = parentClipObject->scale_x.GetValue(timeline_frame_number);
parentObject_scale_y = parentClipObject->scale_y.GetValue(timeline_frame_number);
parentObject_shear_x = parentClipObject->shear_x.GetValue(timeline_frame_number);
parentObject_shear_y = parentClipObject->shear_y.GetValue(timeline_frame_number);
parentObject_rotation = parentClipObject->rotation.GetValue(timeline_frame_number);
}
// Get the parentTrackedObject properties
if (parentTrackedObject){
// Convert Clip's frame position to Timeline's frame position
long clip_start_position = round(Position() * info.fps.ToDouble()) + 1;
long clip_start_frame = (Start() * info.fps.ToDouble()) + 1;
double timeline_frame_number = frame->number + clip_start_position - clip_start_frame;
// Get parentTrackedObject's parent clip's properties
std::map<std::string, float> trackedObjectParentClipProperties =
parentTrackedObject->GetParentClipProperties(timeline_frame_number);
// Get the attached object's parent clip's properties
if (!trackedObjectParentClipProperties.empty())
{
// Get parent object's properties (Tracked Object)
float parentObject_frame_number = trackedObjectParentClipProperties["frame_number"];
// Access the parentTrackedObject's properties
std::map<std::string, float> trackedObjectProperties = parentTrackedObject->GetBoxValues(parentObject_frame_number);
// Get the Tracked Object's properties and correct them by the clip's reference system
parentObject_location_x = trackedObjectProperties["cx"] - 0.5 + trackedObjectParentClipProperties["location_x"];
parentObject_location_y = trackedObjectProperties["cy"] - 0.5 + trackedObjectParentClipProperties["location_y"];
parentObject_scale_x = trackedObjectProperties["w"]*trackedObjectProperties["sx"];
parentObject_scale_y = trackedObjectProperties["h"]*trackedObjectProperties["sy"];
parentObject_rotation = trackedObjectProperties["r"] + trackedObjectParentClipProperties["rotation"];
}
else
{
// Access the parentTrackedObject's properties
std::map<std::string, float> trackedObjectProperties = parentTrackedObject->GetBoxValues(timeline_frame_number);
// Get the Tracked Object's properties and correct them by the clip's reference system
parentObject_location_x = trackedObjectProperties["cx"] - 0.5;
parentObject_location_y = trackedObjectProperties["cy"] - 0.5;
parentObject_scale_x = trackedObjectProperties["w"]*trackedObjectProperties["sx"];
parentObject_scale_y = trackedObjectProperties["h"]*trackedObjectProperties["sy"];
parentObject_rotation = trackedObjectProperties["r"];
}
}
/* GRAVITY LOCATION - Initialize X & Y to the correct values (before applying location curves) */
float x = 0.0; // left
float y = 0.0; // top
// Adjust size for scale x and scale y
float sx = scale_x.GetValue(frame->number); // percentage X scale
float sy = scale_y.GetValue(frame->number); // percentage Y scale
// Change clip's scale to parentObject's scale
if(parentObject_scale_x != 0.0 && parentObject_scale_y != 0.0){
sx*= parentObject_scale_x;
sy*= parentObject_scale_y;
}
float scaled_source_width = source_size.width() * sx;
float scaled_source_height = source_size.height() * sy;
switch (gravity)
{
case (GRAVITY_TOP_LEFT):
// This is only here to prevent unused-enum warnings
break;
case (GRAVITY_TOP):
x = (width - scaled_source_width) / 2.0; // center
break;
case (GRAVITY_TOP_RIGHT):
x = width - scaled_source_width; // right
break;
case (GRAVITY_LEFT):
y = (height - scaled_source_height) / 2.0; // center
break;
case (GRAVITY_CENTER):
x = (width - scaled_source_width) / 2.0; // center
y = (height - scaled_source_height) / 2.0; // center
break;
case (GRAVITY_RIGHT):
x = width - scaled_source_width; // right
y = (height - scaled_source_height) / 2.0; // center
break;
case (GRAVITY_BOTTOM_LEFT):
y = (height - scaled_source_height); // bottom
break;
case (GRAVITY_BOTTOM):
x = (width - scaled_source_width) / 2.0; // center
y = (height - scaled_source_height); // bottom
break;
case (GRAVITY_BOTTOM_RIGHT):
x = width - scaled_source_width; // right
y = (height - scaled_source_height); // bottom
break;
}
// Debug output
ZmqLogger::Instance()->AppendDebugMethod(
"Clip::get_transform (Gravity)",
"frame->number", frame->number,
"source_clip->gravity", gravity,
"scaled_source_width", scaled_source_width,
"scaled_source_height", scaled_source_height);
QTransform transform;
/* LOCATION, ROTATION, AND SCALE */
float r = rotation.GetValue(frame->number) + parentObject_rotation; // rotate in degrees
x += (width * (location_x.GetValue(frame->number) + parentObject_location_x )); // move in percentage of final width
y += (height * (location_y.GetValue(frame->number) + parentObject_location_y )); // move in percentage of final height
float shear_x_value = shear_x.GetValue(frame->number) + parentObject_shear_x;
float shear_y_value = shear_y.GetValue(frame->number) + parentObject_shear_y;
float origin_x_value = origin_x.GetValue(frame->number);
float origin_y_value = origin_y.GetValue(frame->number);
// Transform source image (if needed)
ZmqLogger::Instance()->AppendDebugMethod(
"Clip::get_transform (Build QTransform - if needed)",
"frame->number", frame->number,
"x", x, "y", y,
"r", r,
"sx", sx, "sy", sy);
if (!isEqual(x, 0) || !isEqual(y, 0)) {
// TRANSLATE/MOVE CLIP
transform.translate(x, y);
}
if (!isEqual(r, 0) || !isEqual(shear_x_value, 0) || !isEqual(shear_y_value, 0)) {
// ROTATE CLIP (around origin_x, origin_y)
float origin_x_offset = (scaled_source_width * origin_x_value);
float origin_y_offset = (scaled_source_height * origin_y_value);
transform.translate(origin_x_offset, origin_y_offset);
transform.rotate(r);
transform.shear(shear_x_value, shear_y_value);
transform.translate(-origin_x_offset,-origin_y_offset);
}
// SCALE CLIP (if needed)
float source_width_scale = (float(source_size.width()) / float(source_image->width())) * sx;
float source_height_scale = (float(source_size.height()) / float(source_image->height())) * sy;
if (!isEqual(source_width_scale, 1.0) || !isEqual(source_height_scale, 1.0)) {
transform.scale(source_width_scale, source_height_scale);
}
return transform;
}
// Adjust frame number for Clip position and start (which can result in a different number)
int64_t Clip::adjust_timeline_framenumber(int64_t clip_frame_number) {
// Get clip position from parent clip (if any)
float position = 0.0;
float start = 0.0;
Clip *parent = static_cast<Clip *>(ParentClip());
if (parent) {
position = parent->Position();
start = parent->Start();
}
// Adjust start frame and position based on parent clip.
// This ensures the same frame # is used by mapped readers and clips,
// when calculating samples per frame.
// Thus, this prevents gaps and mismatches in # of samples.
int64_t clip_start_frame = (start * info.fps.ToDouble()) + 1;
int64_t clip_start_position = round(position * info.fps.ToDouble()) + 1;
int64_t frame_number = clip_frame_number + clip_start_position - clip_start_frame;
return frame_number;
}
AudioResampler.h
Header file for AudioResampler class.
ChunkReader.h
Header file for ChunkReader class.
Clip.h
Header file for Clip class.
DummyReader.h
Header file for DummyReader class.
Exceptions.h
Header file for all Exception classes.
FFmpegReader.h
Header file for FFmpegReader class.
path
path
Definition FFmpegWriter.cpp:1515
FrameMapper.h
Header file for the FrameMapper class.
ImageReader.h
Header file for ImageReader class.
MagickUtilities.h
Header file for MagickUtilities (IM6/IM7 compatibility overlay)
QtImageReader.h
Header file for QtImageReader class.
TextReader.h
Header file for TextReader class.
Timeline.h
Header file for Timeline class.
ZmqLogger.h
Header file for ZeroMQ-based Logger class.
juce::AudioBuffer
Definition Frame.h:38
openshot::AudioResampler
This class is used to resample audio data for many sequential frames.
Definition AudioResampler.h:30
openshot::AudioResampler::SetBuffer
void SetBuffer(juce::AudioBuffer< float > *new_buffer, double sample_rate, double new_sample_rate)
Sets the audio buffer and key settings.
Definition AudioResampler.cpp:60
openshot::AudioResampler::GetResampledBuffer
juce::AudioBuffer< float > * GetResampledBuffer()
Get the resampled audio buffer.
Definition AudioResampler.cpp:106
openshot::CacheBase::SetMaxBytesFromInfo
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.
Definition CacheBase.cpp:30
openshot::CacheMemory::Add
void Add(std::shared_ptr< openshot::Frame > frame)
Add a Frame to the cache.
Definition CacheMemory.cpp:46
openshot::CacheMemory::GetFrame
std::shared_ptr< openshot::Frame > GetFrame(int64_t frame_number)
Get a frame from the cache.
Definition CacheMemory.cpp:80
openshot::CacheMemory::Clear
void Clear()
Clear the cache of all frames.
Definition CacheMemory.cpp:221
openshot::ChunkReader
This class reads a special chunk-formatted file, which can be easily shared in a distributed environm...
Definition ChunkReader.h:79
openshot::ClipBase::Start
float Start() const
Get start position (in seconds) of clip (trim start of video)
Definition ClipBase.h:88
openshot::ClipBase::start
float start
The position in seconds to start playing (used to trim the beginning of a clip)
Definition ClipBase.h:38
openshot::ClipBase::Duration
float Duration() const
Get the length of this clip (in seconds)
Definition ClipBase.h:90
openshot::ClipBase::End
virtual float End() const
Get end position (in seconds) of clip (trim end of video)
Definition ClipBase.h:89
openshot::ClipBase::Id
std::string Id() const
Get the Id of this clip object.
Definition ClipBase.h:85
openshot::ClipBase::JsonValue
virtual Json::Value JsonValue() const =0
Generate Json::Value for this object.
Definition ClipBase.cpp:64
openshot::ClipBase::add_property_choice_json
Json::Value add_property_choice_json(std::string name, int value, int selected_value) const
Generate JSON choice for a property (dropdown properties)
Definition ClipBase.cpp:132
openshot::ClipBase::Layer
int Layer() const
Get layer of clip on timeline (lower number is covered by higher numbers)
Definition ClipBase.h:87
openshot::ClipBase::SetJsonValue
virtual void SetJsonValue(const Json::Value root)=0
Load Json::Value into this object.
Definition ClipBase.cpp:80
openshot::ClipBase::timeline
openshot::TimelineBase * timeline
Pointer to the parent timeline instance (if any)
Definition ClipBase.h:41
openshot::ClipBase::Position
float Position() const
Get position on timeline (in seconds)
Definition ClipBase.h:86
openshot::ClipBase::ParentTimeline
virtual openshot::TimelineBase * ParentTimeline()
Get the associated Timeline pointer (if any)
Definition ClipBase.h:91
openshot::ClipBase::id
std::string id
ID Property for all derived Clip and Effect classes.
Definition ClipBase.h:35
openshot::ClipBase::position
float position
The position on the timeline where this clip should start playing.
Definition ClipBase.h:36
openshot::ClipBase::end
float end
The position in seconds to end playing (used to trim the ending of a clip)
Definition ClipBase.h:39
openshot::ClipBase::previous_properties
std::string previous_properties
This string contains the previous JSON properties.
Definition ClipBase.h:40
openshot::ClipBase::add_property_json
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.
Definition ClipBase.cpp:96
openshot::Clip
This class represents a clip (used to arrange readers on the timeline)
Definition Clip.h:89
openshot::Clip::SetAttachedObject
void SetAttachedObject(std::shared_ptr< openshot::TrackedObjectBase > trackedObject)
Set the pointer to the trackedObject this clip is attached to.
Definition Clip.cpp:262
openshot::Clip::scale_x
openshot::Keyframe scale_x
Curve representing the horizontal scaling in percent (0 to 1)
Definition Clip.h:298
openshot::Clip::location_y
openshot::Keyframe location_y
Curve representing the relative Y position in percent based on the gravity (-1 to 1)
Definition Clip.h:301
openshot::Clip::shear_x
openshot::Keyframe shear_x
Curve representing X shear angle in degrees (-45.0=left, 45.0=right)
Definition Clip.h:306
openshot::Clip::perspective_c4_x
openshot::Keyframe perspective_c4_x
Curves representing X for coordinate 4.
Definition Clip.h:325
openshot::Clip::anchor
openshot::AnchorType anchor
The anchor determines what parent a clip should snap to.
Definition Clip.h:167
openshot::Clip::mixing
openshot::VolumeMixType mixing
What strategy should be followed when mixing audio with other clips.
Definition Clip.h:169
openshot::Clip::Open
void Open() override
Open the internal reader.
Definition Clip.cpp:318
openshot::Clip::rotation
openshot::Keyframe rotation
Curve representing the rotation (0 to 360)
Definition Clip.h:305
openshot::Clip::channel_filter
openshot::Keyframe channel_filter
A number representing an audio channel to filter (clears all other channels)
Definition Clip.h:329
openshot::Clip::display
openshot::FrameDisplayType display
The format to display the frame number (if any)
Definition Clip.h:168
openshot::Clip::init_reader_rotation
void init_reader_rotation()
Update default rotation from reader.
Definition Clip.cpp:115
openshot::Clip::Clip
Clip()
Default Constructor.
Definition Clip.cpp:135
openshot::Clip::perspective_c1_x
openshot::Keyframe perspective_c1_x
Curves representing X for coordinate 1.
Definition Clip.h:319
openshot::Clip::AttachToObject
void AttachToObject(std::string object_id)
Attach clip to Tracked Object or to another Clip.
Definition Clip.cpp:241
openshot::Clip::Json
std::string Json() const override
Generate JSON string of this object.
Definition Clip.cpp:735
openshot::Clip::GetEffect
openshot::EffectBase * GetEffect(const std::string &id)
Look up an effect by ID.
Definition Clip.cpp:470
openshot::Clip::SetJsonValue
void SetJsonValue(const Json::Value root) override
Load Json::Value into this object.
Definition Clip.cpp:962
openshot::Clip::alpha
openshot::Keyframe alpha
Curve representing the alpha (1 to 0)
Definition Clip.h:302
openshot::Clip::has_audio
openshot::Keyframe has_audio
An optional override to determine if this clip has audio (-1=undefined, 0=no, 1=yes)
Definition Clip.h:333
openshot::Clip::perspective_c3_x
openshot::Keyframe perspective_c3_x
Curves representing X for coordinate 3.
Definition Clip.h:323
openshot::Clip::init_reader_settings
void init_reader_settings()
Init reader info details.
Definition Clip.cpp:101
openshot::Clip::perspective_c1_y
openshot::Keyframe perspective_c1_y
Curves representing Y for coordinate 1.
Definition Clip.h:320
openshot::Clip::JsonValue
Json::Value JsonValue() const override
Generate Json::Value for this object.
Definition Clip.cpp:889
openshot::Clip::SetAttachedClip
void SetAttachedClip(Clip *clipObject)
Set the pointer to the clip this clip is attached to.
Definition Clip.cpp:267
openshot::Clip::ParentTimeline
openshot::TimelineBase * ParentTimeline() override
Get the associated Timeline pointer (if any)
Definition Clip.h:276
openshot::Clip::perspective_c4_y
openshot::Keyframe perspective_c4_y
Curves representing Y for coordinate 4.
Definition Clip.h:326
openshot::Clip::time
openshot::Keyframe time
Curve representing the frames over time to play (used for speed and direction of video)
Definition Clip.h:312
openshot::Clip::Waveform
bool Waveform()
Get the waveform property of this clip.
Definition Clip.h:294
openshot::Clip::gravity
openshot::GravityType gravity
The gravity of a clip determines where it snaps to its parent.
Definition Clip.h:165
openshot::Clip::previous_location
AudioLocation previous_location
Previous time-mapped audio location.
Definition Clip.h:95
openshot::Clip::perspective_c3_y
openshot::Keyframe perspective_c3_y
Curves representing Y for coordinate 3.
Definition Clip.h:324
openshot::Clip::AddEffect
void AddEffect(openshot::EffectBase *effect)
Add an effect to the clip.
Definition Clip.cpp:1150
openshot::Clip::Close
void Close() override
Close the internal reader.
Definition Clip.cpp:339
openshot::Clip::~Clip
virtual ~Clip()
Destructor.
Definition Clip.cpp:221
openshot::Clip::perspective_c2_y
openshot::Keyframe perspective_c2_y
Curves representing Y for coordinate 2.
Definition Clip.h:322
openshot::Clip::volume
openshot::Keyframe volume
Curve representing the volume (0 to 1)
Definition Clip.h:313
openshot::Clip::shear_y
openshot::Keyframe shear_y
Curve representing Y shear angle in degrees (-45.0=down, 45.0=up)
Definition Clip.h:307
openshot::Clip::scale_y
openshot::Keyframe scale_y
Curve representing the vertical scaling in percent (0 to 1)
Definition Clip.h:299
openshot::Clip::End
float End() const override
Get end position (in seconds) of clip (trim end of video), which can be affected by the time curve.
Definition Clip.cpp:354
openshot::Clip::GetFrame
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 ...
Definition Clip.cpp:389
openshot::Clip::Reader
openshot::ReaderBase * Reader()
Get the current reader.
Definition Clip.cpp:308
openshot::Clip::RemoveEffect
void RemoveEffect(openshot::EffectBase *effect)
Remove an effect from the clip.
Definition Clip.cpp:1197
openshot::Clip::channel_mapping
openshot::Keyframe channel_mapping
A number representing an audio channel to output (only works when filtering a channel)
Definition Clip.h:330
openshot::Clip::has_video
openshot::Keyframe has_video
An optional override to determine if this clip has video (-1=undefined, 0=no, 1=yes)
Definition Clip.h:334
openshot::Clip::PropertiesJSON
std::string PropertiesJSON(int64_t requested_frame) const override
Definition Clip.cpp:742
openshot::Clip::wave_color
openshot::Color wave_color
Curve representing the color of the audio wave form.
Definition Clip.h:316
openshot::Clip::init_settings
void init_settings()
Init default settings for a clip.
Definition Clip.cpp:36
openshot::Clip::perspective_c2_x
openshot::Keyframe perspective_c2_x
Curves representing X for coordinate 2.
Definition Clip.h:321
openshot::Clip::scale
openshot::ScaleType scale
The scale determines how a clip should be resized to fit its parent.
Definition Clip.h:166
openshot::Clip::location_x
openshot::Keyframe location_x
Curve representing the relative X position in percent based on the gravity (-1 to 1)
Definition Clip.h:300
openshot::Clip::origin_x
openshot::Keyframe origin_x
Curve representing X origin point (0.0=0% (left), 1.0=100% (right))
Definition Clip.h:308
openshot::Clip::getFrameMutex
std::recursive_mutex getFrameMutex
Mutex for multiple threads.
Definition Clip.h:92
openshot::Clip::SetJson
void SetJson(const std::string value) override
Load JSON string into this object.
Definition Clip.cpp:945
openshot::Clip::origin_y
openshot::Keyframe origin_y
Curve representing Y origin point (0.0=0% (top), 1.0=100% (bottom))
Definition Clip.h:309
openshot::Color
This class represents a color (used on the timeline and clips)
Definition Color.h:27
openshot::Color::blue
openshot::Keyframe blue
Curve representing the red value (0 - 255)
Definition Color.h:32
openshot::Color::red
openshot::Keyframe red
Curve representing the red value (0 - 255)
Definition Color.h:30
openshot::Color::green
openshot::Keyframe green
Curve representing the green value (0 - 255)
Definition Color.h:31
openshot::Color::SetJsonValue
void SetJsonValue(const Json::Value root)
Load Json::Value into this object.
Definition Color.cpp:117
openshot::Color::alpha
openshot::Keyframe alpha
Curve representing the alpha value (0 - 255)
Definition Color.h:33
openshot::Color::JsonValue
Json::Value JsonValue() const
Generate Json::Value for this object.
Definition Color.cpp:86
openshot::DummyReader
This class is used as a simple, dummy reader, which can be very useful when writing unit tests....
Definition DummyReader.h:86
openshot::EffectBase
This abstract class is the base class, used by all effects in libopenshot.
Definition EffectBase.h:53
openshot::EffectBase::ParentClip
openshot::ClipBase * ParentClip()
Parent clip object of this effect (which can be unparented and NULL)
Definition EffectBase.cpp:173
openshot::EffectBase::SetJsonValue
virtual void SetJsonValue(const Json::Value root)
Load Json::Value into this object.
Definition EffectBase.cpp:112
openshot::EffectBase::info
EffectInfoStruct info
Information about the current effect.
Definition EffectBase.h:69
openshot::EffectBase::trackedObjects
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)
Definition EffectBase.h:66
openshot::EffectInfo
This class returns a listing of all effects supported by libopenshot.
Definition EffectInfo.h:29
openshot::FFmpegReader
This class uses the FFmpeg libraries, to open video files and audio files, and return openshot::Frame...
Definition FFmpegReader.h:101
openshot::Fraction::ToFloat
float ToFloat()
Return this fraction as a float (i.e. 1/2 = 0.5)
Definition Fraction.cpp:35
openshot::Fraction::ToDouble
double ToDouble() const
Return this fraction as a double (i.e. 1/2 = 0.5)
Definition Fraction.cpp:40
openshot::FrameMapper
This class creates a mapping between 2 different frame rates, applying a specific pull-down technique...
Definition FrameMapper.h:201
openshot::FrameMapper::Reader
ReaderBase * Reader()
Get the current reader.
Definition FrameMapper.cpp:64
openshot::Frame::GetSamplesPerFrame
int GetSamplesPerFrame(openshot::Fraction fps, int sample_rate, int channels)
Calculate the # of samples per video frame (for the current frame number)
Definition Frame.cpp:480
openshot::ImageReader
This class uses the ImageMagick++ libraries, to open image files, and return openshot::Frame objects ...
Definition ImageReader.h:56
openshot::InvalidJSON
Exception for invalid JSON.
Definition Exceptions.h:218
openshot::Keyframe
A Keyframe is a collection of Point instances, which is used to vary a number or property over time.
Definition KeyFrame.h:53
openshot::Keyframe::GetInt
int GetInt(int64_t index) const
Get the rounded INT value at a specific index.
Definition KeyFrame.cpp:282
openshot::Keyframe::SetJsonValue
void SetJsonValue(const Json::Value root)
Load Json::Value into this object.
Definition KeyFrame.cpp:372
openshot::Keyframe::GetDelta
double GetDelta(int64_t index) const
Get the change in Y value (from the previous Y value)
Definition KeyFrame.cpp:392
openshot::Keyframe::GetLength
int64_t GetLength() const
Definition KeyFrame.cpp:410
openshot::Keyframe::GetLong
int64_t GetLong(int64_t index) const
Get the rounded LONG value at a specific index.
Definition KeyFrame.cpp:287
openshot::Keyframe::GetValue
double GetValue(int64_t index) const
Get the value at a specific index.
Definition KeyFrame.cpp:258
openshot::Keyframe::JsonValue
Json::Value JsonValue() const
Generate Json::Value for this object.
Definition KeyFrame.cpp:339
openshot::Keyframe::IsIncreasing
bool IsIncreasing(int index) const
Get the direction of the curve at a specific index (increasing or decreasing)
Definition KeyFrame.cpp:292
openshot::Keyframe::GetCount
int64_t GetCount() const
Get the number of points (i.e. # of points)
Definition KeyFrame.cpp:417
openshot::OutOfBoundsFrame
Exception for frames that are out of bounds.
Definition Exceptions.h:301
openshot::QtImageReader
This class uses the Qt library, to open image files, and return openshot::Frame objects containing th...
Definition QtImageReader.h:75
openshot::ReaderBase
This abstract class is the base class, used by all readers in libopenshot.
Definition ReaderBase.h:76
openshot::ReaderBase::IsOpen
virtual bool IsOpen()=0
Determine if reader is open or closed.
openshot::ReaderBase::Name
virtual std::string Name()=0
Return the type name of the class.
openshot::ReaderBase::info
openshot::ReaderInfo info
Information about the current media file.
Definition ReaderBase.h:88
openshot::ReaderBase::SetJsonValue
virtual void SetJsonValue(const Json::Value root)=0
Load Json::Value into this object.
Definition ReaderBase.cpp:162
openshot::ReaderBase::JsonValue
virtual Json::Value JsonValue() const =0
Generate Json::Value for this object.
Definition ReaderBase.cpp:107
openshot::ReaderBase::Open
virtual void Open()=0
Open the reader (and start consuming resources, such as images or video files)
openshot::ReaderBase::GetFrame
virtual std::shared_ptr< openshot::Frame > GetFrame(int64_t number)=0
openshot::ReaderBase::ParentClip
openshot::ClipBase * ParentClip()
Parent clip object of this reader (which can be unparented and NULL)
Definition ReaderBase.cpp:245
openshot::ReaderBase::Close
virtual void Close()=0
Close the reader (and any resources it was consuming)
openshot::ReaderClosed
Exception when a reader is closed, and a frame is requested.
Definition Exceptions.h:364
openshot::TextReader
This class uses the ImageMagick++ libraries, to create frames with "Text", and return openshot::Frame...
Definition TextReader.h:63
openshot::TimelineBase
This class represents a timeline (used for building generic timeline implementations)
Definition TimelineBase.h:40
openshot::Timeline
This class represents a timeline.
Definition Timeline.h:150
openshot::Timeline::AddTrackedObject
void AddTrackedObject(std::shared_ptr< openshot::TrackedObjectBase > trackedObject)
Add to the tracked_objects map a pointer to a tracked object (TrackedObjectBBox)
Definition Timeline.cpp:223
openshot::Timeline::GetTrackedObject
std::shared_ptr< openshot::TrackedObjectBase > GetTrackedObject(std::string id) const
Return tracked object pointer by it's id.
Definition Timeline.cpp:241
openshot::Timeline::GetClip
openshot::Clip * GetClip(const std::string &id)
Look up a single clip by ID.
Definition Timeline.cpp:408
openshot::Timeline::apply_effects
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)
Definition Timeline.cpp:526
openshot::ZmqLogger::AppendDebugMethod
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.
Definition ZmqLogger.cpp:178
openshot::ZmqLogger::Instance
static ZmqLogger * Instance()
Create or get an instance of this logger singleton (invoke the class with this method)
Definition ZmqLogger.cpp:35
openshot
This namespace is the default namespace for all code in the openshot library.
Definition Compressor.h:29
openshot::AnchorType
AnchorType
This enumeration determines what parent a clip should be aligned to.
Definition Enums.h:45
openshot::ANCHOR_CANVAS
@ ANCHOR_CANVAS
Anchor the clip to the canvas.
Definition Enums.h:46
openshot::ChunkVersion
ChunkVersion
This enumeration allows the user to choose which version of the chunk they would like (low,...
Definition ChunkReader.h:50
openshot::GravityType
GravityType
This enumeration determines how clips are aligned to their parent container.
Definition Enums.h:22
openshot::GRAVITY_TOP_LEFT
@ GRAVITY_TOP_LEFT
Align clip to the top left of its parent.
Definition Enums.h:23
openshot::GRAVITY_LEFT
@ GRAVITY_LEFT
Align clip to the left of its parent (middle aligned)
Definition Enums.h:26
openshot::GRAVITY_TOP_RIGHT
@ GRAVITY_TOP_RIGHT
Align clip to the top right of its parent.
Definition Enums.h:25
openshot::GRAVITY_RIGHT
@ GRAVITY_RIGHT
Align clip to the right of its parent (middle aligned)
Definition Enums.h:28
openshot::GRAVITY_BOTTOM_LEFT
@ GRAVITY_BOTTOM_LEFT
Align clip to the bottom left of its parent.
Definition Enums.h:29
openshot::GRAVITY_BOTTOM
@ GRAVITY_BOTTOM
Align clip to the bottom center of its parent.
Definition Enums.h:30
openshot::GRAVITY_TOP
@ GRAVITY_TOP
Align clip to the top center of its parent.
Definition Enums.h:24
openshot::GRAVITY_BOTTOM_RIGHT
@ GRAVITY_BOTTOM_RIGHT
Align clip to the bottom right of its parent.
Definition Enums.h:31
openshot::GRAVITY_CENTER
@ GRAVITY_CENTER
Align clip to the center of its parent (middle aligned)
Definition Enums.h:27
openshot::ScaleType
ScaleType
This enumeration determines how clips are scaled to fit their parent container.
Definition Enums.h:36
openshot::SCALE_FIT
@ SCALE_FIT
Scale the clip until either height or width fills the canvas (with no cropping)
Definition Enums.h:38
openshot::SCALE_STRETCH
@ SCALE_STRETCH
Scale the clip until both height and width fill the canvas (distort to fit)
Definition Enums.h:39
openshot::SCALE_CROP
@ SCALE_CROP
Scale the clip until both height and width fill the canvas (cropping the overlap)
Definition Enums.h:37
openshot::SCALE_NONE
@ SCALE_NONE
Do not scale the clip.
Definition Enums.h:40
openshot::VolumeMixType
VolumeMixType
This enumeration determines the strategy when mixing audio with other clips.
Definition Enums.h:61
openshot::VOLUME_MIX_AVERAGE
@ VOLUME_MIX_AVERAGE
Evenly divide the overlapping clips volume keyframes, so that the sum does not exceed 100%.
Definition Enums.h:63
openshot::VOLUME_MIX_NONE
@ VOLUME_MIX_NONE
Do not apply any volume mixing adjustments. Just add the samples together.
Definition Enums.h:62
openshot::VOLUME_MIX_REDUCE
@ VOLUME_MIX_REDUCE
Reduce volume by about %25, and then mix (louder, but could cause pops if the sum exceeds 100%)
Definition Enums.h:64
openshot::FrameDisplayType
FrameDisplayType
This enumeration determines the display format of the clip's frame number (if any)....
Definition Enums.h:52
openshot::FRAME_DISPLAY_CLIP
@ FRAME_DISPLAY_CLIP
Display the clip's internal frame number.
Definition Enums.h:54
openshot::FRAME_DISPLAY_TIMELINE
@ FRAME_DISPLAY_TIMELINE
Display the timeline's frame number.
Definition Enums.h:55
openshot::FRAME_DISPLAY_BOTH
@ FRAME_DISPLAY_BOTH
Display both the clip's and timeline's frame number.
Definition Enums.h:56
openshot::FRAME_DISPLAY_NONE
@ FRAME_DISPLAY_NONE
Do not display the frame number.
Definition Enums.h:53
openshot::stringToJson
const Json::Value stringToJson(const std::string value)
Definition Json.cpp:16
openshot::AudioLocation
This struct holds the associated video frame and starting sample # for an audio packet.
Definition AudioLocation.h:25
openshot::AudioLocation::frame
int64_t frame
Definition AudioLocation.h:26
openshot::AudioLocation::sample_start
int sample_start
Definition AudioLocation.h:27
openshot::CompareClipEffects
Definition Clip.h:48
openshot::EffectInfoStruct::has_tracked_object
bool has_tracked_object
Determines if this effect track objects through the clip.
Definition EffectBase.h:42
openshot::ReaderInfo::duration
float duration
Length of time (in seconds)
Definition ReaderBase.h:43
openshot::ReaderInfo::width
int width
The width of the video (in pixesl)
Definition ReaderBase.h:46
openshot::ReaderInfo::channels
int channels
The number of audio channels used in the audio stream.
Definition ReaderBase.h:61
openshot::ReaderInfo::fps
openshot::Fraction fps
Frames per second, as a fraction (i.e. 24/1 = 24 fps)
Definition ReaderBase.h:48
openshot::ReaderInfo::height
int height
The height of the video (in pixels)
Definition ReaderBase.h:45
openshot::ReaderInfo::video_length
int64_t video_length
The number of frames in the video stream.
Definition ReaderBase.h:53
openshot::ReaderInfo::metadata
std::map< std::string, std::string > metadata
An optional map/dictionary of metadata for this reader.
Definition ReaderBase.h:65
openshot::ReaderInfo::channel_layout
openshot::ChannelLayout channel_layout
The channel layout (mono, stereo, 5 point surround, etc...)
Definition ReaderBase.h:62
openshot::ReaderInfo::sample_rate
int sample_rate
The number of audio samples per second (44100 is a common sample rate)
Definition ReaderBase.h:60
openshot::TimelineInfoStruct
This struct contains info about the current Timeline clip instance.
Definition TimelineBase.h:33
openshot::TimelineInfoStruct::is_top_clip
bool is_top_clip
Is clip on top (if overlapping another clip)
Definition TimelineBase.h:34