• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

mcallegari / qlcplus / 13763878004

10 Mar 2025 11:47AM UTC coverage: 31.887%. Remained the same
13763878004

push

github

mcallegari
4.14.1 release to date

14701 of 46103 relevant lines covered (31.89%)

26418.09 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/engine/src/video.cpp
1
/*
2
  Q Light Controller Plus
3
  video.cpp
4

5
  Copyright (c) Massimo Callegari
6

7
  Licensed under the Apache License, Version 2.0 (the "License");
8
  you may not use this file except in compliance with the License.
9
  You may obtain a copy of the License at
10

11
      http://www.apache.org/licenses/LICENSE-2.0.txt
12

13
  Unless required by applicable law or agreed to in writing, software
14
  distributed under the License is distributed on an "AS IS" BASIS,
15
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
  See the License for the specific language governing permissions and
17
  limitations under the License.
18
*/
19

20
#include <QXmlStreamReader>
21
#include <QXmlStreamWriter>
22
#include <QMediaPlayer>
23
#include <QDebug>
24
#include <QFile>
25

26
#include "video.h"
27
#include "doc.h"
28

29
#define KXMLQLCVideoSource      QString("Source")
30
#define KXMLQLCVideoScreen      QString("Screen")
31
#define KXMLQLCVideoFullscreen  QString("Fullscreen")
32
#define KXMLQLCVideoGeometry    QString("Geometry")
33
#define KXMLQLCVideoRotation    QString("Rotation")
34
#define KXMLQLCVideoZIndex      QString("ZIndex")
35

36
const QStringList Video::m_defaultVideoCaps =
37
        QStringList() << "*.avi" << "*.wmv" << "*.mkv" << "*.mp4" << "*.mov" << "*.mpg" << "*.mpeg" << "*.flv" << "*.webm";
38
const QStringList Video::m_defaultPictureCaps =
39
        QStringList() << "*.png" << "*.bmp" << "*.jpg" << "*.jpeg" << "*.gif";
40

41
/*****************************************************************************
42
 * Initialization
43
 *****************************************************************************/
44

45
Video::Video(Doc* doc)
×
46
  : Function(doc, Function::VideoType)
47
  , m_doc(doc)
×
48
  , m_sourceUrl("")
×
49
  , m_isPicture(false)
×
50
  , m_videoDuration(0)
×
51
  , m_resolution(QSize(0,0))
52
  , m_customGeometry(QRect())
53
  , m_rotation(QVector3D(0, 0, 0))
54
  , m_zIndex(1)
×
55
  , m_screen(0)
×
56
  , m_fullscreen(false)
×
57
{
58
    setName(tr("New Video"));
×
59
    setRunOrder(Video::SingleShot);
×
60

61
    registerAttribute(tr("Volume"), Function::LastWins, 0, 100, 100);
×
62
    registerAttribute(tr("X Rotation"), Function::LastWins, -360.0, 360.0, 0.0);
×
63
    registerAttribute(tr("Y Rotation"), Function::LastWins, -360.0, 360.0, 0.0);
×
64
    registerAttribute(tr("Z Rotation"), Function::LastWins, -360.0, 360.0, 0.0);
×
65
    registerAttribute(tr("X Position"), Function::LastWins, -100.0, 100.0, 0.0);
×
66
    registerAttribute(tr("Y Position"), Function::LastWins, -100.0, 100.0, 0.0);
×
67
    registerAttribute(tr("Width scale"), Function::LastWins, 0, 1000.0, 100.0);
×
68
    registerAttribute(tr("Height scale"), Function::LastWins, 0, 1000.0, 100.0);
×
69

70
    // Listen to member Function removals
71
    connect(doc, SIGNAL(functionRemoved(quint32)),
×
72
            this, SLOT(slotFunctionRemoved(quint32)));
73
}
×
74

75
Video::~Video()
×
76
{
77
}
×
78

79
QIcon Video::getIcon() const
×
80
{
81
    return QIcon(":/video.png");
×
82
}
83

84
/*****************************************************************************
85
 * Copying
86
 *****************************************************************************/
87

88
Function* Video::createCopy(Doc* doc, bool addToDoc)
×
89
{
90
    Q_ASSERT(doc != NULL);
91

92
    Function* copy = new Video(doc);
×
93
    if (copy->copyFrom(this) == false)
×
94
    {
95
        delete copy;
×
96
        copy = NULL;
97
    }
98
    if (addToDoc == true && doc->addFunction(copy) == false)
×
99
    {
100
        delete copy;
×
101
        copy = NULL;
102
    }
103

104
    return copy;
×
105
}
106

107
bool Video::copyFrom(const Function* function)
×
108
{
109
    const Video* vid = qobject_cast<const Video*> (function);
110
    if (vid == NULL)
×
111
        return false;
112

113
    setSourceUrl(vid->m_sourceUrl);
×
114
    m_videoDuration = vid->m_videoDuration;
×
115

116
    return Function::copyFrom(function);
×
117
}
118

119
QStringList Video::getVideoCapabilities()
×
120
{
121
    QStringList caps;
122
    QStringList mimeTypes;
123
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
124
    mimeTypes = QMediaPlayer::supportedMimeTypes();
×
125
#endif
126

127
    if (mimeTypes.isEmpty())
×
128
    {
129
        return m_defaultVideoCaps;
130
    }
131
    else
132
    {
133
        qDebug() << "Supported video types:" << mimeTypes;
134

135
        foreach (QString mime, mimeTypes)
×
136
        {
137
            if (mime.startsWith("video/"))
×
138
            {
139
                if (mime.endsWith("/3gpp")) caps << "*.3gp";
×
140
                else if (mime.endsWith("/mp4")) caps << "*.mp4";
×
141
                else if (mime.endsWith("/avi")) caps << "*.avi";
×
142
                else if (mime.endsWith("/m2ts")) caps << "*.m2ts";
×
143
                else if (mime.endsWith("m4v")) caps << "*.m4v";
×
144
                else if (mime.endsWith("/mpeg")) caps << "*.mpeg";
×
145
                else if (mime.endsWith("/mpg")) caps << "*.mpg";
×
146
                else if (mime.endsWith("/quicktime")) caps << "*.mov";
×
147
                else if (mime.endsWith("/webm")) caps << "*.webm";
×
148
                else if (mime.endsWith("matroska")) caps << "*.mkv";
×
149
            }
150
        }
×
151
    }
152
    return caps;
153
}
154

155
QStringList Video::getPictureCapabilities()
×
156
{
157
    return m_defaultPictureCaps;
×
158
}
159

160
/*********************************************************************
161
 * Properties
162
 *********************************************************************/
163
void Video::setTotalDuration(quint32 duration)
×
164
{
165
    if (m_videoDuration == (qint64)duration)
×
166
        return;
167

168
    m_videoDuration = (qint64)duration;
×
169
    emit totalTimeChanged(m_videoDuration);
×
170
}
171

172
quint32 Video::totalDuration()
×
173
{
174
    return (quint32)m_videoDuration;
×
175
}
176

177
QSize Video::resolution()
×
178
{
179
    return m_resolution;
×
180
}
181

182
void Video::setResolution(QSize size)
×
183
{
184
    m_resolution = size;
×
185
    emit metaDataChanged("Resolution", QVariant(m_resolution));
×
186
}
×
187

188
QRect Video::customGeometry()
×
189
{
190
    return m_customGeometry;
×
191
}
192

193
void Video::setCustomGeometry(QRect rect)
×
194
{
195
    if (rect == m_customGeometry)
×
196
        return;
197

198
    m_customGeometry = rect;
×
199
    emit customGeometryChanged(rect);
×
200
}
201

202
QVector3D Video::rotation() const
×
203
{
204
    return m_rotation;
×
205
}
206

207
void Video::setRotation(QVector3D rotation)
×
208
{
209
    if (m_rotation == rotation)
210
        return;
211

212
    m_rotation = rotation;
×
213
    emit rotationChanged(m_rotation);
×
214
}
215

216
int Video::zIndex() const
×
217
{
218
    return m_zIndex;
×
219
}
220

221
void Video::setZIndex(int idx)
×
222
{
223
    if (m_zIndex == idx)
×
224
        return;
225

226
    m_zIndex = idx;
×
227
    emit zIndexChanged(m_zIndex);
×
228
}
229

230
void Video::setAudioCodec(QString codec)
×
231
{
232
    m_audioCodec = codec;
×
233
    emit metaDataChanged("AudioCodec", QVariant(m_audioCodec));
×
234
}
×
235

236
QString Video::audioCodec()
×
237
{
238
    return m_audioCodec;
×
239
}
240

241
void Video::setVideoCodec(QString codec)
×
242
{
243
    m_videoCodec = codec;
×
244
    emit metaDataChanged("VideoCodec", QVariant(m_videoCodec));
×
245
}
×
246

247
QString Video::videoCodec()
×
248
{
249
    return m_videoCodec;
×
250
}
251

252
bool Video::setSourceUrl(QString filename)
×
253
{
254
    m_sourceUrl = filename;
×
255
    qDebug() << Q_FUNC_INFO << "Source name set:" << m_sourceUrl;
256

257
    QString fileExt = "*" + filename.mid(filename.lastIndexOf('.'));
×
258

259
    if (m_defaultPictureCaps.contains(fileExt))
×
260
    {
261
        m_isPicture = true;
×
262
        setZIndex(2);
×
263
    }
264

265
    if (m_sourceUrl.contains("://"))
×
266
    {
267
        QUrl url(m_sourceUrl);
×
268
        setName(url.fileName());
×
269
    }
×
270
    else
271
    {
272
        if (QFile(m_sourceUrl).exists())
×
273
        {
274
            setName(QFileInfo(m_sourceUrl).fileName());
×
275
        }
276
        else
277
        {
278
            doc()->appendToErrorLog(tr("Video file <b>%1</b> not found").arg(m_sourceUrl));
×
279
            setName(tr("File not found"));
×
280
        }
281
    }
282

283
    emit sourceChanged(m_sourceUrl);
×
284

285
    return true;
×
286
}
×
287

288
bool Video::isPicture() const
×
289
{
290
    return m_isPicture;
×
291
}
292

293
QString Video::sourceUrl()
×
294
{
295
    return m_sourceUrl;
×
296
}
297

298
void Video::setScreen(int index)
×
299
{
300
    m_screen = index;
×
301
    emit changed(id());
×
302
}
×
303

304
int Video::screen()
×
305
{
306
    return m_screen;
×
307
}
308

309
void Video::setFullscreen(bool enable)
×
310
{
311
    if (m_fullscreen == enable)
×
312
        return;
313

314
    m_fullscreen = enable;
×
315
    emit changed(id());
×
316
}
317

318
qreal Video::intensity()
×
319
{
320
    return getAttributeValue(Intensity);
×
321
}
322

323
bool Video::fullscreen()
×
324
{
325
    return m_fullscreen;
×
326
}
327

328
int Video::adjustAttribute(qreal fraction, int attributeId)
×
329
{
330
    int attrIndex = Function::adjustAttribute(fraction, attributeId);
×
331

332
    switch (attrIndex)
×
333
    {
334
        case Intensity:
×
335
        {
336
            int b = -100 - (int)((qreal)-100.0 * getAttributeValue(Intensity));
×
337
            emit requestBrightnessAdjust(b);
×
338
            emit intensityChanged();
×
339
        }
340
        break;
×
341
        default:
342
        break;
343
    }
344

345
    return attrIndex;
×
346
}
347

348
void Video::slotFunctionRemoved(quint32 fid)
×
349
{
350
    Q_UNUSED(fid)
351
}
×
352

353
/*********************************************************************
354
 * Save & Load
355
 *********************************************************************/
356

357
bool Video::saveXML(QXmlStreamWriter *doc)
×
358
{
359
    Q_ASSERT(doc != NULL);
360

361
    /* Function tag */
362
    doc->writeStartElement(KXMLQLCFunction);
×
363

364
    /* Common attributes */
365
    saveXMLCommon(doc);
×
366

367
    /* Speed */
368
    saveXMLSpeed(doc);
×
369

370
    /* Playback mode */
371
    saveXMLRunOrder(doc);
×
372

373
    doc->writeStartElement(KXMLQLCVideoSource);
×
374
    if (m_screen > 0)
×
375
        doc->writeAttribute(KXMLQLCVideoScreen, QString::number(m_screen));
×
376
    if (m_fullscreen == true)
×
377
        doc->writeAttribute(KXMLQLCVideoFullscreen, "1");
×
378
#ifdef QMLUI
379
    if (m_customGeometry.isNull() == false)
380
    {
381
        QString rect = QString("%1,%2,%3,%4")
382
                .arg(m_customGeometry.x()).arg(m_customGeometry.y())
383
                .arg(m_customGeometry.width()).arg(m_customGeometry.height());
384
        doc->writeAttribute(KXMLQLCVideoGeometry, rect);
385
    }
386
    if (m_rotation.isNull() == false)
387
    {
388
        QString rot = QString("%1,%2,%3").arg(m_rotation.x()).arg(m_rotation.y()).arg(m_rotation.z());
389
        doc->writeAttribute(KXMLQLCVideoRotation, rot);
390
    }
391
    doc->writeAttribute(KXMLQLCVideoZIndex, QString::number(m_zIndex));
392
#endif
393
    if (m_sourceUrl.contains("://"))
×
394
        doc->writeCharacters(m_sourceUrl);
×
395
    else
396
        doc->writeCharacters(m_doc->normalizeComponentPath(m_sourceUrl));
×
397

398
    doc->writeEndElement();
×
399

400
    /* End the <Function> tag */
401
    doc->writeEndElement();
×
402

403
    return true;
×
404
}
405

406
bool Video::loadXML(QXmlStreamReader &root)
×
407
{
408
    if (root.name() != KXMLQLCFunction)
×
409
    {
410
        qWarning() << Q_FUNC_INFO << "Function node not found";
×
411
        return false;
×
412
    }
413

414
    if (root.attributes().value(KXMLQLCFunctionType).toString() != typeToString(Function::VideoType))
×
415
    {
416
        qWarning() << Q_FUNC_INFO << root.attributes().value(KXMLQLCFunctionType).toString()
×
417
                   << "is not Video";
×
418
        return false;
×
419
    }
420

421
    QString fname = name();
×
422

423
    while (root.readNextStartElement())
×
424
    {
425
        if (root.name() == KXMLQLCVideoSource)
×
426
        {
427
            QXmlStreamAttributes attrs = root.attributes();
×
428
            if (attrs.hasAttribute(KXMLQLCVideoScreen))
×
429
                setScreen(attrs.value(KXMLQLCVideoScreen).toString().toInt());
×
430

431
            if (attrs.hasAttribute(KXMLQLCVideoFullscreen))
×
432
            {
433
                if (attrs.value(KXMLQLCVideoFullscreen).toString() == "1")
×
434
                    setFullscreen(true);
×
435
                else
436
                    setFullscreen(false);
×
437
            }
438
#ifdef QMLUI
439
            if (attrs.hasAttribute(KXMLQLCVideoGeometry))
440
            {
441
                QStringList slist = attrs.value(KXMLQLCVideoGeometry).toString().split(",");
442
                if (slist.count() == 4)
443
                {
444
                    QRect r;
445
                    r.setX(slist.at(0).toInt());
446
                    r.setY(slist.at(1).toInt());
447
                    r.setWidth(slist.at(2).toInt());
448
                    r.setHeight(slist.at(3).toInt());
449

450
                    setCustomGeometry(r);
451
                }
452
            }
453
            if (attrs.hasAttribute(KXMLQLCVideoRotation))
454
            {
455
                QStringList slist = attrs.value(KXMLQLCVideoRotation).toString().split(",");
456
                if (slist.count() == 3)
457
                {
458
                    QVector3D v;
459
                    v.setX(slist.at(0).toInt());
460
                    v.setY(slist.at(1).toInt());
461
                    v.setZ(slist.at(2).toInt());
462
                    setRotation(v);
463
                }
464
            }
465
            if (attrs.hasAttribute(KXMLQLCVideoZIndex))
466
            {
467
                setZIndex(attrs.value(KXMLQLCVideoZIndex).toInt());
468
            }
469
#endif
470

471
            QString path = root.readElementText();
×
472
            if (path.contains("://") == true)
×
473
                setSourceUrl(path);
×
474
            else
475
                setSourceUrl(m_doc->denormalizeComponentPath(path));
×
476
        }
×
477
        else if (root.name() == KXMLQLCFunctionSpeed)
×
478
        {
479
            loadXMLSpeed(root);
×
480
        }
481
        else if (root.name() == KXMLQLCFunctionRunOrder)
×
482
        {
483
            loadXMLRunOrder(root);
×
484
        }
485
        else
486
        {
487
            qWarning() << Q_FUNC_INFO << "Unknown Video tag:" << root.name();
×
488
            root.skipCurrentElement();
×
489
        }
490
    }
491

492
    setName(fname);
×
493

494
    return true;
495
}
×
496

497
void Video::postLoad()
×
498
{
499
}
×
500

501
/*********************************************************************
502
 * Running
503
 *********************************************************************/
504
void Video::preRun(MasterTimer* timer)
×
505
{
506
    emit requestPlayback();
×
507
    Function::preRun(timer);
×
508
}
×
509

510
void Video::setPause(bool enable)
×
511
{
512
    if (isRunning())
×
513
    {
514
        emit requestPause(enable);
×
515
        Function::setPause(enable);
×
516
    }
517
}
×
518

519
void Video::write(MasterTimer* timer, QList<Universe *> universes)
×
520
{
521
    Q_UNUSED(timer)
522
    Q_UNUSED(universes)
523

524
    incrementElapsed();
×
525
}
×
526

527
void Video::postRun(MasterTimer* timer, QList<Universe*> universes)
×
528
{
529
    emit requestStop();
×
530
    Function::postRun(timer, universes);
×
531
}
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc