From: Simon A. Eugster Date: Sun, 18 Jul 2010 16:49:20 +0000 (+0000) Subject: Waveform monitor added. X-Git-Url: https://git.sesse.net/?a=commitdiff_plain;h=ae4435f6e34b423b256b38d3f480d1893650ef78;p=kdenlive Waveform monitor added. Vectorscope only calculated when visible (\!QWidget::visibleRange.isEmpty()). svn path=/trunk/kdenlive/; revision=4599 --- diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index f2ef96c2..e5c95180 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -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 index 00000000..e69de29b diff --git a/src/colorcorrection/waveformgenerator.cpp b/src/colorcorrection/waveformgenerator.cpp new file mode 100644 index 00000000..195da5ac --- /dev/null +++ b/src/colorcorrection/waveformgenerator.cpp @@ -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 +#include +#include +#include + +#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 index 00000000..10e86a94 --- /dev/null +++ b/src/colorcorrection/waveformgenerator.h @@ -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 +#include +#include + +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 diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index ccec3a7b..02358ec9 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -53,6 +53,7 @@ #include "cliptranscode.h" #include "ui_templateclip_ui.h" #include "vectorscope.h" +#include "waveform.h" #include #include @@ -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); } diff --git a/src/mainwindow.h b/src/mainwindow.h index 897e0f43..9c8e4ecd 100644 --- a/src/mainwindow.h +++ b/src/mainwindow.h @@ -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; diff --git a/src/vectorscope.cpp b/src/vectorscope.cpp index 41de1551..7e85de5e 100644 --- a/src/vectorscope.cpp +++ b/src/vectorscope.cpp @@ -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(); +} diff --git a/src/vectorscope.h b/src/vectorscope.h index 05a5b339..0a85045c 100644 --- a/src/vectorscope.h +++ b/src/vectorscope.h @@ -37,6 +37,7 @@ protected: void resizeEvent(QResizeEvent *event); void mousePressEvent(QMouseEvent *); void mouseMoveEvent(QMouseEvent *event); + void raise(); private: Monitor *m_projMonitor; diff --git a/src/waveform.cpp b/src/waveform.cpp index 0b6affb0..4b6c259f 100644 --- a/src/waveform.cpp +++ b/src/waveform.cpp @@ -1,11 +1,116 @@ +/*************************************************************************** + * 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 +#include +#include + #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(); +// } } diff --git a/src/waveform.h b/src/waveform.h index 1f403f95..3e385012 100644 --- a/src/waveform.h +++ b/src/waveform.h @@ -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 #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 diff --git a/src/widgets/waveform_ui.ui b/src/widgets/waveform_ui.ui index 5e7f852c..c2f31361 100644 --- a/src/widgets/waveform_ui.ui +++ b/src/widgets/waveform_ui.ui @@ -185,6 +185,48 @@ Form + + + 5 + + + + + + 0 + 0 + + + + + + + + Paint mode + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + Qt::Horizontal + + + +