]> git.sesse.net Git - kdenlive/blobdiff - src/colorcorrection/waveformgenerator.cpp
Integrate with the required MLT hooks for getting Movit to work.
[kdenlive] / src / colorcorrection / waveformgenerator.cpp
index 648691c52f021920752e06968e06c52179c5a220..4c60518de93752b52ba0252f2ca970461e8cb776 100644 (file)
@@ -8,8 +8,8 @@
  *   (at your option) any later version.                                   *
  ***************************************************************************/
 
-#include <QColor>
-#include <QDebug>
+#include <cmath>
+
 #include <QImage>
 #include <QPainter>
 #include <QSize>
@@ -27,28 +27,25 @@ WaveformGenerator::~WaveformGenerator()
 {
 }
 
-QImage WaveformGenerator::calculateWaveform(const QSize &waveformSize, const QImage &image, const bool &drawAxis, const uint &accelFactor)
+QImage WaveformGenerator::calculateWaveform(const QSize &waveformSize, const QImage &image, WaveformGenerator::PaintMode paintMode,
+                                            bool drawAxis, WaveformGenerator::Rec rec, uint accelFactor)
 {
     Q_ASSERT(accelFactor >= 1);
 
-    QTime time;
-    time.start();
+    //QTime time;
+    //time.start();
 
     QImage wave(waveformSize, QImage::Format_ARGB32);
 
-    if (waveformSize.width() <= 0 || waveformSize.height() <= 0) {
-        qCritical("Waveform size should not be 0.");
+    if (waveformSize.width() <= 0 || waveformSize.height() <= 0 || image.width() <= 0 || image.height() <= 0) {
+        return QImage();
 
     } else {
 
-        qDebug() << "Waveform calculation started.";
-
         // Fill with transparent color
         wave.fill(qRgba(0,0,0,0));
 
         QRgb *col;
-        QRgb waveCol;
-        QPoint wavePoint;
 
         double dY, dx, dy;
 
@@ -58,33 +55,84 @@ QImage WaveformGenerator::calculateWaveform(const QSize &waveformSize, const QIm
         const uint ih = image.height();
         const uint byteCount = iw*ih;
 
+        uint waveValues[waveformSize.width()][waveformSize.height()];
+        for (int i = 0; i < waveformSize.width(); ++i) {
+            for (int j = 0; j < waveformSize.height(); j++) {
+                waveValues[i][j] = 0;
+            }
+        }
+
+        // Number of input pixels that will fall on one scope pixel.
+        // Must be a float because the acceleration factor can be high, leading to <1 expected px per px.
+        const float pixelDepth = (float)((byteCount>>2) / accelFactor)/(ww*wh);
+        const float gain = 255/(8*pixelDepth);
+        //qDebug() << "Pixel depth: expected " << pixelDepth << "; Gain: using " << gain << " (acceleration: " << accelFactor << "x)";
+
+
         // Subtract 1 from sizes because we start counting from 0.
         // Not doing it would result in attempts to paint outside of the image.
         const float hPrediv = (float)(wh-1)/255;
         const float wPrediv = (float)(ww-1)/(iw-1);
 
         const uchar *bits = image.bits();
-        const uint stepsize = 4*accelFactor;
+       const int bpp = image.depth() / 8;
+
+        for (uint i = 0, x = 0; i < byteCount; i += bpp) {
 
-        for (uint i = 0, x = 0; i < byteCount; i += stepsize) {
+            Q_ASSERT(bits < image.bits() + byteCount);
 
             col = (QRgb *)bits;
 
-            // CIE 601 Luminance
+            if (rec == WaveformGenerator::Rec_601) {
+                // CIE 601 Luminance
+                dY = .299*qRed(*col) + .587*qGreen(*col) + .114*qBlue(*col);
+            } else {
+                // CIE 709 Luminance
+                dY = .2125*qRed(*col) + .7154*qGreen(*col) + .0721*qBlue(*col);
+            }
             // dY is on [0,255] now.
-            dY = .299*qRed(*col) + .587*qGreen(*col) + .114*qBlue(*col);
 
             dy = dY*hPrediv;
             dx = x*wPrediv;
-            wavePoint = QPoint((int)dx, (int)(wh-1 - dy));
-
-            waveCol = QRgb(wave.pixel(wavePoint));
-            wave.setPixel(wavePoint, qRgba(CHOP255(9 + qRed(waveCol)), CHOP255(36 + qGreen(waveCol)),
-                                           CHOP255(18 + qBlue(waveCol)), 255));
+            waveValues[(int)dx][(int)dy]++;
+
+            bits += bpp;
+            x += bpp;
+            if (x > iw) {
+                x -= iw;
+                if (accelFactor > 1) {
+                    bits += bpp*iw*(accelFactor-1);
+                    i += bpp*iw*(accelFactor-1);
+                }
+            }
+        }
 
-            bits += stepsize;
-            x += stepsize;
-            x %= iw; // Modulo image width, to represent the current x position in the image
+        switch (paintMode) {
+        case PaintMode_Green:
+            for (int i = 0; i < waveformSize.width(); ++i) {
+                for (int j = 0; j < waveformSize.height(); j++) {
+                    // Logarithmic scale. Needs fine tuning by hand, but looks great.
+                    wave.setPixel(i, waveformSize.height()-j-1, qRgba(CHOP255(52*log(0.1*gain*waveValues[i][j])),
+                                                                      CHOP255(52*log(gain*waveValues[i][j])),
+                                                                      CHOP255(52*log(.25*gain*waveValues[i][j])),
+                                                                      CHOP255(64*log(gain*waveValues[i][j]))));
+                }
+            }
+            break;
+        case PaintMode_Yellow:
+            for (int i = 0; i < waveformSize.width(); ++i) {
+                for (int j = 0; j < waveformSize.height(); j++) {
+                    wave.setPixel(i, waveformSize.height()-j-1, qRgba(255,242,0,   CHOP255(gain*waveValues[i][j])));
+                }
+            }
+            break;
+        default:
+            for (int i = 0; i < waveformSize.width(); ++i) {
+                for (int j = 0; j < waveformSize.height(); j++) {
+                    wave.setPixel(i, waveformSize.height()-j-1, qRgba(255,255,255, CHOP255(2*gain*waveValues[i][j])));
+                }
+            }
+            break;
         }
 
         if (drawAxis) {
@@ -92,22 +140,23 @@ QImage WaveformGenerator::calculateWaveform(const QSize &waveformSize, const QIm
             QRgb opx;
             davinci.setPen(qRgba(150,255,200,32));
             davinci.setCompositionMode(QPainter::CompositionMode_Overlay);
-            for (uint i = 0; i <= 10; i++) {
+            for (uint i = 0; i <= 10; ++i) {
                 dy = (float)i/10 * (wh-1);
                 for (uint x = 0; x < ww; x++) {
                     opx = wave.pixel(x, dy);
                     wave.setPixel(x,dy, qRgba(CHOP255(150+qRed(opx)), 255,
                                               CHOP255(200+qBlue(opx)), CHOP255(32+qAlpha(opx))));
                 }
-                //davinci.drawLine(0, dy, ww-1, dy);
             }
         }
 
     }
 
-    uint diff = time.elapsed();
-//    qDebug() << "Waveform calculation ended. Time taken: " << diff << " ms. Sending signal now.";
-    emit signalCalculationFinished(wave, diff);
+    //uint diff = time.elapsed();
+    //emit signalCalculationFinished(wave, diff);
 
     return wave;
 }
+#undef CHOP255
+
+#include "waveformgenerator.moc"