MythTV master
remoteencoder.cpp
Go to the documentation of this file.
1#include <unistd.h>
2
3#include <QStringList>
4
11
13#include "remoteencoder.h"
14
15#define LOC QString("RemoteEncoder(%1): ").arg(m_recordernum)
16
17static constexpr std::chrono::milliseconds MAX_SIZE_CHECK { 500ms };
18
20{
21 if (m_controlSock)
22 {
24 m_controlSock = nullptr;
25 }
26}
27
29{
30 if (!m_controlSock)
31 {
32 LOG(VB_NETWORK, LOG_DEBUG, "RemoteEncoder::Setup(): Connecting...");
33
34 QString ann = QString("ANN Playback %1 %2")
35 .arg(gCoreContext->GetHostName()).arg(static_cast<int>(false));
36
39
40 if (m_controlSock)
41 {
42 LOG(VB_NETWORK, LOG_DEBUG, "RemoteEncoder::Setup(): Connected");
43 }
44 else
45 {
46 LOG(VB_GENERAL, LOG_ERR,
47 "RemoteEncoder::Setup(): Failed to connect to backend");
48 }
49 }
50 else
51 {
52 LOG(VB_NETWORK, LOG_DEBUG, "RemoteEncoder::Setup(): Already connected");
53 }
54 return m_controlSock;
55}
56
58{
59 return (m_recordernum >= 0);
60}
61
63{
64 return m_recordernum;
65}
66
68 QStringList &strlist, uint min_reply_length)
69{
70 QMutexLocker locker(&m_lock);
71 if (!m_controlSock)
72 Setup();
73
74 m_backendError = false;
75
76 if (!m_controlSock)
77 {
78 LOG(VB_GENERAL, LOG_ERR, "RemoteEncoder::SendReceiveStringList(): "
79 "Failed to reconnect with backend.");
80 m_backendError = true;
81 return false;
82 }
83
84 if (!m_controlSock->WriteStringList(strlist))
85 {
86 LOG(VB_GENERAL, LOG_ERR, "RemoteEncoder::SendReceiveStringList(): "
87 "Failed to write data.");
88 m_backendError = true;
89 }
90
91 if (!m_backendError &&
93 {
94 LOG(VB_GENERAL, LOG_ERR,
95 "RemoteEncoder::SendReceiveStringList(): No response.");
96 m_backendError = true;
97 }
98
99 if (!m_backendError &&
100 min_reply_length && ((uint)strlist.size() < min_reply_length))
101 {
102 LOG(VB_GENERAL, LOG_ERR,
103 "RemoteEncoder::SendReceiveStringList(): Response too short");
104 m_backendError = true;
105 }
106
107 if (m_backendError)
108 {
110 m_controlSock = nullptr;
111 return false;
112 }
113
114 return true;
115}
116
118{
119 QStringList strlist( QString("QUERY_RECORDER %1").arg(m_recordernum) );
120 strlist << "IS_RECORDING";
121
122 bool ret = SendReceiveStringList(strlist, 1);
123 if (!ret)
124 {
125 if (ok)
126 *ok = false;
127
128 return false;
129 }
130
131 if (ok)
132 *ok = true;
133
134 return strlist[0].toInt() != 0;
135}
136
138{
139 QStringList strlist( QString("QUERY_RECORDER %1").arg(m_recordernum) );
140 strlist << "GET_RECORDING";
141
142 if (SendReceiveStringList(strlist))
143 {
144 auto *proginfo = new ProgramInfo(strlist);
145 if (proginfo->GetChanID())
146 return proginfo;
147 delete proginfo;
148 }
149
150 return nullptr;
151}
152
160{
161 QStringList strlist( QString("QUERY_RECORDER %1").arg(m_recordernum));
162 strlist << "GET_FRAMERATE";
163
164 bool ok = false;
165 float retval = 30.0F;
166
167 if (SendReceiveStringList(strlist, 1))
168 {
169 retval = strlist[0].toFloat(&ok);
170
171 if (!ok)
172 {
173 LOG(VB_GENERAL, LOG_ERR, LOC +
174 QString("GetFrameRate() failed to parse response '%1'")
175 .arg(strlist[0]));
176 }
177 }
178 else
179 {
180 LOG(VB_GENERAL, LOG_ERR, LOC +
181 "GetFrameRate(): SendReceiveStringList() failed");
182 }
183
184 return (ok) ? retval : 30.0F;
185}
186
195{
197 {
199 }
200
201 QStringList strlist( QString("QUERY_RECORDER %1").arg(m_recordernum));
202 strlist << "GET_FRAMES_WRITTEN";
203
204 if (!SendReceiveStringList(strlist, 1))
205 {
206 LOG(VB_GENERAL, LOG_ERR, LOC + "GetFramesWritten() -- network error");
207 }
208 else
209 {
210 m_cachedFramesWritten = strlist[0].toLongLong();
212 }
213
215}
216
224{
225 QStringList strlist( QString("QUERY_RECORDER %1").arg(m_recordernum));
226 strlist << "GET_FILE_POSITION";
227
228 if (SendReceiveStringList(strlist, 1))
229 return strlist[0].toLongLong();
230
231 return -1;
232}
233
239{
240 QStringList strlist( QString("QUERY_RECORDER %1").arg(m_recordernum));
241 strlist << "GET_MAX_BITRATE";
242
243 if (SendReceiveStringList(strlist, 1))
244 return strlist[0].toLongLong();
245
246 return 20200000LL; // Peek bit rate for HD-PVR
247}
248
256int64_t RemoteEncoder::GetKeyframePosition(uint64_t desired)
257{
258 QStringList strlist( QString("QUERY_RECORDER %1").arg(m_recordernum) );
259 strlist << "GET_KEYFRAME_POS";
260 strlist << QString::number(desired);
261
262 if (SendReceiveStringList(strlist, 1))
263 return strlist[0].toLongLong();
264
265 return -1;
266}
267
268void RemoteEncoder::FillPositionMap(int64_t start, int64_t end,
269 frm_pos_map_t &positionMap)
270{
271 QStringList strlist( QString("QUERY_RECORDER %1").arg(m_recordernum));
272 strlist << "FILL_POSITION_MAP";
273 strlist << QString::number(start);
274 strlist << QString::number(end);
275
276 if (!SendReceiveStringList(strlist))
277 return;
278
279 for (auto it = strlist.cbegin(); it != strlist.cend(); ++it)
280 {
281 bool ok = false;
282 uint64_t index = (*it).toLongLong(&ok);
283 if (++it == strlist.cend() || !ok)
284 break;
285
286 uint64_t pos = (*it).toLongLong(&ok);
287 if (!ok)
288 break;
289
290 positionMap[index] = pos;
291 }
292}
293
294void RemoteEncoder::FillDurationMap(int64_t start, int64_t end,
295 frm_pos_map_t &durationMap)
296{
297 QStringList strlist( QString("QUERY_RECORDER %1").arg(m_recordernum));
298 strlist << "FILL_DURATION_MAP";
299 strlist << QString::number(start);
300 strlist << QString::number(end);
301
302 if (!SendReceiveStringList(strlist))
303 return;
304
305 for (auto it = strlist.cbegin(); it != strlist.cend(); ++it)
306 {
307 bool ok = false;
308 uint64_t index = (*it).toLongLong(&ok);
309 if (++it == strlist.cend() || !ok)
310 break;
311
312 uint64_t pos = (*it).toLongLong(&ok);
313 if (!ok)
314 break;
315
316 durationMap[index] = pos;
317 }
318}
319
321{
322 QStringList strlist( QString("QUERY_RECORDER %1").arg(m_recordernum));
323 strlist << "CANCEL_NEXT_RECORDING";
324 strlist << QString::number((cancel) ? 1 : 0);
325
326 SendReceiveStringList(strlist);
327}
328
330{
331 QStringList strlist( QString("QUERY_RECORDER %1").arg(m_recordernum));
332 strlist << "FRONTEND_READY";
333
334 SendReceiveStringList(strlist);
335}
336
342{
343 QStringList strlist( QString("QUERY_RECORDER %1").arg(m_recordernum) );
344 strlist << "STOP_PLAYING";
345
346 SendReceiveStringList(strlist);
347}
348
354void RemoteEncoder::SpawnLiveTV(const QString& chainId, bool pip, const QString& startchan)
355{
356 QStringList strlist( QString("QUERY_RECORDER %1").arg(m_recordernum));
357 strlist << "SPAWN_LIVETV";
358 strlist << chainId;
359 strlist << QString::number((int)pip);
360 strlist << startchan;
361
362 SendReceiveStringList(strlist);
363}
364
371{
372 QStringList strlist( QString("QUERY_RECORDER %1").arg(m_recordernum) );
373 strlist << "STOP_LIVETV";
374
375 SendReceiveStringList(strlist);
376}
377
384{
385 QStringList strlist( QString("QUERY_RECORDER %1").arg(m_recordernum) );
386 strlist << "PAUSE";
387
388 if (SendReceiveStringList(strlist))
389 m_lastinput = "";
390}
391
393{
394 QStringList strlist( QString("QUERY_RECORDER %1").arg(m_recordernum) );
395 strlist << "FINISH_RECORDING";
396
397 SendReceiveStringList(strlist);
398}
399
401{
402 QStringList strlist( QString("QUERY_RECORDER %1").arg(m_recordernum) );
403 strlist << "SET_LIVE_RECORDING";
404 strlist << QString::number(static_cast<int>(recording));
405
406 SendReceiveStringList(strlist);
407}
408
410{
411 if (!m_lastinput.isEmpty())
412 return m_lastinput;
413
414 QStringList strlist( QString("QUERY_RECORDER %1").arg(m_recordernum) );
415 strlist << "GET_INPUT";
416
417 if (SendReceiveStringList(strlist, 1))
418 {
419 m_lastinput = strlist[0];
420 return m_lastinput;
421 }
422
423 return "Error";
424}
425
426QString RemoteEncoder::SetInput(const QString& input)
427{
428 QStringList strlist( QString("QUERY_RECORDER %1").arg(m_recordernum) );
429 strlist << "SET_INPUT";
430 strlist << input;
431
432 if (SendReceiveStringList(strlist, 1))
433 {
434 m_lastchannel = "";
435 m_lastinput = "";
436 return strlist[0];
437 }
438
439 return (m_lastinput.isEmpty()) ? "Error" : m_lastinput;
440}
441
442void RemoteEncoder::ToggleChannelFavorite(const QString& changroupname)
443{
444 QStringList strlist( QString("QUERY_RECORDER %1").arg(m_recordernum) );
445 strlist << "TOGGLE_CHANNEL_FAVORITE";
446 strlist << changroupname;
447
448 SendReceiveStringList(strlist);
449}
450
451void RemoteEncoder::ChangeChannel(int channeldirection)
452{
453 QStringList strlist( QString("QUERY_RECORDER %1").arg(m_recordernum) );
454 strlist << "CHANGE_CHANNEL";
455 strlist << QString::number(channeldirection);
456
457 if (!SendReceiveStringList(strlist))
458 return;
459
460 m_lastchannel = "";
461 m_lastinput = "";
462}
463
464void RemoteEncoder::SetChannel(const QString& channel)
465{
466 QStringList strlist( QString("QUERY_RECORDER %1").arg(m_recordernum) );
467 strlist << "SET_CHANNEL";
468 strlist << channel;
469
470 if (!SendReceiveStringList(strlist))
471 return;
472
473 m_lastchannel = "";
474 m_lastinput = "";
475}
476
493std::chrono::milliseconds RemoteEncoder::SetSignalMonitoringRate(std::chrono::milliseconds rate, int notifyFrontend)
494{
495 QStringList strlist( QString("QUERY_RECORDER %1").arg(m_recordernum) );
496 strlist << "SET_SIGNAL_MONITORING_RATE";
497 strlist << QString::number(rate.count());
498 strlist << QString::number(notifyFrontend);
499
500 if (SendReceiveStringList(strlist, 1))
501 return std::chrono::milliseconds(strlist[0].toInt());
502
503 return 0ms;
504}
505
507{
508 QMutexLocker locker(&m_lock);
509
510 QMap<QString,uint>::const_iterator it = m_cachedTimeout.constFind(input);
511 if (it != m_cachedTimeout.constEnd())
512 return *it;
513
514 uint cardid = m_recordernum;
515 uint timeout = 0xffffffff;
517 query.prepare(
518 "SELECT channel_timeout, cardtype "
519 "FROM capturecard "
520 "WHERE capturecard.inputname = :INNAME AND "
521 " capturecard.cardid = :CARDID");
522 query.bindValue(":INNAME", input);
523 query.bindValue(":CARDID", cardid);
524 if (!query.exec() || !query.isActive())
525 MythDB::DBError("Getting timeout", query);
526 else if (query.next() &&
527 SignalMonitor::IsRequired(query.value(1).toString()))
528 timeout = std::max(query.value(0).toInt(), 500);
529
530#if 0
531 LOG(VB_PLAYBACK, LOG_DEBUG, "RemoteEncoder: " +
532 QString("GetSignalLockTimeout(%1): Set lock timeout to %2 ms")
533 .arg(cardid).arg(timeout));
534#endif
535 m_cachedTimeout[input] = timeout;
536 return timeout;
537}
538
539
541{
542 QStringList strlist( QString("QUERY_RECORDER %1").arg(m_recordernum) );
543
544 if (kPictureAttribute_Contrast == attr)
545 strlist << "GET_CONTRAST";
546 else if (kPictureAttribute_Brightness == attr)
547 strlist << "GET_BRIGHTNESS";
548 else if (kPictureAttribute_Colour == attr)
549 strlist << "GET_COLOUR";
550 else if (kPictureAttribute_Hue == attr)
551 strlist << "GET_HUE";
552 else
553 return -1;
554
555 if (SendReceiveStringList(strlist, 1))
556 return strlist[0].toInt();
557
558 return -1;
559}
560
570{
571 QStringList strlist( QString("QUERY_RECORDER %1").arg(m_recordernum) );
572
573 if (kPictureAttribute_Contrast == attr)
574 strlist << "CHANGE_CONTRAST";
575 else if (kPictureAttribute_Brightness == attr)
576 strlist << "CHANGE_BRIGHTNESS";
577 else if (kPictureAttribute_Colour == attr)
578 strlist << "CHANGE_COLOUR";
579 else if (kPictureAttribute_Hue == attr)
580 strlist << "CHANGE_HUE";
581 else
582 return -1;
583
584 strlist << QString::number(type);
585 strlist << QString::number((int)up);
586
587 if (SendReceiveStringList(strlist, 1))
588 return strlist[0].toInt();
589
590 return -1;
591}
592
594{
595 QStringList strlist( QString("QUERY_RECORDER %1").arg(m_recordernum) );
596 strlist << "CHANGE_DEINTERLACER";
597 strlist << QString::number(deint_mode);
598
599 SendReceiveStringList(strlist);
600}
601
611bool RemoteEncoder::CheckChannel(const QString& channel)
612{
613 QStringList strlist( QString("QUERY_RECORDER %1").arg(m_recordernum) );
614 strlist << "CHECK_CHANNEL";
615 strlist << channel;
616
617 if (SendReceiveStringList(strlist, 1))
618 return strlist[0].toInt() != 0;
619
620 return false;
621}
622
632bool RemoteEncoder::ShouldSwitchToAnotherCard(const QString& channelid)
633{
634 // this function returns true if the channelid is not a valid
635 // channel on the current recorder. It queries to server in order
636 // to determine this.
637 QStringList strlist( QString("QUERY_RECORDER %1").arg(m_recordernum) );
638 strlist << "SHOULD_SWITCH_CARD";
639 strlist << channelid;
640
641 if (SendReceiveStringList(strlist, 1))
642 return strlist[0].toInt() != 0;
643
644 return false;
645}
646
654 const QString &prefix,
655 uint &complete_valid_channel_on_rec,
656 bool &is_extra_char_useful,
657 QString &needed_spacer)
658{
659 QStringList strlist( QString("QUERY_RECORDER %1").arg(m_recordernum) );
660 strlist << "CHECK_CHANNEL_PREFIX";
661 strlist << prefix;
662
663 if (!SendReceiveStringList(strlist, 4))
664 return false;
665
666 complete_valid_channel_on_rec = strlist[1].toInt();
667 is_extra_char_useful = (strlist[2].toInt() != 0);
668 needed_spacer = (strlist[3] == "X") ? "" : strlist[3];
669
670 return strlist[0].toInt() != 0;
671}
672
673static QString cleanup(const QString &str)
674{
675 if (str == " ")
676 return "";
677 return str;
678}
679
680static QString make_safe(const QString &str)
681{
682 if (str.isEmpty())
683 return " ";
684 return str;
685}
686
694 QString &title, QString &subtitle,
695 QString &desc, QString &category,
696 QString &starttime, QString &endtime,
697 QString &callsign, QString &iconpath,
698 QString &channelname, QString &chanid,
699 QString &seriesid, QString &programid)
700{
701 QStringList strlist( QString("QUERY_RECORDER %1").arg(m_recordernum) );
702 strlist << "GET_NEXT_PROGRAM_INFO";
703 strlist << channelname;
704 strlist << chanid;
705 strlist << QString::number(direction);
706 strlist << starttime;
707
708 if (!SendReceiveStringList(strlist, 12))
709 return;
710
711 title = cleanup(strlist[0]);
712 subtitle = cleanup(strlist[1]);
713 desc = cleanup(strlist[2]);
714 category = cleanup(strlist[3]);
715 starttime = cleanup(strlist[4]);
716 endtime = cleanup(strlist[5]);
717 callsign = cleanup(strlist[6]);
718 iconpath = cleanup(strlist[7]);
719 channelname = cleanup(strlist[8]);
720 chanid = cleanup(strlist[9]);
721 seriesid = cleanup(strlist[10]);
722 programid = cleanup(strlist[11]);
723}
724
726{
727 QStringList strlist( QString("QUERY_RECORDER %1").arg(m_recordernum));
728 strlist << "GET_CHANNEL_INFO";
729 strlist << QString::number(chanid);
730
731 if (!SendReceiveStringList(strlist, 6))
732 return;
733
734 infoMap["chanid"] = cleanup(strlist[0]);
735 infoMap["sourceid"] = cleanup(strlist[1]);
736 infoMap["callsign"] = cleanup(strlist[2]);
737 infoMap["channum"] = cleanup(strlist[3]);
738 infoMap["channame"] = cleanup(strlist[4]);
739 infoMap["XMLTV"] = cleanup(strlist[5]);
740
741 infoMap["oldchannum"] = infoMap["channum"];
742}
743
745{
746 QStringList strlist( "SET_CHANNEL_INFO" );
747 strlist << make_safe(infoMap["chanid"]);
748 strlist << make_safe(infoMap["sourceid"]);
749 strlist << make_safe(infoMap["oldchannum"]);
750 strlist << make_safe(infoMap["callsign"]);
751 strlist << make_safe(infoMap["channum"]);
752 strlist << make_safe(infoMap["channame"]);
753 strlist << make_safe(infoMap["XMLTV"]);
754
755 if (SendReceiveStringList(strlist, 1))
756 return strlist[0].toInt() != 0;
757
758 return false;
759}
QSqlQuery wrapper that fetches a DB connection from the connection pool.
Definition: mythdbcon.h:128
bool prepare(const QString &query)
QSqlQuery::prepare() is not thread safe in Qt <= 3.3.2.
Definition: mythdbcon.cpp:837
QVariant value(int i) const
Definition: mythdbcon.h:204
bool isActive(void) const
Definition: mythdbcon.h:215
bool exec(void)
Wrap QSqlQuery::exec() so we can display SQL.
Definition: mythdbcon.cpp:618
void bindValue(const QString &placeholder, const QVariant &val)
Add a single binding.
Definition: mythdbcon.cpp:888
bool next(void)
Wrap QSqlQuery::next() so we can display the query results.
Definition: mythdbcon.cpp:812
static MSqlQueryInfo InitCon(ConnectionReuse _reuse=kNormalConnection)
Only use this in combination with MSqlQuery constructor.
Definition: mythdbcon.cpp:550
QString GetHostName(void)
MythSocket * ConnectCommandSocket(const QString &hostname, int port, const QString &announcement, bool *proto_mismatch=nullptr, int maxConnTry=-1, std::chrono::milliseconds setup_timeout=-1ms)
static void DBError(const QString &where, const MSqlQuery &query)
Definition: mythdb.cpp:226
bool ReadStringList(QStringList &list, std::chrono::milliseconds timeoutMS=kShortTimeout)
Definition: mythsocket.cpp:313
static constexpr std::chrono::milliseconds kShortTimeout
Definition: mythsocket.h:70
bool WriteStringList(const QStringList &list)
Definition: mythsocket.cpp:301
std::chrono::milliseconds restart(void)
Returns milliseconds elapsed since last start() or restart() and resets the count.
Definition: mythtimer.cpp:62
std::chrono::milliseconds elapsed(void)
Returns milliseconds elapsed since last start() or restart()
Definition: mythtimer.cpp:91
bool isRunning(void) const
Returns true if start() or restart() has been called at least once since construction and since any c...
Definition: mythtimer.cpp:135
Holds information on recordings and videos.
Definition: programinfo.h:68
virtual int DecrRef(void)
Decrements reference count and deletes on 0.
long long m_cachedFramesWritten
Definition: remoteencoder.h:99
std::chrono::milliseconds SetSignalMonitoringRate(std::chrono::milliseconds rate, int notifyFrontend=1)
Sets the signal monitoring rate.
ProgramInfo * GetRecording(void)
void StopLiveTV(void)
Tells TVRec to stop a "Live TV" recorder.
void StopPlaying(void)
Tells TVRec to stop streaming a recording to the frontend.
bool ShouldSwitchToAnotherCard(const QString &channelid)
Checks if named channel exists on current tuner, or another tuner.
void SpawnLiveTV(const QString &chainid, bool pip, const QString &startchan)
Tells TVRec to Spawn a "Live TV" recorder.
void ChangeChannel(int channeldirection)
QMap< QString, uint > m_cachedTimeout
void SetLiveRecording(bool recording)
void FillPositionMap(int64_t start, int64_t end, frm_pos_map_t &positionMap)
int ChangePictureAttribute(PictureAdjustType type, PictureAttribute attr, bool up)
Changes brightness/contrast/colour/hue of a recording.
QString m_remotehost
Definition: remoteencoder.h:92
int GetPictureAttribute(PictureAttribute attr)
bool IsValidRecorder(void) const
void GetChannelInfo(InfoMap &infoMap, uint chanid=0)
bool CheckChannelPrefix(const QString &prefix, uint &complete_valid_channel_on_rec, bool &is_extra_char_useful, QString &needed_spacer)
Checks a prefix against the channels in the DB.
float GetFrameRate(void)
Returns recordering frame rate set by nvr.
QString m_lastchannel
Definition: remoteencoder.h:95
long long GetFramesWritten(void)
Returns number of frames written to disk by TVRec's RecorderBase instance.
long long GetFilePosition(void)
Returns total number of bytes written by TVRec's RingBuffer.
void PauseRecorder(void)
Tells TVRec to pause a recorder, used for channel and input changes.
void ChangeDeinterlacer(int deint_mode)
bool SendReceiveStringList(QStringList &strlist, uint min_reply_length=0)
void SetChannel(const QString &channel)
uint GetSignalLockTimeout(const QString &input)
void FrontendReady(void)
QString SetInput(const QString &input)
bool SetChannelInfo(const InfoMap &infoMap)
MythTimer m_lastTimeCheck
void FillDurationMap(int64_t start, int64_t end, frm_pos_map_t &durationMap)
QString GetInput(void)
bool Setup(void)
bool CheckChannel(const QString &channel)
Checks if named channel exists on current tuner.
void FinishRecording(void)
int64_t GetKeyframePosition(uint64_t desired)
Returns byte position in RingBuffer of a keyframe.
void CancelNextRecording(bool cancel)
int GetRecorderNumber(void) const
short m_remoteport
Definition: remoteencoder.h:93
void ToggleChannelFavorite(const QString &changroupname)
long long GetMaxBitrate()
Returns the maximum bits per second this recorder can produce.
QString m_lastinput
Definition: remoteencoder.h:96
bool IsRecording(bool *ok=nullptr)
void GetNextProgram(int direction, QString &title, QString &subtitle, QString &desc, QString &category, QString &starttime, QString &endtime, QString &callsign, QString &iconpath, QString &channelname, QString &chanid, QString &seriesid, QString &programid)
Returns information about the program that would be seen if we changed the channel using ChangeChanne...
MythSocket * m_controlSock
Definition: remoteencoder.h:89
static bool IsRequired(const QString &cardtype)
Returns true iff the card type supports signal monitoring.
unsigned int uint
Definition: freesurround.h:24
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
QHash< QString, QString > InfoMap
Definition: mythtypes.h:15
QMap< long long, long long > frm_pos_map_t
Frame # -> File offset map.
Definition: programtypes.h:44
#define LOC
static QString make_safe(const QString &str)
static constexpr std::chrono::milliseconds MAX_SIZE_CHECK
static QString cleanup(const QString &str)
PictureAdjustType
Definition: tv.h:124
PictureAttribute
@ kPictureAttribute_Contrast
@ kPictureAttribute_Brightness
@ kPictureAttribute_Colour
@ kPictureAttribute_Hue