File indexing completed on 2024-05-12 04:54:57

0001 /*
0002     SPDX-FileCopyrightText: 2006-2008 Marco Gulino <marco@kmobiletools.org>
0003     SPDX-FileCopyrightText: Jean-Baptiste Mardelle <jb@kdenlive.org>
0004 
0005     SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
0006 */
0007 
0008 #include "mltpreview.h"
0009 #include "../src/lib/localeHandling.h"
0010 
0011 #include <QDebug>
0012 #include <QImage>
0013 #include <QVarLengthArray>
0014 #include <QtGlobal>
0015 
0016 extern "C" {
0017 Q_DECL_EXPORT ThumbCreator *new_creator()
0018 {
0019     return new MltPreview;
0020 }
0021 }
0022 
0023 MltPreview::MltPreview()
0024 {
0025     // After initialising the MLT factory, set the locale back from user default to C
0026     // to ensure numbers are always serialised with . as decimal point.
0027     Mlt::Factory::init();
0028     LocaleHandling::resetLocale();
0029 }
0030 
0031 MltPreview::~MltPreview()
0032 {
0033     Mlt::Factory::close();
0034 }
0035 
0036 bool MltPreview::create(const QString &path, int width, int height, QImage &img)
0037 {
0038     std::unique_ptr<Mlt::Profile> profile(new Mlt::Profile());
0039     std::shared_ptr<Mlt::Producer> producer(new Mlt::Producer(*profile.get(), path.toUtf8().data()));
0040 
0041     if (producer->is_blank()) {
0042         return false;
0043     }
0044     int frame = 75;
0045     uint variance = 10;
0046     int ct = 1;
0047     double ar = profile->dar();
0048     if (ar < 1e-6) {
0049         ar = 1.0;
0050     }
0051     int wanted_width = width;
0052     int wanted_height = int(width / profile->dar());
0053     if (wanted_height > height) {
0054         wanted_height = height;
0055         wanted_width = int(height * ar);
0056     }
0057     // We don't need audio
0058     producer->set("audio_index", -1);
0059 
0060     // Add normalizers
0061     Mlt::Filter scaler(*profile.get(), "swscale");
0062     Mlt::Filter padder(*profile.get(), "resize");
0063     Mlt::Filter converter(*profile.get(), "avcolor_space");
0064 
0065     if (scaler.is_valid()) {
0066         producer->attach(scaler);
0067     }
0068     if (padder.is_valid()) {
0069         producer->attach(padder);
0070     }
0071     if (converter.is_valid()) {
0072         producer->attach(converter);
0073     }
0074 
0075     // img = getFrame(producer, frame, width, height);
0076     while (variance <= 40 && ct < 4) {
0077         img = getFrame(producer, frame, wanted_width, wanted_height);
0078         variance = uint(imageVariance(img));
0079         frame += 100 * ct;
0080         ct++;
0081     }
0082     return (!img.isNull());
0083 }
0084 
0085 QImage MltPreview::getFrame(std::shared_ptr<Mlt::Producer> producer, int framepos, int width, int height)
0086 {
0087     QImage mltImage(width, height, QImage::Format_ARGB32);
0088     if (producer == nullptr) {
0089         return mltImage;
0090     }
0091 
0092     producer->seek(framepos);
0093     Mlt::Frame *frame = producer->get_frame();
0094     if (frame == nullptr || !frame->is_valid()) {
0095         return mltImage;
0096     }
0097 
0098     mlt_image_format format = mlt_image_rgba;
0099     const uchar *imagedata = frame->get_image(format, width, height);
0100     if (imagedata != nullptr) {
0101         memcpy(mltImage.bits(), imagedata, size_t(width * height * 4));
0102         mltImage = mltImage.rgbSwapped();
0103     }
0104 
0105     delete frame;
0106     return mltImage;
0107 }
0108 
0109 int MltPreview::imageVariance(const QImage &image)
0110 {
0111     if (image.isNull()) {
0112         return 0;
0113     }
0114     int delta = 0;
0115     int avg = 0;
0116     int bytes = int(image.sizeInBytes());
0117     int STEPS = bytes / 2;
0118     if (STEPS < 1) {
0119         return 0;
0120     }
0121     QVarLengthArray<uchar> pivot(STEPS);
0122     qDebug() << "Using " << STEPS << " steps\n";
0123     const uchar *bits = image.bits();
0124     // First pass: get pivots and taking average
0125     for (int i = 0; i < STEPS; i++) {
0126         pivot[i] = bits[2 * i];
0127         avg += pivot.at(i);
0128     }
0129     avg = avg / STEPS;
0130     // Second Step: calculate delta (average?)
0131     for (int i = 0; i < STEPS; ++i) {
0132         int curdelta = abs(avg - pivot.at(i));
0133         delta += curdelta;
0134     }
0135     return delta / STEPS;
0136 }
0137 
0138 ThumbCreator::Flags MltPreview::flags() const
0139 {
0140     return None;
0141 }