File indexing completed on 2024-04-21 04:51:33

0001 /*
0002 SPDX-FileCopyrightText: 2016 Jean-Baptiste Mardelle <jb@kdenlive.org>
0003 This file is part of Kdenlive. See www.kdenlive.org.
0004 
0005 SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
0006 */
0007 
0008 #include "kthumb.h"
0009 #include "core.h"
0010 #include "kdenlivesettings.h"
0011 #include "profiles/profilemodel.hpp"
0012 
0013 #include <mlt++/Mlt.h>
0014 
0015 #include <QPixmap>
0016 // static
0017 QPixmap KThumb::getImage(const QUrl &url, int width, int height)
0018 {
0019     if (!url.isValid()) {
0020         return QPixmap();
0021     }
0022     return getImage(url, 0, width, height);
0023 }
0024 
0025 // static
0026 QPixmap KThumb::getImage(const QUrl &url, int frame, int width, int height)
0027 {
0028     QScopedPointer<Mlt::Profile> profile(new Mlt::Profile(pCore->getCurrentProfilePath().toUtf8().constData()));
0029     if (height == -1) {
0030         height = int(width * double(profile->height()) / profile->width());
0031     }
0032     QPixmap pix(width, height);
0033     if (!url.isValid()) {
0034         return pix;
0035     }
0036     Mlt::Producer *producer = new Mlt::Producer(*(profile.data()), url.toLocalFile().toUtf8().constData());
0037     if (KdenliveSettings::gpu_accel()) {
0038         QString service = producer->get("mlt_service");
0039         QString res = producer->get("resource");
0040         delete producer;
0041         producer = new Mlt::Producer(*(profile.data()), service.toUtf8().constData(), res.toUtf8().constData());
0042         Mlt::Filter scaler(*(profile.data()), "swscale");
0043         Mlt::Filter converter(*(profile.data()), "avcolor_space");
0044         producer->attach(scaler);
0045         producer->attach(converter);
0046     }
0047     pix = QPixmap::fromImage(getFrame(producer, frame, width, height));
0048     delete producer;
0049     return pix;
0050 }
0051 
0052 // static
0053 QImage KThumb::getFrame(Mlt::Producer *producer, int framepos, int width, int height, int displayWidth)
0054 {
0055     if (producer == nullptr || !producer->is_valid()) {
0056         QImage p(displayWidth == 0 ? width : displayWidth, height, QImage::Format_ARGB32_Premultiplied);
0057         p.fill(QColor(Qt::red).rgb());
0058         return p;
0059     }
0060     if (producer->is_blank()) {
0061         QImage p(displayWidth == 0 ? width : displayWidth, height, QImage::Format_ARGB32_Premultiplied);
0062         p.fill(QColor(Qt::black).rgb());
0063         return p;
0064     }
0065 
0066     producer->seek(framepos);
0067     Mlt::Frame *frame = producer->get_frame();
0068     const QImage p = getFrame(frame, width, height, displayWidth);
0069     delete frame;
0070     return p;
0071 }
0072 
0073 // static
0074 QImage KThumb::getFrame(Mlt::Producer &producer, int framepos, int width, int height, int displayWidth)
0075 {
0076     if (!producer.is_valid()) {
0077         QImage p(displayWidth, height, QImage::Format_ARGB32_Premultiplied);
0078         p.fill(QColor(Qt::red).rgb());
0079         return p;
0080     }
0081     producer.seek(framepos);
0082     Mlt::Frame *frame = producer.get_frame();
0083     const QImage p = getFrame(frame, width, height, displayWidth);
0084     delete frame;
0085     return p;
0086 }
0087 
0088 // static
0089 QImage KThumb::getFrame(Mlt::Frame *frame, int width, int height, int scaledWidth)
0090 {
0091     if (frame == nullptr || !frame->is_valid()) {
0092         qDebug() << "* * * *INVALID FRAME";
0093         return QImage();
0094     }
0095     int ow = width;
0096     int oh = height;
0097     mlt_image_format format = mlt_image_rgba;
0098     const uchar *imagedata = frame->get_image(format, ow, oh);
0099     if (imagedata) {
0100         QImage temp(ow, oh, QImage::Format_ARGB32);
0101         memcpy(temp.scanLine(0), imagedata, unsigned(ow * oh * 4));
0102         if (scaledWidth == 0 || scaledWidth == width) {
0103             return temp.rgbSwapped();
0104         }
0105         return temp.rgbSwapped().scaled(scaledWidth, height == 0 ? oh : height);
0106     }
0107     return QImage();
0108 }
0109 
0110 // static
0111 int KThumb::imageVariance(const QImage &image)
0112 {
0113     int delta = 0;
0114     int avg = 0;
0115     int bytes = int(image.sizeInBytes());
0116     int STEPS = bytes / 2;
0117     QVarLengthArray<uchar> pivot(STEPS);
0118     const uchar *bits = image.bits();
0119     // First pass: get pivots and taking average
0120     for (int i = 0; i < STEPS; ++i) {
0121         pivot[i] = bits[2 * i];
0122         avg += pivot.at(i);
0123     }
0124     if (STEPS != 0) {
0125         avg = avg / STEPS;
0126     }
0127     // Second Step: calculate delta (average?)
0128     for (int i = 0; i < STEPS; ++i) {
0129         int curdelta = abs(int(avg - pivot.at(i)));
0130         delta += curdelta;
0131     }
0132     if (STEPS != 0) {
0133         return delta / STEPS;
0134     }
0135     return 0;
0136 }