Commit ae4435f6 authored by Simon Eugster's avatar Simon Eugster
Browse files

Waveform monitor added.

Vectorscope only calculated when visible (\!QWidget::visibleRange.isEmpty()).

svn path=/trunk/kdenlive/; revision=4599
parent 97e1fc1a
......@@ -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)
......
/***************************************************************************
* 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;
}
/***************************************************************************
* 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
......@@ -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);
}
......
......@@ -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;
......
......@@ -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();
}
......@@ -37,6 +37,7 @@ protected:
void resizeEvent(QResizeEvent *event);
void mousePressEvent(QMouseEvent *);
void mouseMoveEvent(QMouseEvent *event);
void raise();
private:
Monitor *m_projMonitor;
......
/***************************************************************************
* 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();
// }
}
/***************************************************************************
* 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
......@@ -185,6 +185,48 @@
<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/>
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment