Merge branch 'develop' into clip-refactor-keyframes

# Conflicts:
#	src/CacheDisk.cpp
#	src/Clip.cpp
#	src/Frame.cpp
#	src/QtHtmlReader.cpp
#	src/QtImageReader.cpp
#	src/QtTextReader.cpp
#	src/effects/Bars.cpp
#	src/effects/Crop.cpp
This commit is contained in:
Jonathan Thomas
2020-10-16 15:32:43 -05:00
32 changed files with 521 additions and 421 deletions

View File

@@ -29,6 +29,21 @@
*/
#include "../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
@@ -141,7 +130,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
@@ -155,7 +144,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
@@ -231,7 +221,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_Premultiplied));
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
@@ -256,13 +247,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_Premultiplied));
wave_image = std::make_shared<QImage>(width, height, QImage::Format_RGBA8888_Premultiplied);
wave_image->fill(QColor(QString::fromStdString("#000000")));
}
@@ -297,7 +288,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
@@ -602,11 +593,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
@@ -618,7 +613,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_Premultiplied));
auto thumbnail = std::make_shared<QImage>(
new_width, new_height, QImage::Format_RGBA8888_Premultiplied);
thumbnail->fill(QColor(QString::fromStdString(background_color)));
// Create painter
@@ -636,16 +632,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
@@ -669,14 +671,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_Premultiplied)));
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);
@@ -687,14 +691,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_Premultiplied)));
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();
@@ -747,7 +753,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_Premultiplied));
image = std::make_shared<QImage>(new_width, new_height, QImage::Format_RGBA8888_Premultiplied);
// Fill with solid color
image->fill(QColor(QString::fromStdString(color)));
@@ -759,30 +765,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_Premultiplied)
*image = image->convertToFormat(QImage::Format_RGBA8888_Premultiplied);
// 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
@@ -822,7 +829,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)
@@ -831,7 +837,8 @@ void Frame::AddImage(std::shared_ptr<QImage> new_image, bool only_odd_lines)
ret = true;
}
else if (new_image->format() != QImage::Format_RGBA8888_Premultiplied) {
new_image = std::shared_ptr<QImage>(new QImage(new_image->convertToFormat(QImage::Format_RGBA8888_Premultiplied)));
new_image = std::make_shared<QImage>(
new_image->convertToFormat(QImage::Format_RGBA8888_Premultiplied));
}
}
if (ret) {
@@ -941,7 +948,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"));
@@ -970,7 +978,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_Premultiplied, (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();