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