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