Merge branch 'clip-refactor-keyframes' into opencv

This commit is contained in:
Brenno
2020-10-19 22:29:48 -03:00
195 changed files with 2323 additions and 1542 deletions

View File

@@ -28,7 +28,22 @@
* along with OpenShot Library. If not, see <http://www.gnu.org/licenses/>.
*/
#include "../include/Frame.h"
#include "Frame.h"
#include "JuceHeader.h"
#include <QApplication>
#include <QImage>
#include <QPixmap>
#include <QBitmap>
#include <QColor>
#include <QString>
#include <QVector>
#include <QPainter>
#include <QHBoxLayout>
#include <QWidget>
#include <QLabel>
#include <QPointF>
#include <QWidget>
#include <thread> // for std::this_thread::sleep_for
#include <chrono> // for std::chrono::milliseconds
@@ -36,57 +51,31 @@
using namespace std;
using namespace openshot;
// Constructor - blank frame (300x200 blank image, 48kHz audio silence)
Frame::Frame() : number(1), pixel_ratio(1,1), channels(2), width(1), height(1), color("#000000"),
channel_layout(LAYOUT_STEREO), sample_rate(44100), qbuffer(NULL), has_audio_data(false), has_image_data(false),
max_audio_sample(0)
{
// Init the image magic and audio buffer
audio = std::shared_ptr<juce::AudioSampleBuffer>(new juce::AudioSampleBuffer(channels, 0));
// initialize the audio samples to zero (silence)
audio->clear();
}
// Constructor - image only (48kHz audio silence)
Frame::Frame(int64_t number, int width, int height, std::string color)
: number(number), pixel_ratio(1,1), channels(2), width(width), height(height), color(color),
channel_layout(LAYOUT_STEREO), sample_rate(44100), qbuffer(NULL), has_audio_data(false), has_image_data(false),
max_audio_sample(0)
{
// Init the image magic and audio buffer
audio = std::shared_ptr<juce::AudioSampleBuffer>(new juce::AudioSampleBuffer(channels, 0));
// initialize the audio samples to zero (silence)
audio->clear();
}
// Constructor - audio only (300x200 blank image)
Frame::Frame(int64_t number, int samples, int channels) :
number(number), pixel_ratio(1,1), channels(channels), width(1), height(1), color("#000000"),
channel_layout(LAYOUT_STEREO), sample_rate(44100), qbuffer(NULL), has_audio_data(false), has_image_data(false),
max_audio_sample(0)
{
// Init the image magic and audio buffer
audio = std::shared_ptr<juce::AudioSampleBuffer>(new juce::AudioSampleBuffer(channels, samples));
// initialize the audio samples to zero (silence)
audio->clear();
}
// Constructor - image & audio
Frame::Frame(int64_t number, int width, int height, std::string color, int samples, int channels)
: number(number), pixel_ratio(1,1), channels(channels), width(width), height(height), color(color),
channel_layout(LAYOUT_STEREO), sample_rate(44100), qbuffer(NULL), has_audio_data(false), has_image_data(false),
: audio(std::make_shared<juce::AudioSampleBuffer>(channels, samples)),
number(number), width(width), height(height),
pixel_ratio(1,1), color(color), qbuffer(NULL),
channels(channels), channel_layout(LAYOUT_STEREO),
sample_rate(44100),
has_audio_data(false), has_image_data(false),
max_audio_sample(0)
{
// Init the image magic and audio buffer
audio = std::shared_ptr<juce::AudioSampleBuffer>(new juce::AudioSampleBuffer(channels, samples));
// initialize the audio samples to zero (silence)
// zero (fill with silence) the audio buffer
audio->clear();
}
// Delegating Constructor - blank frame
Frame::Frame() : Frame::Frame(1, 1, 1, "#000000", 0, 2) {};
// Delegating Constructor - image only
Frame::Frame(int64_t number, int width, int height, std::string color)
: Frame::Frame(number, width, height, color, 0, 2) {};
// Delegating Constructor - audio only
Frame::Frame(int64_t number, int samples, int channels)
: Frame::Frame(number, 1, 1, "#000000", samples, channels) {};
// Copy constructor
Frame::Frame ( const Frame &other )
@@ -120,11 +109,11 @@ void Frame::DeepCopy(const Frame& other)
max_audio_sample = other.max_audio_sample;
if (other.image)
image = std::shared_ptr<QImage>(new QImage(*(other.image)));
image = std::make_shared<QImage>(*(other.image));
if (other.audio)
audio = std::shared_ptr<juce::AudioSampleBuffer>(new juce::AudioSampleBuffer(*(other.audio)));
audio = std::make_shared<juce::AudioSampleBuffer>(*(other.audio));
if (other.wave_image)
wave_image = std::shared_ptr<QImage>(new QImage(*(other.wave_image)));
wave_image = std::make_shared<QImage>(*(other.wave_image));
}
// Destructor
@@ -144,7 +133,7 @@ void Frame::Display()
// Only create the QApplication once
static int argc = 1;
static char* argv[1] = {NULL};
previewApp = std::shared_ptr<QApplication>(new QApplication(argc, argv));
previewApp = std::make_shared<QApplication>(argc, argv);
}
// Get preview image
@@ -158,7 +147,8 @@ void Frame::Display()
int new_height = previewImage->size().height() * pixel_ratio.Reciprocal().ToDouble();
// Resize to fix DAR
previewImage = std::shared_ptr<QImage>(new QImage(previewImage->scaled(new_width, new_height, Qt::IgnoreAspectRatio, Qt::SmoothTransformation)));
previewImage = std::make_shared<QImage>(previewImage->scaled(
new_width, new_height, Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
}
// Create window
@@ -234,7 +224,8 @@ std::shared_ptr<QImage> Frame::GetWaveform(int width, int height, int Red, int G
}
// Create blank image
wave_image = std::shared_ptr<QImage>(new QImage(total_width, total_height, QImage::Format_RGBA8888));
wave_image = std::make_shared<QImage>(
total_width, total_height, QImage::Format_RGBA8888_Premultiplied);
wave_image->fill(QColor(0,0,0,0));
// Load QPainter with wave_image device
@@ -259,13 +250,13 @@ std::shared_ptr<QImage> Frame::GetWaveform(int width, int height, int Red, int G
// Resize Image (if requested)
if (width != total_width || height != total_height) {
QImage scaled_wave_image = wave_image->scaled(width, height, Qt::IgnoreAspectRatio, Qt::FastTransformation);
wave_image = std::shared_ptr<QImage>(new QImage(scaled_wave_image));
wave_image = std::make_shared<QImage>(scaled_wave_image);
}
}
else
{
// No audio samples present
wave_image = std::shared_ptr<QImage>(new QImage(width, height, QImage::Format_RGBA8888));
wave_image = std::make_shared<QImage>(width, height, QImage::Format_RGBA8888_Premultiplied);
wave_image->fill(QColor(QString::fromStdString("#000000")));
}
@@ -300,7 +291,7 @@ void Frame::DisplayWaveform()
// Only create the QApplication once
static int argc = 1;
static char* argv[1] = {NULL};
previewApp = std::shared_ptr<QApplication>(new QApplication(argc, argv));
previewApp = std::make_shared<QApplication>(argc, argv);
}
// Create window
@@ -605,11 +596,15 @@ void Frame::Save(std::string path, float scale, std::string format, int quality)
int new_height = previewImage->size().height() * pixel_ratio.Reciprocal().ToDouble();
// Resize to fix DAR
previewImage = std::shared_ptr<QImage>(new QImage(previewImage->scaled(new_width, new_height, Qt::IgnoreAspectRatio, Qt::SmoothTransformation)));
previewImage = std::make_shared<QImage>(previewImage->scaled(
new_width, new_height,
Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
}
// Resize image
previewImage = std::shared_ptr<QImage>(new QImage(previewImage->scaled(new_width * scale, new_height * scale, Qt::KeepAspectRatio, Qt::SmoothTransformation)));
previewImage = std::make_shared<QImage>(previewImage->scaled(
new_width * scale, new_height * scale,
Qt::KeepAspectRatio, Qt::SmoothTransformation));
}
// Save image
@@ -621,7 +616,8 @@ void Frame::Thumbnail(std::string path, int new_width, int new_height, std::stri
std::string background_color, bool ignore_aspect, std::string format, int quality, float rotate) {
// Create blank thumbnail image & fill background color
std::shared_ptr<QImage> thumbnail = std::shared_ptr<QImage>(new QImage(new_width, new_height, QImage::Format_RGBA8888));
auto thumbnail = std::make_shared<QImage>(
new_width, new_height, QImage::Format_RGBA8888_Premultiplied);
thumbnail->fill(QColor(QString::fromStdString(background_color)));
// Create painter
@@ -639,16 +635,22 @@ void Frame::Thumbnail(std::string path, int new_width, int new_height, std::stri
int aspect_height = previewImage->size().height() * pixel_ratio.Reciprocal().ToDouble();
// Resize to fix DAR
previewImage = std::shared_ptr<QImage>(new QImage(previewImage->scaled(aspect_width, aspect_height, Qt::IgnoreAspectRatio, Qt::SmoothTransformation)));
previewImage = std::make_shared<QImage>(previewImage->scaled(
aspect_width, aspect_height,
Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
}
// Resize frame image
if (ignore_aspect)
// Ignore aspect ratio
previewImage = std::shared_ptr<QImage>(new QImage(previewImage->scaled(new_width, new_height, Qt::IgnoreAspectRatio, Qt::SmoothTransformation)));
previewImage = std::make_shared<QImage>(previewImage->scaled(
new_width, new_height,
Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
else
// Maintain aspect ratio
previewImage = std::shared_ptr<QImage>(new QImage(previewImage->scaled(new_width, new_height, Qt::KeepAspectRatio, Qt::SmoothTransformation)));
previewImage = std::make_shared<QImage>(previewImage->scaled(
new_width, new_height,
Qt::KeepAspectRatio, Qt::SmoothTransformation));
// Composite frame image onto background (centered)
int x = (new_width - previewImage->size().width()) / 2.0; // center
@@ -672,14 +674,16 @@ void Frame::Thumbnail(std::string path, int new_width, int new_height, std::stri
// Overlay Image (if any)
if (overlay_path != "") {
// Open overlay
std::shared_ptr<QImage> overlay = std::shared_ptr<QImage>(new QImage());
auto overlay = std::make_shared<QImage>();
overlay->load(QString::fromStdString(overlay_path));
// Set pixel format
overlay = std::shared_ptr<QImage>(new QImage(overlay->convertToFormat(QImage::Format_RGBA8888)));
overlay = std::make_shared<QImage>(
overlay->convertToFormat(QImage::Format_RGBA8888_Premultiplied));
// Resize to fit
overlay = std::shared_ptr<QImage>(new QImage(overlay->scaled(new_width, new_height, Qt::IgnoreAspectRatio, Qt::SmoothTransformation)));
overlay = std::make_shared<QImage>(overlay->scaled(
new_width, new_height, Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
// Composite onto thumbnail
painter.setCompositionMode(QPainter::CompositionMode_SourceOver);
@@ -690,14 +694,16 @@ void Frame::Thumbnail(std::string path, int new_width, int new_height, std::stri
// Mask Image (if any)
if (mask_path != "") {
// Open mask
std::shared_ptr<QImage> mask = std::shared_ptr<QImage>(new QImage());
auto mask = std::make_shared<QImage>();
mask->load(QString::fromStdString(mask_path));
// Set pixel format
mask = std::shared_ptr<QImage>(new QImage(mask->convertToFormat(QImage::Format_RGBA8888)));
mask = std::make_shared<QImage>(
mask->convertToFormat(QImage::Format_RGBA8888_Premultiplied));
// Resize to fit
mask = std::shared_ptr<QImage>(new QImage(mask->scaled(new_width, new_height, Qt::IgnoreAspectRatio, Qt::SmoothTransformation)));
mask = std::make_shared<QImage>(mask->scaled(
new_width, new_height, Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
// Negate mask
mask->invertPixels();
@@ -750,7 +756,7 @@ void Frame::AddColor(int new_width, int new_height, std::string new_color)
const GenericScopedLock<juce::CriticalSection> lock(addingImageSection);
#pragma omp critical (AddImage)
{
image = std::shared_ptr<QImage>(new QImage(new_width, new_height, QImage::Format_RGBA8888));
image = std::make_shared<QImage>(new_width, new_height, QImage::Format_RGBA8888_Premultiplied);
// Fill with solid color
image->fill(QColor(QString::fromStdString(color)));
@@ -762,30 +768,31 @@ void Frame::AddColor(int new_width, int new_height, std::string new_color)
}
// Add (or replace) pixel data to the frame
void Frame::AddImage(int new_width, int new_height, int bytes_per_pixel, QImage::Format type, const unsigned char *pixels_)
void Frame::AddImage(
int new_width, int new_height, int bytes_per_pixel,
QImage::Format type, const unsigned char *pixels_)
{
// Create new buffer
const GenericScopedLock<juce::CriticalSection> lock(addingImageSection);
int buffer_size = new_width * new_height * bytes_per_pixel;
qbuffer = new unsigned char[buffer_size]();
// Copy buffer data
memcpy((unsigned char*)qbuffer, pixels_, buffer_size);
// Create new image object, and fill with pixel data
#pragma omp critical (AddImage)
{
image = std::shared_ptr<QImage>(new QImage(qbuffer, new_width, new_height, new_width * bytes_per_pixel, type, (QImageCleanupFunction) &openshot::Frame::cleanUpBuffer, (void*) qbuffer));
const GenericScopedLock<juce::CriticalSection> lock(addingImageSection);
int buffer_size = new_width * new_height * bytes_per_pixel;
qbuffer = new unsigned char[buffer_size]();
// Always convert to RGBA8888 (if different)
if (image->format() != QImage::Format_RGBA8888)
*image = image->convertToFormat(QImage::Format_RGBA8888);
// Copy buffer data
memcpy((unsigned char*)qbuffer, pixels_, buffer_size);
// Update height and width
width = image->width();
height = image->height();
has_image_data = true;
}
} // Release addingImageSection lock
// Create new image object from pixel data
auto new_image = std::make_shared<QImage>(
qbuffer,
new_width, new_height,
new_width * bytes_per_pixel,
type,
(QImageCleanupFunction) &openshot::Frame::cleanUpBuffer,
(void*) qbuffer
);
AddImage(new_image);
}
// Add (or replace) pixel data to the frame
@@ -801,9 +808,9 @@ void Frame::AddImage(std::shared_ptr<QImage> new_image)
{
image = new_image;
// Always convert to RGBA8888 (if different)
if (image->format() != QImage::Format_RGBA8888)
*image = image->convertToFormat(QImage::Format_RGBA8888);
// Always convert to Format_RGBA8888_Premultiplied (if different)
if (image->format() != QImage::Format_RGBA8888_Premultiplied)
*image = image->convertToFormat(QImage::Format_RGBA8888_Premultiplied);
// Update height and width
width = image->width();
@@ -825,7 +832,6 @@ void Frame::AddImage(std::shared_ptr<QImage> new_image, bool only_odd_lines)
AddImage(new_image);
} else {
// Ignore image of different sizes or formats
bool ret=false;
#pragma omp critical (AddImage)
@@ -833,8 +839,9 @@ void Frame::AddImage(std::shared_ptr<QImage> new_image, bool only_odd_lines)
if (image == new_image || image->size() != new_image->size()) {
ret = true;
}
else if (new_image->format() != image->format()) {
new_image = std::shared_ptr<QImage>(new QImage(new_image->convertToFormat(image->format())));
else if (new_image->format() != QImage::Format_RGBA8888_Premultiplied) {
new_image = std::make_shared<QImage>(
new_image->convertToFormat(QImage::Format_RGBA8888_Premultiplied));
}
}
if (ret) {
@@ -992,7 +999,8 @@ std::shared_ptr<Magick::Image> Frame::GetMagickImage()
const QRgb *tmpBits = (const QRgb*)image->constBits();
// Create new image object, and fill with pixel data
std::shared_ptr<Magick::Image> magick_image = std::shared_ptr<Magick::Image>(new Magick::Image(image->width(), image->height(),"RGBA", Magick::CharPixel, tmpBits));
auto magick_image = std::make_shared<Magick::Image>(
image->width(), image->height(),"RGBA", Magick::CharPixel, tmpBits);
// Give image a transparent background color
magick_image->backgroundColor(Magick::Color("none"));
@@ -1021,7 +1029,9 @@ void Frame::AddMagickImage(std::shared_ptr<Magick::Image> new_image)
MagickCore::ExportImagePixels(new_image->constImage(), 0, 0, new_image->columns(), new_image->rows(), "RGBA", Magick::CharPixel, buffer, &exception);
// Create QImage of frame data
image = std::shared_ptr<QImage>(new QImage(qbuffer, width, height, width * BPP, QImage::Format_RGBA8888, (QImageCleanupFunction) &cleanUpBuffer, (void*) qbuffer));
image = std::make_shared<QImage>(
qbuffer, width, height, width * BPP, QImage::Format_RGBA8888_Premultiplied,
(QImageCleanupFunction) &cleanUpBuffer, (void*) qbuffer);
// Update height and width
width = image->width();