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