MythTV master
mpegrecorder.cpp
Go to the documentation of this file.
1// -*- Mode: c++ -*-
2
3// C++ headers
4#include <algorithm>
5#include <chrono> // for milliseconds
6#include <cinttypes>
7#include <fcntl.h>
8#include <thread> // for sleep_for
9#include <unistd.h>
10#include <vector>
11
12// System headers
13#include <sys/types.h>
14#include <sys/stat.h>
15#include <sys/ioctl.h>
16#include <sys/time.h>
17#include <sys/poll.h>
18
19#include <QtGlobal>
20
21#include <linux/videodev2.h>
22
23// MythTV headers
27
28#include "cardutil.h"
29#include "io/mythmediabuffer.h"
30#include "mpegrecorder.h"
31#include "programinfo.h"
32#include "recordingprofile.h"
33#include "tv_rec.h"
34
35#define LOC QString("MPEGRec[%1](%2): ") \
36 .arg(m_tvrec ? m_tvrec->GetInputId() : -1).arg(m_videodevice)
37
38const std::array<const int,14> MpegRecorder::kAudRateL1
39{
40 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448
41};
42
43const std::array<const int,14> MpegRecorder::kAudRateL2
44{
45 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384
46};
47
48const std::array<const int,14> MpegRecorder::kAudRateL3
49{
50 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320
51};
52
53const std::array<const std::string,15> MpegRecorder::kStreamType
54{
55 "MPEG-2 PS", "MPEG-2 TS", "MPEG-1 VCD", "PES AV",
56 "", "PES V", "", "PES A",
57 "", "", "DVD", "VCD",
58 "SVCD", "DVD-Special 1", "DVD-Special 2"
59};
60
61const std::array<const std::string,4> MpegRecorder::kAspectRatio
62{
63 "Square", "4:3", "16:9", "2.21:1"
64};
65
67{
69
70 if (m_chanfd >= 0)
71 {
73 m_chanfd = -1;
74 }
75 if (m_readfd >= 0)
76 {
78 m_readfd = -1;
79 }
80
82 {
85
86 delete m_deviceReadBuffer;
87 m_deviceReadBuffer = nullptr;
88 }
89
90}
91
92static int find_index(const std::array<const int,14> &audio_rate, int value)
93{
94 for (uint i = 0; i < audio_rate.size(); i++)
95 {
96 if (audio_rate[i] == value)
97 return i;
98 }
99
100 return -1;
101}
102
103void MpegRecorder::SetOption(const QString &opt, int value)
104{
105 if (opt == "width")
106 {
107 m_width = value;
108 }
109 else if (opt == "height")
110 {
111 m_height = value;
112 }
113 else if (opt == "mpeg2bitrate")
114 {
115 m_bitrate = value;
116 }
117 else if (opt == "mpeg2maxbitrate")
118 {
119 m_maxBitrate = value;
120 }
121 else if (opt == "samplerate")
122 {
123 m_audSampleRate = value;
124 }
125 else if (opt == "mpeg2audbitratel1")
126 {
127 int index = find_index(kAudRateL1, value);
128 if (index >= 0)
129 {
130 m_audBitrateL1 = index + 1;
131 }
132 else
133 {
134 LOG(VB_GENERAL, LOG_ERR, LOC + "Audiorate(L1): " +
135 QString("%1 is invalid").arg(value));
136 }
137 }
138 else if (opt == "mpeg2audbitratel2")
139 {
140 int index = find_index(kAudRateL2, value);
141 if (index >= 0)
142 {
143 m_audBitrateL2 = index + 1;
144 }
145 else
146 {
147 LOG(VB_GENERAL, LOG_ERR, LOC + "Audiorate(L2): " +
148 QString("%1 is invalid").arg(value));
149 }
150 }
151 else if (opt == "mpeg2audbitratel3")
152 {
153 int index = find_index(kAudRateL3, value);
154 if (index >= 0)
155 {
156 m_audBitrateL3 = index + 1;
157 }
158 else
159 {
160 LOG(VB_GENERAL, LOG_ERR, LOC + "Audiorate(L2): " +
161 QString("%1 is invalid").arg(value));
162 }
163 }
164 else if (opt == "mpeg2audvolume")
165 {
166 m_audVolume = value;
167 }
168 else if (opt.endsWith("_mpeg4avgbitrate"))
169 {
170 if (opt.startsWith("low"))
171 m_lowMpeg4AvgBitrate = value;
172 else if (opt.startsWith("medium"))
174 else if (opt.startsWith("high"))
175 m_highMpeg4AvgBitrate = value;
176 else
177 V4LRecorder::SetOption(opt, value);
178 }
179 else if (opt.endsWith("_mpeg4peakbitrate"))
180 {
181 if (opt.startsWith("low"))
182 m_lowMpeg4PeakBitrate = value;
183 else if (opt.startsWith("medium"))
185 else if (opt.startsWith("high"))
187 else
188 V4LRecorder::SetOption(opt, value);
189 }
190 else
191 {
192 V4LRecorder::SetOption(opt, value);
193 }
194}
195
196void MpegRecorder::SetOption(const QString &opt, const QString &value)
197{
198 std::string value_ss = value.toStdString();
199 if (opt == "mpeg2streamtype")
200 {
201 bool found = false;
202 for (size_t i = 0; i < kStreamType.size(); i++)
203 {
204 if (kStreamType[i] == value_ss)
205 {
206 if (kStreamType[i] == "MPEG-2 TS")
207 {
209 }
210 else if (kStreamType[i] == "MPEG-2 PS")
211 {
213 }
214 else
215 {
216 // TODO Expand AVContainer to include other types in
217 // streamType
219 }
220 m_streamType = i;
221 found = true;
222 break;
223 }
224 }
225
226 if (!found)
227 {
228 LOG(VB_GENERAL, LOG_ERR, LOC + "MPEG2 stream type: " +
229 QString("%1 is invalid").arg(value));
230 }
231 }
232 else if (opt == "mpeg2language")
233 {
234 bool ok = false;
235 m_language = value.toInt(&ok); // on failure language will be 0
236 if (!ok)
237 {
238 LOG(VB_GENERAL, LOG_ERR, LOC + "MPEG2 language (stereo) flag " +
239 QString("'%1' is invalid").arg(value));
240 }
241 }
242 else if (opt == "mpeg2aspectratio")
243 {
244 bool found = false;
245 for (size_t i = 0; i < kAspectRatio.size(); i++)
246 {
247 if (kAspectRatio[i] == value_ss)
248 {
249 m_aspectRatio = i + 1;
250 found = true;
251 break;
252 }
253 }
254
255 if (!found)
256 {
257 LOG(VB_GENERAL, LOG_ERR, LOC + "MPEG2 Aspect-ratio: " +
258 QString("%1 is invalid").arg(value));
259 }
260 }
261 else if (opt == "mpeg2audtype")
262 {
263 if (value == "Layer I")
264 {
265 m_audType = V4L2_MPEG_AUDIO_ENCODING_LAYER_1 + 1;
266 }
267 else if (value == "Layer II")
268 {
269 m_audType = V4L2_MPEG_AUDIO_ENCODING_LAYER_2 + 1;
270 }
271 else if (value == "Layer III")
272 {
273 m_audType = V4L2_MPEG_AUDIO_ENCODING_LAYER_3 + 1;
274 }
275 else
276 {
277 LOG(VB_GENERAL, LOG_ERR, LOC + "MPEG2 audio layer: " +
278 QString("%1 is invalid").arg(value));
279 }
280 }
281 else if (opt == "audiocodec")
282 {
283 if (value == "AAC Hardware Encoder")
284 m_audType = V4L2_MPEG_AUDIO_ENCODING_AAC + 1;
285 else if (value == "AC3 Hardware Encoder")
286 m_audType = V4L2_MPEG_AUDIO_ENCODING_AC3 + 1;
287 }
288 else
289 {
290 V4LRecorder::SetOption(opt, value);
291 }
292}
293
295 const QString &videodev,
296 [[maybe_unused]] const QString &audiodev,
297 [[maybe_unused]] const QString &vbidev)
298{
299 if (videodev.startsWith("file:", Qt::CaseInsensitive))
300 {
301 m_deviceIsMpegFile = true;
302 m_bufferSize = 64000;
303 QString newVideoDev = videodev;
304 if (newVideoDev.startsWith("file:", Qt::CaseInsensitive))
305 newVideoDev = newVideoDev.remove(0,5);
306 SetOption("videodevice", newVideoDev);
307 }
308 else
309 {
310 SetOption("videodevice", videodev);
311 }
312 SetOption("vbidevice", vbidev);
313 SetOption("audiodevice", audiodev);
314
315 SetOption("tvformat", gCoreContext->GetSetting("TVFormat"));
316 SetOption("vbiformat", gCoreContext->GetSetting("VbiFormat"));
317
318 SetIntOption(profile, "mpeg2bitrate");
319 SetIntOption(profile, "mpeg2maxbitrate");
320 SetStrOption(profile, "mpeg2streamtype");
321 SetStrOption(profile, "mpeg2aspectratio");
322 SetStrOption(profile, "mpeg2language");
323
324 SetIntOption(profile, "samplerate");
325 SetStrOption(profile, "mpeg2audtype");
326 SetIntOption(profile, "mpeg2audbitratel1");
327 SetIntOption(profile, "mpeg2audbitratel2");
328 SetIntOption(profile, "mpeg2audbitratel3");
329 SetIntOption(profile, "mpeg2audvolume");
330
331 SetIntOption(profile, "width");
332 SetIntOption(profile, "height");
333
334 SetIntOption(profile, "low_mpeg4avgbitrate");
335 SetIntOption(profile, "low_mpeg4peakbitrate");
336 SetIntOption(profile, "medium_mpeg4avgbitrate");
337 SetIntOption(profile, "medium_mpeg4peakbitrate");
338 SetIntOption(profile, "high_mpeg4avgbitrate");
339 SetIntOption(profile, "high_mpeg4peakbitrate");
340
341 SetStrOption(profile, "audiocodec");
342}
343
344// same as the base class, it just doesn't complain if an option is missing
346{
347 const StandardSetting *setting = profile->byName(name);
348 if (setting)
349 SetOption(name, setting->getValue().toInt());
350}
351
352// same as the base class, it just doesn't complain if an option is missing
354{
355 const StandardSetting *setting = profile->byName(name);
356 if (setting)
357 SetOption(name, setting->getValue());
358}
359
361{
362 QByteArray vdevice = m_videodevice.toLatin1();
363 m_chanfd = m_readfd = open(vdevice.constData(), O_RDONLY);
364
365 if (m_readfd < 0)
366 {
367 LOG(VB_GENERAL, LOG_ERR, LOC + QString("Can't open MPEG File '%1'")
368 .arg(m_videodevice) + ENO);
369 m_error = LOC + QString("Can't open MPEG File '%1'")
370 .arg(m_videodevice) + ENO;
371 return false;
372 }
373 return true;
374}
375
377{
378 // open implicitly starts encoding, so we need the lock..
379 QMutexLocker locker(&m_startStopEncodingLock);
380
381 QByteArray vdevice = m_videodevice.toLatin1();
382 m_chanfd = open(vdevice.constData(), O_RDWR);
383 if (m_chanfd < 0)
384 {
385 LOG(VB_GENERAL, LOG_ERR, LOC + "Can't open video device. " + ENO);
386 m_error = LOC + "Can't open video device. " + ENO;
387 return false;
388 }
389
390 m_bufferSize = 4096;
391
392 bool supports_tuner = false;
393 bool supports_audio = false;
394 uint32_t capabilities = 0;
396 {
397 m_supportsSlicedVbi = ((capabilities & V4L2_CAP_SLICED_VBI_CAPTURE) != 0U);
398 supports_tuner = ((capabilities & V4L2_CAP_TUNER) != 0U);
399 supports_audio = ((capabilities & V4L2_CAP_AUDIO) != 0U);
401 if (m_driver == "hdpvr")
402 {
404 m_useIForKeyframe = false;
405 }
406 }
407
408 if (!(capabilities & V4L2_CAP_VIDEO_CAPTURE))
409 {
410 LOG(VB_GENERAL, LOG_ERR, LOC + "V4L version 1, unsupported");
411 m_error = LOC + "V4L version 1, unsupported";
413 m_chanfd = -1;
414 return false;
415 }
416
418 {
420 m_chanfd = -1;
421 return false;
422 }
423
424 if (supports_tuner)
425 SetLanguageMode(m_chanfd); // we don't care if this fails...
426
427 if (supports_audio)
428 SetRecordingVolume(m_chanfd); // we don't care if this fails...
429
431 {
433 m_chanfd = -1;
434 return false;
435 }
436
437 SetVBIOptions(m_chanfd); // we don't care if this fails...
438
439 m_readfd = open(vdevice.constData(), O_RDWR | O_NONBLOCK);
440
441 if (m_readfd < 0)
442 {
443 LOG(VB_GENERAL, LOG_ERR, LOC + "Can't open video device." + ENO);
444 m_error = LOC + "Can't open video device." + ENO;
446 m_chanfd = -1;
447 return false;
448 }
449
451 {
454
455 delete m_deviceReadBuffer;
456 m_deviceReadBuffer = nullptr;
457 }
458
460
462 {
463 LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to allocate DRB buffer");
464 m_error = "Failed to allocate DRB buffer";
466 m_chanfd = -1;
468 m_readfd = -1;
469 return false;
470 }
471
472 if (!m_deviceReadBuffer->Setup(vdevice.constData(), m_readfd))
473 {
474 LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to setup DRB buffer");
475 m_error = "Failed to setup DRB buffer";
477 m_chanfd = -1;
479 m_readfd = -1;
480 return false;
481 }
482
483 LOG(VB_RECORD, LOG_INFO, LOC + "DRB ready");
484
485 if (m_vbiFd >= 0)
486 m_vbiThread = new VBIThread(this);
487
488 return true;
489}
490
491
493{
494 if (m_driver == "hdpvr")
495 return true;
496
497 struct v4l2_format vfmt {};
498
499 vfmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
500
501 if (ioctl(chanfd, VIDIOC_G_FMT, &vfmt) < 0)
502 {
503 LOG(VB_GENERAL, LOG_ERR, LOC + "Error getting format" + ENO);
504 m_error = LOC + "Error getting format" + ENO;
505 return false;
506 }
507
508 vfmt.fmt.pix.width = m_width;
509 vfmt.fmt.pix.height = m_height;
510
511 if (ioctl(chanfd, VIDIOC_S_FMT, &vfmt) < 0)
512 {
513 LOG(VB_GENERAL, LOG_ERR, LOC + "Error setting format" + ENO);
514 m_error = LOC + "Error setting format" + ENO;
515 return false;
516 }
517
518 return true;
519}
520
523{
524 struct v4l2_tuner vt {};
525 if (ioctl(chanfd, VIDIOC_G_TUNER, &vt) < 0)
526 {
527 LOG(VB_GENERAL, LOG_WARNING, LOC + "Unable to get audio mode" + ENO);
528 return false;
529 }
530
531 switch (m_language)
532 {
533 case 0:
534 vt.audmode = V4L2_TUNER_MODE_LANG1;
535 break;
536 case 1:
537 vt.audmode = V4L2_TUNER_MODE_LANG2;
538 break;
539 case 2:
540 vt.audmode = V4L2_TUNER_MODE_LANG1_LANG2;
541 break;
542 default:
543 vt.audmode = V4L2_TUNER_MODE_LANG1;
544 }
545
546 int audio_layer = GetFilteredAudioLayer();
547 bool success = true;
548 if ((2 == m_language) && (1 == audio_layer))
549 {
550 LOG(VB_GENERAL, LOG_WARNING,
551 "Dual audio mode incompatible with Layer I audio."
552 "\n\t\t\tFalling back to Main Language");
553 vt.audmode = V4L2_TUNER_MODE_LANG1;
554 success = false;
555 }
556
557 if (ioctl(chanfd, VIDIOC_S_TUNER, &vt) < 0)
558 {
559 LOG(VB_GENERAL, LOG_WARNING, LOC + "Unable to set audio mode" + ENO);
560 success = false;
561 }
562
563 return success;
564}
565
567{
568 // Get volume min/max values
569 struct v4l2_queryctrl qctrl {};
570 qctrl.id = V4L2_CID_AUDIO_VOLUME;
571 if ((ioctl(chanfd, VIDIOC_QUERYCTRL, &qctrl) < 0) ||
572 (qctrl.flags & V4L2_CTRL_FLAG_DISABLED))
573 {
574 LOG(VB_CHANNEL, LOG_WARNING,
575 LOC + "Audio volume control not supported.");
576 return false;
577 }
578
579 // calculate volume in card units.
580 int range = qctrl.maximum - qctrl.minimum;
581 int value = (int) ((range * m_audVolume * 0.01F) + qctrl.minimum);
582 int ctrl_volume = std::clamp(value, qctrl.minimum, qctrl.maximum);
583
584 // Set recording volume
585 struct v4l2_control ctrl {.id=V4L2_CID_AUDIO_VOLUME, .value=ctrl_volume};
586
587 if (ioctl(chanfd, VIDIOC_S_CTRL, &ctrl) < 0)
588 {
589 LOG(VB_GENERAL, LOG_WARNING, LOC +
590 "Unable to set recording volume" + ENO + "\n\t\t\t" +
591 "If you are using an AverMedia M179 card this is normal.");
592 return false;
593 }
594
595 return true;
596}
597
599{
600 uint st = (uint) m_streamType;
601
602 if (m_driver == "ivtv")
603 {
604 switch (st)
605 {
606 case 2: st = 2; break;
607 case 10:
608 case 13:
609 case 14: st = 10; break;
610 case 11: st = 11; break;
611 case 12: st = 12; break;
612 default: st = 0; break;
613 }
614 }
615
616 if (st != (uint) m_streamType)
617 {
618 LOG(VB_GENERAL, LOG_WARNING, LOC +
619 QString("Stream type '%1'\n\t\t\t"
620 "is not supported by %2 driver, using '%3' instead.")
621 .arg(QString::fromStdString(kStreamType[m_streamType]),
622 m_driver,
623 QString::fromStdString(kStreamType[st])));
624 }
625
626 return st;
627}
628
630{
632
633 sr = (m_driver == "ivtv") ? 48000 : sr; // only 48kHz works properly.
634
635 if (sr != (uint) m_audSampleRate)
636 {
637 LOG(VB_GENERAL, LOG_WARNING, LOC +
638 QString("Audio sample rate %1 Hz\n\t\t\t"
639 "is not supported by %2 driver, using %3 Hz instead.")
640 .arg(m_audSampleRate).arg(m_driver).arg(sr));
641 }
642
643 switch (sr)
644 {
645 case 32000: return V4L2_MPEG_AUDIO_SAMPLING_FREQ_32000;
646 case 44100: return V4L2_MPEG_AUDIO_SAMPLING_FREQ_44100;
647 case 48000:
648 default: return V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000;
649 }
650}
651
653{
654 uint layer = (uint) m_audType;
655
656 layer = std::clamp(layer, 1U, 3U);
657
658 layer = (m_driver == "ivtv") ? 2 : layer;
659
660 if (layer != (uint) m_audType)
661 {
662 LOG(VB_GENERAL, LOG_WARNING, LOC +
663 QString("MPEG layer %1 does not work properly\n\t\t\t"
664 "with %2 driver. Using MPEG layer %3 audio instead.")
665 .arg(m_audType).arg(m_driver).arg(layer));
666 }
667
668 return layer;
669}
670
672{
673 if (2 == audio_layer)
674 return std::max(m_audBitrateL2, 10);
675 if (3 == audio_layer)
676 return m_audBitrateL3;
677 return std::max(m_audBitrateL1, 6);
678}
679
680static int streamtype_ivtv_to_v4l2(int st)
681{
682 switch (st)
683 {
684 case 0: return V4L2_MPEG_STREAM_TYPE_MPEG2_PS;
685 case 1: return V4L2_MPEG_STREAM_TYPE_MPEG2_TS;
686 case 2: return V4L2_MPEG_STREAM_TYPE_MPEG1_VCD;
687 case 3: /* PES A/V */
688 case 5: /* PES V */
689 case 7: /* PES A */
690 return V4L2_MPEG_STREAM_TYPE_MPEG2_PS;
691 case 10: return V4L2_MPEG_STREAM_TYPE_MPEG2_DVD;
692 case 11: return V4L2_MPEG_STREAM_TYPE_MPEG1_VCD; /* VCD */
693 case 12: return V4L2_MPEG_STREAM_TYPE_MPEG2_SVCD;
694 case 13: /* DVD-Special 1 */
695 case 14: /* DVD-Special 2 */
696 return V4L2_MPEG_STREAM_TYPE_MPEG2_DVD;
697 default: return V4L2_MPEG_STREAM_TYPE_MPEG2_TS;
698 }
699}
700
701static void add_ext_ctrl(std::vector<struct v4l2_ext_control> &ctrl_list,
702 uint32_t id, int32_t value)
703{
704 struct v4l2_ext_control tmp_ctrl {};
705 tmp_ctrl.id = id;
706 tmp_ctrl.value = value;
707 ctrl_list.push_back(tmp_ctrl);
708}
709
710static void set_ctrls(int fd, std::vector<struct v4l2_ext_control> &ext_ctrls)
711{
712 static QMutex s_controlDescriptionLock;
713 static QMap<uint32_t,QString> s_controlDescription;
714
715 s_controlDescriptionLock.lock();
716 if (s_controlDescription.isEmpty())
717 {
718 s_controlDescription[V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ] =
719 "Audio Sampling Frequency";
720 s_controlDescription[V4L2_CID_MPEG_VIDEO_ASPECT] =
721 "Video Aspect ratio";
722 s_controlDescription[V4L2_CID_MPEG_AUDIO_ENCODING] =
723 "Audio Encoding";
724 s_controlDescription[V4L2_CID_MPEG_AUDIO_L2_BITRATE] =
725 "Audio L2 Bitrate";
726 s_controlDescription[V4L2_CID_MPEG_VIDEO_BITRATE_PEAK] =
727 "Video Peak Bitrate";
728 s_controlDescription[V4L2_CID_MPEG_VIDEO_BITRATE] =
729 "Video Average Bitrate";
730 s_controlDescription[V4L2_CID_MPEG_STREAM_TYPE] =
731 "MPEG Stream type";
732 s_controlDescription[V4L2_CID_MPEG_VIDEO_BITRATE_MODE] =
733 "MPEG Bitrate mode";
734 }
735 s_controlDescriptionLock.unlock();
736
737 for (auto & ext_ctrl : ext_ctrls)
738 {
739 struct v4l2_ext_controls ctrls {};
740
741 int value = ext_ctrl.value;
742
743 ctrls.ctrl_class = V4L2_CTRL_CLASS_MPEG;
744 ctrls.count = 1;
745 ctrls.controls = &ext_ctrl;
746
747 if (ioctl(fd, VIDIOC_S_EXT_CTRLS, &ctrls) < 0)
748 {
749 QMutexLocker locker(&s_controlDescriptionLock);
750 LOG(VB_GENERAL, LOG_ERR, QString("mpegrecorder.cpp:set_ctrls(): ") +
751 QString("Could not set %1 to %2")
752 .arg(s_controlDescription[ext_ctrl.id]).arg(value) +
753 ENO);
754 }
755 }
756}
757
759{
760 std::vector<struct v4l2_ext_control> ext_ctrls;
761
762 // Set controls
763 if (m_driver != "hdpvr")
764 {
765 if (!m_driver.startsWith("saa7164"))
766 {
767 add_ext_ctrl(ext_ctrls, V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ,
769
770 uint audio_layer = GetFilteredAudioLayer();
771 add_ext_ctrl(ext_ctrls, V4L2_CID_MPEG_AUDIO_ENCODING,
772 audio_layer - 1);
773
774 uint audbitrate = GetFilteredAudioBitRate(audio_layer);
775 add_ext_ctrl(ext_ctrls, V4L2_CID_MPEG_AUDIO_L2_BITRATE,
776 audbitrate - 1);
777 }
778
779 add_ext_ctrl(ext_ctrls, V4L2_CID_MPEG_VIDEO_ASPECT,
780 m_aspectRatio - 1);
781
782 add_ext_ctrl(ext_ctrls, V4L2_CID_MPEG_STREAM_TYPE,
784
785 }
786 else
787 {
790 }
792
793 if (m_driver == "hdpvr" || m_driver.startsWith("saa7164"))
794 {
795 add_ext_ctrl(ext_ctrls, V4L2_CID_MPEG_VIDEO_BITRATE_MODE,
797 V4L2_MPEG_VIDEO_BITRATE_MODE_CBR :
798 V4L2_MPEG_VIDEO_BITRATE_MODE_VBR);
799 }
800
801 add_ext_ctrl(ext_ctrls, V4L2_CID_MPEG_VIDEO_BITRATE,
802 m_bitrate * 1000);
803
804 add_ext_ctrl(ext_ctrls, V4L2_CID_MPEG_VIDEO_BITRATE_PEAK,
805 m_maxBitrate * 1000);
806
807 set_ctrls(chanfd, ext_ctrls);
808
809 bool ok = false;
810 int audioinput = m_audioDeviceName.toUInt(&ok);
811 if (ok)
812 {
813 struct v4l2_audio ain {};
814 ain.index = audioinput;
815 if (ioctl(chanfd, VIDIOC_ENUMAUDIO, &ain) < 0)
816 {
817 LOG(VB_GENERAL, LOG_WARNING, LOC + "Unable to get audio input.");
818 }
819 else
820 {
821 ain.index = audioinput;
822 if (ioctl(chanfd, VIDIOC_S_AUDIO, &ain) < 0)
823 {
824 LOG(VB_GENERAL, LOG_WARNING,
825 LOC + "Unable to set audio input.");
826 }
827 }
828 }
829
830 // query supported audio codecs if spdif is not used
831 if (m_driver == "hdpvr" && audioinput != 2)
832 {
833 struct v4l2_queryctrl qctrl {};
834 qctrl.id = V4L2_CID_MPEG_AUDIO_ENCODING;
835
836 if (!ioctl(chanfd, VIDIOC_QUERYCTRL, &qctrl))
837 {
838 uint audio_enc = std::clamp(m_audType-1, qctrl.minimum, qctrl.maximum);
839 add_ext_ctrl(ext_ctrls, V4L2_CID_MPEG_AUDIO_ENCODING, audio_enc);
840 }
841 else
842 {
843 LOG(VB_GENERAL, LOG_WARNING, LOC +
844 "Unable to get supported audio codecs." + ENO);
845 }
846 }
847
848 return true;
849}
850
852{
854 return true;
855
856 if (m_driver == "hdpvr")
857 return true;
858
859#ifdef V4L2_CAP_SLICED_VBI_CAPTURE
861 {
862 int fd = 0;
863
864 if (OpenVBIDevice() >= 0)
865 fd = m_vbiFd;
866 else
867 fd = chanfd;
868
869 struct v4l2_format vbifmt {};
870 vbifmt.type = V4L2_BUF_TYPE_SLICED_VBI_CAPTURE;
871 vbifmt.fmt.sliced.service_set |= (VBIMode::PAL_TT == m_vbiMode) ?
872 V4L2_SLICED_VBI_625 : V4L2_SLICED_VBI_525;
873
874 if (ioctl(fd, VIDIOC_S_FMT, &vbifmt) < 0)
875 {
876 if (m_vbiFd >= 0)
877 {
878 fd = chanfd; // Retry with video device instead
879 if (ioctl(fd, VIDIOC_S_FMT, &vbifmt) < 0)
880 {
881 LOG(VB_GENERAL, LOG_WARNING, LOC +
882 "Unable to enable VBI embedding (/dev/vbiX)" + ENO);
883 return false;
884 }
885 }
886 else
887 {
888 LOG(VB_GENERAL, LOG_WARNING, LOC +
889 "Unable to enable VBI embedding (/dev/videoX)" + ENO);
890 return false;
891 }
892 }
893
894 if (ioctl(fd, VIDIOC_G_FMT, &vbifmt) >= 0)
895 {
896 LOG(VB_RECORD, LOG_INFO,
897 LOC + QString("VBI service: %1, io size: %2")
898 .arg(vbifmt.fmt.sliced.service_set)
899 .arg(vbifmt.fmt.sliced.io_size));
900
901 struct v4l2_ext_control vbi_ctrl {};
902 vbi_ctrl.id = V4L2_CID_MPEG_STREAM_VBI_FMT;
903 vbi_ctrl.value = V4L2_MPEG_STREAM_VBI_FMT_IVTV;
904
905 struct v4l2_ext_controls ctrls {};
906 ctrls.ctrl_class = V4L2_CTRL_CLASS_MPEG;
907 ctrls.count = 1;
908 ctrls.controls = &vbi_ctrl;
909
910 if (ioctl(fd, VIDIOC_S_EXT_CTRLS, &ctrls) < 0)
911 {
912 LOG(VB_GENERAL, LOG_WARNING, LOC +
913 "Unable to set VBI embedding format" + ENO);
914 }
915 else
916 {
917 return true;
918 }
919 }
920 }
921#endif // V4L2_CAP_SLICED_VBI_CAPTURE
922
923 return OpenVBIDevice() >= 0;
924}
925
927{
930}
931
933{
934 if (!Open())
935 {
936 if (m_error.isEmpty())
937 m_error = "Failed to open V4L device";
938 return;
939 }
940
941 bool has_select = true;
942
943#ifdef Q_OS_FREEBSD
944 // HACK. FreeBSD PVR150/500 driver doesn't currently support select()
945 has_select = false;
946#endif
947
948 if (m_driver == "hdpvr")
949 {
950 int progNum = 1;
951 auto *sd = new MPEGStreamData(progNum,
952 m_tvrec ? m_tvrec->GetInputId() : -1,
953 true);
954 sd->SetRecordingType(m_recordingType);
955 SetStreamData(sd);
956
959
960 // Make sure the first things in the file are a PAT & PMT
964 }
965
966 {
967 QMutexLocker locker(&m_pauseLock);
968 m_requestRecording = true;
969 m_requestHelper = true;
970 m_recording = true;
971 m_recordingWait.wakeAll();
972 }
973
974 auto *buffer = new unsigned char[m_bufferSize + 1];
975 int len = 0;
976 int remainder = 0;
977
978 bool good_data = false;
979 bool gap = false;
980 QDateTime gap_start;
981
982 MythTimer elapsedTimer;
983 float elapsed = NAN;
984 long long bytesRead = 0;
985
986 bool ok { false };
987 // Bytes per second, but env var is BITS PER SECOND
988 int dummyBPS = qEnvironmentVariableIntValue("DUMMYBPS", &ok) / 8;
989 if (ok)
990 {
991 LOG(VB_GENERAL, LOG_INFO,
992 LOC + QString("Throttling dummy recorder to %1 bits per second")
993 .arg(dummyBPS * 8));
994 }
995
996 struct timeval tv {};
997 fd_set rdset;
998
1000 {
1001 elapsedTimer.start();
1002 }
1003 else if (m_deviceReadBuffer)
1004 {
1005 LOG(VB_RECORD, LOG_INFO, LOC + "Initial startup of recorder");
1006 StartEncoding();
1007 }
1008
1009 QByteArray vdevice = m_videodevice.toLatin1();
1010 while (IsRecordingRequested() && !IsErrored())
1011 {
1012 if (PauseAndWait(100ms))
1013 continue;
1014
1016 {
1017 if (dummyBPS && bytesRead)
1018 {
1019 elapsed = (elapsedTimer.elapsed().count() / 1000.0F) + 1;
1020 while ((bytesRead / elapsed) > dummyBPS)
1021 {
1022 std::this_thread::sleep_for(50ms);
1023 elapsed = (elapsedTimer.elapsed().count() / 1000.0F) + 1;
1024 }
1025 }
1026 else if (GetFramesWritten())
1027 {
1028 elapsed = (elapsedTimer.elapsed().count() / 1000.0F) + 1;
1029 while ((GetFramesWritten() / elapsed) > 30)
1030 {
1031 std::this_thread::sleep_for(50ms);
1032 elapsed = (elapsedTimer.elapsed().count() / 1000.0F) + 1;
1033 }
1034 }
1035 }
1036
1038 {
1040 (&(buffer[remainder]), m_bufferSize - remainder);
1041
1042 // Check for DRB errors
1044 {
1045 LOG(VB_GENERAL, LOG_ERR, LOC + "Device error detected");
1046
1047 if (good_data)
1048 {
1049 if (gap)
1050 {
1051 /* Already processing a gap, which means
1052 * restarting the encoding didn't work! */
1053 SetRecordingStatus(RecStatus::Failing, __FILE__, __LINE__);
1054 }
1055 else
1056 {
1057 gap = true;
1058 }
1059 }
1060
1061 if (!RestartEncoding())
1062 SetRecordingStatus(RecStatus::Failing, __FILE__, __LINE__);
1063 }
1064 else if (m_deviceReadBuffer->IsEOF() &&
1066 {
1067 LOG(VB_GENERAL, LOG_ERR, LOC + "Device EOF detected");
1068 m_error = "Device EOF detected";
1069 }
1070 else
1071 {
1072 // If we have seen good data, but now have a gap, note it
1073 if (good_data)
1074 {
1075 if (gap)
1076 {
1077 QMutexLocker locker(&m_statisticsLock);
1078 QDateTime gap_end(MythDate::current());
1079
1081 (gap_start, gap_end));
1082 LOG(VB_RECORD, LOG_DEBUG,
1083 LOC + QString("Inserted gap %1 dur %2")
1084 .arg(m_recordingGaps.back().toString())
1085 .arg(gap_start.secsTo(gap_end)));
1086 gap = false;
1087 }
1088 else
1089 {
1090 gap_start = MythDate::current();
1091 }
1092 }
1093 else
1094 {
1095 good_data = true;
1096 }
1097 }
1098 }
1099 else if (m_readfd < 0)
1100 {
1101 continue;
1102 }
1103 else
1104 {
1105 if (has_select)
1106 {
1107 tv.tv_sec = 5;
1108 tv.tv_usec = 0;
1109 FD_ZERO(&rdset); // NOLINT(readability-isolate-declaration)
1110 FD_SET(m_readfd, &rdset);
1111
1112 switch (select(m_readfd + 1, &rdset, nullptr, nullptr, &tv))
1113 {
1114 case -1:
1115 if (errno == EINTR)
1116 continue;
1117
1118 LOG(VB_GENERAL, LOG_ERR, LOC + "Select error" + ENO);
1119 continue;
1120
1121 case 0:
1122 LOG(VB_GENERAL, LOG_ERR, LOC + "select timeout - "
1123 "driver has stopped responding");
1124
1125 if (close(m_readfd) != 0)
1126 {
1127 LOG(VB_GENERAL, LOG_ERR, LOC + "Close error" + ENO);
1128 }
1129
1130 // Force card to be reopened on next iteration..
1131 m_readfd = -1;
1132 continue;
1133
1134 default:
1135 break;
1136 }
1137 }
1138
1139 len = read(m_readfd, &(buffer[remainder]), m_bufferSize - remainder);
1140
1141 if (len < 0 && !has_select)
1142 {
1143 QMutexLocker locker(&m_pauseLock);
1145 m_unpauseWait.wait(&m_pauseLock, 25);
1146 continue;
1147 }
1148
1149 if ((len == 0) && (m_deviceIsMpegFile))
1150 {
1151 close(m_readfd);
1152 m_readfd = open(vdevice.constData(), O_RDONLY);
1153
1154 if (m_readfd >= 0)
1155 {
1156 len = read(m_readfd,
1157 &(buffer[remainder]), m_bufferSize - remainder);
1158 }
1159
1160 if (len <= 0)
1161 {
1162 m_error = "Failed to read from video file";
1163 continue;
1164 }
1165 }
1166 else if (len < 0 && errno != EAGAIN)
1167 {
1168 LOG(VB_GENERAL, LOG_ERR, LOC + QString("error reading from: %1")
1169 .arg(m_videodevice) + ENO);
1170 continue;
1171 }
1172 }
1173
1174 if (len > 0)
1175 {
1176 bytesRead += len;
1177 len += remainder;
1178
1179 if (m_driver == "hdpvr")
1180 {
1181 remainder = m_streamData->ProcessData(buffer, len);
1182 int start_remain = len - remainder;
1183 if (remainder && (start_remain >= remainder))
1184 memcpy(buffer, buffer+start_remain, remainder);
1185 else if (remainder)
1186 memmove(buffer, buffer+start_remain, remainder);
1187 }
1188 else
1189 {
1190 FindPSKeyFrames(buffer, len);
1191 }
1192 }
1193 }
1194
1195 LOG(VB_RECORD, LOG_INFO, LOC + "run finishing up");
1196
1197 StopEncoding();
1198
1199 {
1200 QMutexLocker locker(&m_pauseLock);
1201 m_requestHelper = false;
1202 }
1203
1204 if (m_vbiThread)
1205 {
1206 m_vbiThread->wait();
1207 delete m_vbiThread;
1208 m_vbiThread = nullptr;
1210 }
1211
1213
1214 delete[] buffer;
1215
1216 if (m_driver == "hdpvr")
1217 {
1220 SetStreamData(nullptr);
1221 }
1222
1223 QMutexLocker locker(&m_pauseLock);
1224 m_requestRecording = false;
1225 m_recording = false;
1226 m_recordingWait.wakeAll();
1227}
1228
1229bool MpegRecorder::ProcessTSPacket(const TSPacket &tspacket_real)
1230{
1231 const uint pid = tspacket_real.PID();
1232
1233 TSPacket *tspacket_fake = nullptr;
1234 if ((m_driver == "hdpvr") && (pid == 0x1001)) // PCRPID for HD-PVR
1235 {
1236 tspacket_fake = tspacket_real.CreateClone();
1237 uint cc = (m_continuityCounter[pid] == 0xFF) ?
1238 0 : (m_continuityCounter[pid] + 1) & 0xf;
1239 tspacket_fake->SetContinuityCounter(cc);
1240 }
1241
1242 const TSPacket &tspacket = tspacket_fake
1243 ? *tspacket_fake : tspacket_real;
1244
1245 bool ret = DTVRecorder::ProcessTSPacket(tspacket);
1246
1247 delete tspacket_fake;
1248
1249 return ret;
1250}
1251
1253{
1254 LOG(VB_RECORD, LOG_INFO, LOC + "Reset(void)");
1256
1257 if (m_h2645Parser != nullptr)
1259
1260 m_startCode = 0xffffffff;
1261
1262 if (m_curRecording)
1263 {
1265 }
1266 if (m_streamData)
1268}
1269
1271{
1272 QMutexLocker locker(&m_pauseLock);
1274 m_paused = false;
1275 m_requestPause = true;
1276}
1277
1278bool MpegRecorder::PauseAndWait(std::chrono::milliseconds timeout)
1279{
1280 QMutexLocker locker(&m_pauseLock);
1281 if (m_requestPause)
1282 {
1283 if (!IsPaused(true))
1284 {
1285 LOG(VB_RECORD, LOG_INFO, LOC + "PauseAndWait pause");
1286
1287 StopEncoding();
1288
1289 m_paused = true;
1290 m_pauseWait.wakeAll();
1291
1292 if (m_tvrec)
1294 }
1295
1296 m_unpauseWait.wait(&m_pauseLock, timeout.count());
1297 }
1298
1299 if (!m_requestPause && IsPaused(true))
1300 {
1301 LOG(VB_RECORD, LOG_INFO, LOC + "PauseAndWait unpause");
1302
1303 if (m_driver == "hdpvr")
1304 {
1305 // HD-PVR will sometimes reset to defaults
1307 }
1308
1309 StartEncoding();
1310
1311 if (m_streamData)
1313
1314 m_paused = false;
1315 }
1316
1317 return IsPaused(true);
1318}
1319
1321{
1322 LOG(VB_RECORD, LOG_INFO, LOC + "RestartEncoding");
1323
1324 QMutexLocker locker(&m_startStopEncodingLock);
1325
1326 StopEncoding();
1327
1328 // Make sure the next things in the file are a PAT & PMT
1329 if (m_streamData &&
1332 {
1333 m_payloadBuffer.clear(); // No reason to keep part of a frame
1336 }
1337
1338 if (m_driver == "hdpvr") // HD-PVR will sometimes reset to defaults
1340
1341 return StartEncoding();
1342}
1343
1345{
1346 QMutexLocker locker(&m_startStopEncodingLock);
1347
1348 LOG(VB_RECORD, LOG_INFO, LOC + "StartEncoding");
1349
1350 if (m_readfd < 0)
1351 {
1352 m_readfd = open(m_videodevice.toLatin1().constData(), O_RDWR | O_NONBLOCK);
1353 if (m_readfd < 0)
1354 {
1355 LOG(VB_GENERAL, LOG_ERR, LOC +
1356 "StartEncoding: Can't open video device." + ENO);
1357 m_error = "Failed to start recording";
1358 return false;
1359 }
1360 }
1361
1362 if (m_h2645Parser != nullptr)
1364
1365 bool good_res = true;
1366 if (m_driver == "hdpvr")
1367 {
1369 m_seenSps = false;
1370 good_res = HandleResolutionChanges();
1371 }
1372
1373 // (at least) with the 3.10 kernel, the V4L2_ENC_CMD_START does
1374 // not reliably start the data flow from a HD-PVR. A read() seems
1375 // to work, though.
1376
1377 int idx = 1;
1378 for ( ; idx < 50; ++idx)
1379 {
1380 uint8_t dummy = 0;
1381 int len = read(m_readfd, &dummy, 0);
1382 if (len == 0)
1383 break;
1384 if (idx == 20)
1385 {
1386 LOG(VB_GENERAL, LOG_ERR, LOC +
1387 "StartEncoding: read failing, re-opening device: " + ENO);
1388 close(m_readfd);
1389 std::this_thread::sleep_for(2ms);
1390 m_readfd = open(m_videodevice.toLatin1().constData(),
1391 O_RDWR | O_NONBLOCK);
1392 if (m_readfd < 0)
1393 {
1394 LOG(VB_GENERAL, LOG_ERR, LOC +
1395 "StartEncoding: Can't open video device." + ENO);
1396 m_error = "Failed to start recording";
1397 return false;
1398 }
1399 }
1400 else
1401 {
1402 LOG(VB_GENERAL, LOG_ERR, LOC +
1403 QString("StartEncoding: read failed, retry in %1 msec:")
1404 .arg(100 * idx) + ENO);
1405 std::this_thread::sleep_for(idx * 100us);
1406 }
1407 }
1408 if (idx == 50)
1409 {
1410 LOG(VB_GENERAL, LOG_ERR, LOC +
1411 "StartEncoding: read from video device failed." + ENO);
1412 m_error = "Failed to start recording";
1413 close(m_readfd);
1414 m_readfd = -1;
1415 return false;
1416 }
1417 if (idx > 0)
1418 {
1419 LOG(VB_RECORD, LOG_WARNING, LOC +
1420 QString("%1 read attempts required to start encoding").arg(idx));
1421 }
1422
1423 if (!good_res) // Try again
1425
1427 {
1428 m_deviceReadBuffer->Reset(m_videodevice.toLatin1().constData(), m_readfd);
1431 }
1432
1433 return true;
1434}
1435
1437{
1438 QMutexLocker locker(&m_startStopEncodingLock);
1439
1440 LOG(VB_RECORD, LOG_INFO, LOC + "StopEncoding");
1441
1442 if (m_readfd < 0)
1443 return;
1444
1445 struct v4l2_encoder_cmd command {};
1446 command.cmd = V4L2_ENC_CMD_STOP;
1447 command.flags = V4L2_ENC_CMD_STOP_AT_GOP_END;
1448
1451
1452 bool stopped = 0 == ioctl(m_readfd, VIDIOC_ENCODER_CMD, &command);
1453 if (stopped)
1454 {
1455 LOG(VB_RECORD, LOG_INFO, LOC + "Encoding stopped");
1456 }
1457 else if (errno != ENOTTY && errno != EINVAL)
1458 {
1459 // Some drivers do not support this ioctl at all. It is marked as
1460 // "experimental" in the V4L2 API spec. These drivers return EINVAL
1461 // in older kernels and ENOTTY in 3.1+
1462
1463 LOG(VB_GENERAL, LOG_WARNING, LOC + "StopEncoding failed" + ENO);
1464 }
1465
1467 {
1468 // allow last bits of data through..
1469 std::this_thread::sleep_for(20ms);
1471 }
1472
1473 // close the fd so streamoff/streamon work in V4LChannel
1474 close(m_readfd);
1475 m_readfd = -1;
1476}
1477
1479{
1482}
1483
1484void MpegRecorder::SetBitrate(int bitrate, int maxbitrate,
1485 const QString & reason)
1486{
1487 if (maxbitrate == bitrate)
1488 {
1489 LOG(VB_RECORD, LOG_INFO, LOC + QString("%1 bitrate %2 kbps CBR")
1490 .arg(reason).arg(bitrate));
1491 }
1492 else
1493 {
1494 LOG(VB_RECORD, LOG_INFO, LOC + QString("%1 bitrate %2/%3 kbps VBR")
1495 .arg(reason).arg(bitrate).arg(maxbitrate));
1496 }
1497
1498 std::vector<struct v4l2_ext_control> ext_ctrls;
1499 add_ext_ctrl(ext_ctrls, V4L2_CID_MPEG_VIDEO_BITRATE_MODE,
1500 (maxbitrate == bitrate) ?
1501 V4L2_MPEG_VIDEO_BITRATE_MODE_CBR :
1502 V4L2_MPEG_VIDEO_BITRATE_MODE_VBR);
1503
1504 add_ext_ctrl(ext_ctrls, V4L2_CID_MPEG_VIDEO_BITRATE,
1505 bitrate * 1000);
1506
1507 add_ext_ctrl(ext_ctrls, V4L2_CID_MPEG_VIDEO_BITRATE_PEAK,
1508 maxbitrate * 1000);
1509
1510 set_ctrls(m_readfd, ext_ctrls);
1511}
1512
1514{
1515 LOG(VB_RECORD, LOG_INFO, LOC + "Checking Resolution");
1516 uint pix = 0;
1517 struct v4l2_format vfmt {};
1518 vfmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1519
1520 if (0 == ioctl(m_chanfd, VIDIOC_G_FMT, &vfmt))
1521 {
1522 LOG(VB_RECORD, LOG_INFO, LOC + QString("Got Resolution %1x%2")
1523 .arg(vfmt.fmt.pix.width).arg(vfmt.fmt.pix.height));
1524 pix = vfmt.fmt.pix.width * vfmt.fmt.pix.height;
1525 }
1526
1527 if (!pix)
1528 {
1529 LOG(VB_RECORD, LOG_INFO, LOC + "Giving up detecting resolution: " + ENO);
1530 return false; // nothing to do, we don't have a resolution yet
1531 }
1532
1533 int old_max = m_maxBitrate;
1534 int old_avg = m_bitrate;
1535 if (pix <= 768*568)
1536 {
1539 }
1540 else if (pix >= 1920*1080)
1541 {
1544 }
1545 else
1546 {
1549 }
1550 m_maxBitrate = std::max(m_maxBitrate, m_bitrate);
1551
1552 if ((old_max != m_maxBitrate) || (old_avg != m_bitrate))
1553 {
1554 if (old_max == old_avg)
1555 {
1556 LOG(VB_RECORD, LOG_INFO, LOC +
1557 QString("Old bitrate %1 CBR").arg(old_avg));
1558 }
1559 else
1560 {
1561 LOG(VB_RECORD, LOG_INFO,LOC +
1562 QString("Old bitrate %1/%2 VBR") .arg(old_avg).arg(old_max));
1563 }
1564
1566 }
1567
1568 return true;
1569}
1570
1572{
1573 LOG(VB_VBI, LOG_INFO, LOC + QString("FormatCC(0x%1,0x%2)")
1574 .arg(code1,0,16).arg(code2,0,16));
1575 // TODO add to CC data vector
1576
1577 // TODO find video frames in output and insert cc_data
1578 // as CEA-708 user_data packets containing CEA-608 captions
1580}
static bool GetV4LInfo(int videofd, QString &input, QString &driver, uint32_t &version, uint32_t &capabilities)
Definition: cardutil.cpp:2369
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...
uint32_t m_startCode
Definition: dtvrecorder.h:136
std::array< uint8_t, 0x1fff+1 > m_continuityCounter
Definition: dtvrecorder.h:183
std::vector< unsigned char > m_payloadBuffer
Definition: dtvrecorder.h:167
bool IsErrored(void) override
Tells us whether an unrecoverable error has been encountered.
Definition: dtvrecorder.h:46
void ResetForNewFile(void) override
bool ProcessTSPacket(const TSPacket &tspacket) override
QString m_recordingType
Definition: dtvrecorder.h:131
H2645Parser * m_h2645Parser
Definition: dtvrecorder.h:152
void HandleSingleProgramPAT(ProgramAssociationTable *pat, bool insert) override
long long GetFramesWritten(void) override
Returns number of frames written to disk.
Definition: dtvrecorder.h:49
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 FindPSKeyFrames(const uint8_t *buffer, uint len) override
bool m_useIForKeyframe
Definition: dtvrecorder.h:215
virtual void SetStreamData(MPEGStreamData *data)
void HandleSingleProgramPMT(ProgramMapTable *pmt, bool insert) override
Buffers reads from device files.
bool IsRunning(void) const
bool Setup(const QString &streamName, int streamfd, uint readQuanta=sizeof(TSPacket), uint deviceBufferSize=0, uint deviceBufferCount=1)
void SetRequestPause(bool request)
uint Read(unsigned char *buf, uint count)
Try to Read count bytes from into buffer.
bool IsErrored(void) const
bool IsEOF(void) const
void Reset(const QString &streamName, int streamfd)
virtual void Reset(void)
Definition: H2645Parser.cpp:91
Encapsulates data about MPEG stream and emits events for each table.
void SetDesiredProgram(int p)
const ProgramMapTable * PMTSingleProgram(void) const
void AddWritingListener(TSPacketListener *val)
void AddMPEGSPListener(MPEGSingleProgramStreamListener *val)
int DesiredProgram(void) const
void RemoveWritingListener(TSPacketListener *val)
const ProgramAssociationTable * PATSingleProgram(void) const
virtual void Reset(void)
virtual int ProcessData(const unsigned char *buffer, int len)
void RemoveAVListener(TSPacketListenerAV *val)
void AddAVListener(TSPacketListenerAV *val)
bool wait(std::chrono::milliseconds time=std::chrono::milliseconds::max())
Wait for the MThread to exit, with a maximum timeout.
Definition: mthread.cpp:284
QRecursiveMutex m_startStopEncodingLock
Definition: mpegrecorder.h:91
bool m_deviceIsMpegFile
Definition: mpegrecorder.h:81
void InitStreamData(void) override
unsigned int m_mediumMpeg4PeakBitrate
Definition: mpegrecorder.h:114
static const std::array< const int, 14 > kAudRateL1
Definition: mpegrecorder.h:122
void SetOption(const QString &opt, int value) override
handles the "wait_for_seqstart" option.
void run(void) override
run() starts the recording process, and does not exit until the recording is complete.
bool m_clearTimeOnPause
Definition: mpegrecorder.h:94
unsigned int m_mediumMpeg4AvgBitrate
Definition: mpegrecorder.h:113
bool PauseAndWait(std::chrono::milliseconds timeout=100ms) override
If m_requestPause is true, sets pause and blocks up to timeout milliseconds or until unpaused,...
bool Open(void)
bool SetV4L2DeviceOptions(int chanfd)
static const std::array< const int, 14 > kAudRateL2
Definition: mpegrecorder.h:123
void Reset(void) override
Reset the recorder to the startup state.
void SetOptionsFromProfile(RecordingProfile *profile, const QString &videodev, const QString &audiodev, const QString &vbidev) override
Sets basic recorder options.
static const std::array< const std::string, 15 > kStreamType
Definition: mpegrecorder.h:125
void TeardownAll(void)
bool ProcessTSPacket(const TSPacket &tspacket) override
void SetBitrate(int bitrate, int maxbitrate, const QString &reason)
QString m_driver
Definition: mpegrecorder.h:86
void SetStrOption(RecordingProfile *profile, const QString &name)
bool SetRecordingVolume(int chanfd)
DeviceReadBuffer * m_deviceReadBuffer
Definition: mpegrecorder.h:130
uint32_t m_version
Definition: mpegrecorder.h:87
void SetIntOption(RecordingProfile *profile, const QString &name)
bool m_supportsSlicedVbi
Definition: mpegrecorder.h:88
uint GetFilteredAudioSampleRate(void) const
static const std::array< const std::string, 4 > kAspectRatio
Definition: mpegrecorder.h:126
bool RestartEncoding(void)
bool OpenMpegFileAsInput(void)
unsigned int m_lowMpeg4PeakBitrate
Definition: mpegrecorder.h:112
QString m_card
Definition: mpegrecorder.h:85
bool OpenV4L2DeviceAsInput(void)
bool SetLanguageMode(int chanfd)
Set audio language mode.
uint GetFilteredAudioLayer(void) const
static const std::array< const int, 14 > kAudRateL3
Definition: mpegrecorder.h:124
unsigned int m_highMpeg4PeakBitrate
Definition: mpegrecorder.h:116
bool HandleResolutionChanges(void)
unsigned int m_language
0 is Main Lang; 1 is SAP Lang; 2 is Dual
Definition: mpegrecorder.h:110
void StopEncoding(void)
void Pause(bool clear=true) override
Pause tells recorder to pause, it should not block.
unsigned int m_lowMpeg4AvgBitrate
Definition: mpegrecorder.h:111
uint GetFilteredAudioBitRate(uint audio_layer) const
bool SetVideoCaptureFormat(int chanfd)
void FormatCC(uint code1, uint code2) override
bool SetVBIOptions(int chanfd)
uint GetFilteredStreamType(void) const
unsigned int m_highMpeg4AvgBitrate
Definition: mpegrecorder.h:115
bool StartEncoding(void)
QString GetSetting(const QString &key, const QString &defaultval="")
A QElapsedTimer based timer to replace use of QTime as a timer.
Definition: mythtimer.h:14
std::chrono::milliseconds elapsed(void)
Returns milliseconds elapsed since last start() or restart()
Definition: mythtimer.cpp:91
void start(void)
starts measuring elapsed time.
Definition: mythtimer.cpp:47
void ClearPositionMap(MarkTypes type) const
AVContainer m_containerFormat
Definition: recorderbase.h:295
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
QString m_videodevice
Definition: recorderbase.h:299
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
RecordingInfo * m_curRecording
Definition: recorderbase.h:311
QWaitCondition m_unpauseWait
Definition: recorderbase.h:318
QWaitCondition m_recordingWait
Definition: recorderbase.h:323
virtual QString getValue(void) const
unsigned int PID(void) const
Definition: tspacket.h:93
void SetContinuityCounter(unsigned int cc)
Definition: tspacket.h:170
Used to access the data of a Transport Stream packet.
Definition: tspacket.h:208
TSPacket * CreateClone(void) const
Definition: tspacket.h:224
static constexpr unsigned int kSize
Definition: tspacket.h:261
void RecorderPaused(void)
This is a callback, called by the "recorder" instance when it has actually paused.
Definition: tv_rec.cpp:2998
uint GetInputId(void) const
Returns the inputid.
Definition: tv_rec.h:234
VBIThread * m_vbiThread
Definition: v4lrecorder.h:43
friend class VBIThread
Definition: v4lrecorder.h:17
int OpenVBIDevice(void)
Definition: v4lrecorder.cpp:68
void CloseVBIDevice(void)
void StopRecording(void) override
StopRecording() signals to the recorder that it should stop recording and exit cleanly.
Definition: v4lrecorder.cpp:43
void SetOption(const QString &name, const QString &value) override
Set an specific option.
Definition: v4lrecorder.cpp:56
volatile bool m_requestHelper
Definition: v4lrecorder.h:45
QString m_audioDeviceName
Definition: v4lrecorder.h:36
@ None
Definition: tv.h:12
@ PAL_TT
Definition: tv.h:13
#define O_NONBLOCK
Definition: compat.h:142
unsigned int uint
Definition: compat.h:60
#define close
Definition: compat.h:28
#define LOC
static void add_ext_ctrl(std::vector< struct v4l2_ext_control > &ctrl_list, uint32_t id, int32_t value)
static int find_index(const std::array< const int, 14 > &audio_rate, int value)
static int streamtype_ivtv_to_v4l2(int st)
static void set_ctrls(int fd, std::vector< struct v4l2_ext_control > &ext_ctrls)
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
static void clear(SettingsMap &cache, SettingsMap &overrides, const QString &myKey)
Definition: mythdb.cpp:948
#define ENO
This can be appended to the LOG args with "+".
Definition: mythlogging.h:74
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
QDateTime current(bool stripped)
Returns current Date and Time in UTC.
Definition: mythdate.cpp:15
def read(device=None, features=[])
Definition: disc.py:35
@ MARK_GOP_BYFRAME
Definition: programtypes.h:63
static eu8 clamp(eu8 value, eu8 low, eu8 high)
Definition: pxsup2dast.c:204
@ formatMPEG2_TS
Definition: recordingfile.h:15
@ formatMPEG2_PS
Definition: recordingfile.h:16
@ formatUnknown
Definition: recordingfile.h:13