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