MythTV  master
v4l2encrecorder.cpp
Go to the documentation of this file.
1 /* -*- Mode: c++ -*-
2  * Class V4L2encRecorder
3  *
4  * Copyright (C) John Poet 2014
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
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19  */
20 
21 #include <chrono> // for milliseconds
22 #include <sys/ioctl.h>
23 #include <thread> // for sleep_for
24 
25 // Qt includes
26 #include <QString>
27 
28 // MythTV includes
29 #include "io/mythmediabuffer.h"
32 #include "recorders/v4lchannel.h"
33 #include "recordingprofile.h"
34 #include "tv_rec.h"
35 
36 #define LOC QString("V4L2Rec[%1](%2): ") \
37  .arg(m_tvrec ? m_tvrec->GetInputId() : -1) \
38  .arg(m_channel->GetDevice())
39 
41  V4LRecorder(rec), m_channel(channel)
42 {
43  if (!Open())
44  {
45  m_error = "Failed to open device";
46  LOG(VB_GENERAL, LOG_ERR, LOC + "Open() -- " + m_error);
47  return;
48  }
49 }
50 
51 
53 {
54  const StandardSetting *setting = profile->byName(name);
55  if (setting)
56  {
57  if (!m_streamHandler->SetOption(name, setting->getValue().toInt()))
58  V4LRecorder::SetOption(name, setting->getValue().toInt());
59  }
60 }
61 
63 {
64  const StandardSetting *setting = profile->byName(name);
65  if (setting)
66  {
67  if (!m_streamHandler->SetOption(name, setting->getValue()))
68  V4LRecorder::SetOption(name, setting->getValue());
69  }
70 }
71 
73  const QString &videodev,
74  const QString &audiodev,
75  const QString &vbidev)
76 {
77  LOG(VB_GENERAL, LOG_INFO, LOC + "SetOptionsFromProfile() -- begin"); //debugging
78 
79  (void)audiodev;
80  (void)vbidev;
81 
82  SetOption("videodevice", videodev);
83  SetOption("vbidevice", vbidev);
84  SetOption("audiodevice", audiodev);
85 
86  SetOption("tvformat", gCoreContext->GetSetting("TVFormat"));
87  SetOption("vbiformat", gCoreContext->GetSetting("VbiFormat"));
88 
89  SetIntOption(profile, "mpeg2bitratemode");
90  SetIntOption(profile, "mpeg2bitrate");
91  SetIntOption(profile, "mpeg2maxbitrate");
92  SetStrOption(profile, "mpeg2streamtype");
93  SetStrOption(profile, "mpeg2aspectratio");
94  SetStrOption(profile, "mpeg2language");
95 
96  SetIntOption(profile, "samplerate");
97  SetStrOption(profile, "mpeg2audtype");
98  SetIntOption(profile, "audbitratemode");
99  SetIntOption(profile, "mpeg2audbitratel1");
100  SetIntOption(profile, "mpeg2audbitratel2");
101  SetIntOption(profile, "mpeg2audbitratel3");
102  SetIntOption(profile, "mpeg2audvolume");
103 
104  SetIntOption(profile, "width");
105  SetIntOption(profile, "height");
106 
107  SetIntOption(profile, "low_mpegbitratemode");
108  SetIntOption(profile, "low_mpegavgbitrate");
109  SetIntOption(profile, "low_mpegpeakbitrate");
110  SetIntOption(profile, "medium_mpegbitratemode");
111  SetIntOption(profile, "medium_mpegavgbitrate");
112  SetIntOption(profile, "medium_mpegpeakbitrate");
113  SetIntOption(profile, "high_mpegbitratemode");
114  SetIntOption(profile, "high_mpegavgbitrate");
115  SetIntOption(profile, "high_mpegpeakbitrate");
116 
117  SetStrOption(profile, "audiocodec");
118 
119  LOG(VB_GENERAL, LOG_INFO, LOC + "SetOptionsFromProfile -- end"); // debugging
120 }
121 
123 {
124  LOG(VB_RECORD, LOG_INFO, LOC + "StartNewFile -- begin"); // debugging
125  // Make sure the first things in the file are a PAT & PMT
128  LOG(VB_RECORD, LOG_INFO, LOC + "StartNewFile -- end"); // debugging
129 }
130 
131 
133 {
134  LOG(VB_RECORD, LOG_INFO, LOC + "run() -- begin");
135 
136  bool is_TS = false;
137 
138  if (!m_streamData)
139  {
140  m_error = "MPEGStreamData pointer has not been set";
141  LOG(VB_GENERAL, LOG_ERR, LOC + "run() -- " + m_error);
142  Close();
143  return;
144  }
145 
147 
148  {
149  QMutexLocker locker(&m_pauseLock);
150  m_requestRecording = true;
151  m_recording = true;
152  m_recordingWait.wakeAll();
153  }
154 
155  if (m_channel->HasGeneratedPAT())
156  {
158  const ProgramMapTable *pmt = m_channel->GetGeneratedPMT();
159  m_streamData->Reset(pat->ProgramNumber(0));
161  m_streamData->HandleTables(pat->ProgramPID(0), *pmt);
162  LOG(VB_GENERAL, LOG_INFO, LOC + "PMT set"); // debugging
163  }
164 
165  StartNewFile();
166  is_TS = (m_streamHandler->GetStreamType() == V4L2_MPEG_STREAM_TYPE_MPEG2_TS);
167 
168  if (is_TS)
169  {
170  LOG(VB_RECORD, LOG_INFO, LOC + "mpeg2ts");
173  }
174  else
175  {
176  LOG(VB_RECORD, LOG_INFO, LOC + "program stream (non mpeg2ts)");
178  }
179 
181 
182  StartEncoding();
183 
184  while (IsRecordingRequested() && !IsErrored())
185  {
186  if (PauseAndWait())
187  continue;
188 
189  if (is_TS && !m_inputPmt)
190  {
191  LOG(VB_GENERAL, LOG_WARNING, LOC +
192  "Recording will not commence until a PMT is set.");
193  std::this_thread::sleep_for(5ms);
194  continue;
195  }
196 
197  bool failing = false;
198  bool failed = false;
199  if (!m_streamHandler->Status(failed, failing))
200  {
201  if (failed)
202  {
203  m_error = "Stream handler died unexpectedly.";
204  LOG(VB_GENERAL, LOG_ERR, LOC + "run() -- " + m_error);
205  }
206  else if (failing)
207  {
208  SetRecordingStatus(RecStatus::Failing, __FILE__, __LINE__);
209  }
210  }
211  }
212  LOG(VB_RECORD, LOG_INFO, LOC + "Shutting down");
213 
214  StopEncoding();
215 
217  if (m_streamHandler->GetStreamType() == V4L2_MPEG_STREAM_TYPE_MPEG2_TS)
218  {
221  }
222  else
224 
225  Close();
226 
227  FinishRecording();
228 
229  QMutexLocker locker(&m_pauseLock);
230  m_recording = false;
231  m_recordingWait.wakeAll();
232 
233  LOG(VB_RECORD, LOG_INFO, LOC + "run() -- end");
234 }
235 
237 {
238  LOG(VB_RECORD, LOG_INFO, LOC + "Open() -- begin");
239 
240  if (IsOpen())
241  {
242  LOG(VB_RECORD, LOG_WARNING, LOC + "Open() -- Card already open");
243  return true;
244  }
245 
246 // ?? ResetForNewFile();
247 
249  m_channel->GetAudioDevice().toInt(),
250  m_tvrec ? m_tvrec->GetInputId() : -1);
251  if (!m_streamHandler)
252  {
253  LOG(VB_GENERAL, LOG_ERR, LOC +
254  "Open() -- Failed to get a stream handler.");
255  return false;
256  }
257 
258  if (!m_streamHandler->IsOpen())
259  {
260  LOG(VB_GENERAL, LOG_ERR, LOC +
261  QString("Open() -- Failed to open recorder: %1")
262  .arg(m_streamHandler->ErrorString()));
264  m_tvrec ? m_tvrec->GetInputId() : -1);
265  return false;
266  }
267 
268  m_useIForKeyframe = false;
269 
270  LOG(VB_RECORD, LOG_INFO, LOC + "Open() -- Success.");
271  return true;
272 }
273 
275 {
276  LOG(VB_RECORD, LOG_INFO, LOC + "Close() -- begin");
277 
278  if (IsOpen())
280  m_tvrec ? m_tvrec->GetInputId() : -1);
281 
282 
283  LOG(VB_RECORD, LOG_INFO, LOC + "Close() -- end");
284 }
285 
286 bool V4L2encRecorder::PauseAndWait(std::chrono::milliseconds timeout)
287 {
288  QMutexLocker locker(&m_pauseLock);
289  if (m_requestPause)
290  {
291  if (!IsPaused(true))
292  {
293  LOG(VB_RECORD, LOG_INFO, LOC + "PauseAndWait() -- pause");
294 
295  StopEncoding();
296 
297  m_paused = true;
298  m_pauseWait.wakeAll();
299 
300  if (m_tvrec)
302  }
303  }
304  else if (IsPaused(true))
305  {
306  LOG(VB_RECORD, LOG_INFO, LOC + "PauseAndWait() -- unpause");
307  StartEncoding();
308 
309  if (m_streamData)
311 
312  m_paused = false;
313  }
314 
315  // Always wait a little bit, unless woken up
316  m_unpauseWait.wait(&m_pauseLock, timeout.count());
317 
318  return IsPaused(true);
319 }
320 
322 {
323  LOG(VB_RECORD, LOG_DEBUG, LOC + "V4L2encRecorder::StartEncoding() -- begin");
324  if (m_h2645Parser != nullptr)
325  m_h2645Parser->Reset();
327  m_seenSps = false;
328 
329  LOG(VB_RECORD, LOG_DEBUG, LOC + "V4L2encRecorder::StartEncoding() -- end");
331 }
332 
334 {
335  LOG(VB_RECORD, LOG_DEBUG, LOC + "V4L2encRecorder::StopEncoding()");
337 }
DTVRecorder::HandleSingleProgramPMT
void HandleSingleProgramPMT(ProgramMapTable *pmt, bool insert) override
Definition: dtvrecorder.cpp:1405
V4L2encStreamHandler::Return
static void Return(V4L2encStreamHandler *&ref, int inputid)
Definition: v4l2encstreamhandler.cpp:95
ProgramAssociationTable::ProgramPID
uint ProgramPID(uint i) const
Definition: mpegtables.h:648
V4L2encRecorder::PauseAndWait
bool PauseAndWait(std::chrono::milliseconds timeout=500ms) override
If m_requestPause is true, sets pause and blocks up to timeout milliseconds or until unpaused,...
Definition: v4l2encrecorder.cpp:286
hardwareprofile.smolt.timeout
float timeout
Definition: smolt.py:103
V4L2encRecorder::run
void run(void) override
run() starts the recording process, and does not exit until the recording is complete.
Definition: v4l2encrecorder.cpp:132
DTVRecorder::m_inputPmt
ProgramMapTable * m_inputPmt
PMT on input side.
Definition: dtvrecorder.h:177
V4L2encStreamHandler::IsOpen
bool IsOpen(void) const
Definition: v4l2encstreamhandler.h:46
PID::MPEG_PAT_PID
@ MPEG_PAT_PID
Definition: mpegtables.h:211
V4LRecorder
Abstract base class for Video4Linux based recorders.
Definition: v4lrecorder.h:25
V4L2encRecorder::SetOptionsFromProfile
void SetOptionsFromProfile(RecordingProfile *profile, const QString &videodev, const QString &audiodev, const QString &vbidev) override
Sets basic recorder options.
Definition: v4l2encrecorder.cpp:72
V4L2encRecorder::StopEncoding
bool StopEncoding(void)
Definition: v4l2encrecorder.cpp:333
ProgramMapTable
A PMT table maps a program described in the ProgramAssociationTable to various PID's which describe t...
Definition: mpegtables.h:694
H2645Parser::Reset
virtual void Reset(void)
Definition: H2645Parser.cpp:93
V4L2encRecorder::m_channel
V4LChannel * m_channel
Definition: v4l2encrecorder.h:55
RecorderBase::m_tvrec
TVRec * m_tvrec
Definition: recorderbase.h:315
DTVRecorder::IsErrored
bool IsErrored(void) override
Tells us whether an unrecoverable error has been encountered.
Definition: dtvrecorder.h:45
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
LOC
#define LOC
Definition: v4l2encrecorder.cpp:36
DTVRecorder::FinishRecording
void FinishRecording(void) override
Flushes the ringbuffer, and if this is not a live LiveTV recording saves the position map and filesiz...
Definition: dtvrecorder.cpp:126
V4L2encStreamHandler::GetStreamType
int GetStreamType(void)
Definition: v4l2encstreamhandler.cpp:816
V4L2encRecorder::SetIntOption
void SetIntOption(RecordingProfile *profile, const QString &name)
Definition: v4l2encrecorder.cpp:52
DTVChannel::GetGeneratedPMT
const ProgramMapTable * GetGeneratedPMT(void) const
Definition: dtvchannel.h:139
MPEGStreamData::PMTSingleProgram
const ProgramMapTable * PMTSingleProgram(void) const
Definition: mpegstreamdata.h:266
V4L2encStreamHandler::StopEncoding
bool StopEncoding(void)
Definition: v4l2encstreamhandler.cpp:610
v4l2encstreamhandler.h
V4L2encStreamHandler::SetOption
bool SetOption(const QString &opt, int value)
Definition: v4l2encstreamhandler.cpp:705
StreamHandler::RemoveListener
virtual void RemoveListener(MPEGStreamData *data)
Definition: streamhandler.cpp:80
RecorderBase::m_pauseLock
QMutex m_pauseLock
Definition: recorderbase.h:338
V4LRecorder::SetOption
void SetOption(const QString &name, const QString &value) override
Set an specific option.
Definition: v4lrecorder.cpp:56
RecorderBase::m_requestPause
bool m_requestPause
Definition: recorderbase.h:339
RecorderBase::m_recordingWait
QWaitCondition m_recordingWait
Definition: recorderbase.h:347
TVRec::RecorderPaused
void RecorderPaused(void)
This is a callback, called by the "recorder" instance when it has actually paused.
Definition: tv_rec.cpp:2897
TVRec::GetInputId
uint GetInputId(void) const
Returns the inputid.
Definition: tv_rec.h:236
RecorderBase::m_paused
bool m_paused
Definition: recorderbase.h:340
MPEGStreamData::PATSingleProgram
const ProgramAssociationTable * PATSingleProgram(void) const
Definition: mpegstreamdata.h:264
DTVRecorder::HandleSingleProgramPAT
void HandleSingleProgramPAT(ProgramAssociationTable *pat, bool insert) override
Definition: dtvrecorder.cpp:1385
MPEGStreamData::AddPSStreamListener
void AddPSStreamListener(PSStreamListener *val)
Definition: mpegstreamdata.cpp:1741
ProgramAssociationTable::ProgramNumber
uint ProgramNumber(uint i) const
Definition: mpegtables.h:645
hardwareprofile.scan.profile
profile
Definition: scan.py:99
v4lchannel.h
V4L2encRecorder::m_streamHandler
V4L2encStreamHandler * m_streamHandler
Definition: v4l2encrecorder.h:56
MPEGStreamData::HandleTables
virtual bool HandleTables(uint pid, const PSIPTable &psip)
Process PSIP packets.
Definition: mpegstreamdata.cpp:668
RecStatus::Failing
@ Failing
Definition: recordingstatus.h:18
DTVChannel::GetGeneratedPAT
const ProgramAssociationTable * GetGeneratedPAT(void) const
Definition: dtvchannel.h:138
MPEGStreamData::RemoveWritingListener
void RemoveWritingListener(TSPacketListener *val)
Definition: mpegstreamdata.cpp:1660
V4L2encRecorder::V4L2encRecorder
V4L2encRecorder(TVRec *rec, V4LChannel *channel)
Definition: v4l2encrecorder.cpp:40
V4L2encStreamHandler::ErrorString
QString ErrorString(void) const
Definition: v4l2encstreamhandler.h:60
V4L2encStreamHandler::StartEncoding
bool StartEncoding(void)
Definition: v4l2encstreamhandler.cpp:501
RecorderBase::IsRecordingRequested
virtual bool IsRecordingRequested(void)
Tells us if StopRecording() has been called.
Definition: recorderbase.cpp:250
v4l2encrecorder.h
DTVRecorder::m_h2645Parser
H2645Parser * m_h2645Parser
Definition: dtvrecorder.h:151
DTVRecorder::m_seenSps
bool m_seenSps
Definition: dtvrecorder.h:150
StandardSetting::getValue
virtual QString getValue(void) const
Definition: standardsettings.h:52
V4L2encRecorder::SetStrOption
void SetStrOption(RecordingProfile *profile, const QString &name)
Definition: v4l2encrecorder.cpp:62
gCoreContext
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
Definition: mythcorecontext.cpp:54
ProgramAssociationTable
The Program Association Table lists all the programs in a stream, and is always found on PID 0.
Definition: mpegtables.h:617
mythmediabuffer.h
RecorderBase::m_pauseWait
QWaitCondition m_pauseWait
Definition: recorderbase.h:341
MPEGStreamData::RemovePSStreamListener
void RemovePSStreamListener(PSStreamListener *val)
Definition: mpegstreamdata.cpp:1752
MPEGStreamData::AddAVListener
void AddAVListener(TSPacketListenerAV *val)
Definition: mpegstreamdata.cpp:1674
V4L2encStreamHandler::Status
bool Status(bool &failed, bool &failing)
Definition: v4l2encstreamhandler.cpp:138
V4L2encRecorder::Open
bool Open(void)
Definition: v4l2encrecorder.cpp:236
DTVRecorder::m_waitForKeyframeOption
bool m_waitForKeyframeOption
Wait for the a GOP/SEQ-start before sending data.
Definition: dtvrecorder.h:154
RecorderBase::SetRecordingStatus
virtual void SetRecordingStatus(RecStatus::Type status, const QString &file, int line)
Definition: recorderbase.cpp:396
DTVRecorder::m_streamData
MPEGStreamData * m_streamData
Definition: dtvrecorder.h:162
MPEGStreamData::AddWritingListener
void AddWritingListener(TSPacketListener *val)
Definition: mpegstreamdata.cpp:1649
MPEGStreamData::DesiredProgram
int DesiredProgram(void) const
Definition: mpegstreamdata.h:260
DTVRecorder::m_error
QString m_error
non-empty iff irrecoverable recording error detected
Definition: dtvrecorder.h:160
V4LChannel::GetAudioDevice
QString GetAudioDevice(void) const
Definition: v4lchannel.h:62
DTVRecorder::m_useIForKeyframe
bool m_useIForKeyframe
Definition: dtvrecorder.h:212
TVRec
This is the coordinating class of the Recorder Subsystem.
Definition: tv_rec.h:144
RecorderBase::m_recording
bool m_recording
True while recording is actually being performed.
Definition: recorderbase.h:346
MPEGStreamData::Reset
virtual void Reset(void)
Definition: mpegstreamdata.h:94
tv_rec.h
StandardSetting
Definition: standardsettings.h:29
StreamHandler::AddListener
virtual void AddListener(MPEGStreamData *data, bool allow_section_reader=false, bool needs_buffering=false, const QString &output_file=QString())
Definition: streamhandler.cpp:35
recordingprofile.h
DTVChannel::HasGeneratedPAT
bool HasGeneratedPAT(void) const
Definition: dtvchannel.h:136
V4L2encStreamHandler::Get
static V4L2encStreamHandler * Get(const QString &devname, int audioinput, int inputid)
Definition: v4l2encstreamhandler.cpp:63
RecordingProfile
Definition: recordingprofile.h:41
RecorderBase::m_unpauseWait
QWaitCondition m_unpauseWait
Definition: recorderbase.h:342
V4L2encRecorder::IsOpen
bool IsOpen(void) const
Definition: v4l2encrecorder.h:37
MPEGStreamData::RemoveAVListener
void RemoveAVListener(TSPacketListenerAV *val)
Definition: mpegstreamdata.cpp:1695
V4LChannel
Implements tuning for TV cards using the V4L driver API, both versions 1 and 2.
Definition: v4lchannel.h:30
RecorderBase::IsPaused
virtual bool IsPaused(bool holding_lock=false) const
Returns true iff recorder is paused.
Definition: recorderbase.cpp:282
V4LChannel::GetDevice
QString GetDevice(void) const override
Returns String representing device, useful for debugging.
Definition: v4lchannel.h:60
V4L2encRecorder::Close
void Close(void)
Definition: v4l2encrecorder.cpp:274
V4L2encRecorder::StartNewFile
void StartNewFile(void) override
Definition: v4l2encrecorder.cpp:122
V4L2encRecorder::StartEncoding
bool StartEncoding(void)
Definition: v4l2encrecorder.cpp:321
V4L2encStreamHandler::Configure
bool Configure(void)
Definition: v4l2encstreamhandler.cpp:401
MythCoreContext::GetSetting
QString GetSetting(const QString &key, const QString &defaultval="")
Definition: mythcorecontext.cpp:896
RecorderBase::m_requestRecording
bool m_requestRecording
True if API call has requested a recording be [re]started.
Definition: recorderbase.h:344