File indexing completed on 2024-04-21 08:41:09

0001 /*
0002     SPDX-FileCopyrightText: 2008 Jean-Baptiste Mardelle <jb@kdenlive.org>
0003 
0004 SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
0005 */
0006 
0007 #include "proxytest.h"
0008 
0009 #include "core.h"
0010 #include "doc/kdenlivedoc.h"
0011 #include "kdenlivesettings.h"
0012 
0013 #include "kdenlive_debug.h"
0014 #include <QDialogButtonBox>
0015 #include <QFontDatabase>
0016 #include <QPushButton>
0017 #include <QTreeWidget>
0018 #include <QWheelEvent>
0019 #include <QtConcurrent>
0020 
0021 #include "klocalizedstring.h"
0022 #include <kio/directorysizejob.h>
0023 
0024 ProxyTest::ProxyTest(QWidget *parent)
0025     : QDialog(parent)
0026     , m_closing(false)
0027 {
0028     setFont(QFontDatabase::systemFont(QFontDatabase::SmallestReadableFont));
0029     setupUi(this);
0030     setWindowTitle(i18nc("@title:window", "Compare Proxy Profile"));
0031     buttonBox->button(QDialogButtonBox::Apply)->setText(i18n("Test Proxy Profiles"));
0032     infoWidget->hide();
0033     paramBox->setVisible(false);
0034     m_failedProfiles = new MyTreeWidgetItem(resultList, {i18n("Failing profiles")});
0035     resultList->addTopLevelItem(m_failedProfiles);
0036     m_failedProfiles->setExpanded(false);
0037     m_failedProfiles->setHidden(true);
0038     connect(resultList, &QTreeWidget::itemSelectionChanged, resultList, [&]() {
0039         QTreeWidgetItem *item = resultList->currentItem();
0040         if (item) {
0041             paramBox->setPlainText(item->data(0, Qt::UserRole).toString());
0042             paramBox->setVisible(true);
0043         } else {
0044             paramBox->clear();
0045             paramBox->setVisible(false);
0046         }
0047     });
0048     connect(buttonBox->button(QDialogButtonBox::Apply), &QPushButton::clicked, this, [this]() {
0049         infoWidget->setText(i18n("Starting process"));
0050         infoWidget->animatedShow();
0051         resultList->setCursor(Qt::BusyCursor);
0052         buttonBox->button(QDialogButtonBox::Apply)->setEnabled(false);
0053 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
0054         QtConcurrent::run(this, &ProxyTest::startTest);
0055 #else
0056         QtConcurrent::run(&ProxyTest::startTest, this);
0057 #endif
0058     });
0059 }
0060 
0061 void ProxyTest::addAnalysis(const QStringList &data)
0062 {
0063     QStringList itemData = data;
0064     QString params = itemData.takeFirst();
0065     if (itemData.size() == 1) {
0066         // This proxy profile failed
0067         MyTreeWidgetItem *item = new MyTreeWidgetItem(m_failedProfiles, itemData);
0068         item->setData(0, Qt::UserRole, params);
0069         item->setIcon(0, QIcon::fromTheme(QStringLiteral("window-close")));
0070         m_failedProfiles->setHidden(false);
0071         // m_failedProfiles->addChild(item);
0072     } else {
0073         MyTreeWidgetItem *item = new MyTreeWidgetItem(resultList, itemData);
0074         qDebug() << "=== ADDING ANALYSIS: " << itemData;
0075         item->setData(0, Qt::UserRole, params);
0076         item->setData(1, Qt::UserRole, itemData.at(1).toInt());
0077         QTime t = QTime(0, 0).addMSecs(itemData.at(1).toInt());
0078         qDebug() << "TIME: " << itemData.at(1).toInt() << " = " << t.toString(QStringLiteral("mm:ss:z"));
0079         item->setText(1, t.toString(QStringLiteral("mm:ss:z")));
0080         item->setText(2, KIO::convertSize(itemData.at(2).toInt()));
0081         item->setData(2, Qt::UserRole, itemData.at(2).toInt());
0082         // resultList->addTopLevelItem(item);
0083     }
0084 }
0085 
0086 void ProxyTest::showMessage(const QString &message)
0087 {
0088     infoWidget->setText(message);
0089     if (!message.isEmpty()) {
0090         infoWidget->animatedShow();
0091     } else {
0092         // Tests finished
0093         infoWidget->animatedHide();
0094         resultList->setCursor(Qt::ArrowCursor);
0095     }
0096 }
0097 
0098 ProxyTest::~ProxyTest()
0099 {
0100     m_closing = true;
0101     Q_EMIT jobCanceled();
0102     // Wait until concurrent tread is finished
0103     QMutexLocker lk(&m_locker);
0104 }
0105 
0106 void ProxyTest::startTest()
0107 {
0108     // load proxy profiles
0109     KConfig conf(QStringLiteral("encodingprofiles.rc"), KConfig::CascadeConfig, QStandardPaths::AppDataLocation);
0110     KConfigGroup group(&conf, "proxy");
0111     QMap<QString, QString> values = group.entryMap();
0112     QMapIterator<QString, QString> k(values);
0113     int proxyResize = pCore->currentDoc()->getDocumentProperty(QStringLiteral("proxyresize")).toInt();
0114     QElapsedTimer timer;
0115     QTemporaryFile src(QDir::temp().absoluteFilePath(QString("XXXXXX.mov")));
0116     if (!src.open()) {
0117         // Something went wrong
0118         QMetaObject::invokeMethod(this, "showMessage", Qt::QueuedConnection, Q_ARG(QString, i18n("Cannot create temporary files")));
0119         return;
0120     }
0121     QMutexLocker lk1(&m_locker);
0122     m_process.reset(new QProcess());
0123     connect(this, &ProxyTest::jobCanceled, m_process.get(), &QProcess::kill, Qt::DirectConnection);
0124     QMetaObject::invokeMethod(this, "showMessage", Qt::QueuedConnection, Q_ARG(QString, i18n("Generating a 60 seconds test video %1", src.fileName())));
0125     QStringList source = {QStringLiteral("-y"),
0126                           QStringLiteral("-f"),
0127                           QStringLiteral("lavfi"),
0128                           QStringLiteral("-i"),
0129                           QStringLiteral("testsrc=duration=60:size=1920x1080:rate=25"),
0130                           QStringLiteral("-c:v"),
0131                           QStringLiteral("libx264"),
0132                           QStringLiteral("-pix_fmt"),
0133                           QStringLiteral("yuv420p"),
0134                           src.fileName()};
0135     m_process->start(KdenliveSettings::ffmpegpath(), source);
0136     m_process->waitForStarted();
0137     if (m_closing) {
0138         return;
0139     }
0140     m_process->waitForFinished(-1);
0141     if (m_closing) {
0142         return;
0143     }
0144 
0145     while (k.hasNext() && !m_closing) {
0146         k.next();
0147         if (!k.key().isEmpty()) {
0148             QMetaObject::invokeMethod(this, "showMessage", Qt::QueuedConnection, Q_ARG(QString, i18n("Processing %1", k.key())));
0149             QString params = k.value().section(QLatin1Char(';'), 0, 0);
0150             QString extension = k.value().section(QLatin1Char(';'), 1, 1);
0151             // Testing vaapi support
0152             QTemporaryFile tmp(QDir::temp().absoluteFilePath(QString("XXXXXX.%1").arg(extension)));
0153             if (!tmp.open()) {
0154                 // Something went wrong
0155                 QMetaObject::invokeMethod(this, "showMessage", Qt::QueuedConnection, Q_ARG(QString, i18n("Cannot create temporary files")));
0156                 return;
0157             }
0158             tmp.close();
0159             params.replace(QStringLiteral("%width"), QString::number(proxyResize));
0160             if (params.contains(QStringLiteral("%frameSize"))) {
0161                 int w = proxyResize;
0162                 int h = w * 1080 / 1920;
0163                 params.replace(QStringLiteral("%frameSize"), QString("%1x%2").arg(w).arg(h));
0164             }
0165             params.replace(QStringLiteral("%nvcodec"), QStringLiteral("h264_cuvid"));
0166             m_process.reset(new QProcess());
0167             connect(this, &ProxyTest::jobCanceled, m_process.get(), &QProcess::kill, Qt::DirectConnection);
0168             QStringList parameters = {QStringLiteral("-hide_banner"), QStringLiteral("-y"), QStringLiteral("-stats"), QStringLiteral("-v"),
0169                                       QStringLiteral("error")};
0170             if (params.contains(QLatin1String("-i "))) {
0171                 // we have some pre-filename parameters, filename will be inserted later
0172             } else {
0173                 parameters << QStringLiteral("-i") << src.fileName();
0174             }
0175             QStringList paramList = params.split(QLatin1Char(' '), Qt::SkipEmptyParts);
0176             for (const QString &s : qAsConst(paramList)) {
0177                 QString t = s.simplified();
0178                 if (t != QLatin1String("-noautorotate")) {
0179                     parameters << t;
0180                     if (t == QLatin1String("-i")) {
0181                         parameters << src.fileName();
0182                     }
0183                 }
0184             }
0185             parameters << tmp.fileName();
0186             qDebug() << "==== STARTING TEST PROFILE : " << k.key() << " = " << parameters;
0187             m_process->start(KdenliveSettings::ffmpegpath(), parameters);
0188             m_process->waitForStarted();
0189             timer.start();
0190             bool success = false;
0191             QStringList results = {params};
0192             if (m_process->waitForFinished(-1)) {
0193                 if (m_closing) {
0194                     return;
0195                 }
0196                 qint64 elapsed = timer.elapsed();
0197                 qint64 size = tmp.size();
0198                 if (size > 0) {
0199                     success = true;
0200                     results << QStringList({k.key(), QString::number(elapsed), QString::number(size)});
0201                 }
0202             }
0203             if (!success) {
0204                 if (m_closing) {
0205                     return;
0206                 }
0207                 qDebug() << "==== PROFILE FAILED: " << k.key() << " !!!!!!!!!!!!";
0208                 results << QStringList({k.key()});
0209             }
0210             QMetaObject::invokeMethod(this, "addAnalysis", Qt::QueuedConnection, Q_ARG(QStringList, results));
0211         }
0212     }
0213     if (m_closing) {
0214         return;
0215     }
0216     QMetaObject::invokeMethod(this, "showMessage", Qt::QueuedConnection, Q_ARG(QString, QString()));
0217 }