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 }