MythTV  master
NuppelVideoRecorder.cpp
Go to the documentation of this file.
1 #include <cerrno>
2 #include <cmath>
3 #include <cstdio>
4 #include <cstdlib>
5 #include <fcntl.h>
6 #include <limits> // workaround QTBUG-90395
7 #include <sys/ioctl.h>
8 #include <sys/mman.h>
9 #include <sys/stat.h>
10 #include <sys/types.h>
11 #include <unistd.h>
12 
13 #include <QStringList>
14 #include <QtEndian>
15 
16 #include "libmyth/mythcontext.h"
20 
21 #include "NuppelVideoRecorder.h"
22 #include "audioinput.h"
23 #include "channelbase.h"
24 #include "fourcc.h"
25 #include "mythavutil.h"
26 #include "mythsystemevent.h"
27 #include "recorders/vbitext/cc.h"
28 #include "recorders/vbitext/vbi.h"
29 #include "recordingprofile.h"
30 #include "tv_play.h"
31 #include "tv_rec.h"
32 
33 #if HAVE_BIGENDIAN
34 extern "C" {
35 #ifndef MYTHTV_BSWAP_H
36 #define MYTHTV_BSWAP_H
37 
38 #include <cstdint> /* uint32_t */
39 
40 #define bswap_dbl(x) bswap_64(x)
41 
42 #if HAVE_BYTESWAP_H
43 # include <byteswap.h> /* bswap_16|32|64 */
44 #elif HAVE_SYS_ENDIAN_H
45 # include <sys/endian.h>
46 # if !defined(bswap_16) && defined(bswap16)
47 # define bswap_16(x) bswap16(x)
48 # endif
49 # if !defined(bswap_32) && defined(bswap32)
50 # define bswap_32(x) bswap32(x)
51 # endif
52 # if !defined(bswap_64) && defined(bswap64)
53 # define bswap_64(x) bswap64(x)
54 # endif
55 #elif CONFIG_DARWIN
56 # include <libkern/OSByteOrder.h>
57 # define bswap_16(x) OSSwapInt16(x)
58 # define bswap_32(x) OSSwapInt32(x)
59 # define bswap_64(x) OSSwapInt64(x)
60 #elif HAVE_BIGENDIAN
61 # error Byte swapping functions not defined for this platform
62 #endif
63 
64 #endif /* ndef MYTHTV_BSWAP_H */
65 }
66 #endif
67 
68 extern "C" {
69 #include "libswscale/swscale.h"
70 #include "libavutil/imgutils.h"
71 }
72 
73 #ifdef USING_V4L2
74 #include <linux/videodev2.h>
75 #include "go7007_myth.h"
76 #endif // USING_V4L2
77 
78 #include "io/mythmediabuffer.h"
79 #include "RTjpegN.h"
80 
81 #define LOC QString("NVR(%1): ").arg(m_videodevice)
82 
84 {
85  RunProlog();
87  RunEpilog();
88 }
89 
91 {
92  RunProlog();
94  RunEpilog();
95 }
96 
98  V4LRecorder(rec)
99 {
100  m_channelObj = channel;
101  m_seekTable = new std::vector<struct seektable_entry>;
102  m_ccd = new CC608Decoder(this);
103 
105 
107 }
108 
110 {
112  {
113  delete m_ringBuffer;
114  m_ringBuffer = nullptr;
115  }
116  delete m_rtjc;
117  delete [] m_mp3Buf;
118  if (m_gf)
119  lame_close(m_gf);
120  delete [] m_strm;
121  if (m_audioDevice)
122  {
123  delete m_audioDevice;
124  m_audioDevice = nullptr;
125  }
126  if (m_fd >= 0)
127  close(m_fd);
128  if (m_seekTable)
129  {
130  m_seekTable->clear();
131  delete m_seekTable;
132  }
133 
134  while (!m_videoBuffer.empty())
135  {
136  struct vidbuffertype *vb = m_videoBuffer.back();
137  delete [] vb->buffer;
138  delete vb;
139  m_videoBuffer.pop_back();
140  }
141  while (!m_audioBuffer.empty())
142  {
143  struct audbuffertype *ab = m_audioBuffer.back();
144  delete [] ab->buffer;
145  delete ab;
146  m_audioBuffer.pop_back();
147  }
148  while (!m_textBuffer.empty())
149  {
150  struct txtbuffertype *tb = m_textBuffer.back();
151  delete [] tb->buffer;
152  delete tb;
153  m_textBuffer.pop_back();
154  }
155 
156  if (m_mpaVidCodec)
157  avcodec_free_context(&m_mpaVidCtx);
158 
159  delete m_ccd;
160 }
161 
162 void NuppelVideoRecorder::SetOption(const QString &opt, int value)
163 {
164  if (opt == "width")
165  m_wOut = m_width = value;
166  else if (opt == "height")
167  m_hOut = m_height = value;
168  else if (opt == "rtjpegchromafilter")
169  m_m1 = value;
170  else if (opt == "rtjpeglumafilter")
171  m_m2 = value;
172  else if (opt == "rtjpegquality")
173  m_q = value;
174  else if ((opt == "mpeg4bitrate") || (opt == "mpeg2bitrate"))
175  m_targetBitRate = value;
176  else if (opt == "scalebitrate")
177  m_scaleBitRate = value;
178  else if (opt == "mpeg4maxquality")
179  {
180  if (value > 0)
181  m_maxQuality = value;
182  else
183  m_maxQuality = 1;
184  }
185  else if (opt == "mpeg4minquality")
186  m_minQuality = value;
187  else if (opt == "mpeg4qualdiff")
188  m_qualDiff = value;
189  else if (opt == "encodingthreadcount")
190  m_encodingThreadCount = value;
191  else if (opt == "mpeg4optionvhq")
192  {
193  if (value)
194  m_mbDecision = FF_MB_DECISION_RD;
195  else
196  m_mbDecision = FF_MB_DECISION_SIMPLE;
197  }
198  else if (opt == "mpeg4option4mv")
199  {
200  if (value)
201  m_mp4Opts |= AV_CODEC_FLAG_4MV;
202  else
203  m_mp4Opts &= ~AV_CODEC_FLAG_4MV;
204  }
205  else if (opt == "mpeg4optionidct")
206  {
207  if (value)
208  m_mp4Opts |= AV_CODEC_FLAG_INTERLACED_DCT;
209  else
210  m_mp4Opts &= ~AV_CODEC_FLAG_INTERLACED_DCT;
211  }
212  else if (opt == "mpeg4optionime")
213  {
214  if (value)
215  m_mp4Opts |= AV_CODEC_FLAG_INTERLACED_ME;
216  else
217  m_mp4Opts &= ~AV_CODEC_FLAG_INTERLACED_ME;
218  }
219  else if (opt == "hardwaremjpegquality")
220  m_hmjpgQuality = value;
221  else if (opt == "hardwaremjpeghdecimation")
222  m_hmjpgHDecimation = value;
223  else if (opt == "hardwaremjpegvdecimation")
224  m_hmjpgVDecimation = value;
225  else if (opt == "audiocompression")
226  m_compressAudio = (value != 0);
227  else if (opt == "mp3quality")
228  m_mp3Quality = value;
229  else if (opt == "samplerate")
230  m_audioSampleRate = value;
231  else if (opt == "audioframesize")
232  m_audioBufferSize = value;
233  else if (opt == "pip_mode")
234  m_pipMode = value;
235  else if (opt == "inpixfmt")
236  m_inPixFmt = (VideoFrameType)value;
237  else if (opt == "skipbtaudio")
238  m_skipBtAudio = (value != 0);
239  else if (opt == "volume")
240  m_volume = value;
241  else
242  V4LRecorder::SetOption(opt, value);
243 }
244 
245 void NuppelVideoRecorder::SetOption(const QString &name, const QString &value)
246 {
247  V4LRecorder::SetOption(name, value);
248 }
249 
251  const QString &videodev,
252  const QString &audiodev,
253  const QString &vbidev)
254 {
255  SetOption("videodevice", videodev);
256  SetOption("vbidevice", vbidev);
257  SetOption("tvformat", gCoreContext->GetSetting("TVFormat"));
258  SetOption("vbiformat", gCoreContext->GetSetting("VbiFormat"));
259  SetOption("audiodevice", audiodev);
260 
261  QString setting;
262  const StandardSetting *tmp = profile->byName("videocodec");
263  if (tmp)
264  setting = tmp->getValue();
265 
266  if (setting == "MPEG-4")
267  {
268  SetOption("videocodec", "mpeg4");
269 
270  SetIntOption(profile, "mpeg4bitrate");
271  SetIntOption(profile, "scalebitrate");
272  SetIntOption(profile, "mpeg4maxquality");
273  SetIntOption(profile, "mpeg4minquality");
274  SetIntOption(profile, "mpeg4qualdiff");
275 #ifdef USING_FFMPEG_THREADS
276  SetIntOption(profile, "encodingthreadcount");
277 #endif
278  SetIntOption(profile, "mpeg4optionvhq");
279  SetIntOption(profile, "mpeg4option4mv");
280  SetIntOption(profile, "mpeg4optionidct");
281  SetIntOption(profile, "mpeg4optionime");
282  }
283  else if (setting == "MPEG-2")
284  {
285  SetOption("videocodec", "mpeg2video");
286 
287  SetIntOption(profile, "mpeg2bitrate");
288  SetIntOption(profile, "scalebitrate");
289 #ifdef USING_FFMPEG_THREADS
290  SetIntOption(profile, "encodingthreadcount");
291 #endif
292  }
293  else if (setting == "RTjpeg")
294  {
295  SetOption("videocodec", "rtjpeg");
296 
297  SetIntOption(profile, "rtjpegquality");
298  SetIntOption(profile, "rtjpegchromafilter");
299  SetIntOption(profile, "rtjpeglumafilter");
300  }
301  else if (setting == "Hardware MJPEG")
302  {
303  SetOption("videocodec", "hardware-mjpeg");
304 
305  SetIntOption(profile, "hardwaremjpegquality");
306  SetIntOption(profile, "hardwaremjpeghdecimation");
307  SetIntOption(profile, "hardwaremjpegvdecimation");
308  }
309  else
310  {
311  LOG(VB_GENERAL, LOG_ERR, LOC +
312  "Unknown video codec. "
313  "Please go into the TV Settings, Recording Profiles and "
314  "setup the four 'Software Encoders' profiles. "
315  "Assuming RTjpeg for now.");
316 
317  SetOption("videocodec", "rtjpeg");
318 
319  SetIntOption(profile, "rtjpegquality");
320  SetIntOption(profile, "rtjpegchromafilter");
321  SetIntOption(profile, "rtjpeglumafilter");
322  }
323 
324  setting.clear();
325  if ((tmp = profile->byName("audiocodec")))
326  setting = tmp->getValue();
327 
328  if (setting == "MP3")
329  {
330  SetOption("audiocompression", 1);
331  SetIntOption(profile, "mp3quality");
332  SetIntOption(profile, "samplerate");
333  }
334  else if (setting == "Uncompressed")
335  {
336  SetOption("audiocompression", 0);
337  SetIntOption(profile, "samplerate");
338  }
339  else
340  {
341  LOG(VB_GENERAL, LOG_ERR, LOC + "Unknown audio codec");
342  SetOption("audiocompression", 0);
343  }
344 
345  SetIntOption(profile, "volume");
346 
347  SetIntOption(profile, "width");
348  SetIntOption(profile, "height");
349 }
350 
352 {
353  QMutexLocker locker(&m_pauseLock);
356  m_requestPause = true;
357 
358  // The wakeAll is to make sure [write|audio|main]paused are
359  // set immediately, even if we were already paused previously.
360  m_unpauseWait.wakeAll();
361 }
362 
363 bool NuppelVideoRecorder::IsPaused(bool holding_lock) const
364 {
365  if (!holding_lock)
366  m_pauseLock.lock();
367  bool ret = m_audioPaused && m_mainPaused && m_writePaused;
368  if (!holding_lock)
369  m_pauseLock.unlock();
370  return ret;
371 }
372 
373 void NuppelVideoRecorder::SetVideoFilters(QString& /*filters*/)
374 {
375 }
376 
378 {
379  return m_recording;
380 }
381 
383 {
384  return m_framesWritten;
385 }
386 
388 {
389  return m_channelFd;
390 }
391 
393 {
394  if (!m_useAvCodec)
395  m_useAvCodec = true;
396 
397  if (m_mpaVidCodec)
398  avcodec_free_context(&m_mpaVidCtx);
399 
400  QByteArray vcodec = m_videocodec.toLatin1();
401  m_mpaVidCodec = avcodec_find_encoder_by_name(vcodec.constData());
402 
403  if (!m_mpaVidCodec)
404  {
405  LOG(VB_GENERAL, LOG_ERR, LOC + QString("Video Codec not found: %1")
406  .arg(vcodec.constData()));
407  return false;
408  }
409 
410  m_mpaVidCtx = avcodec_alloc_context3(nullptr);
411 
412  switch (m_pictureFormat)
413  {
414  case AV_PIX_FMT_YUV420P:
415  case AV_PIX_FMT_YUV422P:
416  case AV_PIX_FMT_YUVJ420P:
417  m_mpaVidCtx->pix_fmt = m_pictureFormat;
418  break;
419  default:
420  LOG(VB_GENERAL, LOG_ERR, LOC + QString("Unknown picture format: %1")
421  .arg(m_pictureFormat));
422  }
423 
424  m_mpaVidCtx->width = m_wOut;
425  m_mpaVidCtx->height = (int)(m_height * m_heightMultiplier);
426 
427  int usebitrate = m_targetBitRate * 1000;
428  if (m_scaleBitRate)
429  {
430  float diff = (m_wOut * m_hOut) / (640.0 * 480.0);
431  usebitrate = (int)(diff * usebitrate);
432  }
433 
434  if (m_targetBitRate == -1)
435  usebitrate = -1;
436 
437  m_mpaVidCtx->time_base.den = (int)ceil(m_videoFrameRate * 100 *
439  m_mpaVidCtx->time_base.num = 100;
440 
441  // avcodec needs specific settings for mpeg2 compression
442  switch (m_mpaVidCtx->time_base.den)
443  {
444  case 2397:
445  case 2398: m_mpaVidCtx->time_base.den = 24000;
446  m_mpaVidCtx->time_base.num = 1001;
447  break;
448  case 2997:
449  case 2998: m_mpaVidCtx->time_base.den = 30000;
450  m_mpaVidCtx->time_base.num = 1001;
451  break;
452  case 5994:
453  case 5995: m_mpaVidCtx->time_base.den = 60000;
454  m_mpaVidCtx->time_base.num = 1001;
455  break;
456  }
457 
458  AVDictionary *opts = nullptr;
459 
460  m_mpaVidCtx->bit_rate = usebitrate;
461  m_mpaVidCtx->bit_rate_tolerance = usebitrate * 100;
462  m_mpaVidCtx->qmin = m_maxQuality;
463  m_mpaVidCtx->qmax = m_minQuality;
464  m_mpaVidCtx->max_qdiff = m_qualDiff;
465  m_mpaVidCtx->flags = m_mp4Opts;
466  m_mpaVidCtx->mb_decision = m_mbDecision;
467 
468  m_mpaVidCtx->qblur = 0.5;
469  m_mpaVidCtx->max_b_frames = 0;
470  m_mpaVidCtx->b_quant_factor = 0;
471  av_dict_set(&opts, "rc_strategy", "2", 0);
472  av_dict_set(&opts, "b_strategy", "0", 0);
473  m_mpaVidCtx->gop_size = 30;
474  m_mpaVidCtx->rc_max_rate = 0;
475  m_mpaVidCtx->rc_min_rate = 0;
476  m_mpaVidCtx->rc_buffer_size = 0;
477  m_mpaVidCtx->rc_override_count = 0;
478  av_dict_set(&opts, "rc_init_cplx", "0", 0);
479  m_mpaVidCtx->dct_algo = FF_DCT_AUTO;
480  m_mpaVidCtx->idct_algo = FF_IDCT_AUTO;
481  if (m_videocodec.toLower() == "huffyuv" || m_videocodec.toLower() == "mjpeg")
482  m_mpaVidCtx->strict_std_compliance = FF_COMPLIANCE_UNOFFICIAL;
483  m_mpaVidCtx->thread_count = m_encodingThreadCount;
484 
485  if (avcodec_open2(m_mpaVidCtx, m_mpaVidCodec, &opts) < 0)
486  {
487  LOG(VB_GENERAL, LOG_ERR, LOC + QString("Unable to open FFMPEG/%1 codec")
488  .arg(m_videocodec));
489  return false;
490  }
491 
492 
493  return true;
494 }
495 
497 {
498  m_pictureFormat = AV_PIX_FMT_YUV420P;
499 
500  m_rtjc = new RTjpeg();
501  int setval = RTJ_YUV420;
502  m_rtjc->SetFormat(&setval);
503  setval = (int)(m_hOut * m_heightMultiplier);
504  m_rtjc->SetSize(&m_wOut, &setval);
505  m_rtjc->SetQuality(&m_q);
506  setval = 2;
507  m_rtjc->SetIntra(&setval, &m_m1, &m_m2);
508 }
509 
510 
512 {
513  int tot_height = (int)(m_height * m_heightMultiplier);
514  double aspectnum = m_wOut / (double)tot_height;
515  uint aspect = 0;
516 
517  if (aspectnum == 0.0)
518  aspect = 0;
519  else if (fabs(aspectnum - 1.3333333333333333) < 0.001)
520  aspect = 2;
521  else if (fabs(aspectnum - 1.7777777777777777) < 0.001)
522  aspect = 3;
523  else if (fabs(aspectnum - 2.21) < 0.001)
524  aspect = 4;
525  else
526  aspect = aspectnum * 1000000;
527 
528  if ((aspect > 0) && (aspect != m_videoAspect))
529  {
530  m_videoAspect = aspect;
531  AspectChange((AspectRatio)aspect, 0);
532  }
533 
534  if (m_wOut && tot_height &&
535  ((uint)tot_height != m_videoHeight ||
536  (uint)m_wOut != m_videoWidth))
537  {
538  m_videoHeight = tot_height;
540  ResolutionChange(m_wOut, tot_height, 0);
541  }
542 
543  int den = (int)ceil(m_videoFrameRate * 100 * m_frameRateMultiplier);
544  int num = 100;
545 
546  // avcodec needs specific settings for mpeg2 compression
547  switch (den)
548  {
549  case 2397:
550  case 2398: den = 24000;
551  num = 1001;
552  break;
553  case 2997:
554  case 2998: den = 30000;
555  num = 1001;
556  break;
557  case 5994:
558  case 5995: den = 60000;
559  num = 1001;
560  break;
561  }
562 
563  FrameRate frameRate(den, num);
564  if (frameRate.isNonzero() && frameRate != m_frameRate)
565  {
566  m_frameRate = frameRate;
567  LOG(VB_RECORD, LOG_INFO, LOC + QString("NVR: frame rate = %1")
568  .arg(frameRate.toDouble() * 1000));
569  FrameRateChange(frameRate.toDouble() * 1000, 0);
570  }
571 }
572 
574 {
575  if (AudioInit() != 0)
576  {
577  LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to init audio input device");
578  }
579 
580  if (m_videocodec == "hardware-mjpeg")
581  {
582  m_videocodec = "mjpeg";
583  m_hardwareEncode = true;
584 
585  MJPEGInit();
586 
588 
589  if (m_ntsc)
590  {
591  switch (m_hmjpgVDecimation)
592  {
593  case 2: m_height = 240; break;
594  case 4: m_height = 120; break;
595  default: m_height = 480; break;
596  }
597  }
598  else
599  {
600  switch (m_hmjpgVDecimation)
601  {
602  case 2: m_height = 288; break;
603  case 4: m_height = 144; break;
604  default: m_height = 576; break;
605  }
606  }
607  }
608 
609  if (!m_ringBuffer)
610  {
611  LOG(VB_GENERAL, LOG_WARNING, LOC + "Warning, old RingBuffer creation");
612  m_ringBuffer = MythMediaBuffer::Create("output.nuv", true);
613  m_weMadeBuffer = true;
614  m_livetv = false;
615  if (!m_ringBuffer || !m_ringBuffer->IsOpen())
616  {
617  m_error = "Could not open RingBuffer";
618  LOG(VB_GENERAL, LOG_ERR, LOC + m_error);
619  return;
620  }
621  }
622  else
624 
625  m_audioBytes = 0;
626 
627  InitBuffers();
628 }
629 
630 int NuppelVideoRecorder::AudioInit(bool skipdevice)
631 {
632  if (!skipdevice)
633  {
634  int blocksize = 0;
636  if (!m_audioDevice)
637  {
638  LOG(VB_GENERAL, LOG_ERR, LOC +
639  QString("Failed to create audio device: %1") .arg(m_audioDeviceName));
640  return 1;
641  }
642 
644  {
645  LOG(VB_GENERAL, LOG_ERR, LOC +
646  QString("Failed to open audio device %1").arg(m_audioDeviceName));
647  return 1;
648  }
649 
650  if ((blocksize = m_audioDevice->GetBlockSize()) <= 0)
651  {
652  blocksize = 1024;
653  LOG(VB_GENERAL, LOG_ERR, LOC +
654  QString("Failed to determine audio block size on %1,"
655  "using default 1024 bytes").arg(m_audioDeviceName));
656  }
657 
658  m_audioDevice->Close();
659  m_audioBufferSize = blocksize;
660  }
661 
663  LOG(VB_AUDIO, LOG_INFO, LOC +
664  QString("Audio device %1 buffer size: %1 bytes")
665  .arg(m_audioBufferSize));
666 
667  if (m_compressAudio)
668  {
669  int tmp = 0;
670  m_gf = lame_init();
671  lame_set_bWriteVbrTag(m_gf, 0);
672  lame_set_quality(m_gf, m_mp3Quality);
673  lame_set_compression_ratio(m_gf, 11);
674  lame_set_mode(m_gf, m_audioChannels == 2 ? STEREO : MONO);
675  lame_set_num_channels(m_gf, m_audioChannels);
676  lame_set_in_samplerate(m_gf, m_audioSampleRate);
677  if ((tmp = lame_init_params(m_gf)) != 0)
678  {
679  LOG(VB_GENERAL, LOG_ERR, LOC +
680  QString("AudioInit(): lame_init_params error %1").arg(tmp));
681  m_compressAudio = false;
682  }
683 
684  if (m_audioBits != 16)
685  {
686  LOG(VB_GENERAL, LOG_ERR, LOC +
687  "AudioInit(): lame support requires 16bit audio");
688  m_compressAudio = false;
689  }
690  }
691  m_mp3BufSize = (int)(1.25 * 16384 + 7200);
692  m_mp3Buf = new char[m_mp3BufSize];
693 
694  return 0;
695 }
696 
707 {
708  LOG(VB_GENERAL, LOG_ERR, LOC + "MJPEG not supported by device");
709  return false;
710 }
711 
713 {
714  int videomegs = 0;
715  int audiomegs = 2;
716 
717  if (!m_videoBufferSize)
718  {
719  m_videoBufferSize = static_cast<long>(
721  m_wOut, m_hOut));
722  }
723 
724  if (m_width >= 480 || m_height > 288)
725  videomegs = 20;
726  else
727  videomegs = 12;
728 
729  m_videoBufferCount = (videomegs * 1000 * 1000) / static_cast<int>(m_videoBufferSize);
730 
731  if (m_audioBufferSize != 0)
732  m_audioBufferCount = (audiomegs * 1000 * 1000) / static_cast<int>(m_audioBufferSize);
733  else
734  m_audioBufferCount = 0;
735 
736  m_textBufferSize = 8 * (sizeof(teletextsubtitle) + VT_WIDTH);
738 
739  for (int i = 0; i < m_videoBufferCount; i++)
740  {
741  auto *vidbuf = new vidbuffertype;
742  vidbuf->buffer = new unsigned char[m_videoBufferSize];
743  vidbuf->sample = 0;
744  vidbuf->freeToEncode = 0;
745  vidbuf->freeToBuffer = 1;
746  vidbuf->bufferlen = 0;
747  vidbuf->forcekey = false;
748 
749  m_videoBuffer.push_back(vidbuf);
750  }
751 
752  for (int i = 0; i < m_audioBufferCount; i++)
753  {
754  auto *audbuf = new audbuffertype;
755  audbuf->buffer = new unsigned char[m_audioBufferSize];
756  audbuf->sample = 0;
757  audbuf->freeToEncode = 0;
758  audbuf->freeToBuffer = 1;
759 
760  m_audioBuffer.push_back(audbuf);
761  }
762 
763  for (int i = 0; i < m_textBufferCount; i++)
764  {
765  auto *txtbuf = new txtbuffertype;
766  txtbuf->buffer = new unsigned char[m_textBufferSize];
767  txtbuf->freeToEncode = 0;
768  txtbuf->freeToBuffer = 1;
769 
770  m_textBuffer.push_back(txtbuf);
771  }
772 }
773 
775 {
776  for (auto & vidbuf : m_videoBuffer)
777  {
778  delete [] (vidbuf->buffer);
779  vidbuf->buffer = new unsigned char[m_videoBufferSize];
780  }
781 }
782 
784 {
785  delete [] m_strm;
786  m_strm = new signed char[m_width * m_height * 2 + 10];
787 }
788 
790 {
791  if (m_channelFd>0)
792  return true;
793 
794  int retries = 0;
795  QByteArray vdevice = m_videodevice.toLatin1();
796  m_fd = open(vdevice.constData(), O_RDWR);
797  while (m_fd < 0)
798  {
799  usleep(30000);
800  m_fd = open(vdevice.constData(), O_RDWR);
801  if (retries++ > 5)
802  {
803  m_error = QString("Can't open video device: %1").arg(m_videodevice);
804  LOG(VB_GENERAL, LOG_ERR, LOC + m_error + ENO);
805  KillChildren();
806  return false;
807  }
808  }
809 
810  m_channelFd = m_fd;
811  return true;
812 }
813 
815 {
816 #ifdef USING_V4L2
817  m_usingV4l2 = true;
818 
819  struct v4l2_capability vcap {};
820 
821  if (ioctl(m_channelFd, VIDIOC_QUERYCAP, &vcap) < 0)
822  {
823  m_usingV4l2 = false;
824  }
825 
826  if (m_usingV4l2 && !(vcap.capabilities & V4L2_CAP_VIDEO_CAPTURE))
827  {
828  LOG(VB_GENERAL, LOG_ERR, LOC +
829  "Not a v4l2 capture device, falling back to v4l");
830  m_usingV4l2 = false;
831  }
832 
833  if (m_usingV4l2 && !(vcap.capabilities & V4L2_CAP_STREAMING))
834  {
835  LOG(VB_GENERAL, LOG_ERR, LOC +
836  "Won't work with the streaming interface, falling back");
837  m_usingV4l2 = false;
838  }
839 
840  if (vcap.card[0] == 'B' && vcap.card[1] == 'T' &&
841  vcap.card[2] == '8' && vcap.card[4] == '8')
842  m_correctBttv = true;
843 
844  QString driver = (char *)vcap.driver;
845  if (driver == "go7007")
846  m_go7007 = true;
847 #endif // USING_V4L2
848 }
849 
851 {
852  if (lzo_init() != LZO_E_OK)
853  {
854  LOG(VB_GENERAL, LOG_ERR, LOC + "lzo_init() failed, exiting");
855  m_error = "lzo_init() failed, exiting";
856  LOG(VB_GENERAL, LOG_ERR, LOC + m_error);
857  return;
858  }
859 
860  if (!Open())
861  {
862  m_error = "Failed to open device";
863  LOG(VB_GENERAL, LOG_ERR, LOC + m_error);
864  return;
865  }
866 
867  ProbeV4L2();
868 
869  if (m_usingV4l2 && !SetFormatV4L2())
870  {
871  m_error = "Failed to set V4L2 format";
872  LOG(VB_GENERAL, LOG_ERR, LOC + m_error);
873  return;
874  }
875 
876  StreamAllocate();
877 
878  m_positionMapLock.lock();
879  m_positionMap.clear();
880  m_positionMapDelta.clear();
881  m_positionMapLock.unlock();
882 
883  m_useAvCodec = (m_videocodec.toLower() != "rtjpeg");
884  if (m_useAvCodec)
886 
887  if (!m_useAvCodec)
888  SetupRTjpeg();
889 
891 
892  if (CreateNuppelFile() != 0)
893  {
894  m_error = QString("Cannot open '%1' for writing")
895  .arg(m_ringBuffer->GetFilename());
896  LOG(VB_GENERAL, LOG_ERR, LOC + m_error);
897  return;
898  }
899 
900  if (IsHelperRequested())
901  {
902  LOG(VB_GENERAL, LOG_ERR, LOC + "Children are already alive");
903  m_error = "Children are already alive";
904  return;
905  }
906 
907  {
908  QMutexLocker locker(&m_pauseLock);
909  m_requestRecording = true;
910  m_requestHelper = true;
911  m_recording = true;
912  m_recordingWait.wakeAll();
913  }
914 
915  m_writeThread = new NVRWriteThread(this);
916  m_writeThread->start();
917 
918  m_audioThread = new NVRAudioThread(this);
919  m_audioThread->start();
920 
921  if ((m_vbiMode != VBIMode::None) && (OpenVBIDevice() >= 0))
922  m_vbiThread = new VBIThread(this);
923 
924  // save the start time
925  gettimeofday(&m_stm, nullptr);
926 
927  // try to get run at higher scheduling priority, ignore failure
928  myth_nice(-10);
929 
930  if (m_usingV4l2)
931  {
932  m_inPixFmt = FMT_NONE;;
933  DoV4L2();
934  }
935 
936  {
937  QMutexLocker locker(&m_pauseLock);
938  m_requestRecording = false;
939  m_requestHelper = false;
940  m_recording = false;
941  m_recordingWait.wakeAll();
942  }
943 }
944 
945 #ifdef USING_V4L2
947 {
948  struct v4l2_format vfmt {};
949 
950  vfmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
951 
952  vfmt.fmt.pix.width = m_width;
953  vfmt.fmt.pix.height = m_height;
954  vfmt.fmt.pix.field = V4L2_FIELD_INTERLACED;
955 
956  if (m_go7007)
957  vfmt.fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG;
958  else if (m_inPixFmt == FMT_YUV422P)
959  vfmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUV422P;
960  else
961  vfmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUV420;
962 
963  if (ioctl(m_fd, VIDIOC_S_FMT, &vfmt) < 0)
964  {
965  // this is supported by the cx88 and various ati cards.
966  vfmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
967 
968  if (ioctl(m_fd, VIDIOC_S_FMT, &vfmt) < 0)
969  {
970  // this is supported by the HVR-950q
971  vfmt.fmt.pix.pixelformat = V4L2_PIX_FMT_UYVY;
972  if (ioctl(m_fd, VIDIOC_S_FMT, &vfmt) < 0)
973  {
974  LOG(VB_GENERAL, LOG_ERR, LOC +
975  "v4l2: Unable to set desired format");
976  return false;
977  }
978 
979  // we need to convert the buffer - we can't deal with uyvy
980  // directly.
981  if (m_inPixFmt == FMT_YUV422P)
982  {
983  LOG(VB_GENERAL, LOG_ERR, LOC +
984  "v4l2: uyvy format supported, but yuv422 requested.");
985  LOG(VB_GENERAL, LOG_ERR, LOC +
986  "v4l2: unfortunately, this converter hasn't been "
987  "written yet, exiting");
988  return false;
989  }
990  LOG(VB_RECORD, LOG_INFO, LOC +
991  "v4l2: format set, getting uyvy from v4l, converting");
992  }
993  else
994  {
995  // we need to convert the buffer - we can't deal with yuyv directly.
996  if (m_inPixFmt == FMT_YUV422P)
997  {
998  LOG(VB_GENERAL, LOG_ERR, LOC +
999  "v4l2: yuyv format supported, but yuv422 requested.");
1000  LOG(VB_GENERAL, LOG_ERR, LOC +
1001  "v4l2: unfortunately, this converter hasn't been written "
1002  "yet, exiting");
1003  return false;
1004  }
1005  LOG(VB_RECORD, LOG_INFO, LOC +
1006  "v4l2: format set, getting yuyv from v4l, converting");
1007  }
1008  }
1009  else // cool, we can do our preferred format, most likely running on bttv.
1010  LOG(VB_RECORD, LOG_INFO, LOC +
1011  "v4l2: format set, getting yuv420 from v4l");
1012 
1013  // VIDIOC_S_FMT might change the format, check it
1014  if (m_width != (int)vfmt.fmt.pix.width ||
1015  m_height != (int)vfmt.fmt.pix.height)
1016  {
1017  LOG(VB_RECORD, LOG_INFO, LOC +
1018  QString("v4l2: resolution changed. requested %1x%2, using "
1019  "%3x%4 now")
1020  .arg(m_width).arg(m_height)
1021  .arg(vfmt.fmt.pix.width) .arg(vfmt.fmt.pix.height));
1022  m_wOut = m_width = vfmt.fmt.pix.width;
1023  m_hOut = m_height = vfmt.fmt.pix.height;
1024  }
1025 
1026  m_v4l2PixelFormat = vfmt.fmt.pix.pixelformat;
1027 
1028  return true;
1029 }
1030 #else // if !USING_V4L2
1031 bool NuppelVideoRecorder::SetFormatV4L2(void) { return false; }
1032 #endif // !USING_V4L2
1033 
1034 #ifdef USING_V4L2
1035 static constexpr size_t MAX_VIDEO_BUFFERS { 5 };
1037 {
1038  struct v4l2_buffer vbuf {};
1039  struct v4l2_requestbuffers vrbuf {};
1040  struct v4l2_control vc {};
1041 
1042  vc.id = V4L2_CID_AUDIO_MUTE;
1043  vc.value = 0;
1044 
1045  if (ioctl(m_fd, VIDIOC_S_CTRL, &vc) < 0)
1046  LOG(VB_GENERAL, LOG_ERR, LOC +
1047  "VIDIOC_S_CTRL:V4L2_CID_AUDIO_MUTE: " + ENO);
1048 
1049  if (m_go7007)
1050  {
1051  struct go7007_comp_params comp {};
1052  struct go7007_mpeg_params mpeg {};
1053 
1054  comp.gop_size = m_keyframeDist;
1055  comp.max_b_frames = 0;
1056 
1057  if (fabs(m_videoAspect - 1.33333F) < 0.01F)
1058  {
1059  if (m_ntsc)
1061  else
1063  }
1064  else if (fabs(m_videoAspect - 1.77777F) < 0.01F)
1065  {
1066  if (m_ntsc)
1068  else
1070  }
1071  else
1072  {
1074  }
1075 
1076  comp.flags |= GO7007_COMP_CLOSED_GOP;
1077  if (ioctl(m_fd, GO7007IOC_S_COMP_PARAMS, &comp) < 0)
1078  {
1079  m_error = "Unable to set compression params";
1080  LOG(VB_GENERAL, LOG_ERR, LOC + m_error);
1081  return;
1082  }
1083 
1084  if (m_videocodec == "mpeg2video")
1085  mpeg.mpeg_video_standard = GO7007_MPEG_VIDEO_MPEG2;
1086  else
1087  mpeg.mpeg_video_standard = GO7007_MPEG_VIDEO_MPEG4;
1088 
1089  if (ioctl(m_fd, GO7007IOC_S_MPEG_PARAMS, &mpeg) < 0)
1090  {
1091  m_error = "Unable to set MPEG params";
1092  LOG(VB_GENERAL, LOG_ERR, LOC + m_error);
1093  return;
1094  }
1095 
1096  int usebitrate = m_targetBitRate * 1000;
1097  if (m_scaleBitRate)
1098  {
1099  float diff = (m_width * m_height) / (640.0 * 480.0);
1100  usebitrate = (int)(diff * usebitrate);
1101  }
1102 
1103  if (ioctl(m_fd, GO7007IOC_S_BITRATE, &usebitrate) < 0)
1104  {
1105  m_error = "Unable to set bitrate";
1106  LOG(VB_GENERAL, LOG_ERR, LOC + m_error);
1107  return;
1108  }
1109 
1110  m_hardwareEncode = true;
1111  }
1112 
1113  uint numbuffers = MAX_VIDEO_BUFFERS;
1114 
1115  vrbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1116  vrbuf.memory = V4L2_MEMORY_MMAP;
1117  vrbuf.count = numbuffers;
1118 
1119  if (ioctl(m_fd, VIDIOC_REQBUFS, &vrbuf) < 0)
1120  {
1121  m_error = "Not able to get any capture buffers, exiting";
1122  LOG(VB_GENERAL, LOG_ERR, LOC + m_error);
1123  return;
1124  }
1125 
1126  if (vrbuf.count < numbuffers)
1127  {
1128  LOG(VB_GENERAL, LOG_INFO, LOC +
1129  QString("Requested %1 buffers, but only %2 are available. "
1130  "Proceeding anyway").arg(numbuffers).arg(vrbuf.count));
1131  }
1132 
1133  numbuffers = vrbuf.count;
1134 
1135  std::array<uint8_t*,MAX_VIDEO_BUFFERS> buffers {};
1136  std::array<int,MAX_VIDEO_BUFFERS> bufferlen {};
1137 
1138  for (uint i = 0; i < numbuffers; i++)
1139  {
1140  vbuf.type = vrbuf.type;
1141  vbuf.index = i;
1142 
1143  if (ioctl(m_fd, VIDIOC_QUERYBUF, &vbuf) < 0)
1144  {
1145  LOG(VB_GENERAL, LOG_ERR, LOC +
1146  QString("unable to query capture buffer %1").arg(i));
1147  m_error = "Unable to query capture buffer";
1148  return;
1149  }
1150 
1151  buffers[i] = (unsigned char *)mmap(nullptr, vbuf.length,
1152  PROT_READ|PROT_WRITE, MAP_SHARED,
1153  m_fd, vbuf.m.offset);
1154 
1155  if (buffers[i] == MAP_FAILED)
1156  {
1157  LOG(VB_GENERAL, LOG_ERR, LOC + "mmap: " + ENO);
1158  LOG(VB_GENERAL, LOG_ERR, LOC + "Memory map failed");
1159  m_error = "Memory map failed";
1160  return;
1161  }
1162  bufferlen[i] = vbuf.length;
1163  }
1164 
1165  for (uint i = 0; i < numbuffers; i++)
1166  {
1167  memset(buffers[i], 0, bufferlen[i]);
1168  vbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1169  vbuf.index = i;
1170  if (ioctl(m_fd, VIDIOC_QBUF, &vbuf) < 0)
1171  LOG(VB_GENERAL, LOG_ERR, LOC + "unable to enqueue capture buffer (VIDIOC_QBUF failed) " + ENO);
1172  }
1173 
1174  int turnon = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1175  if (ioctl(m_fd, VIDIOC_STREAMON, &turnon) < 0)
1176  LOG(VB_GENERAL, LOG_ERR, LOC + "unable to start capture (VIDIOC_STREAMON failed) " + ENO);
1177 
1178  struct timeval tv {};
1179  fd_set rdset {};
1180  int frame = 0;
1181  bool forcekey = false;
1182 
1183  m_resetCapture = false;
1184 
1185  // setup pixel format conversions for YUYV and UYVY
1186  uint8_t *output_buffer = nullptr;
1187  struct SwsContext *convert_ctx = nullptr;
1188  AVFrame img_out;
1189  if (m_v4l2PixelFormat == V4L2_PIX_FMT_YUYV ||
1190  m_v4l2PixelFormat == V4L2_PIX_FMT_UYVY)
1191  {
1192  AVPixelFormat in_pixfmt = m_v4l2PixelFormat == V4L2_PIX_FMT_YUYV ?
1193  AV_PIX_FMT_YUYV422 :
1194  AV_PIX_FMT_UYVY422;
1195 
1196  output_buffer = (uint8_t*)av_malloc(m_height * m_width * 3 / 2);
1197  if (!output_buffer)
1198  {
1199  m_error = "Cannot initialize image conversion buffer";
1200  LOG(VB_GENERAL, LOG_ERR, LOC + m_error);
1201  return;
1202  }
1203 
1204  convert_ctx = sws_getCachedContext(convert_ctx, m_width, m_height, in_pixfmt,
1205  m_width, m_height, AV_PIX_FMT_YUV420P,
1206  SWS_FAST_BILINEAR, nullptr, nullptr, nullptr);
1207  if (!convert_ctx)
1208  {
1209  m_error = "Cannot initialize image conversion context";
1210  av_free(output_buffer);
1211  LOG(VB_GENERAL, LOG_ERR, LOC + m_error);
1212  return;
1213  }
1214 
1215  av_image_fill_arrays(img_out.data, img_out.linesize,
1216  output_buffer, AV_PIX_FMT_YUV420P, m_width, m_height, IMAGE_ALIGN);
1217  }
1218 
1219  while (IsRecordingRequested() && !IsErrored())
1220  {
1221 again:
1222  {
1223  QMutexLocker locker(&m_pauseLock);
1224  if (m_requestPause)
1225  {
1226  if (!m_mainPaused)
1227  {
1228  m_mainPaused = true;
1229  m_pauseWait.wakeAll();
1230  if (IsPaused(true) && m_tvrec)
1232  }
1233  m_unpauseWait.wait(&m_pauseLock, 100);
1234  if (m_clearTimeOnPause)
1235  gettimeofday(&m_stm, nullptr);
1236  continue;
1237  }
1238 
1239  if (!m_requestPause && m_mainPaused)
1240  {
1241  m_mainPaused = false;
1242  m_unpauseWait.wakeAll();
1243  }
1244  }
1245 
1246  if (m_resetCapture)
1247  {
1248  LOG(VB_GENERAL, LOG_ERR, LOC + "Resetting and re-queueing");
1249  turnon = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1250  if (ioctl(m_fd, VIDIOC_STREAMOFF, &turnon) < 0)
1251  LOG(VB_GENERAL, LOG_ERR, LOC + "unable to stop capture (VIDIOC_STREAMOFF failed) " + ENO);
1252 
1253  for (uint i = 0; i < numbuffers; i++)
1254  {
1255  memset(buffers[i], 0, bufferlen[i]);
1256  vbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1257  vbuf.index = i;
1258  if (ioctl(m_fd, VIDIOC_QBUF, &vbuf) < 0)
1259  LOG(VB_GENERAL, LOG_ERR, LOC + "unable to enqueue capture buffer (VIDIOC_QBUF failed) " + ENO);
1260  }
1261 
1262  if (ioctl(m_fd, VIDIOC_STREAMON, &turnon) < 0)
1263  LOG(VB_GENERAL, LOG_ERR, LOC + "unable to start capture (VIDIOC_STREAMON failed) " + ENO);
1264  m_resetCapture = false;
1265  }
1266 
1267  tv.tv_sec = 5;
1268  tv.tv_usec = 0;
1269  FD_ZERO(&rdset); // NOLINT(readability-isolate-declaration)
1270  FD_SET(m_fd, &rdset);
1271 
1272  switch (select(m_fd+1, &rdset, nullptr, nullptr, &tv))
1273  {
1274  case -1:
1275  if (errno == EINTR)
1276  goto again;
1277  LOG(VB_GENERAL, LOG_ERR, LOC + "select: " + ENO);
1278  continue;
1279  case 0:
1280  LOG(VB_GENERAL, LOG_INFO, LOC + "select timeout");
1281  continue;
1282  default: break;
1283  }
1284 
1285  memset(&vbuf, 0, sizeof(vbuf));
1286  vbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1287  vbuf.memory = V4L2_MEMORY_MMAP;
1288  if (ioctl(m_fd, VIDIOC_DQBUF, &vbuf) < 0)
1289  {
1290  LOG(VB_GENERAL, LOG_ERR, LOC + "DQBUF ioctl failed." + ENO);
1291 
1292  // EIO failed DQBUF de-tunes post 2.6.15.3 for cx88
1293  // EIO or EINVAL on bttv means we need to reset the buffers..
1294  if (errno == EIO && m_channelObj)
1295  {
1296  m_channelObj->Retune();
1297  m_resetCapture = true;
1298  continue;
1299  }
1300 
1301  if (errno == EIO || errno == EINVAL)
1302  {
1303  m_resetCapture = true;
1304  continue;
1305  }
1306 
1307  if (errno == EAGAIN)
1308  continue;
1309  }
1310 
1311  frame = vbuf.index;
1312  if (m_go7007)
1313  forcekey = ((vbuf.flags & V4L2_BUF_FLAG_KEYFRAME) != 0U);
1314 
1315  if (!m_requestPause)
1316  {
1317  if ((m_v4l2PixelFormat == V4L2_PIX_FMT_YUYV) &&
1318  (output_buffer != nullptr))
1319  {
1320  AVFrame img_in;
1321  av_image_fill_arrays(img_in.data, img_in.linesize,
1322  buffers[frame], AV_PIX_FMT_YUYV422, m_width, m_height,
1323  IMAGE_ALIGN);
1324  sws_scale(convert_ctx, img_in.data, img_in.linesize,
1325  0, m_height, img_out.data, img_out.linesize);
1326  BufferIt(output_buffer, m_videoBufferSize);
1327  }
1328  else if ((m_v4l2PixelFormat == V4L2_PIX_FMT_UYVY) &&
1329  (output_buffer != nullptr))
1330  {
1331  AVFrame img_in;
1332  av_image_fill_arrays(img_in.data, img_in.linesize,
1333  buffers[frame], AV_PIX_FMT_UYVY422, m_width, m_height,
1334  IMAGE_ALIGN);
1335  sws_scale(convert_ctx, img_in.data, img_in.linesize,
1336  0, m_height, img_out.data, img_out.linesize);
1337  BufferIt(output_buffer, m_videoBufferSize);
1338  }
1339  else
1340  {
1341  // buffer the frame directly
1342  BufferIt(buffers[frame], vbuf.bytesused, forcekey);
1343  }
1344  }
1345 
1346  vbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1347  if (ioctl(m_fd, VIDIOC_QBUF, &vbuf) < 0)
1348  LOG(VB_GENERAL, LOG_ERR, LOC + "unable to enqueue capture buffer (VIDIOC_QBUF failed) " + ENO);
1349  }
1350 
1351  KillChildren();
1352 
1353  if (ioctl(m_fd, VIDIOC_STREAMOFF, &turnon) < 0)
1354  LOG(VB_GENERAL, LOG_ERR, LOC + "unable to stop capture (VIDIOC_STREAMOFF failed) " + ENO);
1355 
1356  for (uint i = 0; i < numbuffers; i++)
1357  {
1358  munmap(buffers[i], bufferlen[i]);
1359  }
1360 
1361  FinishRecording();
1362 
1363  av_free(output_buffer);
1364  sws_freeContext(convert_ctx);
1365 
1366  close(m_fd);
1367  close(m_channelFd);
1368 }
1369 #else // if !USING_V4L2
1370 void NuppelVideoRecorder::DoV4L2(void) {}
1371 #endif // !USING_V4L2
1372 
1374 {
1375  {
1376  QMutexLocker locker(&m_pauseLock);
1377  m_requestHelper = false;
1378  m_unpauseWait.wakeAll();
1379  }
1380 
1381  if (m_writeThread)
1382  {
1383  m_writeThread->wait();
1384  delete m_writeThread;
1385  m_writeThread = nullptr;
1386  }
1387 
1388  if (m_audioThread)
1389  {
1390  m_audioThread->wait();
1391  delete m_audioThread;
1392  m_audioThread = nullptr;
1393  }
1394 
1395  if (m_vbiThread)
1396  {
1397  m_vbiThread->wait();
1398  delete m_vbiThread;
1399  m_vbiThread = nullptr;
1400  CloseVBIDevice();
1401  }
1402 }
1403 
1404 void NuppelVideoRecorder::BufferIt(unsigned char *buf, int len, bool forcekey)
1405 {
1406  struct timeval now {};
1407 
1408  int act = m_actVideoBuffer;
1409 
1410  if (!m_videoBuffer[act]->freeToBuffer) {
1411  return;
1412  }
1413 
1414  gettimeofday(&now, nullptr);
1415 
1416  auto tcres = durationFromTimevalDelta<std::chrono::milliseconds>(now, m_stm);
1417 
1418  m_useBttv = 0;
1419  // here is the non preferable timecode - drop algorithm - fallback
1420  if (!m_useBttv)
1421  {
1422  if (m_tf==0)
1423  m_tf = 2;
1424  else
1425  {
1426  int fn = (tcres - m_oldTc).count();
1427 
1428  // the difference should be less than 1,5*timeperframe or we have
1429  // missed at least one frame, this code might be inaccurate!
1430 
1431  if (m_ntscFrameRate)
1432  fn = (fn+16)/33;
1433  else
1434  fn = (fn+20)/40;
1435  if (fn<1)
1436  fn=1;
1437  m_tf += 2*fn; // two fields
1438  }
1439  }
1440 
1441  m_oldTc = tcres;
1442 
1443  if (!m_videoBuffer[act]->freeToBuffer)
1444  {
1445  LOG(VB_GENERAL, LOG_INFO, LOC +
1446  "DROPPED frame due to full buffer in the recorder.");
1447  return; // we can't buffer the current frame
1448  }
1449 
1450  m_videoBuffer[act]->sample = m_tf;
1451 
1452  // record the time at the start of this frame.
1453  // 'tcres' is at the end of the frame, so subtract the right # of ms
1454  m_videoBuffer[act]->timecode =
1455  (m_ntscFrameRate) ? (tcres - 33ms) : (tcres - 40ms);
1456 
1457  memcpy(m_videoBuffer[act]->buffer, buf, len);
1458  m_videoBuffer[act]->bufferlen = len;
1459  m_videoBuffer[act]->forcekey = forcekey;
1460 
1461  m_videoBuffer[act]->freeToBuffer = 0;
1462  m_actVideoBuffer++;
1464  m_actVideoBuffer = 0; // cycle to begin of buffer
1465  m_videoBuffer[act]->freeToEncode = 1; // set last to prevent race
1466 }
1467 
1469 {
1470 #if HAVE_BIGENDIAN
1471  fh->timecode = bswap_32(fh->timecode);
1472  fh->packetlength = bswap_32(fh->packetlength);
1473 #endif
1475 }
1476 
1478 {
1479  if (newaspect == static_cast<double>(m_videoAspect))
1480  return;
1481 
1482  m_videoAspect = newaspect;
1483 
1484  struct rtframeheader frameheader {};
1485 
1486  frameheader.frametype = 'S';
1487  frameheader.comptype = 'M';
1488  frameheader.packetlength = sizeof(struct rtfileheader);
1489 
1490  WriteFrameheader(&frameheader);
1491 
1492  WriteFileHeader();
1493 }
1494 
1496 {
1497  struct rtfileheader fileheader {};
1498  static const std::string kFinfo { "MythTVVideo" };
1499  static const std::string kVers { "0.07" };
1500 
1501  std::copy(kFinfo.cbegin(), kFinfo.cend(), fileheader.finfo);
1502  std::copy(kVers.cbegin(), kVers.cend(), fileheader.version);
1503  fileheader.width = m_wOut;
1504  fileheader.height = (int)(m_hOut * m_heightMultiplier);
1505  fileheader.desiredwidth = 0;
1506  fileheader.desiredheight = 0;
1507  fileheader.pimode = 'P';
1508  fileheader.aspect = m_videoAspect;
1509  fileheader.fps = m_videoFrameRate;
1510  fileheader.fps *= m_frameRateMultiplier;
1511  fileheader.videoblocks = -1;
1512  fileheader.audioblocks = -1;
1513  fileheader.textsblocks = -1; // TODO: make only -1 if VBI support active?
1514  fileheader.keyframedist = KEYFRAMEDIST;
1515 
1516 #if HAVE_BIGENDIAN
1517  fileheader.width = bswap_32(fileheader.width);
1518  fileheader.height = bswap_32(fileheader.height);
1519  fileheader.desiredwidth = bswap_32(fileheader.desiredwidth);
1520  fileheader.desiredheight = bswap_32(fileheader.desiredheight);
1521  fileheader.aspect = bswap_dbl(fileheader.aspect);
1522  fileheader.fps = bswap_dbl(fileheader.fps);
1523  fileheader.videoblocks = bswap_32(fileheader.videoblocks);
1524  fileheader.audioblocks = bswap_32(fileheader.audioblocks);
1525  fileheader.textsblocks = bswap_32(fileheader.textsblocks);
1526  fileheader.keyframedist = bswap_32(fileheader.keyframedist);
1527 #endif
1528  m_ringBuffer->Write(&fileheader, FILEHEADERSIZE);
1529 }
1530 
1532 {
1533  struct rtframeheader frameheader {};
1534 
1535  WriteFileHeader();
1536 
1537  frameheader.frametype = 'D'; // compressor data
1538 
1539  if (m_useAvCodec)
1540  {
1541  frameheader.comptype = 'F';
1542  frameheader.packetlength = m_mpaVidCtx->extradata_size;
1543 
1544  WriteFrameheader(&frameheader);
1545  m_ringBuffer->Write(m_mpaVidCtx->extradata, frameheader.packetlength);
1546  }
1547  else
1548  {
1549  static std::array<uint32_t,128> s_tbls {};
1550 
1551  frameheader.comptype = 'R'; // compressor data for RTjpeg
1552  frameheader.packetlength = s_tbls.size() * sizeof(uint32_t);
1553 
1554  // compression configuration header
1555  WriteFrameheader(&frameheader);
1556 
1557  m_ringBuffer->Write(s_tbls.data(), s_tbls.size() * sizeof(uint32_t));
1558  }
1559 
1560  memset(&frameheader, 0, sizeof(frameheader));
1561  frameheader.frametype = 'X'; // extended data
1562  frameheader.packetlength = sizeof(extendeddata);
1563 
1564  // extended data header
1565  WriteFrameheader(&frameheader);
1566 
1567  struct extendeddata moredata {};
1568 
1569  moredata.version = 1;
1570  if (m_useAvCodec)
1571  {
1572  int vidfcc = 0;
1573  switch(m_mpaVidCodec->id)
1574  {
1575  case AV_CODEC_ID_MPEG4: vidfcc = FOURCC_DIVX; break;
1576  case AV_CODEC_ID_WMV1: vidfcc = FOURCC_WMV1; break;
1577  case AV_CODEC_ID_MSMPEG4V3: vidfcc = FOURCC_DIV3; break;
1578  case AV_CODEC_ID_MSMPEG4V2: vidfcc = FOURCC_MP42; break;
1579  case AV_CODEC_ID_MSMPEG4V1: vidfcc = FOURCC_MPG4; break;
1580  case AV_CODEC_ID_MJPEG: vidfcc = FOURCC_MJPG; break;
1581  case AV_CODEC_ID_H263:
1582  case AV_CODEC_ID_H263P: vidfcc = FOURCC_H263; break;
1583  case AV_CODEC_ID_H263I: vidfcc = FOURCC_I263; break;
1584  case AV_CODEC_ID_MPEG1VIDEO: vidfcc = FOURCC_MPEG; break;
1585  case AV_CODEC_ID_MPEG2VIDEO: vidfcc = FOURCC_MPG2; break;
1586  case AV_CODEC_ID_HUFFYUV: vidfcc = FOURCC_HFYU; break;
1587  default: break;
1588  }
1589  moredata.video_fourcc = vidfcc;
1590  moredata.lavc_bitrate = m_mpaVidCtx->bit_rate;
1591  moredata.lavc_qmin = m_mpaVidCtx->qmin;
1592  moredata.lavc_qmax = m_mpaVidCtx->qmax;
1593  moredata.lavc_maxqdiff = m_mpaVidCtx->max_qdiff;
1594  }
1595  else
1596  {
1597  moredata.video_fourcc = FOURCC_RJPG;
1598  moredata.rtjpeg_quality = m_q;
1599  moredata.rtjpeg_luma_filter = m_m1;
1600  moredata.rtjpeg_chroma_filter = m_m2;
1601  }
1602 
1603  if (m_compressAudio)
1604  {
1605  moredata.audio_fourcc = FOURCC_LAME;
1606  moredata.audio_compression_ratio = 11;
1607  moredata.audio_quality = m_mp3Quality;
1608  }
1609  else
1610  {
1611  moredata.audio_fourcc = FOURCC_RAWA;
1612  }
1613 
1615  moredata.audio_channels = m_audioChannels;
1617 
1619 
1620 #if HAVE_BIGENDIAN
1621  moredata.version = bswap_32(moredata.version);
1622  moredata.video_fourcc = bswap_32(moredata.video_fourcc);
1623  moredata.audio_fourcc = bswap_32(moredata.audio_fourcc);
1624  moredata.audio_sample_rate = bswap_32(moredata.audio_sample_rate);
1625  moredata.audio_bits_per_sample = bswap_32(moredata.audio_bits_per_sample);
1626  moredata.audio_channels = bswap_32(moredata.audio_channels);
1627  moredata.audio_compression_ratio = bswap_32(moredata.audio_compression_ratio);
1628  moredata.audio_quality = bswap_32(moredata.audio_quality);
1629  moredata.rtjpeg_quality = bswap_32(moredata.rtjpeg_quality);
1630  moredata.rtjpeg_luma_filter = bswap_32(moredata.rtjpeg_luma_filter);
1631  moredata.rtjpeg_chroma_filter = bswap_32(moredata.rtjpeg_chroma_filter);
1632  moredata.lavc_bitrate = bswap_32(moredata.lavc_bitrate);
1633  moredata.lavc_qmin = bswap_32(moredata.lavc_qmin);
1634  moredata.lavc_qmax = bswap_32(moredata.lavc_qmax);
1635  moredata.lavc_maxqdiff = bswap_32(moredata.lavc_maxqdiff);
1636  moredata.seektable_offset = bswap_64(moredata.seektable_offset);
1637  moredata.keyframeadjust_offset = bswap_64(moredata.keyframeadjust_offset);
1638 #endif
1639  m_ringBuffer->Write(&moredata, sizeof(moredata));
1640 
1641  m_lastBlock = 0;
1642  m_lf = 0; // that resets framenumber so that seeking in the
1643  // continues parts works too
1644 }
1645 
1647 {
1648  int numentries = m_seekTable->size();
1649 
1650  struct rtframeheader frameheader {};
1651  frameheader.frametype = 'Q'; // SeekTable
1652  frameheader.packetlength = sizeof(struct seektable_entry) * numentries;
1653 
1654  long long currentpos = m_ringBuffer->GetWritePosition();
1655 
1656  m_ringBuffer->Write(&frameheader, sizeof(frameheader));
1657 
1658  char *seekbuf = new char[frameheader.packetlength];
1659  int offset = 0;
1660 
1661  for (auto & entry : *m_seekTable)
1662  {
1663  memcpy(seekbuf + offset, (const void *)&entry,
1664  sizeof(struct seektable_entry));
1665  offset += sizeof(struct seektable_entry);
1666  }
1667 
1668  m_ringBuffer->Write(seekbuf, frameheader.packetlength);
1669 
1671  offsetof(struct extendeddata, seektable_offset),
1672  SEEK_SET);
1673 
1674  m_ringBuffer->Write(&currentpos, sizeof(long long));
1675 
1676  m_ringBuffer->WriterSeek(0, SEEK_END);
1677 
1678  delete [] seekbuf;
1679 }
1680 
1682  const std::vector<struct kfatable_entry> &kfa_table)
1683 {
1684  int numentries = kfa_table.size();
1685 
1686  struct rtframeheader frameheader {};
1687  frameheader.frametype = 'K'; // KFA Table
1688  frameheader.packetlength = sizeof(struct kfatable_entry) * numentries;
1689 
1690  long long currentpos = m_ringBuffer->GetWritePosition();
1691 
1692  m_ringBuffer->Write(&frameheader, sizeof(frameheader));
1693 
1694  char *kfa_buf = new char[frameheader.packetlength];
1695  uint offset = 0;
1696 
1697  for (const auto& kfa : kfa_table)
1698  {
1699  memcpy(kfa_buf + offset, &kfa,
1700  sizeof(struct kfatable_entry));
1701  offset += sizeof(struct kfatable_entry);
1702  }
1703 
1704  m_ringBuffer->Write(kfa_buf, frameheader.packetlength);
1705 
1706 
1708  offsetof(struct extendeddata, keyframeadjust_offset),
1709  SEEK_SET);
1710 
1711  m_ringBuffer->Write(&currentpos, sizeof(long long));
1712 
1713  m_ringBuffer->WriterSeek(0, SEEK_END);
1714 
1715  delete [] kfa_buf;
1716 }
1717 
1718 void NuppelVideoRecorder::UpdateSeekTable(int frame_num, long offset)
1719 {
1720  long long position = m_ringBuffer->GetWritePosition() + offset;
1721  struct seektable_entry ste { position, frame_num};
1722  m_seekTable->push_back(ste);
1723 
1724  m_positionMapLock.lock();
1725  if (!m_positionMap.contains(ste.keyframe_number))
1726  {
1727  m_positionMapDelta[ste.keyframe_number] = position;
1728  m_positionMap[ste.keyframe_number] = position;
1729  m_lastPositionMapPos = position;
1730  }
1731  m_positionMapLock.unlock();
1732 }
1733 
1735 {
1736  m_framesWritten = 0;
1737 
1738  if (!m_ringBuffer)
1739  {
1740  LOG(VB_GENERAL, LOG_ERR, LOC +
1741  "No ringbuffer, recorder wasn't initialized.");
1742  return -1;
1743  }
1744 
1745  if (!m_ringBuffer->IsOpen())
1746  {
1747  LOG(VB_GENERAL, LOG_ERR, LOC + "Ringbuffer isn't open");
1748  return -1;
1749  }
1750 
1751  WriteHeader();
1752 
1753  return 0;
1754 }
1755 
1757 {
1758  ResetForNewFile();
1759 
1760  for (int i = 0; i < m_videoBufferCount; i++)
1761  {
1762  vidbuffertype *vidbuf = m_videoBuffer[i];
1763  vidbuf->sample = 0;
1764  vidbuf->timecode = 0ms;
1765  vidbuf->freeToEncode = 0;
1766  vidbuf->freeToBuffer = 1;
1767  vidbuf->forcekey = false;
1768  }
1769 
1770  for (int i = 0; i < m_audioBufferCount; i++)
1771  {
1772  audbuffertype *audbuf = m_audioBuffer[i];
1773  audbuf->sample = 0;
1774  audbuf->timecode = 0ms;
1775  audbuf->freeToEncode = 0;
1776  audbuf->freeToBuffer = 1;
1777  }
1778 
1779  for (int i = 0; i < m_textBufferCount; i++)
1780  {
1781  txtbuffertype *txtbuf = m_textBuffer[i];
1782  txtbuf->freeToEncode = 0;
1783  txtbuf->freeToBuffer = 1;
1784  }
1785 
1786  m_actVideoEncode = 0;
1787  m_actVideoBuffer = 0;
1788  m_actAudioEncode = 0;
1789  m_actAudioBuffer = 0;
1790  m_actAudioSample = 0;
1791  m_actTextEncode = 0;
1792  m_actTextBuffer = 0;
1793 
1794  m_audioBytes = 0;
1795  m_effectiveDsp = 0;
1796 
1797  if (m_useAvCodec)
1799 
1800  if (m_curRecording)
1802 }
1803 
1805 {
1806  if (!m_audioDevice)
1807  {
1808  LOG(VB_GENERAL, LOG_ERR, LOC +
1809  QString("Invalid audio device (%1), exiting").arg(m_audioDeviceName));
1810  return;
1811  }
1812 
1814  {
1815  LOG(VB_GENERAL, LOG_ERR, LOC +
1816  QString("Failed to open audio device %1").arg(m_audioDeviceName));
1817  return;
1818  }
1819 
1820  if (!m_audioDevice->Start())
1821  {
1822  LOG(VB_GENERAL, LOG_ERR, LOC +
1823  QString("Failed to start audio capture on %1").arg(m_audioDeviceName));
1824  return;
1825  }
1826 
1827  struct timeval anow {};
1828  auto *buffer = new unsigned char[m_audioBufferSize];
1830 
1831  while (IsHelperRequested() && !IsErrored())
1832  {
1833  {
1834  QMutexLocker locker(&m_pauseLock);
1835  if (m_requestPause)
1836  {
1837  if (!m_audioPaused)
1838  {
1839  m_audioPaused = true;
1840  m_pauseWait.wakeAll();
1841  if (IsPaused(true) && m_tvrec)
1843  }
1844  m_unpauseWait.wait(&m_pauseLock, 100);
1845  continue;
1846  }
1847 
1848  if (!m_requestPause && m_audioPaused)
1849  {
1850  m_audioPaused = false;
1851  m_unpauseWait.wakeAll();
1852  }
1853  }
1854 
1855  if (!IsHelperRequested() || IsErrored())
1856  break;
1857 
1858  int lastread = m_audioDevice->GetSamples(buffer, m_audioBufferSize);
1859  if (m_audioBufferSize != lastread)
1860  {
1861  LOG(VB_GENERAL, LOG_ERR, LOC +
1862  QString("Short read, %1 of %2 bytes from ")
1863  .arg(lastread).arg(m_audioBufferSize) + m_audioDeviceName);
1864  }
1865 
1866  /* record the current time */
1867  /* Don't assume that the sound device's record buffer is empty
1868  (like we used to.) Measure to see how much stuff is in there,
1869  and correct for it when calculating the timestamp */
1870  gettimeofday(&anow, nullptr);
1871  int bytes_read = std::max(m_audioDevice->GetNumReadyBytes(), 0);
1872 
1873  int act = m_actAudioBuffer;
1874 
1875  if (!m_audioBuffer[act]->freeToBuffer)
1876  {
1877  LOG(VB_GENERAL, LOG_ERR, LOC + "Ran out of free AUDIO buffers :-(");
1878  m_actAudioSample++;
1879  continue;
1880  }
1881 
1882  m_audioBuffer[act]->sample = m_actAudioSample;
1883 
1884  /* calculate timecode. First compute the difference
1885  between now and stm (start time) */
1886  m_audioBuffer[act]->timecode =
1887  durationFromTimevalDelta<std::chrono::milliseconds>(anow, m_stm);
1888  /* We want the timestamp to point to the start of this
1889  audio chunk. So, subtract off the length of the chunk
1890  and the length of audio still in the capture buffer. */
1891  m_audioBuffer[act]->timecode -= millisecondsFromFloat(
1892  (bytes_read + m_audioBufferSize)
1893  * 1000.0 / (m_audioSampleRate * m_audioBytesPerSample));
1894 
1895  memcpy(m_audioBuffer[act]->buffer, buffer, m_audioBufferSize);
1896 
1897  m_audioBuffer[act]->freeToBuffer = 0;
1898  m_actAudioBuffer++;
1900  m_actAudioBuffer = 0;
1901  m_audioBuffer[act]->freeToEncode = 1;
1902 
1903  m_actAudioSample++;
1904  }
1905 
1906  delete [] buffer;
1907 
1908  if (m_audioDevice->IsOpen())
1909  m_audioDevice->Close();
1910 }
1911 
1912 #ifdef USING_V4L2
1914 {
1915  struct timeval tnow {};
1916  gettimeofday(&tnow, nullptr);
1917 
1918  int act = m_actTextBuffer;
1919  if (!m_textBuffer[act]->freeToBuffer)
1920  {
1921  LOG(VB_GENERAL, LOG_ERR, LOC +
1922  QString("Teletext #%1: ran out of free TEXT buffers :-(").arg(act));
1923  return;
1924  }
1925 
1926  // calculate timecode:
1927  // compute the difference between now and stm (start time)
1928  m_textBuffer[act]->timecode =
1929  durationFromTimevalDelta<std::chrono::milliseconds>(tnow, m_stm);
1930  m_textBuffer[act]->pagenr = (vbidata->teletextpage.pgno << 16) +
1931  vbidata->teletextpage.subno;
1932 
1933  unsigned char *inpos = vbidata->teletextpage.data[0];
1934  unsigned char *outpos = m_textBuffer[act]->buffer;
1935  *outpos = 0;
1936  struct teletextsubtitle st {};
1937  std::vector<uint8_t> linebuf {};
1938  linebuf.reserve(VT_WIDTH + 1);
1939 
1940  for (int y = 0; y < VT_HEIGHT; y++)
1941  {
1942  char c = ' ';
1943  char last_c = ' ';
1944  int hid = 0;
1945  int gfx = 0;
1946  int dbl = 0;
1947  int box = 0;
1948  int sep = 0;
1949  int hold = 0;
1950  int visible = 0;
1951  int fg = 7;
1952  int bg = 0;
1953 
1954  for (int x = 0; x < VT_WIDTH; ++x)
1955  {
1956  c = *inpos++;
1957  switch (c)
1958  {
1959  case 0x00 ... 0x07: /* alpha + fg color */
1960  fg = c & 7;
1961  gfx = 0;
1962  sep = 0;
1963  hid = 0;
1964  goto ctrl;
1965  case 0x08: /* flash */
1966  case 0x09: /* steady */
1967  goto ctrl;
1968  case 0x0a: /* end box */
1969  box = 0;
1970  goto ctrl;
1971  case 0x0b: /* start box */
1972  box = 1;
1973  goto ctrl;
1974  case 0x0c: /* normal height */
1975  dbl = 0;
1976  goto ctrl;
1977  case 0x0d: /* double height */
1978  if (y < VT_HEIGHT-2) /* ignored on last 2 lines */
1979  {
1980  dbl = 1;
1981  }
1982  goto ctrl;
1983  case 0x10 ... 0x17: /* gfx + fg color */
1984  fg = c & 7;
1985  gfx = 1;
1986  hid = 0;
1987  goto ctrl;
1988  case 0x18: /* conceal */
1989  hid = 1;
1990  goto ctrl;
1991  case 0x19: /* contiguous gfx */
1992  hid = 0;
1993  sep = 0;
1994  goto ctrl;
1995  case 0x1a: /* separate gfx */
1996  sep = 1;
1997  goto ctrl;
1998  case 0x1c: /* black bf */
1999  bg = 0;
2000  goto ctrl;
2001  case 0x1d: /* new bg */
2002  bg = fg;
2003  goto ctrl;
2004  case 0x1e: /* hold gfx */
2005  hold = 1;
2006  goto ctrl;
2007  case 0x1f: /* release gfx */
2008  hold = 0;
2009  goto ctrl;
2010  case 0x0e: /* SO */
2011  case 0x0f: /* SI */
2012  case 0x1b: /* ESC */
2013  goto ctrl;
2014 
2015  ctrl:
2016  c = ' ';
2017  if (hold && gfx)
2018  c = last_c;
2019  break;
2020  }
2021  if (gfx)
2022  {
2023  if ((c & 0xa0) == 0x20)
2024  {
2025  last_c = c;
2026  c += (c & 0x40) ? 32 : -32;
2027  }
2028  }
2029  if (hid)
2030  c = ' ';
2031 
2032  if (visible || (c != ' '))
2033  {
2034  if (!visible)
2035  {
2036  st.row = y;
2037  st.col = x;
2038  st.dbl = dbl;
2039  st.fg = fg;
2040  st.bg = bg;
2041  linebuf.clear();
2042  }
2043  linebuf.push_back(c);
2044  visible = 1;
2045  }
2046 
2047  (void) box;
2048  (void) sep;
2049  }
2050  if (visible)
2051  {
2052  st.len = linebuf.size() + 1;
2053  int maxlen = 200;
2054  int bufsize = ((outpos - m_textBuffer[act]->buffer + 1) + st.len);
2055  if (bufsize > maxlen)
2056  break;
2057  memcpy(outpos, &st, sizeof(st));
2058  outpos += sizeof(st);
2059  int count = std::max(st.len, static_cast<uint8_t>(41));
2060  std::copy(linebuf.cbegin(), linebuf.cbegin() + count, outpos);
2061  outpos += count;
2062  *outpos = 0;
2063  }
2064  }
2065 
2066  m_textBuffer[act]->bufferlen = outpos - m_textBuffer[act]->buffer + 1;
2067  m_textBuffer[act]->freeToBuffer = 0;
2068  m_actTextBuffer++;
2069  if (m_actTextBuffer >= m_textBufferCount)
2070  m_actTextBuffer = 0;
2071  m_textBuffer[act]->freeToEncode = 1;
2072 }
2073 #else // USING_V4L2
2074 void NuppelVideoRecorder::FormatTT(struct VBIData*) {}
2075 #endif // USING_V4L2
2076 
2078 {
2079  struct timeval tnow {};
2080  gettimeofday (&tnow, nullptr);
2081 
2082  // calculate timecode:
2083  // compute the difference between now and stm (start time)
2084  auto tc = durationFromTimevalDelta<std::chrono::milliseconds>(tnow, m_stm);
2085  m_ccd->FormatCC(tc, code1, code2);
2086 }
2087 
2088 void NuppelVideoRecorder::AddTextData(unsigned char *buf, int len,
2089  std::chrono::milliseconds timecode, char /*type*/)
2090 {
2091  int act = m_actTextBuffer;
2092  if (!m_textBuffer[act]->freeToBuffer)
2093  {
2094  LOG(VB_GENERAL, LOG_ERR, LOC + QString("Teletext#%1").arg(act) +
2095  " ran out of free TEXT buffers :-(");
2096  return;
2097  }
2098 
2099  m_textBuffer[act]->timecode = timecode;
2100  memcpy(m_textBuffer[act]->buffer, buf, len);
2101  m_textBuffer[act]->bufferlen = len + sizeof(ccsubtitle);
2102 
2103  m_textBuffer[act]->freeToBuffer = 0;
2104  m_actTextBuffer++;
2106  m_actTextBuffer = 0;
2107  m_textBuffer[act]->freeToEncode = 1;
2108 }
2109 
2111 {
2112  while (IsHelperRequested() && !IsErrored())
2113  {
2114  {
2115  QMutexLocker locker(&m_pauseLock);
2116  if (m_requestPause)
2117  {
2118  if (!m_writePaused)
2119  {
2120  m_writePaused = true;
2121  m_pauseWait.wakeAll();
2122  if (IsPaused(true) && m_tvrec)
2124  }
2125  m_unpauseWait.wait(&m_pauseLock, 100);
2126  continue;
2127  }
2128 
2129  if (!m_requestPause && m_writePaused)
2130  {
2131  m_writePaused = false;
2132  m_unpauseWait.wakeAll();
2133  }
2134  }
2135 
2136  if (!IsHelperRequested() || IsErrored())
2137  break;
2138 
2140 
2141  enum
2142  { ACTION_NONE,
2143  ACTION_VIDEO,
2144  ACTION_AUDIO,
2145  ACTION_TEXT
2146  } action = ACTION_NONE;
2147  std::chrono::milliseconds firsttimecode = -1ms;
2148 
2149  if (m_videoBuffer[m_actVideoEncode]->freeToEncode)
2150  {
2151  action = ACTION_VIDEO;
2152  firsttimecode = m_videoBuffer[m_actVideoEncode]->timecode;
2153  }
2154 
2155  if (m_audioBufferCount &&
2156  m_audioBuffer[m_actAudioEncode]->freeToEncode &&
2157  (action == ACTION_NONE ||
2158  (m_audioBuffer[m_actAudioEncode]->timecode < firsttimecode)))
2159  {
2160  action = ACTION_AUDIO;
2161  firsttimecode = m_audioBuffer[m_actAudioEncode]->timecode;
2162  }
2163 
2164  if (m_textBufferCount &&
2165  m_textBuffer[m_actTextEncode]->freeToEncode &&
2166  (action == ACTION_NONE ||
2167  (m_textBuffer[m_actTextEncode]->timecode < firsttimecode)))
2168  {
2169  action = ACTION_TEXT;
2170  }
2171 
2172  switch (action)
2173  {
2174  case ACTION_VIDEO:
2175  {
2177  m_videoBuffer[m_actVideoEncode]->bufferlen,
2178  m_width, m_height);
2179  frame.m_frameNumber = m_videoBuffer[m_actVideoEncode]->sample;
2180  frame.m_timecode = m_videoBuffer[m_actVideoEncode]->timecode;
2181  frame.m_forceKey = m_videoBuffer[m_actVideoEncode]->forcekey;
2182  WriteVideo(&frame);
2183  // Ensure buffer isn't deleted
2184  frame.m_buffer = nullptr;
2185 
2186  m_videoBuffer[m_actVideoEncode]->sample = 0;
2187  m_videoBuffer[m_actVideoEncode]->freeToEncode = 0;
2188  m_videoBuffer[m_actVideoEncode]->freeToBuffer = 1;
2189  m_videoBuffer[m_actVideoEncode]->forcekey = false;
2190  m_actVideoEncode++;
2192  m_actVideoEncode = 0;
2193  break;
2194  }
2195  case ACTION_AUDIO:
2196  {
2199  m_audioBuffer[m_actAudioEncode]->timecode);
2200  if (IsErrored()) {
2201  LOG(VB_GENERAL, LOG_ERR, LOC +
2202  "ACTION_AUDIO cannot be completed due to error.");
2203  StopRecording();
2204  break;
2205  }
2206  m_audioBuffer[m_actAudioEncode]->sample = 0;
2207  m_audioBuffer[m_actAudioEncode]->freeToEncode = 0;
2208  m_audioBuffer[m_actAudioEncode]->freeToBuffer = 1;
2209  m_actAudioEncode++;
2211  m_actAudioEncode = 0;
2212  break;
2213  }
2214  case ACTION_TEXT:
2215  {
2217  m_textBuffer[m_actTextEncode]->bufferlen,
2218  m_textBuffer[m_actTextEncode]->timecode,
2219  m_textBuffer[m_actTextEncode]->pagenr);
2220  m_textBuffer[m_actTextEncode]->freeToEncode = 0;
2221  m_textBuffer[m_actTextEncode]->freeToBuffer = 1;
2222  m_actTextEncode++;
2224  m_actTextEncode = 0;
2225  break;
2226  }
2227  default:
2228  {
2229  usleep(100);
2230  break;
2231  }
2232  }
2233  }
2234 }
2235 
2237 {
2238  m_framesWritten = 0;
2239  m_lf = 0;
2240  m_lastBlock = 0;
2241 
2242  m_seekTable->clear();
2243 
2244  ClearStatistics();
2245 
2246  m_positionMapLock.lock();
2247  m_positionMap.clear();
2248  m_positionMapDelta.clear();
2249  m_positionMapLock.unlock();
2250 
2251  if (m_go7007)
2252  m_resetCapture = true;
2253 }
2254 
2256 {
2257  CreateNuppelFile();
2258 }
2259 
2261 {
2263 
2264  WriteSeekTable();
2265 
2267 
2268  m_positionMapLock.lock();
2269  m_positionMap.clear();
2270  m_positionMapDelta.clear();
2271  m_positionMapLock.unlock();
2272 }
2273 
2275  bool forcekey)
2276 {
2277  int tmp = 0;
2278  lzo_uint out_len = kOutLen;
2279  struct rtframeheader frameheader {};
2280  int raw = 0;
2281  int compressthis = m_compression;
2282  std::array<uint8_t*,3> planes {
2283  frame->m_buffer + frame->m_offsets[0],
2284  frame->m_buffer + frame->m_offsets[1],
2285  frame->m_buffer + frame->m_offsets[2] };
2286  int fnum = frame->m_frameNumber;
2287  std::chrono::milliseconds timecode = frame->m_timecode;
2288 
2289  if (m_lf == 0)
2290  { // this will be triggered every new file
2291  m_lf = fnum;
2292  m_startNum = fnum;
2293  m_lastTimecode = 0;
2294  m_frameOfGop = 0;
2295  forcekey = true;
2296  }
2297 
2298  // see if it's time for a seeker header, sync information and a keyframe
2299  frameheader.keyframe = m_frameOfGop; // no keyframe defaulted
2300 
2301  bool wantkeyframe = forcekey;
2302 
2303  bool writesync = false;
2304 
2305  if ((!m_go7007 && (((fnum-m_startNum)>>1) % m_keyframeDist == 0 && !skipsync)) ||
2306  (m_go7007 && frame->m_forceKey))
2307  writesync = true;
2308 
2309  if (writesync)
2310  {
2311  m_ringBuffer->Write("RTjjjjjjjjjjjjjjjjjjjjjjjj", FRAMEHEADERSIZE);
2312 
2313  UpdateSeekTable(((fnum - m_startNum) >> 1) / m_keyframeDist);
2314 
2315  frameheader.frametype = 'S'; // sync frame
2316  frameheader.comptype = 'V'; // video sync information
2317  frameheader.filters = 0; // no filters applied
2318  frameheader.packetlength = 0; // no data packet
2319  frameheader.timecode = (fnum-m_startNum)>>1;
2320  // write video sync info
2321  WriteFrameheader(&frameheader);
2322  frameheader.frametype = 'S'; // sync frame
2323  frameheader.comptype = 'A'; // video sync information
2324  frameheader.filters = 0; // no filters applied
2325  frameheader.packetlength = 0; // no data packet
2326  frameheader.timecode = m_effectiveDsp; // effective dsp frequency
2327  // write audio sync info
2328  WriteFrameheader(&frameheader);
2329 
2330  wantkeyframe = true;
2331  //m_ringBuffer->Sync();
2332  }
2333 
2334  if (wantkeyframe)
2335  {
2336  frameheader.keyframe=0;
2337  m_frameOfGop=0;
2338  }
2339 
2340  if (m_useAvCodec)
2341  {
2342  MythAVFrame mpa_picture;
2343  MythAVUtil::FillAVFrame(mpa_picture, frame);
2344 
2345  if (wantkeyframe)
2346  mpa_picture->pict_type = AV_PICTURE_TYPE_I;
2347  else
2348  mpa_picture->pict_type = AV_PICTURE_TYPE_NONE;
2349 
2350  if (!m_hardwareEncode)
2351  {
2352  AVPacket *packet = av_packet_alloc();
2353  if (packet == nullptr)
2354  {
2355  LOG(VB_RECORD, LOG_ERR, "packet allocation failed");
2356  return;
2357  }
2358  packet->data = (uint8_t *)m_strm;
2359  packet->size = frame->m_bufferSize;
2360 
2361  bool got_packet = false;
2362  int ret = avcodec_receive_packet(m_mpaVidCtx, packet);
2363  if (ret == 0)
2364  got_packet = true;
2365  if (ret == AVERROR(EAGAIN))
2366  ret = 0;
2367  if (ret == 0)
2368  ret = avcodec_send_frame(m_mpaVidCtx, mpa_picture);
2369  // if ret from avcodec_send_frame is AVERROR(EAGAIN) then
2370  // there are 2 packets to be received while only 1 frame to be
2371  // sent. The code does not cater for this. Hopefully it will not happen.
2372 
2373  if (ret < 0)
2374  {
2375  std::string error;
2376  LOG(VB_GENERAL, LOG_ERR, LOC + QString("video encode error: %1 (%2)")
2377  .arg(av_make_error_stdstring(error, ret)).arg(got_packet));
2378  av_packet_free(&packet);
2379  return;
2380  }
2381 
2382  if (!got_packet)
2383  {
2384  av_packet_free(&packet);
2385  return;
2386  }
2387 
2388 
2389  tmp = packet->size;
2390  av_packet_free(&packet);
2391  }
2392  }
2393  else
2394  {
2395  int freecount = 0;
2396  freecount = m_actVideoBuffer > m_actVideoEncode ?
2399 
2400  if (freecount < (m_videoBufferCount / 3))
2401  compressthis = 0; // speed up the encode process
2402 
2403  if (freecount < 5)
2404  raw = 1; // speed up the encode process
2405 
2406  if (m_transcoding)
2407  {
2408  raw = 0;
2409  compressthis = 1;
2410  }
2411 
2412  if (!raw)
2413  {
2414  if (wantkeyframe)
2415  m_rtjc->SetNextKey();
2416  tmp = m_rtjc->Compress(m_strm, planes.data());
2417  }
2418  else
2419  tmp = frame->m_bufferSize;
2420 
2421  // here is lzo compression afterwards
2422  if (compressthis)
2423  {
2424  int r = 0;
2425  if (raw)
2426  {
2427  r = lzo1x_1_compress(frame->m_buffer, frame->m_bufferSize,
2428  m_out.data(), &out_len, m_wrkmem.data());
2429  }
2430  else
2431  {
2432  r = lzo1x_1_compress((unsigned char *)m_strm, tmp, m_out.data(),
2433  &out_len, m_wrkmem.data());
2434  }
2435  if (r != LZO_E_OK)
2436  {
2437  LOG(VB_GENERAL, LOG_ERR, LOC + "lzo compression failed");
2438  return;
2439  }
2440  }
2441  }
2442 
2443  frameheader.frametype = 'V'; // video frame
2444  frameheader.timecode = timecode.count();
2445  m_lastTimecode = frameheader.timecode;
2446  frameheader.filters = 0; // no filters applied
2447 
2448  // compr ends here
2449  if (m_useAvCodec)
2450  {
2451  if (m_mpaVidCodec->id == AV_CODEC_ID_RAWVIDEO)
2452  {
2453  frameheader.comptype = '0';
2454  frameheader.packetlength = frame->m_bufferSize;
2455  WriteFrameheader(&frameheader);
2456  m_ringBuffer->Write(frame->m_buffer, frame->m_bufferSize);
2457  }
2458  else if (m_hardwareEncode)
2459  {
2460  frameheader.comptype = '4';
2461  frameheader.packetlength = frame->m_bufferSize;
2462  WriteFrameheader(&frameheader);
2463  m_ringBuffer->Write(frame->m_buffer, frame->m_bufferSize);
2464  }
2465  else
2466  {
2467  frameheader.comptype = '4';
2468  frameheader.packetlength = tmp;
2469  WriteFrameheader(&frameheader);
2471  }
2472  }
2473  else if (compressthis == 0 || (tmp < (int)out_len))
2474  {
2475  if (!raw)
2476  {
2477  frameheader.comptype = '1'; // video compression: RTjpeg only
2478  frameheader.packetlength = tmp;
2479  WriteFrameheader(&frameheader);
2481  }
2482  else
2483  {
2484  frameheader.comptype = '0'; // raw YUV420
2485  frameheader.packetlength = frame->m_bufferSize;
2486  WriteFrameheader(&frameheader);
2487  m_ringBuffer->Write(frame->m_buffer, frame->m_bufferSize); // we write buf directly
2488  }
2489  }
2490  else
2491  {
2492  if (!raw)
2493  frameheader.comptype = '2'; // video compression: RTjpeg with lzo
2494  else
2495  frameheader.comptype = '3'; // raw YUV420 with lzo
2496  frameheader.packetlength = out_len;
2497  WriteFrameheader(&frameheader);
2498  m_ringBuffer->Write(m_out.data(), out_len);
2499  }
2500 
2501  if (m_framesWritten == 0)
2502  SendMythSystemRecEvent("REC_STARTED_WRITING", m_curRecording);
2503 
2504  m_frameOfGop++;
2505  m_framesWritten++;
2506 
2507  // now we reset the last frame number so that we can find out
2508  // how many frames we didn't get next time
2509  m_lf = fnum;
2510 }
2511 
2512 void NuppelVideoRecorder::WriteAudio(unsigned char *buf, int fnum, std::chrono::milliseconds timecode)
2513 {
2514  struct rtframeheader frameheader {};
2515 
2516  if (m_lastBlock == 0)
2517  {
2518  m_firstTc = -1ms;
2519  }
2520 
2521  if (m_lastBlock != 0)
2522  {
2523  if (fnum != (m_lastBlock+1))
2524  {
2525  m_audioBehind = fnum - (m_lastBlock+1);
2526  LOG(VB_RECORD, LOG_INFO, LOC + QString("audio behind %1 %2").
2527  arg(m_lastBlock).arg(fnum));
2528  }
2529  }
2530 
2531  frameheader.frametype = 'A'; // audio frame
2532  frameheader.timecode = timecode.count();
2533 
2534  if (m_firstTc == -1ms)
2535  {
2536  m_firstTc = timecode;
2537 #if 0
2538  LOG(VB_GENERAL, LOG_DEBUG, LOC +
2539  QString("first timecode=%1").arg(m_firstTc.count()));
2540 #endif
2541  }
2542  else
2543  {
2544  timecode -= m_firstTc; // this is to avoid the lack between the beginning
2545  // of recording and the first timestamp, maybe we
2546  // can calculate the audio-video +-lack at the
2547  // beginning too
2548  auto abytes = (double)m_audioBytes; // - (double)m_audioBufferSize;
2549  // wrong guess ;-)
2550  // need seconds instead of msec's
2551  auto mt = (double)timecode.count();
2552  if (mt > 0.0)
2553  {
2554  double eff = (abytes / mt) * (100000.0 / m_audioBytesPerSample);
2555  m_effectiveDsp = (int)eff;
2556  }
2557  }
2558 
2559  if (m_compressAudio)
2560  {
2561  std::array<uint8_t,7200> mp3gapless {};
2562  int compressedsize = 0;
2563  int gaplesssize = 0;
2564  int lameret = 0;
2565 
2566  int sample_cnt = m_audioBufferSize / m_audioBytesPerSample;
2567 
2568 #if (Q_BYTE_ORDER == Q_BIG_ENDIAN)
2569  auto buf16 = reinterpret_cast<uint16_t *>(buf);
2570  for (int i = 0; i < m_audioChannels * sample_cnt; i++)
2571  buf16[i] = qToLittleEndian<quint16>(buf16[i]);
2572 #endif
2573  if (m_audioChannels == 2)
2574  {
2575  lameret = lame_encode_buffer_interleaved(
2576  m_gf, (short int*) buf, sample_cnt,
2577  (unsigned char*) m_mp3Buf, m_mp3BufSize);
2578  }
2579  else
2580  {
2581  lameret = lame_encode_buffer(
2582  m_gf, (short int*) buf, (short int*) buf, sample_cnt,
2583  (unsigned char*) m_mp3Buf, m_mp3BufSize);
2584  }
2585 
2586  if (lameret < 0)
2587  {
2588  LOG(VB_GENERAL, LOG_ERR, LOC +
2589  QString("lame error '%1'").arg(lameret));
2590  m_error = QString("Audio Encoding Error '%1'")
2591  .arg(lameret);
2592  return;
2593  }
2594  compressedsize = lameret;
2595 
2596  lameret = lame_encode_flush_nogap(m_gf, mp3gapless.data(), mp3gapless.size());
2597  if (lameret < 0)
2598  {
2599  LOG(VB_GENERAL, LOG_ERR, LOC +
2600  QString("lame error '%1'").arg(lameret));
2601  m_error = QString("Audio Encoding Error '%1'")
2602  .arg(lameret);
2603  return;
2604  }
2605  gaplesssize = lameret;
2606 
2607  frameheader.comptype = '3'; // audio is compressed
2608  frameheader.packetlength = compressedsize + gaplesssize;
2609 
2610  if (frameheader.packetlength > 0)
2611  {
2612  WriteFrameheader(&frameheader);
2613  m_ringBuffer->Write(m_mp3Buf, compressedsize);
2614  m_ringBuffer->Write(mp3gapless.data(), gaplesssize);
2615  }
2617  }
2618  else
2619  {
2620  frameheader.comptype = '0'; // uncompressed audio
2621  frameheader.packetlength = m_audioBufferSize;
2622 
2623  WriteFrameheader(&frameheader);
2625  m_audioBytes += m_audioBufferSize; // only audio no header!!
2626  }
2627 
2628  // this will probably never happen and if there would be a
2629  // 'uncountable' video frame drop -> material==worthless
2630  if (m_audioBehind > 0)
2631  {
2632  LOG(VB_RECORD, LOG_INFO, LOC + "audio behind");
2633  frameheader.frametype = 'A'; // audio frame
2634  frameheader.comptype = 'N'; // output a nullframe with
2635  frameheader.packetlength = 0;
2636  WriteFrameheader(&frameheader);
2638  m_audioBehind--;
2639  }
2640 
2641  m_lastBlock = fnum;
2642 }
2643 
2644 void NuppelVideoRecorder::WriteText(unsigned char *buf, int len, std::chrono::milliseconds timecode,
2645  int pagenr)
2646 {
2647  struct rtframeheader frameheader {};
2648 
2649  frameheader.frametype = 'T'; // text frame
2650  frameheader.timecode = timecode.count();
2651 
2652  if (VBIMode::PAL_TT == m_vbiMode)
2653  {
2654  frameheader.comptype = 'T'; // european teletext
2655  frameheader.packetlength = len + 4;
2656  WriteFrameheader(&frameheader);
2657  union page_t {
2658  int32_t m_val32;
2659  struct { int8_t m_a,m_b,m_c,m_d; } m_val8;
2660  } v {};
2661  v.m_val32 = pagenr;
2662  m_ringBuffer->Write(&v.m_val8.m_d, sizeof(int8_t));
2663  m_ringBuffer->Write(&v.m_val8.m_c, sizeof(int8_t));
2664  m_ringBuffer->Write(&v.m_val8.m_b, sizeof(int8_t));
2665  m_ringBuffer->Write(&v.m_val8.m_a, sizeof(int8_t));
2666  m_ringBuffer->Write(buf, len);
2667  }
2668  else if (VBIMode::NTSC_CC == m_vbiMode)
2669  {
2670  frameheader.comptype = 'C'; // NTSC CC
2671  frameheader.packetlength = len;
2672 
2673  WriteFrameheader(&frameheader);
2674  m_ringBuffer->Write(buf, len);
2675  }
2676 }
2677 
2678 /* vim: set expandtab tabstop=4 shiftwidth=4: */
rtframeheader
Definition: format.h:34
NuppelVideoRecorder::m_channelFd
int m_channelFd
Definition: NuppelVideoRecorder.h:278
NuppelVideoRecorder::m_heightMultiplier
double m_heightMultiplier
Definition: NuppelVideoRecorder.h:236
NuppelVideoRecorder::m_q
int m_q
Definition: NuppelVideoRecorder.h:162
extendeddata::version
int version
Definition: format.h:98
NuppelVideoRecorder::m_actAudioBuffer
int m_actAudioBuffer
Definition: NuppelVideoRecorder.h:201
mpeg
Definition: mythchrono.h:51
RecorderBase::SetPositionMapType
void SetPositionMapType(MarkTypes type)
Set seektable type.
Definition: recorderbase.h:279
FOURCC_I263
#define FOURCC_I263
Definition: fourcc.h:96
MARK_KEYFRAME
@ MARK_KEYFRAME
Definition: programtypes.h:63
rtfileheader::fps
double fps
Definition: format.h:27
NuppelVideoRecorder::FormatCC
void FormatCC(uint code1, uint code2) override
Definition: NuppelVideoRecorder.cpp:2077
MThread::start
void start(QThread::Priority p=QThread::InheritPriority)
Tell MThread to start running the thread in the near future.
Definition: mthread.cpp:283
ENO
#define ENO
This can be appended to the LOG args with "+".
Definition: mythlogging.h:73
NuppelVideoRecorder::m_keyframeDist
int m_keyframeDist
Definition: NuppelVideoRecorder.h:222
FILEHEADERSIZE
#define FILEHEADERSIZE
Definition: format.h:140
vbi.h
NuppelVideoRecorder::m_audioChannels
int m_audioChannels
Definition: NuppelVideoRecorder.h:170
teletextsubtitle::row
unsigned char row
Definition: format.h:175
NuppelVideoRecorder::m_audioBits
int m_audioBits
Definition: NuppelVideoRecorder.h:171
vidbuffertype::buffer
unsigned char * buffer
Definition: format.h:149
NuppelVideoRecorder::m_actVideoBuffer
int m_actVideoBuffer
Definition: NuppelVideoRecorder.h:198
NuppelVideoRecorder::m_audioBytes
unsigned long long m_audioBytes
Definition: NuppelVideoRecorder.h:169
NuppelVideoRecorder::StartNewFile
void StartNewFile(void) override
Definition: NuppelVideoRecorder.cpp:2255
NuppelVideoRecorder::StreamAllocate
void StreamAllocate(void)
Definition: NuppelVideoRecorder.cpp:783
V4LRecorder::m_vbiThread
VBIThread * m_vbiThread
Definition: v4lrecorder.h:56
error
static void error(const char *str,...)
Definition: vbi.cpp:36
rtfileheader::height
int height
Definition: format.h:21
FrameRate::toDouble
double toDouble(void) const
Definition: recorderbase.h:41
NuppelVideoRecorder::m_encodingThreadCount
int m_encodingThreadCount
Number of threads to use for MPEG-2 and MPEG-4 encoding.
Definition: NuppelVideoRecorder.h:259
NuppelVideoRecorder::m_clearTimeOnPause
bool m_clearTimeOnPause
Definition: NuppelVideoRecorder.h:275
vidbuffertype::freeToEncode
int freeToEncode
Definition: format.h:147
extendeddata::lavc_maxqdiff
int lavc_maxqdiff
Definition: format.h:117
NuppelVideoRecorder::run
void run(void) override
run() starts the recording process, and does not exit until the recording is complete.
Definition: NuppelVideoRecorder.cpp:850
NuppelVideoRecorder::m_videoBuffer
std::vector< struct vidbuffertype * > m_videoBuffer
Definition: NuppelVideoRecorder.h:193
NuppelVideoRecorder::kOutLen
static constexpr size_t kOutLen
Definition: NuppelVideoRecorder.h:188
AudioInput::GetBlockSize
virtual int GetBlockSize(void)=0
NuppelVideoRecorder::m_hmjpgHDecimation
int m_hmjpgHDecimation
Definition: NuppelVideoRecorder.h:271
CC608Decoder::FormatCC
void FormatCC(std::chrono::milliseconds tc, int code1, int code2)
Definition: cc608decoder.cpp:50
NuppelVideoRecorder::m_actTextEncode
int m_actTextEncode
Definition: NuppelVideoRecorder.h:204
NuppelVideoRecorder::m_videoBufferSize
long m_videoBufferSize
Definition: NuppelVideoRecorder.h:211
NuppelVideoRecorder::m_frameOfGop
int m_frameOfGop
Definition: NuppelVideoRecorder.h:242
V4LRecorder
Abstract base class for Video4Linux based recorders.
Definition: v4lrecorder.h:25
NuppelVideoRecorder::Open
bool Open(void)
Definition: NuppelVideoRecorder.cpp:789
MThread::wait
bool wait(std::chrono::milliseconds time=std::chrono::milliseconds::max())
Wait for the MThread to exit, with a maximum timeout.
Definition: mthread.cpp:300
GO7007IOC_S_COMP_PARAMS
#define GO7007IOC_S_COMP_PARAMS
Definition: go7007_myth.h:91
GO7007_ASPECT_RATIO_4_3_NTSC
@ GO7007_ASPECT_RATIO_4_3_NTSC
Definition: go7007_myth.h:29
NuppelVideoRecorder::AddTextData
void AddTextData(unsigned char *buf, int len, std::chrono::milliseconds timecode, char type) override
Definition: NuppelVideoRecorder.cpp:2088
NuppelVideoRecorder::SetVideoFilters
void SetVideoFilters(QString &filters) override
Tells recorder which filters to use.
Definition: NuppelVideoRecorder.cpp:373
NuppelVideoRecorder::m_wrkmem
std::array< uint8_t, LZO1X_1_MEM_COMPRESS > __LZO_MMODEL m_wrkmem
Definition: NuppelVideoRecorder.h:191
NuppelVideoRecorder::m_usingV4l2
bool m_usingV4l2
Definition: NuppelVideoRecorder.h:277
NuppelVideoRecorder::WriteAudio
void WriteAudio(unsigned char *buf, int fnum, std::chrono::milliseconds timecode)
Definition: NuppelVideoRecorder.cpp:2512
V4LRecorder::m_requestHelper
volatile bool m_requestHelper
Definition: v4lrecorder.h:59
NuppelVideoRecorder.h
NuppelVideoRecorder::m_extendedDataOffset
long long m_extendedDataOffset
Definition: NuppelVideoRecorder.h:226
NuppelVideoRecorder::m_textBuffer
std::vector< struct txtbuffertype * > m_textBuffer
Definition: NuppelVideoRecorder.h:195
MythMediaBuffer::GetWritePosition
long long GetWritePosition(void) const
Returns how far into a ThreadedFileWriter file we have written.
Definition: mythmediabuffer.cpp:1787
NuppelVideoRecorder::m_hmjpgQuality
int m_hmjpgQuality
Definition: NuppelVideoRecorder.h:270
vt_page::subno
int subno
Definition: vt.h:38
GO7007_COMP_CLOSED_GOP
#define GO7007_COMP_CLOSED_GOP
Definition: go7007_myth.h:45
NuppelVideoRecorder::m_framesWritten
long long m_framesWritten
Definition: NuppelVideoRecorder.h:228
NuppelVideoRecorder::m_seekTable
std::vector< struct seektable_entry > * m_seekTable
Definition: NuppelVideoRecorder.h:223
CC608Decoder
Definition: cc608decoder.h:53
V4LRecorder::OpenVBIDevice
int OpenVBIDevice(void)
Definition: v4lrecorder.cpp:94
MythAVFrame
MythAVFrame little utility class that act as a safe way to allocate an AVFrame which can then be allo...
Definition: mythaverror.h:52
go7007_myth.h
go7007_comp_params::max_b_frames
__u32 max_b_frames
Definition: go7007_myth.h:39
NuppelVideoRecorder::m_lastTimecode
int m_lastTimecode
Definition: NuppelVideoRecorder.h:243
rtfileheader::width
int width
Definition: format.h:20
NuppelVideoRecorder::WriteText
void WriteText(unsigned char *buf, int len, std::chrono::milliseconds timecode, int pagenr)
Definition: NuppelVideoRecorder.cpp:2644
VBIData::teletextpage
vt_page teletextpage
Definition: v4lrecorder.h:20
NuppelVideoRecorder::AudioInit
int AudioInit(bool skipdevice=false)
Definition: NuppelVideoRecorder.cpp:630
extendeddata::audio_channels
int audio_channels
Definition: format.h:104
NuppelVideoRecorder::MJPEGInit
bool MJPEGInit(void)
Determines MJPEG capture resolution.
Definition: NuppelVideoRecorder.cpp:706
RecorderBase::m_tvrec
TVRec * m_tvrec
Definition: recorderbase.h:315
DTVRecorder::IsErrored
bool IsErrored(void) override
Tells us whether an unrecoverable error has been encountered.
Definition: dtvrecorder.h:45
FOURCC_HFYU
#define FOURCC_HFYU
Definition: fourcc.h:95
MythMediaBuffer::Write
int Write(const void *Buffer, uint Count)
Writes buffer to ThreadedFileWriter::Write(const void*,uint)
Definition: mythmediabuffer.cpp:1625
NuppelVideoRecorder::m_audioBytesPerSample
int m_audioBytesPerSample
Definition: NuppelVideoRecorder.h:172
rtfileheader::textsblocks
int textsblocks
Definition: format.h:30
rtfileheader::desiredheight
int desiredheight
Definition: format.h:23
NuppelVideoRecorder::SetupRTjpeg
void SetupRTjpeg(void)
Definition: NuppelVideoRecorder.cpp:496
rtframeheader::timecode
int timecode
Definition: format.h:85
NuppelVideoRecorder::m_writePaused
bool m_writePaused
Definition: NuppelVideoRecorder.h:231
RTjpeg::SetNextKey
void SetNextKey(void)
Definition: RTjpegN.cpp:3261
AudioInput::GetSamples
virtual int GetSamples(void *buf, uint nbytes)=0
seektable_entry
Definition: format.h:127
FMT_YUV422P
@ FMT_YUV422P
Definition: mythframe.h:37
RecorderBase::m_videoWidth
uint m_videoWidth
Definition: recorderbase.h:332
txtbuffertype::freeToEncode
int freeToEncode
Definition: format.h:167
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
MThread::RunProlog
void RunProlog(void)
Sets up a thread, call this if you reimplement run().
Definition: mthread.cpp:196
VBIMode::None
@ None
Definition: tv.h:11
channelbase.h
NuppelVideoRecorder::ResizeVideoBuffers
void ResizeVideoBuffers(void)
Definition: NuppelVideoRecorder.cpp:774
NuppelVideoRecorder::m_mp4Opts
int m_mp4Opts
Definition: NuppelVideoRecorder.h:256
NuppelVideoRecorder::m_scaleBitRate
int m_scaleBitRate
Definition: NuppelVideoRecorder.h:252
NuppelVideoRecorder::m_v4l2PixelFormat
uint32_t m_v4l2PixelFormat
Definition: NuppelVideoRecorder.h:264
NuppelVideoRecorder::m_audioThread
NVRAudioThread * m_audioThread
Definition: NuppelVideoRecorder.h:218
mythsystemevent.h
NuppelVideoRecorder::SetNewVideoParams
void SetNewVideoParams(double newaspect)
Definition: NuppelVideoRecorder.cpp:1477
V4LRecorder::VBIThread
friend class VBIThread
Definition: v4lrecorder.h:27
go7007_comp_params::gop_size
__u32 gop_size
Definition: go7007_myth.h:38
GO7007_MPEG_VIDEO_MPEG2
@ GO7007_MPEG_VIDEO_MPEG2
Definition: go7007_myth.h:51
NuppelVideoRecorder::m_videoBufferCount
int m_videoBufferCount
Definition: NuppelVideoRecorder.h:207
MythVideoFrame::m_offsets
FrameOffsets m_offsets
Definition: mythframe.h:143
MythVideoFrame::m_forceKey
bool m_forceKey
Definition: mythframe.h:139
NVRWriteThread::run
void run(void) override
Runs the Qt event loop unless we have a QRunnable, in which case we run the runnable run instead.
Definition: NuppelVideoRecorder.cpp:83
kfatable_entry
Definition: format.h:133
DTVRecorder::FinishRecording
void FinishRecording(void) override
Flushes the ringbuffer, and if this is not a live LiveTV recording saves the position map and filesiz...
Definition: dtvrecorder.cpp:126
NuppelVideoRecorder::m_mpaVidCodec
const AVCodec * m_mpaVidCodec
Definition: NuppelVideoRecorder.h:248
NuppelVideoRecorder::m_actAudioEncode
int m_actAudioEncode
Definition: NuppelVideoRecorder.h:200
NuppelVideoRecorder::m_targetBitRate
int m_targetBitRate
Definition: NuppelVideoRecorder.h:251
NuppelVideoRecorder::m_mp3Quality
int m_mp3Quality
Definition: NuppelVideoRecorder.h:181
NuppelVideoRecorder::m_mbDecision
int m_mbDecision
Definition: NuppelVideoRecorder.h:257
extendeddata::audio_fourcc
int audio_fourcc
Definition: format.h:100
rtfileheader::desiredwidth
int desiredwidth
Definition: format.h:22
NuppelVideoRecorder::m_oldTc
std::chrono::milliseconds m_oldTc
Definition: NuppelVideoRecorder.h:240
NuppelVideoRecorder::m_textBufferCount
int m_textBufferCount
Definition: NuppelVideoRecorder.h:209
NuppelVideoRecorder::m_compression
int m_compression
Definition: NuppelVideoRecorder.h:166
VBIMode::PAL_TT
@ PAL_TT
Definition: tv.h:12
extendeddata::rtjpeg_chroma_filter
int rtjpeg_chroma_filter
Definition: format.h:112
KEYFRAMEDIST
static constexpr int8_t KEYFRAMEDIST
Definition: NuppelVideoRecorder.h:39
FOURCC_MJPG
#define FOURCC_MJPG
Definition: fourcc.h:97
audbuffertype
Definition: format.h:154
RecorderBase::m_pauseLock
QMutex m_pauseLock
Definition: recorderbase.h:338
close
#define close
Definition: compat.h:43
V4LRecorder::SetOption
void SetOption(const QString &name, const QString &value) override
Set an specific option.
Definition: v4lrecorder.cpp:56
tmp
static guint32 * tmp
Definition: goom_core.cpp:26
VT_WIDTH
#define VT_WIDTH
Definition: vt.h:4
NuppelVideoRecorder::m_audioBufferCount
int m_audioBufferCount
Definition: NuppelVideoRecorder.h:208
rtfileheader
Definition: format.h:16
AudioInput::IsOpen
virtual bool IsOpen(void)=0
FrameRate::isNonzero
bool isNonzero(void) const
Definition: recorderbase.h:42
RecorderBase::m_requestPause
bool m_requestPause
Definition: recorderbase.h:339
GO7007_ASPECT_RATIO_4_3_PAL
@ GO7007_ASPECT_RATIO_4_3_PAL
Definition: go7007_myth.h:30
FMT_NONE
@ FMT_NONE
Definition: mythframe.h:22
NuppelVideoRecorder::m_audioBuffer
std::vector< struct audbuffertype * > m_audioBuffer
Definition: NuppelVideoRecorder.h:194
NuppelVideoRecorder::m_pipMode
int m_pipMode
Definition: NuppelVideoRecorder.h:165
AudioInput::Start
virtual bool Start(void)=0
RecorderBase::m_recordingWait
QWaitCondition m_recordingWait
Definition: recorderbase.h:347
RecorderBase::m_curRecording
RecordingInfo * m_curRecording
Definition: recorderbase.h:335
AudioInput::Open
virtual bool Open(uint sample_bits, uint sample_rate, uint channels)=0
FRAMEHEADERSIZE
#define FRAMEHEADERSIZE
Definition: format.h:139
NuppelVideoRecorder::m_lastBlock
int m_lastBlock
Definition: NuppelVideoRecorder.h:238
TVRec::RecorderPaused
void RecorderPaused(void)
This is a callback, called by the "recorder" instance when it has actually paused.
Definition: tv_rec.cpp:2895
AVFrame
struct AVFrame AVFrame
Definition: BorderDetector.h:15
rtframeheader::keyframe
char keyframe
Definition: format.h:72
NuppelVideoRecorder::m_startNum
int m_startNum
Definition: NuppelVideoRecorder.h:241
MythMediaBuffer::GetFilename
QString GetFilename(void) const
Definition: mythmediabuffer.cpp:1740
VT_HEIGHT
#define VT_HEIGHT
Definition: vt.h:5
txtbuffertype::buffer
unsigned char * buffer
Definition: format.h:169
NuppelVideoRecorder::m_hmjpgMaxW
int m_hmjpgMaxW
Definition: NuppelVideoRecorder.h:273
go7007_comp_params
Definition: go7007_myth.h:36
programinfo.h
MythVideoFrame::GetBufferSize
static size_t GetBufferSize(VideoFrameType Type, int Width, int Height, int Aligned=MYTH_WIDTH_ALIGNMENT)
Definition: mythframe.cpp:412
NuppelVideoRecorder::m_recording
bool m_recording
Definition: NuppelVideoRecorder.h:220
V4LRecorder::CloseVBIDevice
void CloseVBIDevice(void)
Definition: v4lrecorder.cpp:202
mythlogging.h
NuppelVideoRecorder::m_lf
unsigned int m_lf
Definition: NuppelVideoRecorder.h:158
NuppelVideoRecorder::m_maxQuality
int m_maxQuality
Definition: NuppelVideoRecorder.h:253
NVRAudioThread::m_parent
NuppelVideoRecorder * m_parent
Definition: NuppelVideoRecorder.h:67
ChannelBase
Abstract class providing a generic interface to tuning hardware.
Definition: channelbase.h:31
NuppelVideoRecorder::m_actTextBuffer
int m_actTextBuffer
Definition: NuppelVideoRecorder.h:205
hardwareprofile.scan.profile
profile
Definition: scan.py:99
VBIMode::NTSC_CC
@ NTSC_CC
Definition: tv.h:13
NuppelVideoRecorder::m_minQuality
int m_minQuality
Definition: NuppelVideoRecorder.h:254
txtbuffertype
Definition: format.h:163
RecorderBase::AspectChange
void AspectChange(uint aspect, long long frame)
Note a change in aspect ratio in the recordedmark table.
Definition: recorderbase.cpp:740
audbuffertype::timecode
std::chrono::milliseconds timecode
Definition: format.h:157
MythMediaBuffer::WriterSeek
long long WriterSeek(long long Position, int Whence, bool HasLock=false)
Calls ThreadedFileWriter::Seek(long long,int).
Definition: mythmediabuffer.cpp:1672
FOURCC_LAME
#define FOURCC_LAME
Definition: fourcc.h:81
NuppelVideoRecorder::m_gf
lame_global_flags * m_gf
Definition: NuppelVideoRecorder.h:184
MythFile::copy
MBASE_PUBLIC long long copy(QFile &dst, QFile &src, uint block_size=0)
Copies src file to dst file.
Definition: mythmiscutil.cpp:263
FMT_YV12
@ FMT_YV12
Definition: mythframe.h:24
RTJ_YUV420
@ RTJ_YUV420
Definition: RTjpegN.h:48
AudioInput::GetNumReadyBytes
virtual int GetNumReadyBytes(void)=0
NuppelVideoRecorder::m_mpaVidCtx
AVCodecContext * m_mpaVidCtx
Definition: NuppelVideoRecorder.h:249
MythVideoFrame::m_timecode
std::chrono::milliseconds m_timecode
Definition: mythframe.h:131
GO7007_MPEG_VIDEO_MPEG4
@ GO7007_MPEG_VIDEO_MPEG4
Definition: go7007_myth.h:52
NuppelVideoRecorder::m_mainPaused
bool m_mainPaused
Definition: NuppelVideoRecorder.h:233
NuppelVideoRecorder::m_go7007
bool m_go7007
Definition: NuppelVideoRecorder.h:292
rtfileheader::videoblocks
int videoblocks
Definition: format.h:28
extendeddata::audio_compression_ratio
int audio_compression_ratio
Definition: format.h:107
teletextsubtitle
Definition: format.h:173
V4LRecorder::StopRecording
void StopRecording(void) override
StopRecording() signals to the recorder that it should stop recording and exit cleanly.
Definition: v4lrecorder.cpp:43
rtframeheader::comptype
char comptype
Definition: format.h:43
NuppelVideoRecorder::WriteVideo
void WriteVideo(MythVideoFrame *frame, bool skipsync=false, bool forcekey=false)
Definition: NuppelVideoRecorder.cpp:2274
RecorderBase::m_videoHeight
uint m_videoHeight
Definition: recorderbase.h:331
NuppelVideoRecorder::m_audioPaused
bool m_audioPaused
Definition: NuppelVideoRecorder.h:232
NuppelVideoRecorder::m_mp3Buf
char * m_mp3Buf
Definition: NuppelVideoRecorder.h:182
NVRWriteThread::m_parent
NuppelVideoRecorder * m_parent
Definition: NuppelVideoRecorder.h:56
NuppelVideoRecorder::IsPaused
bool IsPaused(bool holding_lock=false) const override
Returns true iff recorder is paused.
Definition: NuppelVideoRecorder.cpp:363
RecorderBase::ResolutionChange
void ResolutionChange(uint width, uint height, long long frame)
Note a change in video size in the recordedmark table.
Definition: recorderbase.cpp:791
rtfileheader::pimode
char pimode
Definition: format.h:24
vidbuffertype::timecode
std::chrono::milliseconds timecode
Definition: format.h:146
MythVideoFrame::m_frameNumber
long long m_frameNumber
Definition: mythframe.h:129
FrameRate
Definition: recorderbase.h:37
NuppelVideoRecorder::Pause
void Pause(bool clear=true) override
Pause tells recorder to pause, it should not block.
Definition: NuppelVideoRecorder.cpp:351
GO7007_ASPECT_RATIO_16_9_PAL
@ GO7007_ASPECT_RATIO_16_9_PAL
Definition: go7007_myth.h:32
NuppelVideoRecorder::GetVideoFd
int GetVideoFd(void) override
Returns file descriptor of recorder device.
Definition: NuppelVideoRecorder.cpp:387
NuppelVideoRecorder::WriteFrameheader
void WriteFrameheader(rtframeheader *fh)
Definition: NuppelVideoRecorder.cpp:1468
RecorderBase::IsRecordingRequested
virtual bool IsRecordingRequested(void)
Tells us if StopRecording() has been called.
Definition: recorderbase.cpp:250
MythVideoFrame::m_bufferSize
size_t m_bufferSize
Definition: mythframe.h:124
clear
static void clear(SettingsMap &cache, SettingsMap &overrides, const QString &myKey)
Definition: mythdb.cpp:897
MThread::RunEpilog
void RunEpilog(void)
Cleans up a thread's resources, call this if you reimplement run().
Definition: mthread.cpp:209
RecorderBase::m_ntscFrameRate
bool m_ntscFrameRate
Definition: recorderbase.h:326
FOURCC_WMV1
#define FOURCC_WMV1
Definition: fourcc.h:103
RecorderBase::m_videoFrameRate
double m_videoFrameRate
Definition: recorderbase.h:327
go7007_comp_params::flags
__u32 flags
Definition: go7007_myth.h:41
NuppelVideoRecorder::m_ccd
CC608Decoder * m_ccd
Definition: NuppelVideoRecorder.h:290
NuppelVideoRecorder::GetFramesWritten
long long GetFramesWritten(void) override
Returns number of frames written to disk.
Definition: NuppelVideoRecorder.cpp:382
NuppelVideoRecorder::m_compressAudio
bool m_compressAudio
Definition: NuppelVideoRecorder.h:167
NuppelVideoRecorder::m_pictureFormat
AVPixelFormat m_pictureFormat
Definition: NuppelVideoRecorder.h:262
NuppelVideoRecorder::m_fd
int m_fd
Definition: NuppelVideoRecorder.h:156
AudioInput::Close
virtual void Close(void)=0
NVRAudioThread::run
void run(void) override
Runs the Qt event loop unless we have a QRunnable, in which case we run the runnable run instead.
Definition: NuppelVideoRecorder.cpp:90
NuppelVideoRecorder::ResetForNewFile
void ResetForNewFile(void) override
Definition: NuppelVideoRecorder.cpp:2236
NuppelVideoRecorder::m_m2
int m_m2
Definition: NuppelVideoRecorder.h:161
rtfileheader::finfo
char finfo[12]
Definition: format.h:18
MythMediaBuffer::LiveMode
bool LiveMode(void) const
Returns true if this RingBuffer has been assigned a LiveTVChain.
Definition: mythmediabuffer.cpp:1799
DTVRecorder::ClearStatistics
void ClearStatistics(void) override
Definition: dtvrecorder.cpp:184
NuppelVideoRecorder::NVRWriteThread
friend class NVRWriteThread
Definition: NuppelVideoRecorder.h:72
NuppelVideoRecorder::m_audioBehind
int m_audioBehind
Definition: NuppelVideoRecorder.h:244
uint
unsigned int uint
Definition: compat.h:81
RecorderBase::m_videocodec
QString m_videocodec
Definition: recorderbase.h:322
RecorderBase::m_positionMap
frm_pos_map_t m_positionMap
Definition: recorderbase.h:359
V4LRecorder::IsHelperRequested
virtual bool IsHelperRequested(void) const
Definition: v4lrecorder.cpp:50
gCoreContext
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
Definition: mythcorecontext.cpp:55
RecorderBase::m_containerFormat
AVContainer m_containerFormat
Definition: recorderbase.h:319
NuppelVideoRecorder::m_mp3BufSize
int m_mp3BufSize
Definition: NuppelVideoRecorder.h:183
RecorderBase::m_weMadeBuffer
bool m_weMadeBuffer
Definition: recorderbase.h:317
extendeddata::video_fourcc
int video_fourcc
Definition: format.h:99
RecorderBase::FrameRateChange
void FrameRateChange(uint framerate, uint64_t frame)
Note a change in video frame rate in the recordedmark table.
Definition: recorderbase.cpp:807
rtfileheader::audioblocks
int audioblocks
Definition: format.h:29
FOURCC_RAWA
#define FOURCC_RAWA
Definition: fourcc.h:82
mythmediabuffer.h
RecorderBase::m_positionMapDelta
frm_pos_map_t m_positionMapDelta
Definition: recorderbase.h:360
RecorderBase::m_videodevice
QString m_videodevice
Definition: recorderbase.h:323
FOURCC_MPG4
#define FOURCC_MPG4
Definition: fourcc.h:101
extendeddata::audio_bits_per_sample
int audio_bits_per_sample
Definition: format.h:103
NuppelVideoRecorder::m_useAvCodec
bool m_useAvCodec
Definition: NuppelVideoRecorder.h:246
extendeddata::lavc_bitrate
int lavc_bitrate
Definition: format.h:114
NuppelVideoRecorder::m_tf
int m_tf
Definition: NuppelVideoRecorder.h:159
NuppelVideoRecorder::m_hmjpgVDecimation
int m_hmjpgVDecimation
Definition: NuppelVideoRecorder.h:272
buffers
Definition: freesurround.cpp:50
NuppelVideoRecorder::DoV4L2
void DoV4L2(void)
Definition: NuppelVideoRecorder.cpp:1036
NuppelVideoRecorder::m_actVideoEncode
int m_actVideoEncode
Definition: NuppelVideoRecorder.h:197
NuppelVideoRecorder::SetFormatV4L2
bool SetFormatV4L2(void)
Definition: NuppelVideoRecorder.cpp:946
vidbuffertype::freeToBuffer
int freeToBuffer
Definition: format.h:148
GO7007_ASPECT_RATIO_1_1
@ GO7007_ASPECT_RATIO_1_1
Definition: go7007_myth.h:28
RTjpeg
Definition: RTjpegN.h:53
extendeddata::lavc_qmin
int lavc_qmin
Definition: format.h:115
RecorderBase::m_pauseWait
QWaitCondition m_pauseWait
Definition: recorderbase.h:341
MythMediaBuffer::WriterFlush
void WriterFlush(void)
Calls ThreadedFileWriter::Flush(void)
Definition: mythmediabuffer.cpp:1698
RecorderBase::m_ringBuffer
MythMediaBuffer * m_ringBuffer
Definition: recorderbase.h:316
NuppelVideoRecorder::InitBuffers
void InitBuffers(void)
Definition: NuppelVideoRecorder.cpp:712
NuppelVideoRecorder::m_rtjc
RTjpeg * m_rtjc
Definition: NuppelVideoRecorder.h:186
go7007_comp_params::aspect_ratio
enum go7007_aspect_ratio aspect_ratio
Definition: go7007_myth.h:40
GO7007_ASPECT_RATIO_16_9_NTSC
@ GO7007_ASPECT_RATIO_16_9_NTSC
Definition: go7007_myth.h:31
RecorderBase::m_ntsc
bool m_ntsc
Definition: recorderbase.h:325
vidbuffertype::sample
int sample
Definition: format.h:145
GO7007IOC_S_MPEG_PARAMS
#define GO7007IOC_S_MPEG_PARAMS
Definition: go7007_myth.h:87
V4LRecorder::m_vbiMode
int m_vbiMode
Definition: v4lrecorder.h:49
mythmiscutil.h
NuppelVideoRecorder::m_hardwareEncode
bool m_hardwareEncode
Definition: NuppelVideoRecorder.h:269
RTjpeg::SetIntra
int SetIntra(int *key, int *lm, int *cm)
Definition: RTjpegN.cpp:2726
FOURCC_MPG2
#define FOURCC_MPG2
Definition: fourcc.h:100
NuppelVideoRecorder::WriteSeekTable
void WriteSeekTable(void)
Definition: NuppelVideoRecorder.cpp:1646
NuppelVideoRecorder::WriteFileHeader
void WriteFileHeader(void)
Definition: NuppelVideoRecorder.cpp:1495
extendeddata::keyframeadjust_offset
long long keyframeadjust_offset
Definition: format.h:121
NuppelVideoRecorder::WriteKeyFrameAdjustTable
void WriteKeyFrameAdjustTable(const std::vector< struct kfatable_entry > &kfa_table)
Definition: NuppelVideoRecorder.cpp:1681
rtframeheader::filters
char filters
Definition: format.h:75
NuppelVideoRecorder::m_wOut
int m_wOut
Definition: NuppelVideoRecorder.h:266
NuppelVideoRecorder::IsRecording
bool IsRecording(void) override
Tells whether the StartRecorder() loop is running.
Definition: NuppelVideoRecorder.cpp:377
DTVRecorder::m_error
QString m_error
non-empty iff irrecoverable recording error detected
Definition: dtvrecorder.h:160
VBIData
Definition: v4lrecorder.h:17
RTjpeg::SetFormat
int SetFormat(const int *fmt)
Definition: RTjpegN.cpp:2692
ProgramInfo::ClearPositionMap
void ClearPositionMap(MarkTypes type) const
Definition: programinfo.cpp:3809
vidbuffertype::forcekey
bool forcekey
Definition: format.h:151
NuppelVideoRecorder::CreateNuppelFile
int CreateNuppelFile(void)
Definition: NuppelVideoRecorder.cpp:1734
cc.h
NuppelVideoRecorder::Initialize
void Initialize(void) override
This is called between SetOptionsFromProfile() and run() to initialize any devices,...
Definition: NuppelVideoRecorder.cpp:573
formatNUV
@ formatNUV
Definition: recordingfile.h:15
NuppelVideoRecorder::m_lastPositionMapPos
long long m_lastPositionMapPos
Definition: NuppelVideoRecorder.h:224
RecorderBase::m_positionMapLock
QMutex m_positionMapLock
Definition: recorderbase.h:358
audbuffertype::sample
int sample
Definition: format.h:156
NuppelVideoRecorder::doAudioThread
void doAudioThread(void)
Definition: NuppelVideoRecorder.cpp:1804
NuppelVideoRecorder::m_stm
Definition: NuppelVideoRecorder.h:215
audbuffertype::freeToBuffer
int freeToBuffer
Definition: format.h:159
NuppelVideoRecorder::m_actAudioSample
long long m_actAudioSample
Definition: NuppelVideoRecorder.h:202
NuppelVideoRecorder::m_audioBufferSize
long m_audioBufferSize
Definition: NuppelVideoRecorder.h:212
NuppelVideoRecorder::m_audioDevice
AudioInput * m_audioDevice
Definition: NuppelVideoRecorder.h:168
extendeddata::audio_sample_rate
int audio_sample_rate
Definition: format.h:102
RTjpeg::SetSize
int SetSize(const int *w, const int *h)
Definition: RTjpegN.cpp:2698
RecorderBase::AspectRatio
AspectRatio
Definition: recorderbase.h:244
mythavutil.h
TVRec
This is the coordinating class of the Recorder Subsystem.
Definition: tv_rec.h:144
NuppelVideoRecorder::m_firstTc
std::chrono::milliseconds m_firstTc
Definition: NuppelVideoRecorder.h:239
NuppelVideoRecorder::m_inPixFmt
VideoFrameType m_inPixFmt
Definition: NuppelVideoRecorder.h:261
rtframeheader::packetlength
int packetlength
Definition: format.h:87
NuppelVideoRecorder::BufferIt
void BufferIt(unsigned char *buf, int len=-1, bool forcekey=false)
Definition: NuppelVideoRecorder.cpp:1404
rtfileheader::aspect
double aspect
Definition: format.h:26
extendeddata
Definition: format.h:96
mythcontext.h
FOURCC_MP42
#define FOURCC_MP42
Definition: fourcc.h:98
extendeddata::rtjpeg_quality
int rtjpeg_quality
Definition: format.h:110
NuppelVideoRecorder::m_useBttv
int m_useBttv
Definition: NuppelVideoRecorder.h:176
extendeddata::audio_quality
int audio_quality
Definition: format.h:108
tv_rec.h
FOURCC_MPEG
#define FOURCC_MPEG
Definition: fourcc.h:99
NuppelVideoRecorder::m_effectiveDsp
int m_effectiveDsp
Definition: NuppelVideoRecorder.h:174
NuppelVideoRecorder::m_transcoding
bool m_transcoding
Definition: NuppelVideoRecorder.h:179
NuppelVideoRecorder::ProbeV4L2
void ProbeV4L2(void)
Definition: NuppelVideoRecorder.cpp:814
build_compdb.action
action
Definition: build_compdb.py:9
MythMediaBuffer::Create
static MythMediaBuffer * Create(const QString &Filename, bool Write, bool UseReadAhead=true, std::chrono::milliseconds Timeout=kDefaultOpenTimeout, bool StreamOnly=false)
Creates a RingBuffer instance.
Definition: mythmediabuffer.cpp:98
NuppelVideoRecorder::SetupAVCodecVideo
bool SetupAVCodecVideo(void)
Definition: NuppelVideoRecorder.cpp:392
NuppelVideoRecorder::m_correctBttv
bool m_correctBttv
Definition: NuppelVideoRecorder.h:285
NuppelVideoRecorder::m_writeThread
NVRWriteThread * m_writeThread
Definition: NuppelVideoRecorder.h:217
NuppelVideoRecorder::WriteHeader
void WriteHeader(void)
Definition: NuppelVideoRecorder.cpp:1531
NuppelVideoRecorder::UpdateResolutions
void UpdateResolutions(void)
Definition: NuppelVideoRecorder.cpp:511
NuppelVideoRecorder::KillChildren
void KillChildren(void)
Definition: NuppelVideoRecorder.cpp:1373
extendeddata::rtjpeg_luma_filter
int rtjpeg_luma_filter
Definition: format.h:111
rtfileheader::version
char version[5]
Definition: format.h:19
NuppelVideoRecorder::m_resetCapture
bool m_resetCapture
Definition: NuppelVideoRecorder.h:293
FOURCC_DIVX
#define FOURCC_DIVX
Definition: fourcc.h:91
FOURCC_H263
#define FOURCC_H263
Definition: fourcc.h:93
NuppelVideoRecorder::m_textBufferSize
long m_textBufferSize
Definition: NuppelVideoRecorder.h:213
StandardSetting
Definition: standardsettings.h:29
ChannelBase::Retune
virtual bool Retune(void)
Definition: channelbase.h:87
SendMythSystemRecEvent
void SendMythSystemRecEvent(const QString &msg, const RecordingInfo *pginfo)
Definition: mythsystemevent.cpp:333
recordingprofile.h
LOC
#define LOC
Definition: NuppelVideoRecorder.cpp:81
VideoFrameType
VideoFrameType
Definition: mythframe.h:20
uint16_t
unsigned short uint16_t
Definition: iso6937tables.h:3
NuppelVideoRecorder::doWriteThread
void doWriteThread(void)
Definition: NuppelVideoRecorder.cpp:2110
NuppelVideoRecorder::m_height
int m_height
Definition: NuppelVideoRecorder.h:164
NuppelVideoRecorder::FinishRecording
void FinishRecording(void) override
Flushes the ringbuffer, and if this is not a live LiveTV recording saves the position map and filesiz...
Definition: NuppelVideoRecorder.cpp:2260
NuppelVideoRecorder::m_volume
int m_volume
Definition: NuppelVideoRecorder.h:288
RTjpegN.h
audbuffertype::buffer
unsigned char * buffer
Definition: format.h:160
NuppelVideoRecorder::m_strm
signed char * m_strm
Definition: NuppelVideoRecorder.h:157
audioinput.h
myth_nice
bool myth_nice(int val)
Definition: mythmiscutil.cpp:656
NuppelVideoRecorder::m_frameRateMultiplier
double m_frameRateMultiplier
Definition: NuppelVideoRecorder.h:235
RecordingProfile
Definition: recordingprofile.h:41
RecorderBase::m_frameRate
FrameRate m_frameRate
Definition: recorderbase.h:333
MythVideoFrame
Definition: mythframe.h:88
seektable_entry::keyframe_number
int keyframe_number
Definition: format.h:130
go7007_mpeg_params
Definition: go7007_myth.h:56
extendeddata::lavc_qmax
int lavc_qmax
Definition: format.h:116
RTjpeg::SetQuality
int SetQuality(int *quality)
Definition: RTjpegN.cpp:2675
V4LRecorder::m_audioDeviceName
QString m_audioDeviceName
Definition: v4lrecorder.h:47
NuppelVideoRecorder::m_videoAspect
float m_videoAspect
Definition: NuppelVideoRecorder.h:177
RecorderBase::m_unpauseWait
QWaitCondition m_unpauseWait
Definition: recorderbase.h:342
NuppelVideoRecorder::SetOption
void SetOption(const QString &opt, int value) override
handles the "wait_for_seqstart" option.
Definition: NuppelVideoRecorder.cpp:162
RecorderBase::CheckForRingBufferSwitch
virtual bool CheckForRingBufferSwitch(void)
If requested, switch to new RingBuffer/ProgramInfo objects.
Definition: recorderbase.cpp:351
NuppelVideoRecorder::UpdateSeekTable
void UpdateSeekTable(int frame_num, long offset=0)
Definition: NuppelVideoRecorder.cpp:1718
ccsubtitle
Definition: format.h:183
NuppelVideoRecorder::m_hOut
int m_hOut
Definition: NuppelVideoRecorder.h:267
RTjpeg::Compress
int Compress(int8_t *sp, uint8_t **planes)
Definition: RTjpegN.cpp:3266
NuppelVideoRecorder::FormatTT
void FormatTT(struct VBIData *vbidata) override
Definition: NuppelVideoRecorder.cpp:1913
vt_page::data
unsigned char data[VT_HEIGHT][VT_WIDTH]
Definition: vt.h:43
NuppelVideoRecorder::m_channelObj
ChannelBase * m_channelObj
Definition: NuppelVideoRecorder.h:280
NuppelVideoRecorder::NuppelVideoRecorder
NuppelVideoRecorder(TVRec *rec, ChannelBase *channel)
Definition: NuppelVideoRecorder.cpp:97
GO7007IOC_S_BITRATE
#define GO7007IOC_S_BITRATE
Definition: go7007_myth.h:23
AudioInput::CreateDevice
static AudioInput * CreateDevice(const QByteArray &device)
Definition: audioinput.cpp:30
vidbuffertype
Definition: format.h:143
NuppelVideoRecorder::SetOptionsFromProfile
void SetOptionsFromProfile(RecordingProfile *profile, const QString &videodev, const QString &audiodev, const QString &vbidev) override
Sets basic recorder options.
Definition: NuppelVideoRecorder.cpp:250
NuppelVideoRecorder::m_skipBtAudio
bool m_skipBtAudio
Definition: NuppelVideoRecorder.h:282
NuppelVideoRecorder::~NuppelVideoRecorder
~NuppelVideoRecorder() override
Definition: NuppelVideoRecorder.cpp:109
NuppelVideoRecorder::NVRAudioThread
friend class NVRAudioThread
Definition: NuppelVideoRecorder.h:73
MythAVUtil::FillAVFrame
static int FillAVFrame(AVFrame *Frame, const MythVideoFrame *From, AVPixelFormat Fmt=AV_PIX_FMT_NONE)
Initialise AVFrame with content from MythVideoFrame.
Definition: mythavutil.cpp:198
audbuffertype::freeToEncode
int freeToEncode
Definition: format.h:158
rtframeheader::frametype
char frametype
Definition: format.h:36
vt_page::pgno
int pgno
Definition: vt.h:38
rtfileheader::keyframedist
int keyframedist
Definition: format.h:31
NuppelVideoRecorder::Reset
void Reset(void) override
Reset the recorder to the startup state.
Definition: NuppelVideoRecorder.cpp:1756
MAX_VIDEO_BUFFERS
static constexpr size_t MAX_VIDEO_BUFFERS
Definition: NuppelVideoRecorder.cpp:1035
FOURCC_RJPG
#define FOURCC_RJPG
Definition: fourcc.h:102
NuppelVideoRecorder::m_out
std::array< lzo_byte, kOutLen > m_out
Definition: NuppelVideoRecorder.h:189
av_make_error_stdstring
char * av_make_error_stdstring(std::string &errbuf, int errnum)
Definition: mythaverror.cpp:41
txtbuffertype::freeToBuffer
int freeToBuffer
Definition: format.h:168
FOURCC_DIV3
#define FOURCC_DIV3
Definition: fourcc.h:90
NuppelVideoRecorder::m_audioSampleRate
int m_audioSampleRate
Definition: NuppelVideoRecorder.h:173
extendeddata::seektable_offset
long long seektable_offset
Definition: format.h:119
MythMediaBuffer::IsOpen
virtual bool IsOpen(void) const =0
MythCoreContext::GetSetting
QString GetSetting(const QString &key, const QString &defaultval="")
Definition: mythcorecontext.cpp:897
fourcc.h
NuppelVideoRecorder::m_qualDiff
int m_qualDiff
Definition: NuppelVideoRecorder.h:255
RecorderBase::m_requestRecording
bool m_requestRecording
True if API call has requested a recording be [re]started.
Definition: recorderbase.h:344
NuppelVideoRecorder::m_width
int m_width
Definition: NuppelVideoRecorder.h:163
millisecondsFromFloat
std::enable_if_t< std::is_floating_point_v< T >, std::chrono::milliseconds > millisecondsFromFloat(T value)
Helper function for convert a floating point number to a duration.
Definition: mythchrono.h:91
MythVideoFrame::m_buffer
uint8_t * m_buffer
Definition: mythframe.h:120
tv_play.h
NuppelVideoRecorder::m_livetv
bool m_livetv
Definition: NuppelVideoRecorder.h:230
NuppelVideoRecorder::m_m1
int m_m1
Definition: NuppelVideoRecorder.h:160
RecorderBase::SetIntOption
void SetIntOption(RecordingProfile *profile, const QString &name)
Convenience function used to set integer options from a profile.
Definition: recorderbase.cpp:199