]> git.sesse.net Git - kdenlive/commitdiff
Waveform monitor added.
authorSimon A. Eugster <simon.eu@gmail.com>
Sun, 18 Jul 2010 16:49:20 +0000 (16:49 +0000)
committerSimon A. Eugster <simon.eu@gmail.com>
Sun, 18 Jul 2010 16:49:20 +0000 (16:49 +0000)
Vectorscope only calculated when visible (\!QWidget::visibleRange.isEmpty()).

svn path=/trunk/kdenlive/; revision=4599

src/CMakeLists.txt
src/colorcorrection/CMakeLists.txt [new file with mode: 0644]
src/colorcorrection/waveformgenerator.cpp [new file with mode: 0644]
src/colorcorrection/waveformgenerator.h [new file with mode: 0644]
src/mainwindow.cpp
src/mainwindow.h
src/vectorscope.cpp
src/vectorscope.h
src/waveform.cpp
src/waveform.h
src/widgets/waveform_ui.ui

index f2ef96c2c8e8c9fe00750dc38bb83465bbb4de6f..e5c951802f7d19abf8eb82d8acc9fb2b02bbfeb5 100644 (file)
@@ -26,6 +26,7 @@ include_directories (
     ${CMAKE_BINARY_DIR}
 
     ${CMAKE_SOURCE_DIR}/src/widgets
+    ${CMAKE_SOURCE_DIR}/src/colorcorrection
 )
 
 LINK_LIBRARIES(
@@ -198,8 +199,12 @@ set(kdenlive_SRCS
   colortools.cpp
   rebuildgroupcommand.cpp
   waveform.cpp
+  colorcorrection/waveformgenerator.cpp
 )
 
+
+add_subdirectory( ${CMAKE_SOURCE_DIR}/src/colorcorrection )
+
 add_definitions( ${KDE4_DEFINITIONS} )
 
 if(NO_JOGSHUTTLE)
diff --git a/src/colorcorrection/CMakeLists.txt b/src/colorcorrection/CMakeLists.txt
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/src/colorcorrection/waveformgenerator.cpp b/src/colorcorrection/waveformgenerator.cpp
new file mode 100644 (file)
index 0000000..195da5a
--- /dev/null
@@ -0,0 +1,109 @@
+/***************************************************************************
+ *   Copyright (C) 2010 by Simon Andreas Eugster (simon.eu@gmail.com)      *
+ *   This file is part of kdenlive. See www.kdenlive.org.                  *
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version.                                   *
+ ***************************************************************************/
+
+#include <QDebug>
+#include <QTime>
+#include <QColor>
+#include <QPainter>
+
+#include "waveformgenerator.h"
+
+#define CHOP255(a) ((255) < (a) ? (255) : (a))
+
+WaveformGenerator::WaveformGenerator()
+{
+}
+
+WaveformGenerator::~WaveformGenerator()
+{
+}
+
+QImage WaveformGenerator::calculateWaveform(const QSize &waveformSize, const QImage &image, const bool &drawAxis)
+{
+    QTime time;
+    time.start();
+
+    QImage wave(waveformSize, QImage::Format_ARGB32);
+
+    if (waveformSize.width() <= 0 || waveformSize.height() <= 0) {
+        qCritical("Waveform size should not be 0.");
+
+    } 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;
+
+        const uint ww = waveformSize.width();
+        const uint wh = waveformSize.height();
+        const uint iw = image.bytesPerLine();
+        const uint ih = image.height();
+        const uint byteCount = iw*ih;
+
+        // 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;
+
+        for (uint i = 0, x = 0; i < byteCount; i += stepsize) {
+
+            col = (QRgb *)bits;
+
+            // CIE 601 Luminance
+            // 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));
+
+            bits += stepsize;
+            x += stepsize;
+            x %= iw;
+        }
+
+        if (drawAxis) {
+            QPainter davinci(&wave);
+            QRgb opx;
+            davinci.setPen(qRgba(150,255,200,32));
+            davinci.setCompositionMode(QPainter::CompositionMode_Overlay);
+            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);
+
+    return wave;
+}
diff --git a/src/colorcorrection/waveformgenerator.h b/src/colorcorrection/waveformgenerator.h
new file mode 100644 (file)
index 0000000..10e86a9
--- /dev/null
@@ -0,0 +1,33 @@
+/***************************************************************************
+ *   Copyright (C) 2010 by Simon Andreas Eugster (simon.eu@gmail.com)      *
+ *   This file is part of kdenlive. See www.kdenlive.org.                  *
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version.                                   *
+ ***************************************************************************/
+
+#ifndef WAVEFORMGENERATOR_H
+#define WAVEFORMGENERATOR_H
+
+#include <QObject>
+#include <QImage>
+#include <QSize>
+
+class WaveformGenerator : public QObject
+{
+    Q_OBJECT
+
+public:
+    WaveformGenerator();
+    ~WaveformGenerator();
+
+    QImage calculateWaveform(const QSize &waveformSize, const QImage &image, const bool &drawAxis);
+
+signals:
+    void signalCalculationFinished(QImage image, const uint &ms);
+
+};
+
+#endif // WAVEFORMGENERATOR_H
index ccec3a7bb1f27d7f3bc64241f1e7900bbcb6f9ee..02358ec9ed8346e32b34f8e3295d06c15fefd967 100644 (file)
@@ -53,6 +53,7 @@
 #include "cliptranscode.h"
 #include "ui_templateclip_ui.h"
 #include "vectorscope.h"
+#include "waveform.h"
 
 #include <KApplication>
 #include <KAction>
@@ -219,6 +220,12 @@ MainWindow::MainWindow(const QString &MltPath, const KUrl & Url, QWidget *parent
     m_vectorscopeDock->setWidget(m_vectorscope);
     addDockWidget(Qt::TopDockWidgetArea, m_vectorscopeDock);
 
+    m_waveform = new Waveform(m_projectMonitor, m_clipMonitor, this);
+    m_waveformDock = new QDockWidget(i18n("Waveform"), this);
+    m_waveformDock->setObjectName("waveform");
+    m_waveformDock->setWidget(m_waveform);
+    addDockWidget(Qt::TopDockWidgetArea, m_waveformDock);
+
 
     m_undoViewDock = new QDockWidget(i18n("Undo History"), this);
     m_undoViewDock->setObjectName("undo_history");
@@ -248,6 +255,7 @@ MainWindow::MainWindow(const QString &MltPath, const KUrl & Url, QWidget *parent
     tabifyDockWidget(m_clipMonitorDock, m_recMonitorDock);
 #endif
 
+    tabifyDockWidget(m_vectorscopeDock, m_waveformDock);
     tabifyDockWidget(m_vectorscopeDock, m_undoViewDock);
     tabifyDockWidget(m_vectorscopeDock, m_effectListDock);
 
@@ -407,6 +415,7 @@ MainWindow::MainWindow(const QString &MltPath, const KUrl & Url, QWidget *parent
     //connect(m_monitorManager, SIGNAL(connectMonitors()), this, SLOT(slotConnectMonitors()));
     connect(m_monitorManager, SIGNAL(raiseClipMonitor(bool)), this, SLOT(slotRaiseMonitor(bool)));
     connect(m_monitorManager, SIGNAL(raiseClipMonitor(bool)), m_vectorscope, SLOT(slotActiveMonitorChanged(bool)));
+    connect(m_monitorManager, SIGNAL(raiseClipMonitor(bool)), m_waveform, SLOT(slotActiveMonitorChanged(bool)));
     connect(m_effectList, SIGNAL(addEffect(const QDomElement)), this, SLOT(slotAddEffect(const QDomElement)));
     connect(m_effectList, SIGNAL(reloadEffects()), this, SLOT(slotReloadEffects()));
 
@@ -3593,6 +3602,7 @@ void MainWindow::slotShowTitleBars(bool show)
         m_projectListDock->setTitleBarWidget(0);
         m_undoViewDock->setTitleBarWidget(0);
         m_vectorscopeDock->setTitleBarWidget(0);
+        m_waveformDock->setTitleBarWidget(0);
     } else {
         if (!m_effectStackDock->isFloating()) { m_effectStackDock->setTitleBarWidget(new QWidget(this)); }
         if (!m_clipMonitorDock->isFloating()) { m_clipMonitorDock->setTitleBarWidget(new QWidget(this)); }
@@ -3605,6 +3615,7 @@ void MainWindow::slotShowTitleBars(bool show)
         if (!m_projectListDock->isFloating()) { m_projectListDock->setTitleBarWidget(new QWidget(this)); }
         if (!m_undoViewDock->isFloating()) { m_undoViewDock->setTitleBarWidget(new QWidget(this)); }
         if (!m_vectorscopeDock->isFloating()) { m_vectorscopeDock->setTitleBarWidget(new QWidget(this)); }
+        if (!m_waveformDock->isFloating()) { m_waveformDock->setTitleBarWidget(new QWidget(this)); }
     }
     KdenliveSettings::setShowtitlebars(show);
 }
index 897e0f43602fd8af1a4d9b633f87c88b935329bf..9c8e4ecd06c3db8089813f456064d559cc226e48 100644 (file)
@@ -62,6 +62,7 @@ class DocClipBase;
 class Render;
 class Transition;
 class Vectorscope;
+class Waveform;
 class KActionCollection;
 
 class MainWindow : public KXmlGuiWindow
@@ -154,6 +155,9 @@ private:
     QDockWidget *m_vectorscopeDock;
     Vectorscope *m_vectorscope;
 
+    QDockWidget *m_waveformDock;
+    Waveform *m_waveform;
+
     QDockWidget *m_undoViewDock;
     QUndoView *m_undoView;
     QUndoGroup *m_commandStack;
index 41de1551d0407d7a26cf19fb2a01f8d0cdecd4a9..7e85de5e74039dbbc786ee7a52836596c6c25409 100644 (file)
@@ -177,7 +177,10 @@ QPoint Vectorscope::mapToCanvas(QRect inside, QPointF point)
 bool Vectorscope::prodCalcThread()
 {
     bool ok = false;
-    if (m_scopeCalcThread.isRunning()) {
+    if (this->visibleRegion().isEmpty()) {
+        qDebug() << "Nothing to see here. Other widget lying on top of Vectorscope. No need to render.";
+        ok = false;
+    } else if (m_scopeCalcThread.isRunning()) {
         qDebug() << "Calc thread still running.";
         ok = false;
     } else {
@@ -551,7 +554,9 @@ void Vectorscope::slotActiveMonitorChanged(bool isClipMonitor)
 
 void Vectorscope::slotRenderZoneUpdated()
 {
-    qDebug() << "Monitor incoming. New frames total: " << newFrames;
+    qDebug() << "Monitor incoming. New frames total: " << newFrames << ", visible: " << this->isVisible();
+    QRegion region = this->visibleRegion();
+    qDebug() << "Visible region: empty? " << region.isEmpty() << ", size: " << region.boundingRect().width() << "x" << region.boundingRect().height();
     // Monitor has shown a new frame
     newFrames.fetchAndAddRelaxed(1);
     if (cbAutoRefresh->isChecked()) {
@@ -686,3 +691,10 @@ void Vectorscope::resizeEvent(QResizeEvent *event)
     prodWheelThread();
     QWidget::resizeEvent(event);
 }
+
+void Vectorscope::raise()
+{
+    qDebug() << "Raised. Prodding calc thread.";
+    prodCalcThread();
+    QWidget::raise();
+}
index 05a5b3394f6bb078a0241ba13ce3f14930f736a3..0a85045c302622fac3402c5eaf15f85ada87bcb6 100644 (file)
@@ -37,6 +37,7 @@ protected:
     void resizeEvent(QResizeEvent *event);
     void mousePressEvent(QMouseEvent *);
     void mouseMoveEvent(QMouseEvent *event);
+    void raise();
 
 private:
     Monitor *m_projMonitor;
index 0b6affb01aa2d631be9c0f0766bd2cabf265edc0..4b6c259f006b5cdcbf5431864891586f7ed55732 100644 (file)
+/***************************************************************************
+ *   Copyright (C) 2010 by Simon Andreas Eugster (simon.eu@gmail.com)      *
+ *   This file is part of kdenlive. See www.kdenlive.org.                  *
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version.                                   *
+ ***************************************************************************/
+
+#include <QPainter>
+#include <QPoint>
+#include <QDebug>
+
 #include "waveform.h"
 
-Waveform::Waveform(QWidget *parent) :
-    QWidget(parent)
+
+Waveform::Waveform(Monitor *projMonitor, Monitor *clipMonitor, QWidget *parent) :
+    QWidget(parent),
+    m_projMonitor(projMonitor),
+    m_clipMonitor(clipMonitor),
+    m_activeRender(clipMonitor->render),
+    initialDimensionUpdateDone(false)
 {
     setupUi(this);
+    m_waveformGenerator = new WaveformGenerator();
+
+    connect(m_waveformGenerator, SIGNAL(signalCalculationFinished(QImage,uint)), this, SLOT(slotWaveformCalculated(QImage,uint)));
 }
 
 Waveform::~Waveform()
 {
+    delete m_waveformGenerator;
+}
+
+
+
+void Waveform::updateDimensions()
+{
+    // Distance from top/left/right
+    int offset = 6;
+
+    QPoint topleft(offset, line->y()+offset);
+
+    m_scopeRect = QRect(topleft, this->size() - QSize(offset+topleft.x(), offset+topleft.y()));
+}
+
+
+///// Events /////
+
+void Waveform::paintEvent(QPaintEvent *)
+{
+    if (!initialDimensionUpdateDone) {
+        // This is a workaround.
+        // When updating the dimensions in the constructor, the size
+        // of the control items at the top are simply ignored! So do
+        // it here instead.
+        updateDimensions();
+        initialDimensionUpdateDone = true;
+    }
+
+    QPainter davinci(this);
+    QPoint vinciPoint;
+
+    davinci.setRenderHint(QPainter::Antialiasing, true);
+    davinci.fillRect(0, 0, this->size().width(), this->size().height(), QColor(25,25,23));
+
+    davinci.drawImage(m_scopeRect.topLeft(), m_waveform);
+
+}
+
+void Waveform::resizeEvent(QResizeEvent *event)
+{
+    updateDimensions();
+    m_waveformGenerator->calculateWaveform(m_scopeRect.size(), m_activeRender->extractFrame(m_activeRender->seekFramePosition()), true);
+    QWidget::resizeEvent(event);
+}
+
+void Waveform::mouseReleaseEvent(QMouseEvent *)
+{
+    qDebug() << "Calculating scope now. Size: " << m_scopeRect.size().width() << "x" << m_scopeRect.size().height();
+    m_waveformGenerator->calculateWaveform(m_scopeRect.size(), m_activeRender->extractFrame(m_activeRender->seekFramePosition()), true);
+}
+
+
+///// Slots /////
+
+void Waveform::slotWaveformCalculated(QImage waveform, const uint &msec)
+{
+    qDebug() << "Waveform received. Time taken for rendering: " << msec << " ms. Painting it.";
+    m_waveform = waveform;
+    this->update();
+}
+
+void Waveform::slotActiveMonitorChanged(bool isClipMonitor)
+{
+    if (isClipMonitor) {
+        m_activeRender = m_clipMonitor->render;
+        disconnect(this, SLOT(slotRenderZoneUpdated()));
+        connect(m_activeRender, SIGNAL(rendererPosition(int)), this, SLOT(slotRenderZoneUpdated()));
+    } else {
+        m_activeRender = m_projMonitor->render;
+        disconnect(this, SLOT(slotRenderZoneUpdated()));
+        connect(m_activeRender, SIGNAL(rendererPosition(int)), this, SLOT(slotRenderZoneUpdated()));
+    }
+}
+
+void Waveform::slotRenderZoneUpdated()
+{
+    qDebug() << "Monitor incoming.";//New frames total: " << newFrames;
+    // Monitor has shown a new frame
+//    newFrames.fetchAndAddRelaxed(1);
+//    if (cbAutoRefresh->isChecked()) {
+//        prodCalcThread();
+//    }
 }
index 1f403f95435660c56437c961379516ce9a1d4d4c..3e385012257a2eaa3fa9fb33997affcdaaeac0e2 100644 (file)
@@ -1,19 +1,58 @@
+/***************************************************************************
+ *   Copyright (C) 2010 by Simon Andreas Eugster (simon.eu@gmail.com)      *
+ *   This file is part of kdenlive. See www.kdenlive.org.                  *
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version.                                   *
+ ***************************************************************************/
+
 #ifndef WAVEFORM_H
 #define WAVEFORM_H
 
 #include <QWidget>
 
 #include "ui_waveform_ui.h"
+#include "renderer.h"
+#include "monitor.h"
+#include "waveformgenerator.h"
 
 class Waveform_UI;
+class WaveformGenerator;
+class Render;
+class Monitor;
 
 class Waveform : public QWidget, public Ui::Waveform_UI {
     Q_OBJECT
 
 public:
-    Waveform(QWidget *parent = 0);
+    Waveform(Monitor *projMonitor, Monitor *clipMonitor, QWidget *parent = 0);
     ~Waveform();
 
+protected:
+    void paintEvent(QPaintEvent *);
+    void resizeEvent(QResizeEvent *);
+    void mouseReleaseEvent(QMouseEvent *);
+
+private:
+    Monitor *m_projMonitor;
+    Monitor *m_clipMonitor;
+    Render *m_activeRender;
+
+    WaveformGenerator *m_waveformGenerator;
+
+    void updateDimensions();
+    bool initialDimensionUpdateDone;
+
+    QRect m_scopeRect;
+    QImage m_waveform;
+
+private slots:
+    void slotActiveMonitorChanged(bool isClipMonitor);
+    void slotRenderZoneUpdated();
+    void slotWaveformCalculated(QImage waveform, const uint &msec);
+
 };
 
 #endif // WAVEFORM_H
index 5e7f852c3d035824886ea962deac59815e7453e6..c2f31361986980e136a434a5b1ea6be3d7387aa9 100644 (file)
   <property name="windowTitle">
    <string>Form</string>
   </property>
+  <layout class="QGridLayout" name="gridLayout">
+   <property name="horizontalSpacing">
+    <number>5</number>
+   </property>
+   <item row="0" column="1">
+    <widget class="QComboBox" name="paintMode">
+     <property name="sizePolicy">
+      <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
+       <horstretch>0</horstretch>
+       <verstretch>0</verstretch>
+      </sizepolicy>
+     </property>
+    </widget>
+   </item>
+   <item row="0" column="0">
+    <widget class="QLabel" name="lblPaintMode">
+     <property name="text">
+      <string>Paint mode</string>
+     </property>
+    </widget>
+   </item>
+   <item row="2" column="1">
+    <spacer name="verticalSpacer">
+     <property name="orientation">
+      <enum>Qt::Vertical</enum>
+     </property>
+     <property name="sizeHint" stdset="0">
+      <size>
+       <width>20</width>
+       <height>40</height>
+      </size>
+     </property>
+    </spacer>
+   </item>
+   <item row="1" column="0" colspan="2">
+    <widget class="Line" name="line">
+     <property name="orientation">
+      <enum>Qt::Horizontal</enum>
+     </property>
+    </widget>
+   </item>
+  </layout>
  </widget>
  <resources/>
  <connections/>