1 /******************************************************************************
2 QtAV Player Demo: this file is part of QtAV examples
3 Copyright (C) 2012-2017 Wang Bin <wbsecg1@gmail.com>
4
5 * This file is part of QtAV (from 2014)
6
7 This program is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>.
19 ******************************************************************************/
20 #include "Config.h"
21 #include <QtCore/QSettings>
22 #include <QtCore/QCoreApplication>
23 #include <QtCore/QDir>
24 #include <QtCore/QFile>
25 #include <QtCore/QMetaEnum>
26 #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
27 #include <QtGui/QDesktopServices>
28 #else
29 #include <QtCore/QStandardPaths>
30 #endif
31 #include <QtSql/QSqlDatabase>
32 #include <QtSql/QSqlQuery>
33 #include <QtDebug>
34 #include "common.h"
35
36 class Config::Data
37 {
38 public:
Data()39 Data() {
40 is_loading = false;
41 if (!Data::name.isEmpty())
42 file = appDataDir() + QString::fromLatin1("/") + Data::name + QString::fromLatin1(".ini");
43 else
44 file = appDataDir() + QString::fromLatin1("/") + qApp->applicationName() + QString::fromLatin1(".ini");
45 if (!QDir(appDataDir()).exists()) {
46 if (!QDir().mkpath(appDataDir())) {
47 qWarning() << "Failed to create appDataDir: " << appDataDir();
48 }
49 }
50 moveOldCfg();
51 }
52
moveOldCfg()53 void moveOldCfg() {
54 // for old config data migration
55 QString dir_old = qApp->applicationDirPath() + QString::fromLatin1("/data");
56 if (!QDir(dir_old).exists()) {
57 dir_old = QDir::homePath() + QString::fromLatin1("/.QtAV");
58 }
59 if (QDir(dir_old).exists()) {
60 if (!QFile(file).exists()) {
61 QString old = dir_old + QString::fromLatin1("/") + qApp->applicationName() + QString::fromLatin1(".ini");
62 if (QFile(old).exists()) {
63 QFile::copy(old, file);
64 QFile::remove(old);
65 }
66 old = dir_old + QString::fromLatin1("/playlist.qds");
67 if (QFile(old).exists()) {
68 if (!QFile::copy(old, appDataDir() + QString::fromLatin1("/playlist.qds")))
69 qWarning("error to move old playlist data");
70 QFile::remove(old);
71 }
72 old = dir_old + QString::fromLatin1("/history.qds");
73 if (QFile(old).exists()) {
74 if (!QFile::copy(old, appDataDir() + QString::fromLatin1("/history.qds")))
75 qWarning("error to move old history data");
76 QFile::remove(old);
77 }
78 }
79 }
80 }
81
save()82 void save() {
83 if (is_loading)
84 return;
85 qDebug() << "sync config to " << file;
86 QSettings settings(file, QSettings::IniFormat);
87 // TODO: why crash on mac qt5.4 if call on aboutToQuit()
88 settings.setValue(QString::fromLatin1("log"), log);
89 settings.setValue(QString::fromLatin1("language"), lang);
90 settings.setValue(QString::fromLatin1("last_file"), last_file);
91 settings.setValue(QString::fromLatin1("timeout"), timeout);
92 settings.setValue(QString::fromLatin1("abort_timeout"), abort_timeout);
93 settings.setValue(QString::fromLatin1("force_fps"), force_fps);
94 settings.beginGroup(QString::fromLatin1("decoder"));
95 settings.beginGroup(QString::fromLatin1("video"));
96 settings.setValue(QString::fromLatin1("priority"), video_decoders.join(QString::fromLatin1(" ")));
97 settings.endGroup();
98 settings.endGroup();
99 settings.beginGroup(QString::fromLatin1("capture"));
100 settings.setValue(QString::fromLatin1("zeroCopy"), zero_copy);
101 settings.setValue(QString::fromLatin1("dir"), capture_dir);
102 settings.setValue(QString::fromLatin1("format"), capture_fmt);
103 settings.setValue(QString::fromLatin1("quality"), capture_quality);
104 settings.endGroup();
105 settings.beginGroup(QString::fromLatin1("subtitle"));
106 settings.setValue(QString::fromLatin1("enabled"), subtitle_enabled);
107 settings.setValue(QString::fromLatin1("autoLoad"), subtitle_autoload);
108 settings.setValue(QString::fromLatin1("engines"), subtitle_engines);
109 settings.setValue(QString::fromLatin1("delay"), subtitle_delay);
110 settings.setValue(QString::fromLatin1("font"), subtitle_font);
111 settings.setValue(QString::fromLatin1("color"), subtitle_color);
112 settings.setValue(QString::fromLatin1("outline_color"), subtitle_outline_color);
113 settings.setValue(QString::fromLatin1("outline"), subtitle_outline);
114 settings.setValue(QString::fromLatin1("bottom margin"), subtilte_bottom_margin);
115 settings.beginGroup(QString::fromLatin1("ass"));
116 settings.setValue(QString::fromLatin1("font_file"), ass_font_file);
117 settings.setValue(QString::fromLatin1("force_font_file"), ass_force_font_file);
118 settings.setValue(QString::fromLatin1("fonts_dir"), ass_fonts_dir);
119 settings.endGroup();
120 settings.endGroup();
121 settings.beginGroup(QString::fromLatin1("preview"));
122 settings.setValue(QString::fromLatin1("enabled"), preview_enabled);
123 settings.setValue(QString::fromLatin1("width"), preview_w);
124 settings.setValue(QString::fromLatin1("height"), preview_h);
125 settings.endGroup();
126 settings.beginGroup(QString::fromLatin1("avformat"));
127 settings.setValue(QString::fromLatin1("enable"), avformat_on);
128 settings.setValue(QString::fromLatin1("avioflags"), direct ? QString::fromLatin1("direct") : QString::fromLatin1("0"));
129 settings.setValue(QString::fromLatin1("probesize"), probe_size);
130 settings.setValue(QString::fromLatin1("analyzeduration"), analyze_duration);
131 settings.setValue(QString::fromLatin1("extra"), avformat_extra);
132 settings.endGroup();
133 settings.beginGroup(QString::fromLatin1("avfilterVideo"));
134 settings.setValue(QString::fromLatin1("enable"), avfilterVideo_on);
135 settings.setValue(QString::fromLatin1("options"), avfilterVideo);
136 settings.endGroup();
137 settings.beginGroup(QString::fromLatin1("avfilterAudio"));
138 settings.setValue(QString::fromLatin1("enable"), avfilterAudio_on);
139 settings.setValue(QString::fromLatin1("options"), avfilterAudio);
140 settings.endGroup();
141 settings.beginGroup(QString::fromLatin1("opengl"));
142 settings.setValue(QString::fromLatin1("egl"), egl);
143 const char* glname = Config::staticMetaObject.enumerator(Config::staticMetaObject.indexOfEnumerator("OpenGLType")).valueToKey(opengl);
144 settings.setValue(QString::fromLatin1("type"), QString::fromLatin1(glname));
145 settings.setValue(QString::fromLatin1("angle_platform"), angle_dx);
146 settings.endGroup();
147 settings.beginGroup(QString::fromLatin1("shader"));
148 settings.setValue(QString::fromLatin1("enable"), user_shader);
149 settings.setValue(QString::fromLatin1("fbo"), fbo);
150 settings.setValue(QString::fromLatin1("fragHeader"), frag_header);
151 settings.setValue(QString::fromLatin1("fragSample"), frag_sample);
152 settings.setValue(QString::fromLatin1("fragPostProcess"), frag_pp);
153 settings.endGroup();
154 settings.beginGroup(QString::fromLatin1("buffer"));
155 settings.setValue(QString::fromLatin1("value"), buffer_value);
156 settings.endGroup();
157 qDebug() << "sync end";
158 }
159
160 QString file;
161 bool is_loading;
162
163 qreal force_fps;
164 QStringList video_decoders;
165 bool zero_copy;
166
167 QString last_file;
168
169 QString capture_dir;
170 QString capture_fmt;
171 int capture_quality;
172
173 bool avformat_on;
174 bool direct;
175 unsigned int probe_size;
176 int analyze_duration;
177 QString avformat_extra;
178 bool avfilterVideo_on;
179 QString avfilterVideo;
180 bool avfilterAudio_on;
181 QString avfilterAudio;
182
183 QStringList subtitle_engines;
184 bool subtitle_autoload;
185 bool subtitle_enabled;
186 QFont subtitle_font;
187 QColor subtitle_color, subtitle_outline_color;
188 bool subtitle_outline;
189 int subtilte_bottom_margin;
190 qreal subtitle_delay;
191
192 bool ass_force_font_file;
193 QString ass_font_file;
194 QString ass_fonts_dir;
195
196 bool preview_enabled;
197 int preview_w, preview_h;
198
199 bool egl;
200 Config::OpenGLType opengl;
201 QString angle_dx;
202 bool abort_timeout;
203 qreal timeout;
204 int buffer_value;
205 QString log;
206 QString lang;
207
208 QVariantList history;
209
210 bool user_shader;
211 bool fbo;
212 QString frag_header;
213 QString frag_sample;
214 QString frag_pp;
215
216 static QString name;
217 };
218
219 QString Config::Data::name;
220
instance()221 Config& Config::instance()
222 {
223 static Config cfg;
224 return cfg;
225 }
226
setName(const QString & name)227 void Config::setName(const QString &name)
228 {
229 Config::Data::name = name;
230 }
231
getName()232 QString Config::getName()
233 {
234 return Config::Data::name;
235 }
236
defaultConfigFile()237 QString Config::defaultConfigFile()
238 {
239 return appDataDir() + QString::fromLatin1("/") + Data::name + QString::fromLatin1(".ini");;
240 }
241
Config(QObject * parent)242 Config::Config(QObject *parent)
243 : QObject(parent)
244 , mpData(new Data())
245 {
246 // DO NOT call save() in dtor because it's a singleton and may be deleted later than qApp, QFont is not valid
247 connect(qApp, SIGNAL(aboutToQuit()), SLOT(save())); //FIXME: what if qapp not ready
248 reload();
249 }
250
~Config()251 Config::~Config()
252 {
253 delete mpData;
254 }
255
defaultDir()256 QString Config::defaultDir()
257 {
258 return appDataDir();
259 }
260
reset()261 bool Config::reset()
262 {
263 QFile cf(mpData->file);
264 if (!cf.remove()) {
265 qWarning() << "Failed to remove config file: " << cf.errorString();
266 return false;
267 }
268 reload();
269 save();
270 return true;
271 }
272
reload()273 void Config::reload()
274 {
275 QSqlDatabase db(QSqlDatabase::database());
276 if (!db.isOpen()) {
277 db = QSqlDatabase::addDatabase(QString::fromUtf8("QSQLITE"));
278 db.setDatabaseName(appDataDir().append(QString("/%1.db").arg(mpData->name)));
279 if (!db.open())
280 qWarning("error open db");
281 db.exec("CREATE TABLE IF NOT EXISTS history (url TEXT primary key, start BIGINT, duration BIGINT)");
282 }
283 QSqlQuery query(db.exec(QString::fromUtf8("SELECT * FROM history")));
284 while (query.next()) {
285 QVariantMap var;
286 var[QString::fromUtf8("url")] = query.value(0).toString();
287 var[QString::fromUtf8("start")] = query.value(1).toLongLong();
288 var[QString::fromUtf8("duration")] = query.value(2).toLongLong();
289 mpData->history.append(var);
290 }
291 mpData->is_loading = true;
292 QSettings settings(mpData->file, QSettings::IniFormat);
293 setLogLevel(settings.value(QString::fromLatin1("log"), QString()).toString());
294 setLanguage(settings.value(QString::fromLatin1("language"),
295 #if QT_VERSION == QT_VERSION_CHECK(5, 6, 0) && defined(Q_OS_WINPHONE) //qt bug
296 QString::fromLatin1("en_US")
297 #else
298 QString::fromLatin1("system")
299 #endif
300 ).toString());
301 setLastFile(settings.value(QString::fromLatin1("last_file"), QString()).toString());
302 setTimeout(settings.value(QString::fromLatin1("timeout"), 30.0).toReal());
303 setAbortOnTimeout(settings.value(QString::fromLatin1("abort_timeout"), true).toBool());
304 setForceFrameRate(settings.value(QString::fromLatin1("force_fps"), 0.0).toReal());
305 settings.beginGroup(QString::fromLatin1("decoder"));
306 settings.beginGroup(QString::fromLatin1("video"));
307 QString decs_default(QString::fromLatin1("HW FFmpeg")); // HW is ignored
308 setDecoderPriorityNames(settings.value(QString::fromLatin1("priority"), decs_default).toString().split(QString::fromLatin1(" "), QString::SkipEmptyParts));
309 setZeroCopy(settings.value(QString::fromLatin1("zeroCopy"), true).toBool());
310 settings.endGroup(); //video
311 settings.endGroup(); //decoder
312
313 settings.beginGroup(QString::fromLatin1("capture"));
314 setCaptureDir(settings.value(QString::fromLatin1("dir"), QString()).toString());
315 if (captureDir().isEmpty()) {
316 #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
317 setCaptureDir(QDesktopServices::storageLocation(QDesktopServices::PicturesLocation));
318 #else
319 setCaptureDir(QStandardPaths::writableLocation(QStandardPaths::PicturesLocation));
320 #endif
321 }
322 setCaptureFormat(settings.value(QString::fromLatin1("format"), QString::fromLatin1("png")).toString());
323 setCaptureQuality(settings.value(QString::fromLatin1("quality"), 100).toInt());
324 settings.endGroup();
325 settings.beginGroup(QString::fromLatin1("subtitle"));
326 setSubtitleAutoLoad(settings.value(QString::fromLatin1("autoLoad"), true).toBool());
327 setSubtitleEnabled(settings.value(QString::fromLatin1("enabled"), true).toBool());
328 setSubtitleEngines(settings.value(QString::fromLatin1("engines"), QStringList() << QString::fromLatin1("FFmpeg") << QString::fromLatin1("LibASS")).toStringList());
329 setSubtitleDelay(settings.value(QString::fromLatin1("delay"), 0.0).toInt());
330 QFont f;
331 f.setPointSize(20);
332 f.setBold(true);
333 setSubtitleFont(settings.value(QString::fromLatin1("font"), f).value<QFont>());
334 setSubtitleColor(settings.value(QString::fromLatin1("color"), QColor("white")).value<QColor>());
335 setSubtitleOutlineColor(settings.value(QString::fromLatin1("outline_color"), QColor("blue")).value<QColor>());
336 setSubtitleOutline(settings.value(QString::fromLatin1("outline"), true).toBool());
337 setSubtitleBottomMargin(settings.value(QString::fromLatin1("bottom margin"), 8).toInt());
338 settings.beginGroup(QString::fromLatin1("ass"));
339 setAssFontFile(settings.value(QString::fromLatin1("font_file"), QString()).toString());
340 setAssFontFileForced(settings.value(QString::fromLatin1("force_font_file"), false).toBool());
341 setAssFontsDir(settings.value(QString::fromLatin1("fonts_dir"), QString()).toString());
342 settings.endGroup();
343 settings.endGroup();
344 settings.beginGroup(QString::fromLatin1("preview"));
345 setPreviewEnabled(settings.value(QString::fromLatin1("enabled"), true).toBool());
346 setPreviewWidth(settings.value(QString::fromLatin1("width"), 160).toInt());
347 setPreviewHeight(settings.value(QString::fromLatin1("height"), 90).toInt());
348 settings.endGroup();
349 settings.beginGroup(QString::fromLatin1("avformat"));
350 setAvformatOptionsEnabled(settings.value(QString::fromLatin1("enable"), false).toBool());
351 reduceBuffering(settings.value(QString::fromLatin1("avioflags"), 0).toString() == QLatin1String("direct"));
352 probeSize(settings.value(QString::fromLatin1("probesize"), 5000000).toUInt());
353 analyzeDuration(settings.value(QString::fromLatin1("analyzeduration"), 5000000).toInt());
354 avformatExtra(settings.value(QString::fromLatin1("extra"), QString()).toString());
355 settings.endGroup();
356 settings.beginGroup(QString::fromLatin1("avfilterVideo"));
357 avfilterVideoEnable(settings.value(QString::fromLatin1("enable"), true).toBool());
358 avfilterVideoOptions(settings.value(QString::fromLatin1("options"), QString()).toString());
359 settings.endGroup();
360 settings.beginGroup(QString::fromLatin1("avfilterAudio"));
361 avfilterAudioEnable(settings.value(QString::fromLatin1("enable"), true).toBool());
362 avfilterAudioOptions(settings.value(QString::fromLatin1("options"), QString()).toString());
363 settings.endGroup();
364
365 settings.beginGroup(QString::fromLatin1("opengl"));
366 setEGL(settings.value(QString::fromLatin1("egl"), false).toBool());
367 const QString glname = settings.value(QString::fromLatin1("type"), QString::fromLatin1("OpenGLES")).toString();
368 setOpenGLType((Config::OpenGLType)Config::staticMetaObject.enumerator(Config::staticMetaObject.indexOfEnumerator("OpenGLType")).keysToValue(glname.toLatin1().constData()));
369 // d3d11 bad performance (gltexsubimage2d)
370 setANGLEPlatform(settings.value(QString::fromLatin1("angle_platform"), QString::fromLatin1("d3d9")).toString());
371 settings.endGroup();
372
373 settings.beginGroup(QString::fromLatin1("shader"));
374 setUserShaderEnabled(settings.value(QString::fromLatin1("enable"), false).toBool());
375 setIntermediateFBO(settings.value(QString::fromLatin1("fbo"), false).toBool());
376 setFragHeader(settings.value(QString::fromLatin1("fragHeader"), QString()).toString());
377 setFragSample(settings.value(QString::fromLatin1("fragSample"), QString::fromLatin1("// horizontal mirror effect\n"
378 "vec4 sample2d(sampler2D tex, vec2 pos, int p) {\n"
379 " return texture(tex, vec2(1.0-pos.x, pos.y));\n"
380 "}")).toString());
381 setFragPostProcess(settings.value(QString::fromLatin1("fragPostProcess"), QString::fromLatin1("//negate color effect\n"
382 "gl_FragColor.rgb = vec3(1.0-gl_FragColor.r, 1.0-gl_FragColor.g, 1.0-gl_FragColor.b);")).toString());
383 settings.endGroup();
384
385 settings.beginGroup(QString::fromLatin1("buffer"));
386 setBufferValue(settings.value(QString::fromLatin1("value"), -1).toInt());
387 settings.endGroup();
388 mpData->is_loading = false;
389 }
390
forceFrameRate() const391 qreal Config::forceFrameRate() const
392 {
393 return mpData->force_fps;
394 }
395
setForceFrameRate(qreal value)396 Config& Config::setForceFrameRate(qreal value)
397 {
398 if (mpData->force_fps == value)
399 return *this;
400 mpData->force_fps = value;
401 Q_EMIT forceFrameRateChanged();
402 Q_EMIT changed();
403 return *this;
404 }
405
decoderPriorityNames() const406 QStringList Config::decoderPriorityNames() const
407 {
408 return mpData->video_decoders;
409 }
410
setDecoderPriorityNames(const QStringList & value)411 Config& Config::setDecoderPriorityNames(const QStringList &value)
412 {
413 if (mpData->video_decoders == value) {
414 qDebug("decoderPriority not changed");
415 return *this;
416 }
417 mpData->video_decoders = value;
418 Q_EMIT decoderPriorityNamesChanged();
419 Q_EMIT changed();
420 mpData->save();
421 return *this;
422 }
423
zeroCopy() const424 bool Config::zeroCopy() const
425 {
426 return mpData->zero_copy;
427 }
428
setZeroCopy(bool value)429 Config& Config::setZeroCopy(bool value)
430 {
431 if (mpData->zero_copy == value)
432 return *this;
433 mpData->zero_copy = value;
434 Q_EMIT zeroCopyChanged();
435 Q_EMIT changed();
436 mpData->save();
437 return *this;
438 }
439
captureDir() const440 QString Config::captureDir() const
441 {
442 return mpData->capture_dir;
443 }
444
setCaptureDir(const QString & dir)445 Config& Config::setCaptureDir(const QString& dir)
446 {
447 if (mpData->capture_dir == dir)
448 return *this;
449 mpData->capture_dir = dir;
450 Q_EMIT captureDirChanged(dir);
451 Q_EMIT changed();
452 return *this;
453 }
454
captureFormat() const455 QString Config::captureFormat() const
456 {
457 return mpData->capture_fmt;
458 }
459
setCaptureFormat(const QString & format)460 Config& Config::setCaptureFormat(const QString& format)
461 {
462 if (mpData->capture_fmt == format)
463 return *this;
464 mpData->capture_fmt = format;
465 Q_EMIT captureFormatChanged(format);
466 Q_EMIT changed();
467 return *this;
468 }
469
470 // only works for non-yuv capture
captureQuality() const471 int Config::captureQuality() const
472 {
473 return mpData->capture_quality;
474 }
475
setCaptureQuality(int quality)476 Config& Config::setCaptureQuality(int quality)
477 {
478 if (mpData->capture_quality == quality)
479 return *this;
480 mpData->capture_quality = quality;
481 Q_EMIT captureQualityChanged(quality);
482 Q_EMIT changed();
483 return *this;
484 }
485
subtitleEngines() const486 QStringList Config::subtitleEngines() const
487 {
488 return mpData->subtitle_engines;
489 }
490
setSubtitleEngines(const QStringList & value)491 Config& Config::setSubtitleEngines(const QStringList &value)
492 {
493 if (mpData->subtitle_engines == value)
494 return *this;
495 mpData->subtitle_engines = value;
496 Q_EMIT subtitleEnginesChanged();
497 Q_EMIT changed();
498 return *this;
499 }
500
subtitleAutoLoad() const501 bool Config::subtitleAutoLoad() const
502 {
503 return mpData->subtitle_autoload;
504 }
505
setSubtitleAutoLoad(bool value)506 Config& Config::setSubtitleAutoLoad(bool value)
507 {
508 if (mpData->subtitle_autoload == value)
509 return *this;
510 mpData->subtitle_autoload = value;
511 Q_EMIT subtitleAutoLoadChanged();
512 Q_EMIT changed();
513 return *this;
514 }
515
subtitleEnabled() const516 bool Config::subtitleEnabled() const
517 {
518 return mpData->subtitle_enabled;
519 }
520
setSubtitleEnabled(bool value)521 Config& Config::setSubtitleEnabled(bool value)
522 {
523 if (mpData->subtitle_enabled == value)
524 return *this;
525 mpData->subtitle_enabled = value;
526 Q_EMIT subtitleEnabledChanged();
527 Q_EMIT changed();
528 return *this;
529 }
530
subtitleFont() const531 QFont Config::subtitleFont() const
532 {
533 return mpData->subtitle_font;
534 }
535
setSubtitleFont(const QFont & value)536 Config& Config::setSubtitleFont(const QFont& value)
537 {
538 if (mpData->subtitle_font == value)
539 return *this;
540 mpData->subtitle_font = value;
541 Q_EMIT subtitleFontChanged();
542 Q_EMIT changed();
543 return *this;
544 }
545
subtitleOutline() const546 bool Config::subtitleOutline() const
547 {
548 return mpData->subtitle_outline;
549 }
setSubtitleOutline(bool value)550 Config& Config::setSubtitleOutline(bool value)
551 {
552 if (mpData->subtitle_outline == value)
553 return *this;
554 mpData->subtitle_outline = value;
555 Q_EMIT subtitleOutlineChanged();
556 Q_EMIT changed();
557 return *this;
558 }
559
subtitleColor() const560 QColor Config::subtitleColor() const
561 {
562 return mpData->subtitle_color;
563 }
564
setSubtitleColor(const QColor & value)565 Config& Config::setSubtitleColor(const QColor& value)
566 {
567 if (mpData->subtitle_color == value)
568 return *this;
569 mpData->subtitle_color = value;
570 Q_EMIT subtitleColorChanged();
571 Q_EMIT changed();
572 return *this;
573 }
574
subtitleOutlineColor() const575 QColor Config::subtitleOutlineColor() const
576 {
577 return mpData->subtitle_outline_color;
578 }
setSubtitleOutlineColor(const QColor & value)579 Config& Config::setSubtitleOutlineColor(const QColor& value)
580 {
581 if (mpData->subtitle_outline_color == value)
582 return *this;
583 mpData->subtitle_outline_color = value;
584 Q_EMIT subtitleOutlineColorChanged();
585 Q_EMIT changed();
586 return *this;
587 }
588
subtitleBottomMargin() const589 int Config::subtitleBottomMargin() const
590 {
591 return mpData->subtilte_bottom_margin;
592 }
593
setSubtitleBottomMargin(int value)594 Config& Config::setSubtitleBottomMargin(int value)
595 {
596 if (mpData->subtilte_bottom_margin == value)
597 return *this;
598 mpData->subtilte_bottom_margin = value;
599 Q_EMIT subtitleBottomMarginChanged();
600 Q_EMIT changed();
601 return *this;
602 }
603
subtitleDelay() const604 qreal Config::subtitleDelay() const
605 {
606 return mpData->subtitle_delay;
607 }
608
setSubtitleDelay(qreal value)609 Config& Config::setSubtitleDelay(qreal value)
610 {
611 if (mpData->subtitle_delay == value)
612 return *this;
613 mpData->subtitle_delay = value;
614 Q_EMIT subtitleDelayChanged();
615 Q_EMIT changed();
616 return *this;
617 }
618
assFontFile() const619 QString Config::assFontFile() const
620 {
621 return mpData->ass_font_file;
622 }
623
setAssFontFile(const QString & value)624 Config& Config::setAssFontFile(const QString &value)
625 {
626 if (mpData->ass_font_file == value)
627 return *this;
628 mpData->ass_font_file = value;
629 Q_EMIT assFontFileChanged();
630 Q_EMIT changed();
631 return *this;
632 }
633
634
assFontsDir() const635 QString Config::assFontsDir() const
636 {
637 return mpData->ass_fonts_dir;
638 }
639
setAssFontsDir(const QString & value)640 Config& Config::setAssFontsDir(const QString &value)
641 {
642 if (mpData->ass_fonts_dir == value)
643 return *this;
644 mpData->ass_fonts_dir = value;
645 Q_EMIT assFontsDirChanged();
646 Q_EMIT changed();
647 return *this;
648 }
649
isAssFontFileForced() const650 bool Config::isAssFontFileForced() const
651 {
652 return mpData->ass_force_font_file;
653 }
654
setAssFontFileForced(bool value)655 Config& Config::setAssFontFileForced(bool value)
656 {
657 if (mpData->ass_force_font_file == value)
658 return *this;
659 mpData->ass_force_font_file = value;
660 Q_EMIT assFontFileForcedChanged();
661 Q_EMIT changed();
662 return *this;
663 }
664
previewEnabled() const665 bool Config::previewEnabled() const
666 {
667 return mpData->preview_enabled;
668 }
669
setPreviewEnabled(bool value)670 Config& Config::setPreviewEnabled(bool value)
671 {
672 if (mpData->preview_enabled == value)
673 return *this;
674 mpData->preview_enabled = value;
675 Q_EMIT previewEnabledChanged();
676 Q_EMIT changed();
677 return *this;
678 }
679
previewWidth() const680 int Config::previewWidth() const
681 {
682 return mpData->preview_w;
683 }
684
setPreviewWidth(int value)685 Config& Config::setPreviewWidth(int value)
686 {
687 if (mpData->preview_w == value)
688 return *this;
689 mpData->preview_w = value;
690 Q_EMIT previewWidthChanged();
691 Q_EMIT changed();
692 return *this;
693 }
694
previewHeight() const695 int Config::previewHeight() const
696 {
697 return mpData->preview_h;
698 }
699
setPreviewHeight(int value)700 Config& Config::setPreviewHeight(int value)
701 {
702 if (mpData->preview_h == value)
703 return *this;
704 mpData->preview_h = value;
705 Q_EMIT previewHeightChanged();
706 Q_EMIT changed();
707 return *this;
708 }
avformatOptions() const709 QVariantHash Config::avformatOptions() const
710 {
711 QVariantHash vh;
712 if (!mpData->avformat_extra.isEmpty()) {
713 QStringList s(mpData->avformat_extra.split(QString::fromLatin1(" ")));
714 for (int i = 0; i < s.size(); ++i) {
715 int eq = s[i].indexOf(QLatin1String("="));
716 if (eq < 0) {
717 continue;
718 } else {
719 vh[s[i].mid(0, eq)] = s[i].mid(eq+1);
720 }
721 }
722 }
723 if (mpData->probe_size > 0) {
724 vh[QString::fromLatin1("probesize")] = mpData->probe_size;
725 }
726 if (mpData->analyze_duration) {
727 vh[QString::fromLatin1("analyzeduration")] = mpData->analyze_duration;
728 }
729 if (mpData->direct) {
730 vh[QString::fromLatin1("avioflags")] = QString::fromLatin1("direct");
731 };
732 return vh;
733 }
734
avformatOptionsEnabled() const735 bool Config::avformatOptionsEnabled() const
736 {
737 return mpData->avformat_on;
738 }
739
setAvformatOptionsEnabled(bool value)740 Config& Config::setAvformatOptionsEnabled(bool value)
741 {
742 if (mpData->avformat_on == value)
743 return *this;
744 mpData->avformat_on = value;
745 Q_EMIT avformatOptionsEnabledChanged();
746 Q_EMIT changed();
747 return *this;
748 }
749
probeSize() const750 unsigned int Config::probeSize() const
751 {
752 return mpData->probe_size;
753 }
754
probeSize(unsigned int ps)755 Config& Config::probeSize(unsigned int ps)
756 {
757 mpData->probe_size = ps;
758 return *this;
759 }
760
analyzeDuration() const761 int Config::analyzeDuration() const
762 {
763 return mpData->analyze_duration;
764 }
765
analyzeDuration(int ad)766 Config& Config::analyzeDuration(int ad)
767 {
768 mpData->analyze_duration = ad;
769 return *this;
770 }
771
reduceBuffering() const772 bool Config::reduceBuffering() const
773 {
774 return mpData->direct;
775 }
776
reduceBuffering(bool y)777 Config& Config::reduceBuffering(bool y)
778 {
779 mpData->direct = y;
780 return *this;
781 }
782
avformatExtra() const783 QString Config::avformatExtra() const
784 {
785 return mpData->avformat_extra;
786 }
787
avformatExtra(const QString & text)788 Config& Config::avformatExtra(const QString &text)
789 {
790 mpData->avformat_extra = text;
791 return *this;
792 }
793
avfilterVideoOptions() const794 QString Config::avfilterVideoOptions() const
795 {
796 return mpData->avfilterVideo;
797 }
798
avfilterVideoOptions(const QString & options)799 Config& Config::avfilterVideoOptions(const QString& options)
800 {
801 if (mpData->avfilterVideo == options)
802 return *this;
803 mpData->avfilterVideo = options;
804 Q_EMIT avfilterVideoChanged();
805 Q_EMIT changed();
806 return *this;
807 }
808
avfilterVideoEnable() const809 bool Config::avfilterVideoEnable() const
810 {
811 return mpData->avfilterVideo_on;
812 }
813
avfilterVideoEnable(bool e)814 Config& Config::avfilterVideoEnable(bool e)
815 {
816 if (mpData->avfilterVideo_on == e)
817 return *this;
818 mpData->avfilterVideo_on = e;
819 Q_EMIT avfilterVideoChanged();
820 Q_EMIT changed();
821 return *this;
822 }
823
avfilterAudioOptions() const824 QString Config::avfilterAudioOptions() const
825 {
826 return mpData->avfilterAudio;
827 }
828
avfilterAudioOptions(const QString & options)829 Config& Config::avfilterAudioOptions(const QString& options)
830 {
831 if (mpData->avfilterAudio == options)
832 return *this;
833 mpData->avfilterAudio = options;
834 Q_EMIT avfilterAudioChanged();
835 Q_EMIT changed();
836 return *this;
837 }
838
avfilterAudioEnable() const839 bool Config::avfilterAudioEnable() const
840 {
841 return mpData->avfilterAudio_on;
842 }
843
avfilterAudioEnable(bool e)844 Config& Config::avfilterAudioEnable(bool e)
845 {
846 if (mpData->avfilterAudio_on == e)
847 return *this;
848 mpData->avfilterAudio_on = e;
849 Q_EMIT avfilterAudioChanged();
850 Q_EMIT changed();
851 return *this;
852 }
853
isEGL() const854 bool Config::isEGL() const
855 {
856 return mpData->egl;
857 }
858
setEGL(bool value)859 Config& Config::setEGL(bool value)
860 {
861 if (mpData->egl == value)
862 return *this;
863 mpData->egl = value;
864 Q_EMIT EGLChanged();
865 Q_EMIT changed();
866 return *this;
867 }
868
openGLType() const869 Config::OpenGLType Config::openGLType() const
870 {
871 return mpData->opengl;
872 }
873
setOpenGLType(OpenGLType value)874 Config& Config::setOpenGLType(OpenGLType value)
875 {
876 if (mpData->opengl == value)
877 return *this;
878 mpData->opengl = value;
879 Q_EMIT openGLTypeChanged();
880 Q_EMIT changed();
881 return *this;
882 }
883
getANGLEPlatform() const884 QString Config::getANGLEPlatform() const
885 {
886 return mpData->angle_dx;
887 }
888
setANGLEPlatform(const QString & value)889 Config& Config::setANGLEPlatform(const QString& value)
890 {
891 if (mpData->angle_dx == value)
892 return *this;
893 mpData->angle_dx = value;
894 Q_EMIT ANGLEPlatformChanged();
895 Q_EMIT changed();
896 return *this;
897 }
898
userShaderEnabled() const899 bool Config::userShaderEnabled() const
900 {
901 return mpData->user_shader;
902 }
903
setUserShaderEnabled(bool value)904 Config& Config::setUserShaderEnabled(bool value)
905 {
906 if (mpData->user_shader == value)
907 return *this;
908 mpData->user_shader = value;
909 Q_EMIT userShaderEnabledChanged();
910 Q_EMIT changed();
911 return *this;
912 }
913
intermediateFBO() const914 bool Config::intermediateFBO() const
915 {
916 return mpData->fbo;
917 }
918
setIntermediateFBO(bool value)919 Config& Config::setIntermediateFBO(bool value)
920 {
921 if (mpData->fbo == value)
922 return *this;
923 mpData->fbo = value;
924 Q_EMIT intermediateFBOChanged();
925 Q_EMIT changed();
926 return *this;
927 }
928
fragHeader() const929 QString Config::fragHeader() const
930 {
931 return mpData->frag_header;
932 }
933
setFragHeader(const QString & text)934 Config& Config::setFragHeader(const QString &text)
935 {
936 if (mpData->frag_header == text)
937 return *this;
938 mpData->frag_header = text;
939 Q_EMIT fragHeaderChanged();
940 Q_EMIT changed();
941 return *this;
942 }
943
fragSample() const944 QString Config::fragSample() const
945 {
946 return mpData->frag_sample;
947 }
948
setFragSample(const QString & text)949 Config& Config::setFragSample(const QString &text)
950 {
951 if (mpData->frag_sample == text)
952 return *this;
953 mpData->frag_sample = text;
954 Q_EMIT fragSampleChanged();
955 Q_EMIT changed();
956 return *this;
957 }
958
fragPostProcess() const959 QString Config::fragPostProcess() const
960 {
961 return mpData->frag_pp;
962 }
963
setFragPostProcess(const QString & text)964 Config& Config::setFragPostProcess(const QString &text)
965 {
966 if (mpData->frag_pp == text)
967 return *this;
968 mpData->frag_pp = text;
969 Q_EMIT fragPostProcessChanged();
970 Q_EMIT changed();
971 return *this;
972 }
973
bufferValue() const974 int Config::bufferValue() const
975 {
976 return mpData->buffer_value;
977 }
978
setBufferValue(int value)979 Config& Config::setBufferValue(int value)
980 {
981 if (mpData->buffer_value == value)
982 return *this;
983 mpData->buffer_value = value;
984 Q_EMIT bufferValueChanged();
985 Q_EMIT changed();
986 return *this;
987 }
988
timeout() const989 qreal Config::timeout() const
990 {
991 return mpData->timeout;
992 }
993
setTimeout(qreal value)994 Config& Config::setTimeout(qreal value)
995 {
996 if (mpData->timeout == value)
997 return *this;
998 mpData->timeout = value;
999 Q_EMIT timeoutChanged();
1000 Q_EMIT changed();
1001 return *this;
1002 }
1003
logLevel() const1004 QString Config::logLevel() const
1005 {
1006 return mpData->log;
1007 }
1008
setLogLevel(const QString & value)1009 Config& Config::setLogLevel(const QString& value)
1010 {
1011 if (mpData->log == value.toLower())
1012 return *this;
1013 mpData->log = value.toLower();
1014 Q_EMIT logLevelChanged();
1015 Q_EMIT changed();
1016 return *this;
1017 }
1018
language() const1019 QString Config::language() const
1020 {
1021 return mpData->lang;
1022 }
1023
setLanguage(const QString & value)1024 Config& Config::setLanguage(const QString& value)
1025 {
1026 if (mpData->lang == value)
1027 return *this;
1028 mpData->lang = value;
1029 Q_EMIT languageChanged();
1030 Q_EMIT changed();
1031 return *this;
1032 }
1033
history() const1034 QVariantList Config::history() const
1035 {
1036 return mpData->history;
1037 }
1038
addHistory(const QVariantMap & value)1039 void Config::addHistory(const QVariantMap &value)
1040 {
1041 mpData->history.prepend(value);
1042 Q_EMIT historyChanged();
1043 QSqlDatabase db = QSqlDatabase::database();
1044 QSqlQuery query(db);
1045 if (!query.prepare(QString::fromUtf8("INSERT INTO history (url, start, duration) "
1046 "VALUES (:url, :start, :duration)"))) {
1047 qWarning("error prepare sql query");
1048 }
1049 query.bindValue(QString::fromUtf8(":url"), value.value("url").toString());
1050 query.bindValue(QString::fromUtf8(":start"), value.value("start").toLongLong());
1051 query.bindValue(QString::fromUtf8(":duration"), value.value("duration").toLongLong());
1052 if (!query.exec())
1053 qWarning("failed to add history: %d", db.isOpen());
1054 }
1055
removeHistory(const QString & url)1056 void Config::removeHistory(const QString &url)
1057 {
1058 QVariantList::Iterator it = mpData->history.begin();
1059 bool change = false;
1060 while (it != mpData->history.end()) {
1061 if (it->toMap().value("url") != url) {
1062 ++it;
1063 continue;
1064 }
1065 it = mpData->history.erase(it);
1066 change = true;
1067 }
1068 if (!change)
1069 return;
1070 Q_EMIT historyChanged();
1071 QSqlDatabase db = QSqlDatabase::database();
1072 QSqlQuery query(db);
1073 query.prepare(QString::fromUtf8("DELETE FROM history WHERE url = :url"));
1074 query.bindValue(QString::fromUtf8(":url"), url);
1075 if (!query.exec())
1076 qWarning("failed to remove history");
1077 }
1078
clearHistory()1079 void Config::clearHistory()
1080 {
1081 if (mpData->history.isEmpty())
1082 return;
1083 mpData->history.clear();
1084 Q_EMIT historyChanged();
1085 QSqlDatabase db = QSqlDatabase::database();
1086 QSqlQuery query(db);
1087 query.prepare(QString::fromUtf8("DELETE FROM history"));
1088 // 'TRUNCATE table history' is faster
1089 if (!query.exec())
1090 qWarning("failed to clear history");
1091 }
1092
abortOnTimeout() const1093 bool Config::abortOnTimeout() const
1094 {
1095 return mpData->abort_timeout;
1096 }
1097
setAbortOnTimeout(bool value)1098 Config& Config::setAbortOnTimeout(bool value)
1099 {
1100 if (mpData->abort_timeout == value)
1101 return *this;
1102 mpData->abort_timeout = value;
1103 Q_EMIT abortOnTimeoutChanged();
1104 Q_EMIT changed();
1105 return *this;
1106 }
1107
lastFile() const1108 QString Config::lastFile() const
1109 {
1110 return mpData->last_file;
1111 }
1112
setLastFile(const QString & value)1113 Config& Config::setLastFile(const QString &value)
1114 {
1115 if (mpData->last_file == value)
1116 return *this;
1117 mpData->last_file = value;
1118 Q_EMIT lastFileChanged();
1119 Q_EMIT changed();
1120 return *this;
1121 }
1122
save()1123 void Config::save()
1124 {
1125 mpData->save();
1126 }
1127