Merge branch 'develop' into hardware-support

This commit is contained in:
eisneinechse
2019-03-07 10:46:54 -08:00
7 changed files with 166 additions and 171 deletions

View File

@@ -127,7 +127,7 @@ namespace openshot {
std::shared_ptr<Frame> GetOrCreateFrame(int64_t number);
/// Adjust the audio and image of a time mapped frame
std::shared_ptr<Frame> get_time_mapped_frame(std::shared_ptr<Frame> frame, int64_t frame_number);
void get_time_mapped_frame(std::shared_ptr<Frame> frame, int64_t frame_number);
/// Init default settings for a clip
void init_settings();

View File

@@ -52,11 +52,6 @@ namespace openshot {
* \endcode
*/
class Coordinate {
private:
bool increasing; ///< Is the Y value increasing or decreasing?
Fraction repeated; ///< Fraction of repeated Y values (for example, 1/3 would be the first Y value of 3 repeated values)
double delta; ///< This difference in Y value (from the previous unique Y value)
public:
double X; ///< The X value of the coordinate (usually representing the frame #)
double Y; ///< The Y value of the coordinate (usually representing the value of the property being animated)
@@ -69,27 +64,6 @@ namespace openshot {
/// @param y The Y coordinate (usually representing the value of the property being animated)
Coordinate(double x, double y);
/// @brief Set the repeating Fraction (used internally on the timeline, to track changes to coordinates)
/// @param is_repeated The fraction representing how many times this coordinate Y value repeats (only used on the timeline)
void Repeat(Fraction is_repeated) { repeated=is_repeated; }
/// Get the repeating Fraction (used internally on the timeline, to track changes to coordinates)
Fraction Repeat() { return repeated; }
/// @brief Set the increasing flag (used internally on the timeline, to track changes to coordinates)
/// @param is_increasing Indicates if this coordinate Y value is increasing (when compared to the previous coordinate)
void IsIncreasing(bool is_increasing) { increasing = is_increasing; }
/// Get the increasing flag (used internally on the timeline, to track changes to coordinates)
bool IsIncreasing() { return increasing; }
/// @brief Set the delta / difference between previous coordinate value (used internally on the timeline, to track changes to coordinates)
/// @param new_delta Indicates how much this Y value differs from the previous Y value
void Delta(double new_delta) { delta=new_delta; }
/// Get the delta / difference between previous coordinate value (used internally on the timeline, to track changes to coordinates)
float Delta() { return delta; }
/// Get and Set JSON methods
string Json(); ///< Generate JSON string of this object
Json::Value JsonValue(); ///< Generate Json::JsonValue for this object

View File

@@ -340,13 +340,13 @@ std::shared_ptr<Frame> Clip::GetFrame(int64_t requested_frame)
frame->AddAudio(true, channel, 0, original_frame->GetAudioSamples(channel), original_frame->GetAudioSamplesCount(), 1.0);
// Get time mapped frame number (used to increase speed, change direction, etc...)
std::shared_ptr<Frame> new_frame = get_time_mapped_frame(frame, requested_frame);
get_time_mapped_frame(frame, requested_frame);
// Apply effects to the frame (if any)
apply_effects(new_frame);
apply_effects(frame);
// Return processed 'frame'
return new_frame;
return frame;
}
else
// Throw error if reader not initialized
@@ -389,7 +389,7 @@ void Clip::reverse_buffer(juce::AudioSampleBuffer* buffer)
}
// Adjust the audio and image of a time mapped frame
std::shared_ptr<Frame> Clip::get_time_mapped_frame(std::shared_ptr<Frame> frame, int64_t frame_number)
void Clip::get_time_mapped_frame(std::shared_ptr<Frame> frame, int64_t frame_number)
{
// Check for valid reader
if (!reader)
@@ -400,7 +400,6 @@ std::shared_ptr<Frame> Clip::get_time_mapped_frame(std::shared_ptr<Frame> frame,
if (time.Values.size() > 1)
{
const GenericScopedLock<CriticalSection> lock(getFrameCriticalSection);
std::shared_ptr<Frame> new_frame;
// create buffer and resampler
juce::AudioSampleBuffer *samples = NULL;
@@ -408,14 +407,7 @@ std::shared_ptr<Frame> Clip::get_time_mapped_frame(std::shared_ptr<Frame> frame,
resampler = new AudioResampler();
// Get new frame number
int new_frame_number = adjust_frame_number_minimum(round(time.GetValue(frame_number)));
// Create a new frame
int samples_in_frame = Frame::GetSamplesPerFrame(new_frame_number, reader->info.fps, reader->info.sample_rate, frame->GetAudioChannelsCount());
new_frame = std::make_shared<Frame>(new_frame_number, 1, 1, "#000000", samples_in_frame, frame->GetAudioChannelsCount());
// Copy the image from the new frame
new_frame->AddImage(std::shared_ptr<QImage>(new QImage(*GetOrCreateFrame(new_frame_number)->GetImage())));
int new_frame_number = frame->number;
// Get delta (difference in previous Y value)
int delta = int(round(time.GetDelta(frame_number)));
@@ -463,7 +455,7 @@ std::shared_ptr<Frame> Clip::get_time_mapped_frame(std::shared_ptr<Frame> frame,
start -= 1;
for (int channel = 0; channel < channels; channel++)
// Add new (slower) samples, to the frame object
new_frame->AddAudio(true, channel, 0, resampled_buffer->getReadPointer(channel, start),
frame->AddAudio(true, channel, 0, resampled_buffer->getReadPointer(channel, start),
number_of_samples, 1.0f);
// Clean up
@@ -571,7 +563,7 @@ std::shared_ptr<Frame> Clip::get_time_mapped_frame(std::shared_ptr<Frame> frame,
// Add the newly resized audio samples to the current frame
for (int channel = 0; channel < channels; channel++)
// Add new (slower) samples, to the frame object
new_frame->AddAudio(true, channel, 0, buffer->getReadPointer(channel), number_of_samples, 1.0f);
frame->AddAudio(true, channel, 0, buffer->getReadPointer(channel), number_of_samples, 1.0f);
// Clean up
buffer = NULL;
@@ -592,7 +584,7 @@ std::shared_ptr<Frame> Clip::get_time_mapped_frame(std::shared_ptr<Frame> frame,
// Add reversed samples to the frame object
for (int channel = 0; channel < channels; channel++)
new_frame->AddAudio(true, channel, 0, samples->getReadPointer(channel), number_of_samples, 1.0f);
frame->AddAudio(true, channel, 0, samples->getReadPointer(channel), number_of_samples, 1.0f);
}
@@ -600,13 +592,7 @@ std::shared_ptr<Frame> Clip::get_time_mapped_frame(std::shared_ptr<Frame> frame,
delete samples;
samples = NULL;
}
// Return new time mapped frame
return new_frame;
} else
// Use original frame
return frame;
}
}
// Adjust frame number minimum value

View File

@@ -32,12 +32,12 @@ using namespace openshot;
// Default constructor for a coordinate, which defaults the X and Y to zero (0,0)
Coordinate::Coordinate() :
X(0), Y(0), increasing(true), repeated(1,1), delta(0.0) {
X(0), Y(0) {
}
// Constructor which also allows the user to set the X and Y
Coordinate::Coordinate(double x, double y) :
X(x), Y(y), increasing(true), repeated(1,1), delta(0.0) {
X(x), Y(y) {
}
@@ -96,15 +96,4 @@ void Coordinate::SetJsonValue(Json::Value root) {
X = root["X"].asDouble();
if (!root["Y"].isNull())
Y = root["Y"].asDouble();
if (!root["increasing"].isNull())
increasing = root["increasing"].asBool();
if (!root["repeated"].isNull() && root["repeated"].isObject())
{
if (!root["repeated"]["num"].isNull())
repeated.num = root["repeated"]["num"].asInt();
if (!root["repeated"]["den"].isNull())
repeated.den = root["repeated"]["den"].asInt();
}
if (!root["delta"].isNull())
delta = root["delta"].asDouble();
}

View File

@@ -54,9 +54,6 @@ FrameMapper::FrameMapper(ReaderBase *reader, Fraction target, PulldownType targe
// Adjust cache size based on size of frame and audio
final_cache.SetMaxBytesFromInfo(OPEN_MP_NUM_PROCESSORS * 2, info.width, info.height, info.sample_rate, info.channels);
// init mapping between original and target frames
Init();
}
// Destructor
@@ -205,22 +202,23 @@ void FrameMapper::Init()
}
} else {
// Map the remaining framerates using a simple Keyframe curve
// Calculate the difference (to be used as a multiplier)
// Map the remaining framerates using a linear algorithm
double rate_diff = target.ToDouble() / original.ToDouble();
int64_t new_length = reader->info.video_length * rate_diff;
// Build curve for framerate mapping
Keyframe rate_curve;
rate_curve.AddPoint(1, 1, LINEAR);
rate_curve.AddPoint(new_length, reader->info.video_length, LINEAR);
// Calculate the value difference
double value_increment = (reader->info.video_length + 1) / (double) (new_length);
// Loop through curve, and build list of frames
double original_frame_num = 1.0f;
for (int64_t frame_num = 1; frame_num <= new_length; frame_num++)
{
// Add 2 fields per frame
AddField(rate_curve.GetInt(frame_num));
AddField(rate_curve.GetInt(frame_num));
AddField(round(original_frame_num));
AddField(round(original_frame_num));
// Increment original frame number
original_frame_num += value_increment;
}
}
@@ -310,6 +308,11 @@ void FrameMapper::Init()
MappedFrame FrameMapper::GetMappedFrame(int64_t TargetFrameNumber)
{
// Check if mappings are dirty (and need to be recalculated)
if (is_dirty)
// Recalculate mappings
Init();
// Ignore mapping on single image readers
if (info.has_video and !info.has_audio and info.has_single_image) {
// Return the same number
@@ -743,14 +746,16 @@ void FrameMapper::ChangeMapping(Fraction target_fps, PulldownType target_pulldow
SWR_FREE(&avr);
avr = NULL;
}
// Re-init mapping
Init();
}
// Resample audio and map channels (if needed)
void FrameMapper::ResampleMappedAudio(std::shared_ptr<Frame> frame, int64_t original_frame_number)
{
// Check if mappings are dirty (and need to be recalculated)
if (is_dirty)
// Recalculate mappings
Init();
// Init audio buffers / variables
int total_frame_samples = 0;
int channels_in_frame = frame->GetAudioChannelsCount();

View File

@@ -296,17 +296,48 @@ bool Keyframe::IsIncreasing(int index)
Process();
// Is index a valid point?
if (index >= 0 && index < Values.size())
// Return value
return long(round(Values[index].IsIncreasing()));
else if (index < 0 && Values.size() > 0)
// Return the minimum value
return long(round(Values[0].IsIncreasing()));
else if (index >= Values.size() && Values.size() > 0)
// return the maximum value
return long(round(Values[Values.size() - 1].IsIncreasing()));
if (index >= 1 && (index + 1) < Values.size()) {
int64_t current_value = GetLong(index);
int64_t previous_value = 0;
int64_t next_value = 0;
int64_t previous_repeats = 0;
int64_t next_repeats = 0;
// Loop backwards and look for the next unique value
for (vector<Coordinate>::iterator backwards_it = Values.begin() + index; backwards_it != Values.begin(); backwards_it--) {
previous_value = long(round((*backwards_it).Y));
if (previous_value == current_value) {
// Found same value
previous_repeats++;
} else {
// Found non repeating value, no more repeats found
break;
}
}
// Loop forwards and look for the next unique value
for (vector<Coordinate>::iterator forwards_it = Values.begin() + (index + 1); forwards_it != Values.end(); forwards_it++) {
next_value = long(round((*forwards_it).Y));
if (next_value == current_value) {
// Found same value
next_repeats++;
} else {
// Found non repeating value, no more repeats found
break;
}
}
if (current_value < next_value) {
// Increasing
return true;
}
else if (current_value >= next_value) {
// Decreasing
return false;
}
}
else
// return the default direction of most curves (i.e. increasing is true)
// return default true (since most curves increase)
return true;
}
@@ -385,6 +416,7 @@ void Keyframe::SetJsonValue(Json::Value root) {
}
// Get the fraction that represents how many times this value is repeated in the curve
// This is depreciated and will be removed soon.
Fraction Keyframe::GetRepeatFraction(int64_t index)
{
// Check if it needs to be processed
@@ -392,17 +424,42 @@ Fraction Keyframe::GetRepeatFraction(int64_t index)
Process();
// Is index a valid point?
if (index >= 0 && index < Values.size())
// Return value
return Values[index].Repeat();
else if (index < 0 && Values.size() > 0)
// Return the minimum value
return Values[0].Repeat();
else if (index >= Values.size() && Values.size() > 0)
// return the maximum value
return Values[Values.size() - 1].Repeat();
if (index >= 1 && (index + 1) < Values.size()) {
int64_t current_value = GetLong(index);
int64_t previous_value = 0;
int64_t next_value = 0;
int64_t previous_repeats = 0;
int64_t next_repeats = 0;
// Loop backwards and look for the next unique value
for (vector<Coordinate>::iterator backwards_it = Values.begin() + index; backwards_it != Values.begin(); backwards_it--) {
previous_value = long(round((*backwards_it).Y));
if (previous_value == current_value) {
// Found same value
previous_repeats++;
} else {
// Found non repeating value, no more repeats found
break;
}
}
// Loop forwards and look for the next unique value
for (vector<Coordinate>::iterator forwards_it = Values.begin() + (index + 1); forwards_it != Values.end(); forwards_it++) {
next_value = long(round((*forwards_it).Y));
if (next_value == current_value) {
// Found same value
next_repeats++;
} else {
// Found non repeating value, no more repeats found
break;
}
}
int64_t total_repeats = previous_repeats + next_repeats;
return Fraction(previous_repeats, total_repeats);
}
else
// return a blank coordinate (0,0)
// return a blank coordinate
return Fraction(1,1);
}
@@ -414,17 +471,48 @@ double Keyframe::GetDelta(int64_t index)
Process();
// Is index a valid point?
if (index >= 0 && index < Values.size())
// Return value
return Values[index].Delta();
else if (index < 0 && Values.size() > 0)
// Return the minimum value
return Values[0].Delta();
else if (index >= Values.size() && Values.size() > 0)
// return the maximum value
return Values[Values.size() - 1].Delta();
if (index >= 1 && (index + 1) < Values.size()) {
int64_t current_value = GetLong(index);
int64_t previous_value = 0;
int64_t next_value = 0;
int64_t previous_repeats = 0;
int64_t next_repeats = 0;
// Loop backwards and look for the next unique value
for (vector<Coordinate>::iterator backwards_it = Values.begin() + index; backwards_it != Values.begin(); backwards_it--) {
previous_value = long(round((*backwards_it).Y));
if (previous_value == current_value) {
// Found same value
previous_repeats++;
} else {
// Found non repeating value, no more repeats found
break;
}
}
// Loop forwards and look for the next unique value
for (vector<Coordinate>::iterator forwards_it = Values.begin() + (index + 1); forwards_it != Values.end(); forwards_it++) {
next_value = long(round((*forwards_it).Y));
if (next_value == current_value) {
// Found same value
next_repeats++;
} else {
// Found non repeating value, no more repeats found
break;
}
}
// Check for matching previous value (special case for 1st element)
if (current_value == previous_value)
previous_value = 0;
if (previous_repeats == 1)
return current_value - previous_value;
else
return 0.0;
}
else
// return a blank coordinate (0,0)
// return a blank coordinate
return 0.0;
}
@@ -529,7 +617,7 @@ void Keyframe::PrintValues() {
for (vector<Coordinate>::iterator it = Values.begin() + 1; it != Values.end(); it++) {
Coordinate c = *it;
cout << long(round(c.X)) << "\t" << c.Y << "\t" << c.IsIncreasing() << "\t" << c.Repeat().num << "\t" << c.Repeat().den << "\t" << c.Delta() << endl;
cout << long(round(c.X)) << "\t" << c.Y << "\t" << IsIncreasing(c.X) << "\t" << GetRepeatFraction(c.X).num << "\t" << GetRepeatFraction(c.X).den << "\t" << GetDelta(c.X) << endl;
}
}
@@ -567,69 +655,6 @@ void Keyframe::Process() {
// process segment p1,p2
ProcessSegment(x, p1, p2);
}
// Loop through each Value, and set the direction of the coordinate. This is used
// when time mapping, to determine what direction the audio waveforms play.
bool increasing = true;
int repeat_count = 1;
int64_t last_value = 0;
for (vector<Coordinate>::iterator it = Values.begin() + 1; it != Values.end(); it++) {
int current_value = long(round((*it).Y));
int64_t next_value = long(round((*it).Y));
int64_t prev_value = long(round((*it).Y));
if (it + 1 != Values.end())
next_value = long(round((*(it + 1)).Y));
if (it - 1 >= Values.begin())
prev_value = long(round((*(it - 1)).Y));
// Loop forward and look for the next unique value (to determine direction)
for (vector<Coordinate>::iterator direction_it = it + 1; direction_it != Values.end(); direction_it++) {
int64_t next = long(round((*direction_it).Y));
// Detect direction
if (current_value < next)
{
increasing = true;
break;
}
else if (current_value > next)
{
increasing = false;
break;
}
}
// Set direction
(*it).IsIncreasing(increasing);
// Detect repeated Y value
if (current_value == last_value)
// repeated, so increment count
repeat_count++;
else
// reset repeat counter
repeat_count = 1;
// Detect how many 'more' times it's repeated
int additional_repeats = 0;
for (vector<Coordinate>::iterator repeat_it = it + 1; repeat_it != Values.end(); repeat_it++) {
int64_t next = long(round((*repeat_it).Y));
if (next == current_value)
// repeated, so increment count
additional_repeats++;
else
break; // stop looping
}
// Set repeat fraction
(*it).Repeat(Fraction(repeat_count, repeat_count + additional_repeats));
// Set delta (i.e. different from previous unique Y value)
(*it).Delta(current_value - last_value);
// track the last value
last_value = current_value;
}
}
// reset flag

View File

@@ -377,4 +377,20 @@ TEST(Keyframe_Remove_Duplicate_Point)
// Spot check values from the curve
CHECK_EQUAL(kf.GetLength(), 1);
CHECK_CLOSE(kf.GetPoint(0).co.Y, 2.0, 0.01);
}
TEST(Keyframe_Large_Number_Values)
{
// Large value
int64_t large_value = 30 * 60 * 90;
// Create a keyframe curve with 2 points
Keyframe kf;
kf.AddPoint(1, 1.0);
kf.AddPoint(large_value, 100.0); // 90 minutes long
// Spot check values from the curve
CHECK_EQUAL(kf.GetLength(), large_value + 1);
CHECK_CLOSE(kf.GetPoint(0).co.Y, 1.0, 0.01);
CHECK_CLOSE(kf.GetPoint(1).co.Y, 100.0, 0.01);
}