22 #include <AppConfig.h> 
   23 #include <juce_audio_basics/juce_audio_basics.h> 
   24 #include <juce_audio_devices/juce_audio_devices.h> 
   26 #include <QApplication> 
   34 #include <QHBoxLayout> 
   44 Frame::Frame(int64_t number, 
int width, 
int height, std::string color, 
int samples, 
int channels)
 
   45     : audio(std::make_shared<
juce::AudioBuffer<float>>(channels, samples)),
 
   46       number(number), width(width), height(height),
 
   47       pixel_ratio(1,1), color(color),
 
   50       has_audio_data(false), has_image_data(false),
 
   61 Frame::Frame(int64_t number, 
int width, 
int height, std::string color)
 
   62     : 
Frame::
Frame(number, width, height, color, 0, 2) {}
 
   66     : 
Frame::
Frame(number, 1, 1, 
"#000000", samples, channels) {}
 
   89     channels = other.channels;
 
   91     height = other.height;
 
   92     channel_layout = other.channel_layout;
 
   95     sample_rate = other.sample_rate;
 
   96     pixel_ratio = 
Fraction(other.pixel_ratio.
num, other.pixel_ratio.
den);
 
   98     max_audio_sample = other.max_audio_sample;
 
  101         image = std::make_shared<QImage>(*(other.image));
 
  103         audio = std::make_shared<juce::AudioBuffer<float>>(*(other.
audio));
 
  104     if (other.wave_image)
 
  105         wave_image = std::make_shared<QImage>(*(other.wave_image));
 
  121     if (!QApplication::instance()) {
 
  124         static char* argv[1] = {NULL};
 
  125         previewApp = std::make_shared<QApplication>(argc, argv);
 
  129     std::shared_ptr<QImage> previewImage = 
GetImage();
 
  132     if (pixel_ratio.
num != 1 || pixel_ratio.
den != 1)
 
  135         previewImage = std::make_shared<QImage>(previewImage->scaled(
 
  136                 previewImage->size().width(), previewImage->size().height() * pixel_ratio.
Reciprocal().
ToDouble(),
 
  137                 Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
 
  141     QWidget previewWindow;
 
  142     previewWindow.setStyleSheet(
"background-color: #000000;");
 
  147     previewLabel.setPixmap(QPixmap::fromImage(*previewImage));
 
  148     previewLabel.setMask(QPixmap::fromImage(*previewImage).mask());
 
  149     layout.addWidget(&previewLabel);
 
  152     previewWindow.setLayout(&layout);
 
  153     previewWindow.show();
 
  158 std::shared_ptr<QImage> 
Frame::GetWaveform(
int width, 
int height, 
int Red, 
int Green, 
int Blue, 
int Alpha)
 
  164     QVector<QPointF> lines;
 
  165     QVector<QPointF> labels;
 
  169     if (total_samples > 0)
 
  172         int new_height = 200 * 
audio->getNumChannels();
 
  173         int height_padding = 20 * (
audio->getNumChannels() - 1);
 
  174         int total_height = new_height + height_padding;
 
  176         float zero_height = 1.0; 
 
  180         for (
int channel = 0; channel < 
audio->getNumChannels(); channel++)
 
  185             const float *samples = 
audio->getReadPointer(channel);
 
  190                 float value = samples[sample] * 100.0;
 
  194                 if (value > -zero_height && value < 0.0) {
 
  195                     value = -zero_height;
 
  196                 } 
else if (value > 0.0 && value < zero_height) {
 
  201                 lines.push_back(QPointF(X, Y));
 
  202                 lines.push_back(QPointF(X, Y - value));
 
  206             labels.push_back(QPointF(5.0, Y - 5.0));
 
  209             Y += (200 + height_padding);
 
  214         wave_image = std::make_shared<QImage>(
 
  215             total_width, total_height, QImage::Format_RGBA8888_Premultiplied);
 
  216         wave_image->fill(QColor(0,0,0,0));
 
  219         QPainter painter(wave_image.get());
 
  223         pen.setColor(QColor(Red, Green, Blue, Alpha));
 
  225         pen.setStyle(Qt::SolidLine);
 
  229         painter.drawLines(lines);
 
  235         wave_image = std::make_shared<QImage>(width, height, QImage::Format_RGBA8888_Premultiplied);
 
  236         wave_image->fill(QColor(QString::fromStdString(
"#000000")));
 
  240     if (wave_image->width() != width || wave_image->height() != height) {
 
  241         QImage scaled_wave_image = wave_image->scaled(width, height, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
 
  242         wave_image = std::make_shared<QImage>(scaled_wave_image);
 
  260     wave_image = 
GetWaveform(width, height, Red, Green, Blue, Alpha);
 
  263     return wave_image->constBits();
 
  272     if (!QApplication::instance()) {
 
  275         static char* argv[1] = {NULL};
 
  276         previewApp = std::make_shared<QApplication>(argc, argv);
 
  280     QWidget previewWindow;
 
  281     previewWindow.setStyleSheet(
"background-color: #000000;");
 
  286     previewLabel.setPixmap(QPixmap::fromImage(*wave_image));
 
  287     previewLabel.setMask(QPixmap::fromImage(*wave_image).mask());
 
  288     layout.addWidget(&previewLabel);
 
  291     previewWindow.setLayout(&layout);
 
  292     previewWindow.show();
 
  304         return audio->getMagnitude(channel, sample, magnitude_range);
 
  308         return audio->getMagnitude(sample, magnitude_range);
 
  319     return buffer->getWritePointer(channel);
 
  328     float *output = NULL;
 
  329     int num_of_channels = 
audio->getNumChannels();
 
  333     output = 
new float[num_of_channels * num_of_samples];
 
  337     for (
int sample = 0; sample < num_of_samples; sample++)
 
  339         for (
int channel = 0; channel < num_of_channels; channel++)
 
  342             output[position] = buffer->getReadPointer(channel)[sample];
 
  350     *sample_count = num_of_samples;
 
  359     const std::lock_guard<std::recursive_mutex> lock(addingAudioMutex);
 
  361         return audio->getNumChannels();
 
  369     const std::lock_guard<std::recursive_mutex> lock(addingAudioMutex);
 
  370     return max_audio_sample;
 
  381     int64_t total_bytes = 0;
 
  383         total_bytes += 
static_cast<int64_t
>(
 
  384             width * height * 
sizeof(char) * 4);
 
  388         total_bytes += (sample_rate / 24.0) * 
sizeof(float);
 
  404     return image->constBits();
 
  416     return image->constScanLine(row);
 
  420 bool Frame::CheckPixel(
int row, 
int col, 
int red, 
int green, 
int blue, 
int alpha, 
int threshold) {
 
  421     int col_pos = col * 4; 
 
  422     if (!image || row < 0 || row >= (height - 1) ||
 
  423         col_pos < 0 || col_pos >= (width - 1) ) {
 
  428     const unsigned char* pixels = 
GetPixels(row);
 
  429     if (pixels[col_pos + 0] >= (red - threshold) && pixels[col_pos + 0] <= (red + threshold) &&
 
  430         pixels[col_pos + 1] >= (green - threshold) && pixels[col_pos + 1] <= (green + threshold) &&
 
  431         pixels[col_pos + 2] >= (blue - threshold) && pixels[col_pos + 2] <= (blue + threshold) &&
 
  432         pixels[col_pos + 3] >= (alpha - threshold) && pixels[col_pos + 3] <= (alpha + threshold)) {
 
  444     pixel_ratio.
num = num;
 
  445     pixel_ratio.
den = den;
 
  459     if (channels == 0) 
return 0;
 
  465     double previous_samples = (sample_rate * fps_rate) * (
number - 1);
 
  466     double previous_samples_remainder = fmod(previous_samples, (
double)channels); 
 
  467     previous_samples -= previous_samples_remainder;
 
  470     double total_samples = (sample_rate * fps_rate) * 
number;
 
  471     double total_samples_remainder = fmod(total_samples, (
double)channels); 
 
  472     total_samples -= total_samples_remainder;
 
  476     int samples_per_frame = round(total_samples - previous_samples);
 
  477     if (samples_per_frame < 0)
 
  478         samples_per_frame = 0;
 
  479     return samples_per_frame;
 
  509     return channel_layout;
 
  517     std::shared_ptr<QImage> previewImage = 
GetImage();
 
  520     if (pixel_ratio.
num != 1 || pixel_ratio.
den != 1)
 
  523         previewImage = std::make_shared<QImage>(previewImage->scaled(
 
  524                 previewImage->size().width(), previewImage->size().height() * pixel_ratio.
Reciprocal().
ToDouble(),
 
  525                 Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
 
  529     if (fabs(scale) > 1.001 || fabs(scale) < 0.999)
 
  532         previewImage = std::make_shared<QImage>(previewImage->scaled(
 
  533                 previewImage->size().width() * scale, previewImage->size().height() * scale,
 
  534                 Qt::KeepAspectRatio, Qt::SmoothTransformation));
 
  538     previewImage->save(QString::fromStdString(
path), format.c_str(), quality);
 
  542 void Frame::Thumbnail(std::string 
path, 
int new_width, 
int new_height, std::string mask_path, std::string overlay_path,
 
  543         std::string background_color, 
bool ignore_aspect, std::string format, 
int quality, 
float rotate) {
 
  546     auto thumbnail = std::make_shared<QImage>(
 
  547         new_width, new_height, QImage::Format_RGBA8888_Premultiplied);
 
  548     thumbnail->fill(QColor(QString::fromStdString(background_color)));
 
  551     QPainter painter(thumbnail.get());
 
  552     painter.setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform | QPainter::TextAntialiasing, 
true);
 
  555     std::shared_ptr<QImage> previewImage = 
GetImage();
 
  558     if (pixel_ratio.
num != 1 || pixel_ratio.
den != 1)
 
  561         int aspect_width = previewImage->size().width();
 
  562         int aspect_height = previewImage->size().height() * pixel_ratio.
Reciprocal().
ToDouble();
 
  565         previewImage = std::make_shared<QImage>(previewImage->scaled(
 
  566             aspect_width, aspect_height,
 
  567             Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
 
  573         previewImage = std::make_shared<QImage>(previewImage->scaled(
 
  574             new_width, new_height,
 
  575             Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
 
  578         previewImage = std::make_shared<QImage>(previewImage->scaled(
 
  579             new_width, new_height,
 
  580             Qt::KeepAspectRatio, Qt::SmoothTransformation));
 
  583     int x = (new_width - previewImage->size().width()) / 2.0; 
 
  584     int y = (new_height - previewImage->size().height()) / 2.0; 
 
  585     painter.setCompositionMode(QPainter::CompositionMode_SourceOver);
 
  589     QTransform transform;
 
  590     float origin_x = previewImage->width() / 2.0;
 
  591     float origin_y = previewImage->height() / 2.0;
 
  592     transform.translate(origin_x, origin_y);
 
  593     transform.rotate(rotate);
 
  594     transform.translate(-origin_x,-origin_y);
 
  595     painter.setTransform(transform);
 
  598     painter.drawImage(x, y, *previewImage);
 
  602     if (overlay_path != 
"") {
 
  604         auto overlay = std::make_shared<QImage>();
 
  605         overlay->load(QString::fromStdString(overlay_path));
 
  608         overlay = std::make_shared<QImage>(
 
  609             overlay->convertToFormat(QImage::Format_RGBA8888_Premultiplied));
 
  612         overlay = std::make_shared<QImage>(overlay->scaled(
 
  613             new_width, new_height, Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
 
  616         painter.setCompositionMode(QPainter::CompositionMode_SourceOver);
 
  617         painter.drawImage(0, 0, *overlay);
 
  622     if (mask_path != 
"") {
 
  624         auto mask = std::make_shared<QImage>();
 
  625         mask->load(QString::fromStdString(mask_path));
 
  628         mask = std::make_shared<QImage>(
 
  629             mask->convertToFormat(QImage::Format_RGBA8888_Premultiplied));
 
  632         mask = std::make_shared<QImage>(mask->scaled(
 
  633             new_width, new_height, Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
 
  636         mask->invertPixels();
 
  639         unsigned char *pixels = 
static_cast<unsigned char *
>(thumbnail->bits());
 
  640         const unsigned char *mask_pixels = 
static_cast<const unsigned char *
>(mask->constBits());
 
  644         for (
int pixel = 0, byte_index=0; pixel < new_width * new_height; pixel++, byte_index+=4)
 
  647             int gray_value = qGray(mask_pixels[byte_index], mask_pixels[byte_index] + 1, mask_pixels[byte_index] + 2);
 
  648             int Frame_Alpha = pixels[byte_index + 3];
 
  649             int Mask_Value = constrain(Frame_Alpha - gray_value);
 
  652             pixels[byte_index + 3] = Mask_Value;
 
  661     thumbnail->save(QString::fromStdString(
path), format.c_str(), quality);
 
  665 int Frame::constrain(
int color_value)
 
  670     else if (color_value > 255)
 
  678      const std::lock_guard<std::recursive_mutex> lock(addingImageMutex);
 
  683     AddColor(QColor(QString::fromStdString(new_color)));
 
  690     const std::lock_guard<std::recursive_mutex> lock(addingImageMutex);
 
  691     image = std::make_shared<QImage>(width, height, QImage::Format_RGBA8888_Premultiplied);
 
  694     image->fill(new_color);
 
  700     int new_width, 
int new_height, 
int bytes_per_pixel,
 
  701     QImage::Format type, 
const unsigned char *pixels_)
 
  709     auto new_image = std::make_shared<QImage>(
 
  711         new_width, new_height,
 
  712         new_width * bytes_per_pixel,
 
  714         (QImageCleanupFunction) &openshot::cleanUpBuffer,
 
  728     const std::lock_guard<std::recursive_mutex> lock(addingImageMutex);
 
  732     if (image->format() != QImage::Format_RGBA8888_Premultiplied)
 
  733         *image = image->convertToFormat(QImage::Format_RGBA8888_Premultiplied);
 
  736     width = image->width();
 
  737     height = image->height();
 
  756         if (image == new_image || image->size() != new_image->size()) {
 
  759         else if (new_image->format() != QImage::Format_RGBA8888_Premultiplied) {
 
  760             new_image = std::make_shared<QImage>(
 
  761                     new_image->convertToFormat(QImage::Format_RGBA8888_Premultiplied));
 
  768         const std::lock_guard<std::recursive_mutex> lock(addingImageMutex);
 
  769         unsigned char *pixels = image->bits();
 
  770         const unsigned char *new_pixels = new_image->constBits();
 
  777         for (
int row = start; row < image->height(); row += 2) {
 
  778             int offset = row * image->bytesPerLine();
 
  779             memcpy(pixels + offset, new_pixels + offset, image->bytesPerLine());
 
  783         height = image->height();
 
  784         width = image->width();
 
  793     const std::lock_guard<std::recursive_mutex> lock(addingAudioMutex);
 
  796     audio->setSize(channels, length, 
true, 
true, 
false);
 
  797     channel_layout = layout;
 
  801     max_audio_sample = length;
 
  807     if (
audio && !audio_reversed) {
 
  810         audio_reversed = 
true;
 
  815 void Frame::AddAudio(
bool replaceSamples, 
int destChannel, 
int destStartSample, 
const float* source, 
int numSamples, 
float gainToApplyToSource = 1.0f) {
 
  816     const std::lock_guard<std::recursive_mutex> lock(addingAudioMutex);
 
  819     int destStartSampleAdjusted = max(destStartSample, 0);
 
  822     int new_length = destStartSampleAdjusted + numSamples;
 
  823     int new_channel_length = 
audio->getNumChannels();
 
  824     if (destChannel >= new_channel_length)
 
  825         new_channel_length = destChannel + 1;
 
  826     if (new_length > 
audio->getNumSamples() || new_channel_length > 
audio->getNumChannels())
 
  827         audio->setSize(new_channel_length, new_length, 
true, 
true, 
false);
 
  831         audio->clear(destChannel, destStartSampleAdjusted, numSamples);
 
  834     audio->addFrom(destChannel, destStartSampleAdjusted, source, numSamples, gainToApplyToSource);
 
  838     if (new_length > max_audio_sample)
 
  839         max_audio_sample = new_length;
 
  842     audio_reversed = 
false;
 
  846 void Frame::ApplyGainRamp(
int destChannel, 
int destStartSample, 
int numSamples, 
float initial_gain = 0.0f, 
float final_gain = 1.0f)
 
  848     const std::lock_guard<std::recursive_mutex> lock(addingAudioMutex);
 
  851     audio->applyGainRamp(destChannel, destStartSample, numSamples, initial_gain, final_gain);
 
  870     cv::Mat mat = cv::Mat(qimage->height(), qimage->width(), CV_8UC4, (uchar*)qimage->constBits(), qimage->bytesPerLine()).clone();
 
  871     cv::Mat mat2 = cv::Mat(mat.rows, mat.cols, CV_8UC3 );
 
  872     int from_to[] = { 0,0,  1,1,  2,2 };
 
  873     cv::mixChannels( &mat, 1, &mat2, 1, from_to, 3 );
 
  874     cv::cvtColor(mat2, mat2, cv::COLOR_RGB2BGR);
 
  894     cv::cvtColor(img, img, cv::COLOR_BGR2RGB);
 
  895     QImage qimg((uchar*) img.data, img.cols, img.rows, img.step, QImage::Format_RGB888);
 
  897     std::shared_ptr<QImage> imgIn = std::make_shared<QImage>(qimg.copy());
 
  900     if (imgIn->format() != QImage::Format_RGBA8888_Premultiplied)
 
  901         *imgIn = imgIn->convertToFormat(QImage::Format_RGBA8888_Premultiplied);
 
  921     juce::AudioDeviceManager deviceManager;
 
  922     juce::String error = deviceManager.initialise (
 
  929     if (error.isNotEmpty()) {
 
  930         cout << 
"Error on initialise(): " << error << endl;
 
  933     juce::AudioSourcePlayer audioSourcePlayer;
 
  934     deviceManager.addAudioCallback (&audioSourcePlayer);
 
  936     std::unique_ptr<AudioBufferSource> my_source;
 
  940     juce::TimeSliceThread my_thread(
"Audio buffer thread");
 
  943     my_thread.startThread();
 
  945     juce::AudioTransportSource transport1;
 
  946     transport1.setSource (my_source.get(),
 
  949             (
double) sample_rate,
 
  950             audio->getNumChannels()); 
 
  951     transport1.setPosition (0);
 
  952     transport1.setGain(1.0);
 
  956     juce::MixerAudioSource mixer;
 
  957     mixer.addInputSource(&transport1, 
false);
 
  958     audioSourcePlayer.setSource (&mixer);
 
  963     while (transport1.isPlaying())
 
  965         cout << 
"playing" << endl;
 
  966         std::this_thread::sleep_for(std::chrono::seconds(1));
 
  969     cout << 
"DONE!!!" << endl;
 
  972     transport1.setSource (0);
 
  973     audioSourcePlayer.setSource (0);
 
  974     my_thread.stopThread(500);
 
  975     deviceManager.removeAudioCallback (&audioSourcePlayer);
 
  976     deviceManager.closeAudioDevice();
 
  977     deviceManager.removeAllChangeListeners();
 
  978     deviceManager.dispatchPendingMessages();
 
  980     cout << 
"End of Play()" << endl;
 
  988     const std::lock_guard<std::recursive_mutex> lock(addingAudioMutex);
 
  991     audio->setSize(channels, numSamples, 
false, 
true, 
false);
 
  996     max_audio_sample = numSamples;
 
  999     audio_reversed = 
false;