MythTV master
ExternalRecorder.cpp
Go to the documentation of this file.
1/* -*- Mode: c++ -*-
2 * Class ExternalRecorder
3 *
4 * Copyright (C) John Poet 2013
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20#include <thread>
21
22// Qt includes
23#include <QString>
24
25// MythTV includes
27
29#include "ExternalRecorder.h"
30#include "ExternalChannel.h"
31#include "io/mythmediabuffer.h"
32#include "tv_rec.h"
33
34#define LOC QString("ExternalRec[%1](%2): ") \
35 .arg(m_channel->GetInputID()) \
36 .arg(m_channel->GetDescription())
37
39{
40 // Make sure the first things in the file are a PAT & PMT
43}
44
45
47{
48 if (!Open())
49 {
50 m_error = "Failed to open device";
51 LOG(VB_GENERAL, LOG_ERR, LOC + m_error);
52 return;
53 }
54
55 if (!m_streamData)
56 {
57 m_error = "MPEGStreamData pointer has not been set";
58 LOG(VB_GENERAL, LOG_ERR, LOC + m_error);
59 Close();
60 return;
61 }
62
63 {
64 QMutexLocker locker(&m_pauseLock);
65 m_requestRecording = true;
66 m_recording = true;
67 m_recordingWait.wakeAll();
68 }
69
71 {
76 m_streamData->HandleTables(pat->ProgramPID(0), *pmt);
77 LOG(VB_GENERAL, LOG_INFO, LOC + "PMT set");
78 }
79
81
83 m_seenSps = false;
84
88
90
91 while (IsRecordingRequested() && !IsErrored())
92 {
93 if (PauseAndWait())
94 continue;
95
96 if (!m_inputPmt)
97 {
98 LOG(VB_GENERAL, LOG_WARNING, LOC +
99 "Recording will not commence until a PMT is set.");
100 std::this_thread::sleep_for(5ms);
101 continue;
102 }
103
105 {
106 m_error = "Stream handler died unexpectedly.";
107 LOG(VB_GENERAL, LOG_ERR, LOC + m_error);
108 }
109
111 {
112 LOG(VB_GENERAL, LOG_WARNING, LOC +
113 QString("Recording is damaged. Setting status to %1")
115 SetRecordingStatus(RecStatus::Failing, __FILE__, __LINE__);
116
117 // Fudge it with 1 second.
118 QMutexLocker locker(&m_statisticsLock);
119 QDateTime gap_end(MythDate::current());
120 QDateTime gap_start = gap_end.addSecs(-1);
121 m_recordingGaps.push_back(RecordingGap(gap_start, gap_end));
122
124 }
125 }
126
128
132
133 Close();
134
136
137 QMutexLocker locker(&m_pauseLock);
138 m_recording = false;
139 m_recordingWait.wakeAll();
140}
141
143{
144 if (IsOpen())
145 {
146 LOG(VB_GENERAL, LOG_WARNING, LOC + "Card already open");
147 return true;
148 }
149
151
155
156 if (m_streamHandler)
157 {
159 LOG(VB_RECORD, LOG_INFO, LOC + "Opened successfully");
160 else
161 {
163 (m_tvrec ? m_tvrec->GetInputId() : -1));
164
165 return false;
166 }
167 return true;
168 }
169
170 Close();
171 LOG(VB_GENERAL, LOG_ERR, LOC + "Open failed");
172 return false;
173}
174
176{
177 LOG(VB_RECORD, LOG_INFO, LOC + "Close() -- begin");
178
179 if (IsOpen())
181 (m_tvrec ? m_tvrec->GetInputId() : -1));
182
183 LOG(VB_RECORD, LOG_INFO, LOC + "Close() -- end");
184}
185
186bool ExternalRecorder::PauseAndWait(std::chrono::milliseconds timeout)
187{
188 QMutexLocker locker(&m_pauseLock);
189 if (m_requestPause)
190 {
191 if (!IsPaused(true))
192 {
193 LOG(VB_RECORD, LOG_INFO, LOC + "PauseAndWait pause");
194
197
198 m_paused = true;
199 m_pauseWait.wakeAll();
200
201 if (m_tvrec)
203 }
204 }
205 else if (IsPaused(true))
206 {
207 LOG(VB_RECORD, LOG_INFO, LOC + "PauseAndWait unpause");
208
209 // The SignalMonitor will StartStreaming
210
211 if (m_h2645Parser != nullptr)
213
214 if (m_streamData)
216
217 m_paused = false;
220 }
221
222 // Always wait a little bit, unless woken up
223 m_unpauseWait.wait(&m_pauseLock, timeout.count());
224
225 return IsPaused(true);
226}
227
229{
230 LOG(VB_RECORD, LOG_INFO, LOC + "StartStreaming");
232}
233
235{
237}
#define LOC
virtual int GetInputID(void) const
Definition: channelbase.h:67
int GetMajorID(void)
bool HasGeneratedPAT(void) const
Definition: dtvchannel.h:135
const ProgramMapTable * GetGeneratedPMT(void) const
Definition: dtvchannel.h:138
const ProgramAssociationTable * GetGeneratedPAT(void) const
Definition: dtvchannel.h:137
bool m_seenSps
Definition: dtvrecorder.h:151
QString m_error
non-empty iff irrecoverable recording error detected
Definition: dtvrecorder.h:161
void FinishRecording(void) override
Flushes the ringbuffer, and if this is not a live LiveTV recording saves the position map and filesiz...
ProgramMapTable * m_inputPmt
PMT on input side.
Definition: dtvrecorder.h:174
bool IsErrored(void) override
Tells us whether an unrecoverable error has been encountered.
Definition: dtvrecorder.h:46
void ResetForNewFile(void) override
H2645Parser * m_h2645Parser
Definition: dtvrecorder.h:152
void HandleSingleProgramPAT(ProgramAssociationTable *pat, bool insert) override
bool m_waitForKeyframeOption
Wait for the a GOP/SEQ-start before sending data.
Definition: dtvrecorder.h:155
MPEGStreamData * m_streamData
Definition: dtvrecorder.h:163
void HandleSingleProgramPMT(ProgramMapTable *pmt, bool insert) override
QString GetDevice(void) const override
Returns String representing device, useful for debugging.
ExternalChannel * m_channel
ExternalStreamHandler * m_streamHandler
void run(void) override
run() starts the recording process, and does not exit until the recording is complete.
bool IsOpen(void) const
bool PauseAndWait(std::chrono::milliseconds timeout=100ms) override
If m_requestPause is true, sets pause and blocks up to timeout milliseconds or until unpaused,...
void StartNewFile(void) override
static ExternalStreamHandler * Get(const QString &devname, int inputid, int majorid)
static void Return(ExternalStreamHandler *&ref, int inputid)
virtual void Reset(void)
Definition: H2645Parser.cpp:91
const ProgramMapTable * PMTSingleProgram(void) const
void AddWritingListener(TSPacketListener *val)
int DesiredProgram(void) const
void RemoveWritingListener(TSPacketListener *val)
const ProgramAssociationTable * PATSingleProgram(void) const
virtual void Reset(void)
void RemoveAVListener(TSPacketListenerAV *val)
virtual bool HandleTables(uint pid, const PSIPTable &psip)
Process PSIP packets.
void AddAVListener(TSPacketListenerAV *val)
@ MPEG_PAT_PID
Definition: mpegtables.h:211
The Program Association Table lists all the programs in a stream, and is always found on PID 0.
Definition: mpegtables.h:599
uint ProgramNumber(uint i) const
Definition: mpegtables.h:626
uint ProgramPID(uint i) const
Definition: mpegtables.h:629
A PMT table maps a program described in the ProgramAssociationTable to various PID's which describe t...
Definition: mpegtables.h:676
static QString toString(RecStatus::Type recstatus, uint id)
Converts "recstatus" into a short (unreadable) string.
QMutex m_pauseLock
Definition: recorderbase.h:314
bool m_requestPause
Definition: recorderbase.h:315
QMutex m_statisticsLock
Definition: recorderbase.h:351
TVRec * m_tvrec
Definition: recorderbase.h:291
virtual bool IsRecordingRequested(void)
Tells us if StopRecording() has been called.
bool m_recording
True while recording is actually being performed.
Definition: recorderbase.h:322
virtual void SetRecordingStatus(RecStatus::Type status, const QString &file, int line)
QWaitCondition m_pauseWait
Definition: recorderbase.h:317
RecordingGaps m_recordingGaps
Definition: recorderbase.h:358
virtual bool IsPaused(bool holding_lock=false) const
Returns true iff recorder is paused.
bool m_requestRecording
True if API call has requested a recording be [re]started.
Definition: recorderbase.h:320
QWaitCondition m_unpauseWait
Definition: recorderbase.h:318
QWaitCondition m_recordingWait
Definition: recorderbase.h:323
bool IsRunning(void) const
virtual void RemoveListener(MPEGStreamData *data)
virtual void AddListener(MPEGStreamData *data, bool allow_section_reader=false, bool needs_buffering=false, const QString &output_file=QString())
void RecorderPaused(void)
This is a callback, called by the "recorder" instance when it has actually paused.
Definition: tv_rec.cpp:2995
uint GetInputId(void) const
Returns the inputid.
Definition: tv_rec.h:233
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
QDateTime current(bool stripped)
Returns current Date and Time in UTC.
Definition: mythdate.cpp:15
@ kSingleRecord