1 /* Webcamoid, webcam capture application.
2  * Copyright (C) 2016  Gonzalo Exequiel Pedone
3  *
4  * Webcamoid is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 3 of the License, or
7  * (at your option) any later version.
8  *
9  * Webcamoid is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with Webcamoid. If not, see <http://www.gnu.org/licenses/>.
16  *
17  * Web-Site: http://webcamoid.github.io/
18  */
19 
20 #include <QtMath>
21 #include <QPainter>
22 #include <QQmlContext>
23 #include <akfrac.h>
24 #include <akpacket.h>
25 #include <akvideopacket.h>
26 
27 #include "dizzyelement.h"
28 
29 class DizzyElementPrivate
30 {
31     public:
32         qreal m_speed {5.0};
33         qreal m_zoomRate {0.02};
34         qreal m_strength {0.75};
35         QImage m_prevFrame;
36 
37         void setParams(int *dx, int *dy,
38                        int *sx, int *sy,
39                        int width, int height,
40                        qreal phase, qreal zoomRate);
41 };
42 
DizzyElement()43 DizzyElement::DizzyElement():
44     AkElement()
45 {
46     this->d = new DizzyElementPrivate;
47 }
48 
~DizzyElement()49 DizzyElement::~DizzyElement()
50 {
51     delete this->d;
52 }
53 
speed() const54 qreal DizzyElement::speed() const
55 {
56     return this->d->m_speed;
57 }
58 
zoomRate() const59 qreal DizzyElement::zoomRate() const
60 {
61     return this->d->m_zoomRate;
62 }
63 
strength() const64 qreal DizzyElement::strength() const
65 {
66     return this->d->m_strength;
67 }
68 
controlInterfaceProvide(const QString & controlId) const69 QString DizzyElement::controlInterfaceProvide(const QString &controlId) const
70 {
71     Q_UNUSED(controlId)
72 
73     return QString("qrc:/Dizzy/share/qml/main.qml");
74 }
75 
controlInterfaceConfigure(QQmlContext * context,const QString & controlId) const76 void DizzyElement::controlInterfaceConfigure(QQmlContext *context,
77                                              const QString &controlId) const
78 {
79     Q_UNUSED(controlId)
80 
81     context->setContextProperty("Dizzy", const_cast<QObject *>(qobject_cast<const QObject *>(this)));
82     context->setContextProperty("controlId", this->objectName());
83 }
84 
iVideoStream(const AkVideoPacket & packet)85 AkPacket DizzyElement::iVideoStream(const AkVideoPacket &packet)
86 {
87     auto src = packet.toImage();
88 
89     if (src.isNull())
90         return AkPacket();
91 
92     src = src.convertToFormat(QImage::Format_ARGB32);
93     QImage oFrame(src.size(), src.format());
94     oFrame.fill(0);
95 
96     if (this->d->m_prevFrame.isNull()) {
97         this->d->m_prevFrame = QImage(src.size(), src.format());
98         this->d->m_prevFrame.fill(0);
99     }
100 
101     qreal pts = 2 * M_PI * packet.pts() * packet.timeBase().value()
102                 / this->d->m_speed;
103 
104     qreal angle = (2 * M_PI / 180) * sin(pts) + (M_PI / 180) * sin(pts + 2.5);
105     qreal scale = 1.0 + this->d->m_zoomRate;
106 
107     QTransform transform;
108     transform.scale(scale, scale);
109     transform.rotateRadians(angle);
110     this->d->m_prevFrame = this->d->m_prevFrame.transformed(transform);
111 
112     QRect rect(this->d->m_prevFrame.rect());
113     rect.moveCenter(oFrame.rect().center());
114 
115     QPainter painter;
116     painter.begin(&oFrame);
117     painter.drawImage(rect, this->d->m_prevFrame);
118     painter.setOpacity(1.0 - this->d->m_strength);
119     painter.drawImage(0, 0, src);
120     painter.end();
121 
122     this->d->m_prevFrame = oFrame;
123 
124     auto oPacket = AkVideoPacket::fromImage(oFrame, packet);
125     akSend(oPacket)
126 }
127 
setSpeed(qreal speed)128 void DizzyElement::setSpeed(qreal speed)
129 {
130     if (qFuzzyCompare(this->d->m_speed, speed))
131         return;
132 
133     this->d->m_speed = speed;
134     emit this->speedChanged(speed);
135 }
136 
setZoomRate(qreal zoomRate)137 void DizzyElement::setZoomRate(qreal zoomRate)
138 {
139     if (qFuzzyCompare(this->d->m_zoomRate, zoomRate))
140         return;
141 
142     this->d->m_zoomRate = zoomRate;
143     emit this->zoomRateChanged(zoomRate);
144 }
145 
setStrength(qreal strength)146 void DizzyElement::setStrength(qreal strength)
147 {
148     if (qFuzzyCompare(this->d->m_strength, strength))
149         return;
150 
151     this->d->m_strength = strength;
152     emit this->strengthChanged(strength);
153 }
154 
resetSpeed()155 void DizzyElement::resetSpeed()
156 {
157     this->setSpeed(5.0);
158 }
159 
resetZoomRate()160 void DizzyElement::resetZoomRate()
161 {
162     this->setZoomRate(0.02);
163 }
164 
resetStrength()165 void DizzyElement::resetStrength()
166 {
167     this->setStrength(0.15);
168 }
169 
170 #include "moc_dizzyelement.cpp"
171