File indexing completed on 2024-04-14 04:47:55
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 #include <KPluginFactory> 0017 0018 K_PLUGIN_CLASS_WITH_JSON(MltPreview, "mltpreview.json") 0019 0020 MltPreview::MltPreview(QObject *parent, const QVariantList &args) 0021 : KIO::ThumbnailCreator(parent, args) 0022 { 0023 // After initialising the MLT factory, set the locale back from user default to C 0024 // to ensure numbers are always serialised with . as decimal point. 0025 Mlt::Factory::init(); 0026 LocaleHandling::resetLocale(); 0027 } 0028 0029 MltPreview::~MltPreview() 0030 { 0031 Mlt::Factory::close(); 0032 } 0033 0034 KIO::ThumbnailResult MltPreview::create(const KIO::ThumbnailRequest &request) 0035 { 0036 int width = request.targetSize().width(); 0037 int height = request.targetSize().height(); 0038 std::unique_ptr<Mlt::Profile> profile(new Mlt::Profile()); 0039 std::shared_ptr<Mlt::Producer> producer(new Mlt::Producer(*profile.get(), request.url().toLocalFile().toUtf8().data())); 0040 0041 if (producer == nullptr || !producer->is_valid() || producer->is_blank()) { 0042 return KIO::ThumbnailResult::fail(); 0043 } 0044 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 / ar); 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 QImage img; 0076 int length = producer->get_length(); 0077 if (length < 1) { 0078 return KIO::ThumbnailResult::fail(); 0079 } 0080 int frame = qMin(75, length - 1); 0081 while (variance <= 40 && ct < 4 && frame < length) { 0082 img = getFrame(producer, frame, wanted_width, wanted_height); 0083 variance = uint(imageVariance(img)); 0084 frame += 100 * ct; 0085 ct++; 0086 } 0087 0088 if (img.isNull()) { 0089 return KIO::ThumbnailResult::fail(); 0090 } 0091 0092 return KIO::ThumbnailResult::pass(img); 0093 } 0094 0095 QImage MltPreview::getFrame(std::shared_ptr<Mlt::Producer> producer, int framepos, int width, int height) 0096 { 0097 QImage mltImage(width, height, QImage::Format_ARGB32); 0098 if (producer == nullptr) { 0099 return mltImage; 0100 } 0101 producer->seek(framepos); 0102 std::shared_ptr<Mlt::Frame> frame(producer->get_frame()); 0103 if (frame == nullptr || !frame->is_valid()) { 0104 return mltImage; 0105 } 0106 0107 mlt_image_format format = mlt_image_rgba; 0108 const uchar *imagedata = frame->get_image(format, width, height); 0109 if (imagedata != nullptr) { 0110 memcpy(mltImage.bits(), imagedata, size_t(width * height * 4)); 0111 mltImage = mltImage.rgbSwapped(); 0112 } 0113 return mltImage; 0114 } 0115 0116 int MltPreview::imageVariance(const QImage &image) 0117 { 0118 if (image.isNull()) { 0119 return 0; 0120 } 0121 int delta = 0; 0122 int avg = 0; 0123 int bytes = int(image.sizeInBytes()); 0124 int STEPS = bytes / 2; 0125 if (STEPS < 1) { 0126 return 0; 0127 } 0128 QVarLengthArray<uchar> pivot(STEPS); 0129 qDebug() << "Using " << STEPS << " steps\n"; 0130 const uchar *bits = image.bits(); 0131 // First pass: get pivots and taking average 0132 for (int i = 0; i < STEPS; i++) { 0133 pivot[i] = bits[2 * i]; 0134 avg += pivot.at(i); 0135 } 0136 avg = avg / STEPS; 0137 // Second Step: calculate delta (average?) 0138 for (int i = 0; i < STEPS; ++i) { 0139 int curdelta = abs(avg - pivot.at(i)); 0140 delta += curdelta; 0141 } 0142 return delta / STEPS; 0143 } 0144 0145 #include "mltpreview.moc"