MythTV  master
NuppelVideoRecorder.cpp
Go to the documentation of this file.
1 #include <cstdio>
2 #include <cstdlib>
3 #include <fcntl.h>
4 #include <unistd.h>
5 #include <sys/types.h>
6 #include <sys/stat.h>
7 #include "mythconfig.h"
8 #if HAVE_SYS_SOUNDCARD_H
9  #include <sys/soundcard.h>
10 #elif HAVE_SOUNDCARD_H
11  #include <soundcard.h>
12 #endif
13 #include <sys/ioctl.h>
14 #include <sys/mman.h>
15 #include <cerrno>
16 #include <cmath>
17 
18 #include <QStringList>
19 
20 #include <iostream>
21 using namespace std;
22 
23 #include "mythmiscutil.h"
24 #include "mythcontext.h"
25 #include "NuppelVideoRecorder.h"
26 #include "channelbase.h"
27 #include "filtermanager.h"
28 #include "recordingprofile.h"
29 #include "tv_rec.h"
30 #include "tv_play.h"
31 #include "audioinput.h"
32 #include "mythlogging.h"
33 #include "vbitext/cc.h"
34 #include "vbitext/vbi.h"
35 #include "mythavutil.h"
36 #include "fourcc.h"
37 
38 #if HAVE_BIGENDIAN
39 extern "C" {
40 #include "bswap.h"
41 }
42 #endif
43 
44 extern "C" {
45 #include "libswscale/swscale.h"
46 #include "libavutil/imgutils.h"
47 }
48 
49 #ifdef USING_V4L2
50 #include <linux/videodev2.h>
51 
52 #include "go7007_myth.h"
53 
54 #ifdef USING_V4L1
55 #include <linux/videodev.h>
56 #endif // USING_V4L1
57 
58 #ifndef MJPIOC_S_PARAMS
59 #include "videodev_mjpeg.h"
60 #endif
61 
62 #endif // USING_V4L2
63 
64 #define KEYFRAMEDIST 30
65 
66 #include "ringbuffer.h"
67 #include "RTjpegN.h"
68 
69 #include "programinfo.h"
70 #include "mythsystemevent.h"
71 
72 #define LOC QString("NVR(%1): ").arg(videodevice)
73 
75 {
76  RunProlog();
77  m_parent->doWriteThread();
78  RunEpilog();
79 }
80 
82 {
83  RunProlog();
84  m_parent->doAudioThread();
85  RunEpilog();
86 }
87 
89  V4LRecorder(rec), audio_device(nullptr),
90  write_thread(nullptr), audio_thread(nullptr), recording(false)
91 {
92  channelObj = channel;
93 
94  fd = -1;
95  channelfd = -1;
96  lf = tf = 0;
97  M1 = 0, M2 = 0, Q = 255;
98  pid = pid2 = 0;
99  inputchannel = 1;
100  compression = 1;
101  compressaudio = 1;
102  usebttv = 1;
103  width = 352;
104  height = 240;
105  pip_mode = 0;
106  video_aspect = 1.33333;
107 
108  skip_btaudio = false;
109 
110  framerate_multiplier = 1.0;
111  height_multiplier = 1.0;
112 
113  mp3quality = 3;
114  gf = nullptr;
115  rtjc = nullptr;
116  strm = nullptr;
117  mp3buf = nullptr;
118  mp3buf_size = 0;
119 
120  transcoding = false;
121 
122  act_video_encode = 0;
123  act_video_buffer = 0;
124  video_buffer_count = 0;
125  video_buffer_size = 0;
126 
127  act_audio_encode = 0;
128  act_audio_buffer = 0;
129  act_audio_sample = 0;
130  audio_buffer_count = 0;
131  audio_buffer_size = 0;
132 
133  act_text_encode = 0;
134  act_text_buffer = 0;
135  text_buffer_count = 0;
136  text_buffer_size = 0;
137 
138  writepaused = false;
139  audiopaused = false;
140  mainpaused = false;
141 
143 
144  audiobytes = 0;
145  audio_bits = 16;
146  audio_channels = 2;
148  audio_samplerate = 44100;
149  effectivedsp = 0;
150 
151  picture_format = AV_PIX_FMT_YUV420P;
152  v4l2_pixelformat = 0;
153 
154  mpa_vidcodec = nullptr;
155  mpa_vidctx = nullptr;
156 
157  useavcodec = false;
158 
159  targetbitrate = 2200;
160  scalebitrate = 1;
161  maxquality = 2;
162  minquality = 31;
163  qualdiff = 3;
164  mp4opts = 0;
165  mb_decision = FF_MB_DECISION_SIMPLE;
167 
168  oldtc = 0;
169  startnum = 0;
170  frameofgop = 0;
171  lasttimecode = 0;
172  audio_behind = 0;
173 
174  extendeddataOffset = 0;
175  seektable = new vector<struct seektable_entry>;
176 
177  hardware_encode = false;
178  hmjpg_quality = 80;
179  hmjpg_hdecimation = 2;
180  hmjpg_vdecimation = 2;
181  hmjpg_maxw = 640;
182 
183  cleartimeonpause = false;
184 
185  videoFilterList = "";
186  videoFilters = nullptr;
187  FiltMan = new FilterManager;
188  inpixfmt = FMT_YV12;
189  correct_bttv = false;
190 
191  usingv4l2 = false;
192 
194 
195  volume = 100;
196 
197  ccd = new CC608Decoder(this);
198 
199  go7007 = false;
200  resetcapture = false;
201 
203 
205 
206  memset(&stm, 0, sizeof(struct timeval));
207  memset(&tzone, 0, sizeof(struct timezone));
208 
209  lastPositionMapPos = 0;
210  framesWritten = 0;
211  livetv = false;
212  last_block = 0;
213  firsttc = 0;
214  w_out = 0;
215  h_out = 0;
216 }
217 
219 {
220  if (weMadeBuffer && ringBuffer)
221  {
222  delete ringBuffer;
223  ringBuffer = nullptr;
224  }
225  if (rtjc)
226  delete rtjc;
227  if (mp3buf)
228  delete [] mp3buf;
229  if (gf)
230  lame_close(gf);
231  if (strm)
232  delete [] strm;
233  if (audio_device)
234  {
235  delete audio_device;
236  audio_device = nullptr;
237  }
238  if (fd >= 0)
239  close(fd);
240  if (seektable)
241  {
242  seektable->clear();
243  delete seektable;
244  }
245 
246  while (videobuffer.size() > 0)
247  {
248  struct vidbuffertype *vb = videobuffer.back();
249  delete [] vb->buffer;
250  delete vb;
251  videobuffer.pop_back();
252  }
253  while (audiobuffer.size() > 0)
254  {
255  struct audbuffertype *ab = audiobuffer.back();
256  delete [] ab->buffer;
257  delete ab;
258  audiobuffer.pop_back();
259  }
260  while (textbuffer.size() > 0)
261  {
262  struct txtbuffertype *tb = textbuffer.back();
263  delete [] tb->buffer;
264  delete tb;
265  textbuffer.pop_back();
266  }
267 
268  if (mpa_vidcodec)
269  {
270  QMutexLocker locker(avcodeclock);
271  avcodec_free_context(&mpa_vidctx);
272  }
273 
274  if (videoFilters)
275  delete videoFilters;
276  if (FiltMan)
277  delete FiltMan;
278  if (ccd)
279  delete ccd;
280 }
281 
282 void NuppelVideoRecorder::SetOption(const QString &opt, int value)
283 {
284  if (opt == "width")
285  w_out = width = value;
286  else if (opt == "height")
287  h_out = height = value;
288  else if (opt == "rtjpegchromafilter")
289  M1 = value;
290  else if (opt == "rtjpeglumafilter")
291  M2 = value;
292  else if (opt == "rtjpegquality")
293  Q = value;
294  else if ((opt == "mpeg4bitrate") || (opt == "mpeg2bitrate"))
295  targetbitrate = value;
296  else if (opt == "scalebitrate")
297  scalebitrate = value;
298  else if (opt == "mpeg4maxquality")
299  {
300  if (value > 0)
301  maxquality = value;
302  else
303  maxquality = 1;
304  }
305  else if (opt == "mpeg4minquality")
306  minquality = value;
307  else if (opt == "mpeg4qualdiff")
308  qualdiff = value;
309  else if (opt == "encodingthreadcount")
310  encoding_thread_count = value;
311  else if (opt == "mpeg4optionvhq")
312  {
313  if (value)
314  mb_decision = FF_MB_DECISION_RD;
315  else
316  mb_decision = FF_MB_DECISION_SIMPLE;
317  }
318  else if (opt == "mpeg4option4mv")
319  {
320  if (value)
321  mp4opts |= AV_CODEC_FLAG_4MV;
322  else
323  mp4opts &= ~AV_CODEC_FLAG_4MV;
324  }
325  else if (opt == "mpeg4optionidct")
326  {
327  if (value)
328  mp4opts |= AV_CODEC_FLAG_INTERLACED_DCT;
329  else
330  mp4opts &= ~AV_CODEC_FLAG_INTERLACED_DCT;
331  }
332  else if (opt == "mpeg4optionime")
333  {
334  if (value)
335  mp4opts |= AV_CODEC_FLAG_INTERLACED_ME;
336  else
337  mp4opts &= ~AV_CODEC_FLAG_INTERLACED_ME;
338  }
339  else if (opt == "hardwaremjpegquality")
340  hmjpg_quality = value;
341  else if (opt == "hardwaremjpeghdecimation")
342  hmjpg_hdecimation = value;
343  else if (opt == "hardwaremjpegvdecimation")
344  hmjpg_vdecimation = value;
345  else if (opt == "audiocompression")
346  compressaudio = value;
347  else if (opt == "mp3quality")
348  mp3quality = value;
349  else if (opt == "samplerate")
350  audio_samplerate = value;
351  else if (opt == "audioframesize")
352  audio_buffer_size = value;
353  else if (opt == "pip_mode")
354  pip_mode = value;
355  else if (opt == "inpixfmt")
356  inpixfmt = (VideoFrameType)value;
357  else if (opt == "skipbtaudio")
358  skip_btaudio = value;
359  else if (opt == "volume")
360  volume = value;
361  else
362  V4LRecorder::SetOption(opt, value);
363 }
364 
365 void NuppelVideoRecorder::SetOption(const QString &name, const QString &value)
366 {
368 }
369 
371  const QString &videodev,
372  const QString &audiodev,
373  const QString &vbidev)
374 {
375  SetOption("videodevice", videodev);
376  SetOption("vbidevice", vbidev);
377  SetOption("tvformat", gCoreContext->GetSetting("TVFormat"));
378  SetOption("vbiformat", gCoreContext->GetSetting("VbiFormat"));
379  SetOption("audiodevice", audiodev);
380 
381  QString setting;
382  const StandardSetting *tmp = profile->byName("videocodec");
383  if (tmp)
384  setting = tmp->getValue();
385 
386  if (setting == "MPEG-4")
387  {
388  SetOption("videocodec", "mpeg4");
389 
390  SetIntOption(profile, "mpeg4bitrate");
391  SetIntOption(profile, "scalebitrate");
392  SetIntOption(profile, "mpeg4maxquality");
393  SetIntOption(profile, "mpeg4minquality");
394  SetIntOption(profile, "mpeg4qualdiff");
395 #ifdef USING_FFMPEG_THREADS
396  SetIntOption(profile, "encodingthreadcount");
397 #endif
398  SetIntOption(profile, "mpeg4optionvhq");
399  SetIntOption(profile, "mpeg4option4mv");
400  SetIntOption(profile, "mpeg4optionidct");
401  SetIntOption(profile, "mpeg4optionime");
402  }
403  else if (setting == "MPEG-2")
404  {
405  SetOption("videocodec", "mpeg2video");
406 
407  SetIntOption(profile, "mpeg2bitrate");
408  SetIntOption(profile, "scalebitrate");
409 #ifdef USING_FFMPEG_THREADS
410  SetIntOption(profile, "encodingthreadcount");
411 #endif
412  }
413  else if (setting == "RTjpeg")
414  {
415  SetOption("videocodec", "rtjpeg");
416 
417  SetIntOption(profile, "rtjpegquality");
418  SetIntOption(profile, "rtjpegchromafilter");
419  SetIntOption(profile, "rtjpeglumafilter");
420  }
421  else if (setting == "Hardware MJPEG")
422  {
423  SetOption("videocodec", "hardware-mjpeg");
424 
425  SetIntOption(profile, "hardwaremjpegquality");
426  SetIntOption(profile, "hardwaremjpeghdecimation");
427  SetIntOption(profile, "hardwaremjpegvdecimation");
428  }
429  else
430  {
431  LOG(VB_GENERAL, LOG_ERR, LOC +
432  "Unknown video codec. "
433  "Please go into the TV Settings, Recording Profiles and "
434  "setup the four 'Software Encoders' profiles. "
435  "Assuming RTjpeg for now.");
436 
437  SetOption("videocodec", "rtjpeg");
438 
439  SetIntOption(profile, "rtjpegquality");
440  SetIntOption(profile, "rtjpegchromafilter");
441  SetIntOption(profile, "rtjpeglumafilter");
442  }
443 
444  setting.clear();
445  if ((tmp = profile->byName("audiocodec")))
446  setting = tmp->getValue();
447 
448  if (setting == "MP3")
449  {
450  SetOption("audiocompression", 1);
451  SetIntOption(profile, "mp3quality");
452  SetIntOption(profile, "samplerate");
453  }
454  else if (setting == "Uncompressed")
455  {
456  SetOption("audiocompression", 0);
457  SetIntOption(profile, "samplerate");
458  }
459  else
460  {
461  LOG(VB_GENERAL, LOG_ERR, LOC + "Unknown audio codec");
462  SetOption("audiocompression", 0);
463  }
464 
465  SetIntOption(profile, "volume");
466 
467  SetIntOption(profile, "width");
468  SetIntOption(profile, "height");
469 }
470 
472 {
473  QMutexLocker locker(&pauseLock);
475  writepaused = audiopaused = mainpaused = false;
476  request_pause = true;
477 
478  // The wakeAll is to make sure [write|audio|main]paused are
479  // set immediately, even if we were already paused previously.
480  unpauseWait.wakeAll();
481 }
482 
483 bool NuppelVideoRecorder::IsPaused(bool holding_lock) const
484 {
485  if (!holding_lock)
486  pauseLock.lock();
487  bool ret = audiopaused && mainpaused && writepaused;
488  if (!holding_lock)
489  pauseLock.unlock();
490  return ret;
491 }
492 
494 {
495  videoFilterList = filters;
496  InitFilters();
497 }
498 
500 {
501  return recording;
502 }
503 
505 {
506  return framesWritten;
507 }
508 
510 {
511  return channelfd;
512 }
513 
515 {
516  if (!useavcodec)
517  useavcodec = true;
518 
519  if (mpa_vidcodec)
520  {
521  QMutexLocker locker(avcodeclock);
522  avcodec_free_context(&mpa_vidctx);
523  }
524 
525  QByteArray vcodec = videocodec.toLatin1();
526  mpa_vidcodec = avcodec_find_encoder_by_name(vcodec.constData());
527 
528  if (!mpa_vidcodec)
529  {
530  LOG(VB_GENERAL, LOG_ERR, LOC + QString("Video Codec not found: %1")
531  .arg(vcodec.constData()));
532  return false;
533  }
534 
535  mpa_vidctx = avcodec_alloc_context3(nullptr);
536 
537  switch (picture_format)
538  {
539  case AV_PIX_FMT_YUV420P:
540  case AV_PIX_FMT_YUV422P:
541  case AV_PIX_FMT_YUVJ420P:
542  mpa_vidctx->pix_fmt = picture_format;
543  break;
544  default:
545  LOG(VB_GENERAL, LOG_ERR, LOC + QString("Unknown picture format: %1")
546  .arg(picture_format));
547  }
548 
549  mpa_vidctx->width = w_out;
550  mpa_vidctx->height = (int)(height * height_multiplier);
551 
552  int usebitrate = targetbitrate * 1000;
553  if (scalebitrate)
554  {
555  float diff = (w_out * h_out) / (640.0 * 480.0);
556  usebitrate = (int)(diff * usebitrate);
557  }
558 
559  if (targetbitrate == -1)
560  usebitrate = -1;
561 
562  mpa_vidctx->time_base.den = (int)ceil(video_frame_rate * 100 *
564  mpa_vidctx->time_base.num = 100;
565 
566  // avcodec needs specific settings for mpeg2 compression
567  switch (mpa_vidctx->time_base.den)
568  {
569  case 2397:
570  case 2398: mpa_vidctx->time_base.den = 24000;
571  mpa_vidctx->time_base.num = 1001;
572  break;
573  case 2997:
574  case 2998: mpa_vidctx->time_base.den = 30000;
575  mpa_vidctx->time_base.num = 1001;
576  break;
577  case 5994:
578  case 5995: mpa_vidctx->time_base.den = 60000;
579  mpa_vidctx->time_base.num = 1001;
580  break;
581  }
582 
583  AVDictionary *opts = nullptr;
584 
585  mpa_vidctx->bit_rate = usebitrate;
586  mpa_vidctx->bit_rate_tolerance = usebitrate * 100;
587  mpa_vidctx->qmin = maxquality;
588  mpa_vidctx->qmax = minquality;
589  mpa_vidctx->max_qdiff = qualdiff;
590  mpa_vidctx->flags = mp4opts;
591  mpa_vidctx->mb_decision = mb_decision;
592 
593  mpa_vidctx->qblur = 0.5;
594  mpa_vidctx->max_b_frames = 0;
595  mpa_vidctx->b_quant_factor = 0;
596  av_dict_set(&opts, "rc_strategy", "2", 0);
597  av_dict_set(&opts, "b_strategy", "0", 0);
598  mpa_vidctx->gop_size = 30;
599  mpa_vidctx->rc_max_rate = 0;
600  mpa_vidctx->rc_min_rate = 0;
601  mpa_vidctx->rc_buffer_size = 0;
602  // mpa_vidctx->rc_buffer_aggressivity = 1.0;
603  // rc_buf_aggressivity is now "currently useless"
604  mpa_vidctx->rc_override_count = 0;
605  av_dict_set(&opts, "rc_init_cplx", "0", 0);
606  mpa_vidctx->dct_algo = FF_DCT_AUTO;
607  mpa_vidctx->idct_algo = FF_IDCT_AUTO;
608  av_dict_set_int(&opts, "pred", FF_PRED_LEFT, 0);
609  if (videocodec.toLower() == "huffyuv" || videocodec.toLower() == "mjpeg")
610  mpa_vidctx->strict_std_compliance = FF_COMPLIANCE_UNOFFICIAL;
611  mpa_vidctx->thread_count = encoding_thread_count;
612 
613  QMutexLocker locker(avcodeclock);
614 
615  if (avcodec_open2(mpa_vidctx, mpa_vidcodec, &opts) < 0)
616  {
617  LOG(VB_GENERAL, LOG_ERR, LOC + QString("Unable to open FFMPEG/%1 codec")
618  .arg(videocodec));
619  return false;
620  }
621 
622 
623  return true;
624 }
625 
627 {
628  picture_format = AV_PIX_FMT_YUV420P;
629 
630  int setval;
631  rtjc = new RTjpeg();
632  setval = RTJ_YUV420;
633  rtjc->SetFormat(&setval);
634  setval = (int)(h_out * height_multiplier);
635  rtjc->SetSize(&w_out, &setval);
636  rtjc->SetQuality(&Q);
637  setval = 2;
638  rtjc->SetIntra(&setval, &M1, &M2);
639 }
640 
641 
643 {
644  int tot_height = (int)(height * height_multiplier);
645  double aspectnum = w_out / (double)tot_height;
646  uint aspect;
647 
648  if (aspectnum == 0.0)
649  aspect = 0;
650  else if (fabs(aspectnum - 1.3333333333333333) < 0.001)
651  aspect = 2;
652  else if (fabs(aspectnum - 1.7777777777777777) < 0.001)
653  aspect = 3;
654  else if (fabs(aspectnum - 2.21) < 0.001)
655  aspect = 4;
656  else
657  aspect = aspectnum * 1000000;
658 
659  if ((aspect > 0) && (aspect != m_videoAspect))
660  {
661  m_videoAspect = aspect;
662  AspectChange((AspectRatio)aspect, 0);
663  }
664 
665  if (w_out && tot_height &&
666  ((uint)tot_height != m_videoHeight ||
667  (uint)w_out != m_videoWidth))
668  {
669  m_videoHeight = tot_height;
671  ResolutionChange(w_out, tot_height, 0);
672  }
673 
674  int den = (int)ceil(video_frame_rate * 100 * framerate_multiplier);
675  int num = 100;
676 
677  // avcodec needs specific settings for mpeg2 compression
678  switch (den)
679  {
680  case 2397:
681  case 2398: den = 24000;
682  num = 1001;
683  break;
684  case 2997:
685  case 2998: den = 30000;
686  num = 1001;
687  break;
688  case 5994:
689  case 5995: den = 60000;
690  num = 1001;
691  break;
692  }
693 
694  FrameRate frameRate(den, num);
695  if (frameRate.isNonzero() && frameRate != m_frameRate)
696  {
697  m_frameRate = frameRate;
698  LOG(VB_RECORD, LOG_INFO, LOC + QString("NVR: frame rate = %1")
699  .arg(frameRate.toDouble() * 1000));
700  FrameRateChange(frameRate.toDouble() * 1000, 0);
701  }
702 }
703 
705 {
706  if (AudioInit() != 0)
707  {
708  LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to init audio input device");
709  }
710 
711  if (videocodec == "hardware-mjpeg")
712  {
713  videocodec = "mjpeg";
714  hardware_encode = true;
715 
716  MJPEGInit();
717 
719 
720  if (ntsc)
721  {
722  switch (hmjpg_vdecimation)
723  {
724  case 2: height = 240; break;
725  case 4: height = 120; break;
726  default: height = 480; break;
727  }
728  }
729  else
730  {
731  switch (hmjpg_vdecimation)
732  {
733  case 2: height = 288; break;
734  case 4: height = 144; break;
735  default: height = 576; break;
736  }
737  }
738  }
739 
740  if (!ringBuffer)
741  {
742  LOG(VB_GENERAL, LOG_WARNING, LOC + "Warning, old RingBuffer creation");
743  ringBuffer = RingBuffer::Create("output.nuv", true);
744  weMadeBuffer = true;
745  livetv = false;
746  if (!ringBuffer || !ringBuffer->IsOpen())
747  {
748  _error = "Could not open RingBuffer";
749  LOG(VB_GENERAL, LOG_ERR, LOC + _error);
750  return;
751  }
752  }
753  else
755 
756  audiobytes = 0;
757 
758  InitBuffers();
759  InitFilters();
760 }
761 
762 int NuppelVideoRecorder::AudioInit(bool skipdevice)
763 {
764  if (!skipdevice)
765  {
766  int blocksize;
768  if (!audio_device)
769  {
770  LOG(VB_GENERAL, LOG_ERR, LOC +
771  QString("Failed to create audio device: %1") .arg(audiodevice));
772  return 1;
773  }
774 
776  {
777  LOG(VB_GENERAL, LOG_ERR, LOC +
778  QString("Failed to open audio device %1").arg(audiodevice));
779  return 1;
780  }
781 
782  if ((blocksize = audio_device->GetBlockSize()) <= 0)
783  {
784  blocksize = 1024;
785  LOG(VB_GENERAL, LOG_ERR, LOC +
786  QString("Failed to determine audio block size on %1,"
787  "using default 1024 bytes").arg(audiodevice));
788  }
789 
790  audio_device->Close();
791  audio_buffer_size = blocksize;
792  }
793 
795  LOG(VB_AUDIO, LOG_INFO, LOC +
796  QString("Audio device %1 buffer size: %1 bytes")
797  .arg(audio_buffer_size));
798 
799  if (compressaudio)
800  {
801  int tmp;
802  gf = lame_init();
803  lame_set_bWriteVbrTag(gf, 0);
804  lame_set_quality(gf, mp3quality);
805  lame_set_compression_ratio(gf, 11);
806  lame_set_mode(gf, audio_channels == 2 ? STEREO : MONO);
807  lame_set_num_channels(gf, audio_channels);
808  lame_set_in_samplerate(gf, audio_samplerate);
809  if ((tmp = lame_init_params(gf)) != 0)
810  {
811  LOG(VB_GENERAL, LOG_ERR, LOC +
812  QString("AudioInit(): lame_init_params error %1").arg(tmp));
813  compressaudio = false;
814  }
815 
816  if (audio_bits != 16)
817  {
818  LOG(VB_GENERAL, LOG_ERR, LOC +
819  "AudioInit(): lame support requires 16bit audio");
820  compressaudio = false;
821  }
822  }
823  mp3buf_size = (int)(1.25 * 16384 + 7200);
824  mp3buf = new char[mp3buf_size];
825 
826  return 0;
827 }
828 
839 {
840 #ifdef USING_V4L1
841  bool we_opened_fd = false;
842  int init_fd = fd;
843  if (init_fd < 0)
844  {
845  QByteArray vdevice = videodevice.toLatin1();
846  init_fd = open(vdevice.constData(), O_RDWR);
847  we_opened_fd = true;
848 
849  if (init_fd < 0)
850  {
851  LOG(VB_GENERAL, LOG_ERR, LOC + "Can't open video device" + ENO);
852  return false;
853  }
854  }
855 
856  struct video_capability vc;
857  memset(&vc, 0, sizeof(vc));
858  int ret = ioctl(init_fd, VIDIOCGCAP, &vc);
859 
860  if (ret < 0)
861  LOG(VB_GENERAL, LOG_ERR, LOC + "Can't query V4L capabilities" + ENO);
862 
863  if (we_opened_fd)
864  close(init_fd);
865 
866  if (ret < 0)
867  return false;
868 
869  if (vc.maxwidth != 768 && vc.maxwidth != 640)
870  vc.maxwidth = 720;
871 
872  if (vc.type & VID_TYPE_MJPEG_ENCODER)
873  {
874  if (vc.maxwidth >= 768)
875  hmjpg_maxw = 768;
876  else if (vc.maxwidth >= 704)
877  hmjpg_maxw = 704;
878  else
879  hmjpg_maxw = 640;
880  return true;
881  }
882 #endif // USING_V4L1
883 
884  LOG(VB_GENERAL, LOG_ERR, LOC + "MJPEG not supported by device");
885  return false;
886 }
887 
889 {
890  int btmp = video_buffer_size;
891  if (videoFilters)
892  delete videoFilters;
893 
894  QString tmpVideoFilterList;
895 
896  w_out = width;
897  h_out = height;
899 
900  if (correct_bttv && !videoFilterList.contains("adjust"))
901  {
902  if (videoFilterList.isEmpty())
903  tmpVideoFilterList = "adjust";
904  else
905  tmpVideoFilterList = "adjust," + videoFilterList;
906  }
907  else
908  tmpVideoFilterList = videoFilterList;
909 
910  videoFilters = FiltMan->LoadFilters(tmpVideoFilterList, inpixfmt, tmp,
911  w_out, h_out, btmp);
912  if (video_buffer_size && btmp != video_buffer_size)
913  {
914  video_buffer_size = btmp;
916  }
917 }
918 
920 {
921  int videomegs;
922  // cppcheck-suppress variableScope
923  int audiomegs = 2;
924 
925  if (!video_buffer_size)
926  {
928  buffersize(picture_format == AV_PIX_FMT_YUV422P ? FMT_YUV422P : FMT_YV12,
929  w_out, h_out);
930  }
931 
932  if (width >= 480 || height > 288)
933  videomegs = 20;
934  else
935  videomegs = 12;
936 
937  video_buffer_count = (videomegs * 1000 * 1000) / video_buffer_size;
938 
939  if (audio_buffer_size != 0)
940  audio_buffer_count = (audiomegs * 1000 * 1000) / audio_buffer_size;
941  else
942  audio_buffer_count = 0;
943 
944  text_buffer_size = 8 * (sizeof(teletextsubtitle) + VT_WIDTH);
946 
947  for (int i = 0; i < video_buffer_count; i++)
948  {
949  vidbuffertype *vidbuf = new vidbuffertype;
950  vidbuf->buffer = new unsigned char[video_buffer_size];
951  vidbuf->sample = 0;
952  vidbuf->freeToEncode = 0;
953  vidbuf->freeToBuffer = 1;
954  vidbuf->bufferlen = 0;
955  vidbuf->forcekey = 0;
956 
957  videobuffer.push_back(vidbuf);
958  }
959 
960  for (int i = 0; i < audio_buffer_count; i++)
961  {
962  audbuffertype *audbuf = new audbuffertype;
963  audbuf->buffer = new unsigned char[audio_buffer_size];
964  audbuf->sample = 0;
965  audbuf->freeToEncode = 0;
966  audbuf->freeToBuffer = 1;
967 
968  audiobuffer.push_back(audbuf);
969  }
970 
971  for (int i = 0; i < text_buffer_count; i++)
972  {
973  txtbuffertype *txtbuf = new txtbuffertype;
974  txtbuf->buffer = new unsigned char[text_buffer_size];
975  txtbuf->freeToEncode = 0;
976  txtbuf->freeToBuffer = 1;
977 
978  textbuffer.push_back(txtbuf);
979  }
980 }
981 
983 {
984  for (unsigned int i = 0; i < videobuffer.size(); i++)
985  {
986  delete [] (videobuffer[i]->buffer);
987  videobuffer[i]->buffer = new unsigned char[video_buffer_size];
988  }
989 }
990 
992 {
993  delete [] strm;
994  strm = new signed char[width * height * 2 + 10];
995 }
996 
998 {
999  if (channelfd>0)
1000  return true;
1001 
1002  int retries = 0;
1003  QByteArray vdevice = videodevice.toLatin1();
1004  fd = open(vdevice.constData(), O_RDWR);
1005  while (fd < 0)
1006  {
1007  usleep(30000);
1008  fd = open(vdevice.constData(), O_RDWR);
1009  if (retries++ > 5)
1010  {
1011  _error = QString("Can't open video device: %1").arg(videodevice);
1012  LOG(VB_GENERAL, LOG_ERR, LOC + _error + ENO);
1013  KillChildren();
1014  return false;
1015  }
1016  }
1017 
1018  channelfd = fd;
1019  return true;
1020 }
1021 
1023 {
1024 #ifdef USING_V4L2
1025  usingv4l2 = true;
1026 
1027  struct v4l2_capability vcap;
1028  memset(&vcap, 0, sizeof(vcap));
1029 
1030  if (ioctl(channelfd, VIDIOC_QUERYCAP, &vcap) < 0)
1031  {
1032  usingv4l2 = false;
1033  }
1034 
1035  if (usingv4l2 && !(vcap.capabilities & V4L2_CAP_VIDEO_CAPTURE))
1036  {
1037  LOG(VB_GENERAL, LOG_ERR, LOC +
1038  "Not a v4l2 capture device, falling back to v4l");
1039  usingv4l2 = false;
1040  }
1041 
1042  if (usingv4l2 && !(vcap.capabilities & V4L2_CAP_STREAMING))
1043  {
1044  LOG(VB_GENERAL, LOG_ERR, LOC +
1045  "Won't work with the streaming interface, falling back");
1046  usingv4l2 = false;
1047  }
1048 
1049  if (vcap.card[0] == 'B' && vcap.card[1] == 'T' &&
1050  vcap.card[2] == '8' && vcap.card[4] == '8')
1051  correct_bttv = true;
1052 
1053  QString driver = (char *)vcap.driver;
1054  if (driver == "go7007")
1055  go7007 = true;
1056 #endif // USING_V4L2
1057 }
1058 
1060 {
1061  if (lzo_init() != LZO_E_OK)
1062  {
1063  LOG(VB_GENERAL, LOG_ERR, LOC + "lzo_init() failed, exiting");
1064  _error = "lzo_init() failed, exiting";
1065  LOG(VB_GENERAL, LOG_ERR, LOC + _error);
1066  return;
1067  }
1068 
1069  if (!Open())
1070  {
1071  _error = "Failed to open device";
1072  LOG(VB_GENERAL, LOG_ERR, LOC + _error);
1073  return;
1074  }
1075 
1076  ProbeV4L2();
1077 
1078  if (usingv4l2 && !SetFormatV4L2())
1079  {
1080  _error = "Failed to set V4L2 format";
1081  LOG(VB_GENERAL, LOG_ERR, LOC + _error);
1082  return;
1083  }
1084 
1085  StreamAllocate();
1086 
1087  positionMapLock.lock();
1088  positionMap.clear();
1089  positionMapDelta.clear();
1090  positionMapLock.unlock();
1091 
1092  if (videocodec.toLower() == "rtjpeg")
1093  useavcodec = false;
1094  else
1095  useavcodec = true;
1096 
1097  if (useavcodec)
1099 
1100  if (!useavcodec)
1101  SetupRTjpeg();
1102 
1104 
1105  if (CreateNuppelFile() != 0)
1106  {
1107  _error = QString("Cannot open '%1' for writing")
1108  .arg(ringBuffer->GetFilename());
1109  LOG(VB_GENERAL, LOG_ERR, LOC + _error);
1110  return;
1111  }
1112 
1113  if (IsHelperRequested())
1114  {
1115  LOG(VB_GENERAL, LOG_ERR, LOC + "Children are already alive");
1116  _error = "Children are already alive";
1117  return;
1118  }
1119 
1120  {
1121  QMutexLocker locker(&pauseLock);
1122  request_recording = true;
1123  request_helper = true;
1124  recording = true;
1125  recordingWait.wakeAll();
1126  }
1127 
1128  write_thread = new NVRWriteThread(this);
1129  write_thread->start();
1130 
1131  audio_thread = new NVRAudioThread(this);
1132  audio_thread->start();
1133 
1134  if ((vbimode != VBIMode::None) && (OpenVBIDevice() >= 0))
1135  vbi_thread = new VBIThread(this);
1136 
1137  // save the start time
1138  gettimeofday(&stm, &tzone);
1139 
1140  // try to get run at higher scheduling priority, ignore failure
1141  myth_nice(-10);
1142 
1143  if (usingv4l2)
1144  {
1145  inpixfmt = FMT_NONE;
1146  InitFilters();
1147  DoV4L2();
1148  }
1149  else
1150  DoV4L1();
1151 
1152  {
1153  QMutexLocker locker(&pauseLock);
1154  request_recording = false;
1155  request_helper = false;
1156  recording = false;
1157  recordingWait.wakeAll();
1158  }
1159 }
1160 
1161 #ifdef USING_V4L1
1163 {
1164  struct video_capability vc;
1165  struct video_mmap mm;
1166  struct video_mbuf vm;
1167  struct video_channel vchan;
1168  struct video_audio va;
1169  struct video_tuner vt;
1170 
1171  memset(&mm, 0, sizeof(mm));
1172  memset(&vm, 0, sizeof(vm));
1173  memset(&vchan, 0, sizeof(vchan));
1174  memset(&va, 0, sizeof(va));
1175  memset(&vt, 0, sizeof(vt));
1176  memset(&vc, 0, sizeof(vc));
1177 
1178  if (ioctl(fd, VIDIOCGCAP, &vc) < 0)
1179  {
1180  QString tmp = "VIDIOCGCAP: " + ENO;
1181  KillChildren();
1182  LOG(VB_GENERAL, LOG_ERR, tmp);
1183  _error = tmp;
1184  return;
1185  }
1186 
1187  int channelinput = 0;
1188 
1189  if (channelObj)
1190  channelinput = channelObj->GetCurrentInputNum();
1191 
1192  vchan.channel = channelinput;
1193 
1194  if (ioctl(fd, VIDIOCGCHAN, &vchan) < 0)
1195  LOG(VB_GENERAL, LOG_ERR, LOC + "VIDIOCGCHAN: " + ENO);
1196 
1197  // Set volume level for audio recording (unless feature is disabled).
1198  if (!skip_btaudio)
1199  {
1200  // v4l1 compat in Linux 2.6.18 does not set VIDEO_VC_AUDIO,
1201  // so we just use VIDIOCGAUDIO unconditionally.. then only
1202  // report a get failure as an error if VIDEO_VC_AUDIO is set.
1203  if (ioctl(fd, VIDIOCGAUDIO, &va) < 0)
1204  {
1205  bool reports_audio = vchan.flags & VIDEO_VC_AUDIO;
1206  uint err_level = reports_audio ? VB_GENERAL : VB_AUDIO;
1207  // print at VB_GENERAL if driver reports audio.
1208  LOG(err_level, LOG_ERR, LOC + "Failed to get audio" + ENO);
1209  }
1210  else
1211  {
1212  // if channel has a audio then activate it
1213  va.flags &= ~VIDEO_AUDIO_MUTE; // now this really has to work
1214  va.volume = volume * 65535 / 100;
1215  if (ioctl(fd, VIDIOCSAUDIO, &va) < 0)
1216  LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to set audio" + ENO);
1217  }
1218  }
1219 
1220  if ((vc.type & VID_TYPE_MJPEG_ENCODER) && hardware_encode)
1221  {
1222  DoMJPEG();
1223  _error = "MJPEG requested but not available.";
1224  LOG(VB_GENERAL, LOG_ERR, LOC + _error);
1225  return;
1226  }
1227 
1228  inpixfmt = FMT_NONE;
1229  InitFilters();
1230 
1231  if (ioctl(fd, VIDIOCGMBUF, &vm) < 0)
1232  {
1233  QString tmp = "VIDIOCGMBUF: " + ENO;
1234  KillChildren();
1235  LOG(VB_GENERAL, LOG_ERR, LOC + tmp);
1236  _error = tmp;
1237  return;
1238  }
1239 
1240  if (vm.frames < 2)
1241  {
1242  QString tmp = "need a minimum of 2 capture buffers";
1243  KillChildren();
1244  LOG(VB_GENERAL, LOG_ERR, LOC + tmp);
1245  _error = tmp;
1246  return;
1247  }
1248 
1249  int frame;
1250 
1251  unsigned char *buf = (unsigned char *)mmap(0, vm.size,
1252  PROT_READ|PROT_WRITE,
1253  MAP_SHARED,
1254  fd, 0);
1255  if (buf == MAP_FAILED)
1256  {
1257  QString tmp = "mmap: " + ENO;
1258  KillChildren();
1259  LOG(VB_GENERAL, LOG_ERR, LOC + tmp);
1260  _error = tmp;
1261  return;
1262  }
1263 
1264  mm.height = height;
1265  mm.width = width;
1266  if (inpixfmt == FMT_YUV422P)
1267  mm.format = VIDEO_PALETTE_YUV422P;
1268  else
1269  mm.format = VIDEO_PALETTE_YUV420P;
1270 
1271  mm.frame = 0;
1272  if (ioctl(fd, VIDIOCMCAPTURE, &mm)<0)
1273  LOG(VB_GENERAL, LOG_ERR, LOC + "VIDIOCMCAPTUREi0: " + ENO);
1274  mm.frame = 1;
1275  if (ioctl(fd, VIDIOCMCAPTURE, &mm)<0)
1276  LOG(VB_GENERAL, LOG_ERR, LOC + "VIDIOCMCAPTUREi1: " + ENO);
1277 
1278  int syncerrors = 0;
1279 
1280  while (IsRecordingRequested() && !IsErrored())
1281  {
1282  {
1283  QMutexLocker locker(&pauseLock);
1284  if (request_pause)
1285  {
1286  if (!mainpaused)
1287  {
1288  mainpaused = true;
1289  pauseWait.wakeAll();
1290  if (IsPaused(true) && tvrec)
1291  tvrec->RecorderPaused();
1292  }
1293  unpauseWait.wait(&pauseLock, 100);
1294  if (cleartimeonpause)
1295  gettimeofday(&stm, &tzone);
1296  continue;
1297  }
1298 
1299  if (!request_pause && mainpaused)
1300  {
1301  mainpaused = false;
1302  unpauseWait.wakeAll();
1303  }
1304  }
1305 
1306  frame = 0;
1307  mm.frame = 0;
1308  if (ioctl(fd, VIDIOCSYNC, &frame)<0)
1309  {
1310  syncerrors++;
1311  if (syncerrors == 10)
1312  LOG(VB_GENERAL, LOG_ERR, LOC +
1313  "Multiple bttv errors, further messages supressed");
1314  else if (syncerrors < 10)
1315  LOG(VB_GENERAL, LOG_ERR, LOC + "VIDIOCSYNC: " + ENO);
1316  }
1317  else
1318  {
1319  BufferIt(buf+vm.offsets[0], video_buffer_size);
1320  //memset(buf+vm.offsets[0], 0, video_buffer_size);
1321  }
1322 
1323  if (ioctl(fd, VIDIOCMCAPTURE, &mm)<0)
1324  LOG(VB_GENERAL, LOG_ERR, LOC + "VIDIOCMCAPTURE0: " + ENO);
1325 
1326  frame = 1;
1327  mm.frame = 1;
1328  if (ioctl(fd, VIDIOCSYNC, &frame)<0)
1329  {
1330  syncerrors++;
1331  if (syncerrors == 10)
1332  LOG(VB_GENERAL, LOG_ERR, LOC +
1333  "Multiple bttv errors, further messages supressed");
1334  else if (syncerrors < 10)
1335  LOG(VB_GENERAL, LOG_ERR, LOC + "VIDIOCSYNC: " + ENO);
1336  }
1337  else
1338  {
1339  BufferIt(buf+vm.offsets[1], video_buffer_size);
1340  //memset(buf+vm.offsets[1], 0, video_buffer_size);
1341  }
1342  if (ioctl(fd, VIDIOCMCAPTURE, &mm)<0)
1343  LOG(VB_GENERAL, LOG_ERR, LOC + "VIDIOCMCAPTURE1: " + ENO);
1344  }
1345 
1346  munmap(buf, vm.size);
1347 
1348  KillChildren();
1349 
1350  FinishRecording();
1351 
1352  close(fd);
1353 }
1354 #else // if !USING_V4L1
1355 void NuppelVideoRecorder::DoV4L1(void) {}
1356 #endif // !USING_V4L1
1357 
1358 #ifdef USING_V4L2
1360 {
1361  struct v4l2_format vfmt;
1362  memset(&vfmt, 0, sizeof(vfmt));
1363 
1364  vfmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1365 
1366  vfmt.fmt.pix.width = width;
1367  vfmt.fmt.pix.height = height;
1368  vfmt.fmt.pix.field = V4L2_FIELD_INTERLACED;
1369 
1370  if (go7007)
1371  vfmt.fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG;
1372  else if (inpixfmt == FMT_YUV422P)
1373  vfmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUV422P;
1374  else
1375  vfmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUV420;
1376 
1377  if (ioctl(fd, VIDIOC_S_FMT, &vfmt) < 0)
1378  {
1379  // this is supported by the cx88 and various ati cards.
1380  vfmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
1381 
1382  if (ioctl(fd, VIDIOC_S_FMT, &vfmt) < 0)
1383  {
1384  // this is supported by the HVR-950q
1385  vfmt.fmt.pix.pixelformat = V4L2_PIX_FMT_UYVY;
1386  if (ioctl(fd, VIDIOC_S_FMT, &vfmt) < 0)
1387  {
1388  LOG(VB_GENERAL, LOG_ERR, LOC +
1389  "v4l2: Unable to set desired format");
1390  return false;
1391  }
1392  else
1393  {
1394  // we need to convert the buffer - we can't deal with uyvy
1395  // directly.
1396  if (inpixfmt == FMT_YUV422P)
1397  {
1398  LOG(VB_GENERAL, LOG_ERR, LOC +
1399  "v4l2: uyvy format supported, but yuv422 requested.");
1400  LOG(VB_GENERAL, LOG_ERR, LOC +
1401  "v4l2: unfortunately, this converter hasn't been "
1402  "written yet, exiting");
1403  return false;
1404  }
1405  LOG(VB_RECORD, LOG_INFO, LOC +
1406  "v4l2: format set, getting uyvy from v4l, converting");
1407  }
1408  }
1409  else
1410  {
1411  // we need to convert the buffer - we can't deal with yuyv directly.
1412  if (inpixfmt == FMT_YUV422P)
1413  {
1414  LOG(VB_GENERAL, LOG_ERR, LOC +
1415  "v4l2: yuyv format supported, but yuv422 requested.");
1416  LOG(VB_GENERAL, LOG_ERR, LOC +
1417  "v4l2: unfortunately, this converter hasn't been written "
1418  "yet, exiting");
1419  return false;
1420  }
1421  LOG(VB_RECORD, LOG_INFO, LOC +
1422  "v4l2: format set, getting yuyv from v4l, converting");
1423  }
1424  }
1425  else // cool, we can do our preferred format, most likely running on bttv.
1426  LOG(VB_RECORD, LOG_INFO, LOC +
1427  "v4l2: format set, getting yuv420 from v4l");
1428 
1429  // VIDIOC_S_FMT might change the format, check it
1430  if (width != (int)vfmt.fmt.pix.width ||
1431  height != (int)vfmt.fmt.pix.height)
1432  {
1433  LOG(VB_RECORD, LOG_INFO, LOC +
1434  QString("v4l2: resolution changed. requested %1x%2, using "
1435  "%3x%4 now")
1436  .arg(width).arg(height)
1437  .arg(vfmt.fmt.pix.width) .arg(vfmt.fmt.pix.height));
1438  w_out = width = vfmt.fmt.pix.width;
1439  h_out = height = vfmt.fmt.pix.height;
1440  }
1441 
1442  v4l2_pixelformat = vfmt.fmt.pix.pixelformat;
1443 
1444  return true;
1445 }
1446 #else // if !USING_V4L2
1447 bool NuppelVideoRecorder::SetFormatV4L2(void) { return false; }
1448 #endif // !USING_V4L2
1449 
1450 #ifdef USING_V4L2
1451 #define MAX_VIDEO_BUFFERS 5
1453 {
1454  struct v4l2_buffer vbuf;
1455  struct v4l2_requestbuffers vrbuf;
1456  struct v4l2_control vc;
1457 
1458  memset(&vbuf, 0, sizeof(vbuf));
1459  memset(&vrbuf, 0, sizeof(vrbuf));
1460  memset(&vc, 0, sizeof(vc));
1461 
1462  vc.id = V4L2_CID_AUDIO_MUTE;
1463  vc.value = 0;
1464 
1465  if (ioctl(fd, VIDIOC_S_CTRL, &vc) < 0)
1466  LOG(VB_GENERAL, LOG_ERR, LOC +
1467  "VIDIOC_S_CTRL:V4L2_CID_AUDIO_MUTE: " + ENO);
1468 
1469  if (go7007)
1470  {
1471  struct go7007_comp_params comp;
1472  struct go7007_mpeg_params mpeg;
1473 
1474  memset(&comp, 0, sizeof(comp));
1475  comp.gop_size = keyframedist;
1476  comp.max_b_frames = 0;
1477 
1478  if (fabs(video_aspect - 1.33333f) < 0.01f)
1479  {
1480  if (ntsc)
1481  comp.aspect_ratio = GO7007_ASPECT_RATIO_4_3_NTSC;
1482  else
1483  comp.aspect_ratio = GO7007_ASPECT_RATIO_4_3_PAL;
1484  }
1485  else if (fabs(video_aspect - 1.77777f) < 0.01f)
1486  {
1487  if (ntsc)
1488  comp.aspect_ratio = GO7007_ASPECT_RATIO_16_9_NTSC;
1489  else
1490  comp.aspect_ratio = GO7007_ASPECT_RATIO_16_9_PAL;
1491  }
1492  else
1493  {
1494  comp.aspect_ratio = GO7007_ASPECT_RATIO_1_1;
1495  }
1496 
1497  comp.flags |= GO7007_COMP_CLOSED_GOP;
1498  if (ioctl(fd, GO7007IOC_S_COMP_PARAMS, &comp) < 0)
1499  {
1500  _error = "Unable to set compression params";
1501  LOG(VB_GENERAL, LOG_ERR, LOC + _error);
1502  return;
1503  }
1504 
1505  memset(&mpeg, 0, sizeof(mpeg));
1506 
1507  if (videocodec == "mpeg2video")
1509  else
1511 
1512  if (ioctl(fd, GO7007IOC_S_MPEG_PARAMS, &mpeg) < 0)
1513  {
1514  _error = "Unable to set MPEG params";
1515  LOG(VB_GENERAL, LOG_ERR, LOC + _error);
1516  return;
1517  }
1518 
1519  int usebitrate = targetbitrate * 1000;
1520  if (scalebitrate)
1521  {
1522  float diff = (width * height) / (640.0 * 480.0);
1523  usebitrate = (int)(diff * usebitrate);
1524  }
1525 
1526  if (ioctl(fd, GO7007IOC_S_BITRATE, &usebitrate) < 0)
1527  {
1528  _error = "Unable to set bitrate";
1529  LOG(VB_GENERAL, LOG_ERR, LOC + _error);
1530  return;
1531  }
1532 
1533  hardware_encode = true;
1534  }
1535 
1536  uint numbuffers = MAX_VIDEO_BUFFERS;
1537 
1538  vrbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1539  vrbuf.memory = V4L2_MEMORY_MMAP;
1540  vrbuf.count = numbuffers;
1541 
1542  if (ioctl(fd, VIDIOC_REQBUFS, &vrbuf) < 0)
1543  {
1544  _error = "Not able to get any capture buffers, exiting";
1545  LOG(VB_GENERAL, LOG_ERR, LOC + _error);
1546  return;
1547  }
1548 
1549  if (vrbuf.count < numbuffers)
1550  {
1551  LOG(VB_GENERAL, LOG_INFO, LOC +
1552  QString("Requested %1 buffers, but only %2 are available. "
1553  "Proceeding anyway").arg(numbuffers).arg(vrbuf.count));
1554  }
1555 
1556  numbuffers = vrbuf.count;
1557 
1558  unsigned char *buffers[MAX_VIDEO_BUFFERS];
1559  int bufferlen[MAX_VIDEO_BUFFERS];
1560 
1561  for (uint i = 0; i < numbuffers; i++)
1562  {
1563  vbuf.type = vrbuf.type;
1564  vbuf.index = i;
1565 
1566  if (ioctl(fd, VIDIOC_QUERYBUF, &vbuf) < 0)
1567  {
1568  LOG(VB_GENERAL, LOG_ERR, LOC +
1569  QString("unable to query capture buffer %1").arg(i));
1570  _error = "Unable to query capture buffer";
1571  return;
1572  }
1573 
1574  buffers[i] = (unsigned char *)mmap(nullptr, vbuf.length,
1575  PROT_READ|PROT_WRITE, MAP_SHARED,
1576  fd, vbuf.m.offset);
1577 
1578  if (buffers[i] == MAP_FAILED)
1579  {
1580  LOG(VB_GENERAL, LOG_ERR, LOC + "mmap: " + ENO);
1581  LOG(VB_GENERAL, LOG_ERR, LOC + "Memory map failed");
1582  _error = "Memory map failed";
1583  return;
1584  }
1585  bufferlen[i] = vbuf.length;
1586  }
1587 
1588  for (uint i = 0; i < numbuffers; i++)
1589  {
1590  memset(buffers[i], 0, bufferlen[i]);
1591  vbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1592  vbuf.index = i;
1593  if (ioctl(fd, VIDIOC_QBUF, &vbuf) < 0)
1594  LOG(VB_GENERAL, LOG_ERR, LOC + "unable to enqueue capture buffer (VIDIOC_QBUF failed) " + ENO);
1595  }
1596 
1597  int turnon = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1598  if (ioctl(fd, VIDIOC_STREAMON, &turnon) < 0)
1599  LOG(VB_GENERAL, LOG_ERR, LOC + "unable to start capture (VIDIOC_STREAMON failed) " + ENO);
1600 
1601  struct timeval tv;
1602  fd_set rdset;
1603  int frame = 0;
1604  bool forcekey = false;
1605 
1606  resetcapture = false;
1607 
1608  // setup pixel format conversions for YUYV and UYVY
1609  uint8_t *output_buffer = nullptr;
1610  struct SwsContext *convert_ctx = nullptr;
1611  AVFrame img_out;
1612  if (v4l2_pixelformat == V4L2_PIX_FMT_YUYV ||
1613  v4l2_pixelformat == V4L2_PIX_FMT_UYVY)
1614  {
1615  AVPixelFormat in_pixfmt = v4l2_pixelformat == V4L2_PIX_FMT_YUYV ?
1616  AV_PIX_FMT_YUYV422 :
1617  AV_PIX_FMT_UYVY422;
1618 
1619  output_buffer = (uint8_t*)av_malloc(height * width * 3 / 2);
1620  if (!output_buffer)
1621  {
1622  _error = "Cannot initialize image conversion buffer";
1623  LOG(VB_GENERAL, LOG_ERR, LOC + _error);
1624  return;
1625  }
1626 
1627  convert_ctx = sws_getCachedContext(convert_ctx, width, height, in_pixfmt,
1628  width, height, AV_PIX_FMT_YUV420P,
1629  SWS_FAST_BILINEAR, nullptr, nullptr, nullptr);
1630  if (!convert_ctx)
1631  {
1632  _error = "Cannot initialize image conversion context";
1633  av_free(output_buffer);
1634  LOG(VB_GENERAL, LOG_ERR, LOC + _error);
1635  return;
1636  }
1637 
1638  av_image_fill_arrays(img_out.data, img_out.linesize,
1639  output_buffer, AV_PIX_FMT_YUV420P, width, height, IMAGE_ALIGN);
1640  }
1641 
1642  while (IsRecordingRequested() && !IsErrored())
1643  {
1644 again:
1645  {
1646  QMutexLocker locker(&pauseLock);
1647  if (request_pause)
1648  {
1649  if (!mainpaused)
1650  {
1651  mainpaused = true;
1652  pauseWait.wakeAll();
1653  if (IsPaused(true) && tvrec)
1654  tvrec->RecorderPaused();
1655  }
1656  unpauseWait.wait(&pauseLock, 100);
1657  if (cleartimeonpause)
1658  gettimeofday(&stm, &tzone);
1659  continue;
1660  }
1661 
1662  if (!request_pause && mainpaused)
1663  {
1664  mainpaused = false;
1665  unpauseWait.wakeAll();
1666  }
1667  }
1668 
1669  if (resetcapture)
1670  {
1671  LOG(VB_GENERAL, LOG_ERR, LOC + "Resetting and re-queueing");
1672  turnon = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1673  if (ioctl(fd, VIDIOC_STREAMOFF, &turnon) < 0)
1674  LOG(VB_GENERAL, LOG_ERR, LOC + "unable to stop capture (VIDIOC_STREAMOFF failed) " + ENO);
1675 
1676  for (uint i = 0; i < numbuffers; i++)
1677  {
1678  memset(buffers[i], 0, bufferlen[i]);
1679  vbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1680  vbuf.index = i;
1681  if (ioctl(fd, VIDIOC_QBUF, &vbuf) < 0)
1682  LOG(VB_GENERAL, LOG_ERR, LOC + "unable to enqueue capture buffer (VIDIOC_QBUF failed) " + ENO);
1683  }
1684 
1685  if (ioctl(fd, VIDIOC_STREAMON, &turnon) < 0)
1686  LOG(VB_GENERAL, LOG_ERR, LOC + "unable to start capture (VIDIOC_STREAMON failed) " + ENO);
1687  resetcapture = false;
1688  }
1689 
1690  tv.tv_sec = 5;
1691  tv.tv_usec = 0;
1692  FD_ZERO(&rdset);
1693  FD_SET(fd, &rdset);
1694 
1695  switch (select(fd+1, &rdset, nullptr, nullptr, &tv))
1696  {
1697  case -1:
1698  if (errno == EINTR)
1699  goto again;
1700  LOG(VB_GENERAL, LOG_ERR, LOC + "select: " + ENO);
1701  continue;
1702  case 0:
1703  LOG(VB_GENERAL, LOG_INFO, LOC + "select timeout");
1704  continue;
1705  default: break;
1706  }
1707 
1708  memset(&vbuf, 0, sizeof(vbuf));
1709  vbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1710  vbuf.memory = V4L2_MEMORY_MMAP;
1711  if (ioctl(fd, VIDIOC_DQBUF, &vbuf) < 0)
1712  {
1713  LOG(VB_GENERAL, LOG_ERR, LOC + "DQBUF ioctl failed." + ENO);
1714 
1715  // EIO failed DQBUF de-tunes post 2.6.15.3 for cx88
1716  // EIO or EINVAL on bttv means we need to reset the buffers..
1717  if (errno == EIO && channelObj)
1718  {
1719  channelObj->Retune();
1720  resetcapture = true;
1721  continue;
1722  }
1723 
1724  if (errno == EIO || errno == EINVAL)
1725  {
1726  resetcapture = true;
1727  continue;
1728  }
1729 
1730  if (errno == EAGAIN)
1731  continue;
1732  }
1733 
1734  frame = vbuf.index;
1735  if (go7007)
1736  forcekey = vbuf.flags & V4L2_BUF_FLAG_KEYFRAME;
1737 
1738  if (!request_pause)
1739  {
1740  if (v4l2_pixelformat == V4L2_PIX_FMT_YUYV)
1741  {
1742  AVFrame img_in;
1743  av_image_fill_arrays(img_in.data, img_in.linesize,
1744  buffers[frame], AV_PIX_FMT_YUYV422, width, height,
1745  IMAGE_ALIGN);
1746  sws_scale(convert_ctx, img_in.data, img_in.linesize,
1747  0, height, img_out.data, img_out.linesize);
1748  BufferIt(output_buffer, video_buffer_size);
1749  }
1750  else if (v4l2_pixelformat == V4L2_PIX_FMT_UYVY)
1751  {
1752  AVFrame img_in;
1753  av_image_fill_arrays(img_in.data, img_in.linesize,
1754  buffers[frame], AV_PIX_FMT_UYVY422, width, height,
1755  IMAGE_ALIGN);
1756  sws_scale(convert_ctx, img_in.data, img_in.linesize,
1757  0, height, img_out.data, img_out.linesize);
1758  BufferIt(output_buffer, video_buffer_size);
1759  }
1760  else
1761  {
1762  // buffer the frame directly
1763  BufferIt(buffers[frame], vbuf.bytesused, forcekey);
1764  }
1765  }
1766 
1767  vbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1768  if (ioctl(fd, VIDIOC_QBUF, &vbuf) < 0)
1769  LOG(VB_GENERAL, LOG_ERR, LOC + "unable to enqueue capture buffer (VIDIOC_QBUF failed) " + ENO);
1770  }
1771 
1772  KillChildren();
1773 
1774  if (ioctl(fd, VIDIOC_STREAMOFF, &turnon) < 0)
1775  LOG(VB_GENERAL, LOG_ERR, LOC + "unable to stop capture (VIDIOC_STREAMOFF failed) " + ENO);
1776 
1777  for (uint i = 0; i < numbuffers; i++)
1778  {
1779  munmap(buffers[i], bufferlen[i]);
1780  }
1781 
1782  FinishRecording();
1783 
1784  av_free(output_buffer);
1785  sws_freeContext(convert_ctx);
1786 
1787  close(fd);
1788  close(channelfd);
1789 }
1790 #else // if !USING_V4L2
1791 void NuppelVideoRecorder::DoV4L2(void) {}
1792 #endif // !USING_V4L2
1793 
1794 #ifdef USING_V4L1
1796 {
1797  struct mjpeg_params bparm;
1798 
1799  if (ioctl(fd, MJPIOC_G_PARAMS, &bparm) < 0)
1800  {
1801  LOG(VB_GENERAL, LOG_ERR, LOC + "MJPIOC_G_PARAMS: " + ENO);
1802  return;
1803  }
1804 
1805  //bparm.input = 2;
1806  //bparm.norm = 1;
1807  bparm.quality = hmjpg_quality;
1808 
1810  {
1811  bparm.decimation = hmjpg_hdecimation;
1812  }
1813  else
1814  {
1815  bparm.decimation = 0;
1816  bparm.HorDcm = hmjpg_hdecimation;
1817  bparm.VerDcm = (hmjpg_vdecimation + 1) / 2;
1818 
1819  if (hmjpg_vdecimation == 1)
1820  {
1821  bparm.TmpDcm = 1;
1822  bparm.field_per_buff = 2;
1823  }
1824  else
1825  {
1826  bparm.TmpDcm = 2;
1827  bparm.field_per_buff = 1;
1828  }
1829 
1830  bparm.img_width = hmjpg_maxw;
1831 
1832  if (ntsc)
1833  bparm.img_height = 240;
1834  else
1835  bparm.img_height = 288;
1836 
1837  bparm.img_x = 0;
1838  bparm.img_y = 0;
1839  }
1840 
1841  bparm.APPn = 0;
1842 
1843  if (hmjpg_vdecimation == 1)
1844  bparm.APP_len = 14;
1845  else
1846  bparm.APP_len = 0;
1847 
1848  bparm.odd_even = !(hmjpg_vdecimation > 1);
1849 
1850  for (int n = 0; n < bparm.APP_len; n++)
1851  bparm.APP_data[n] = 0;
1852 
1853  if (ioctl(fd, MJPIOC_S_PARAMS, &bparm) < 0)
1854  {
1855  LOG(VB_GENERAL, LOG_DEBUG, LOC + "MJPIOC_S_PARAMS: " + ENO);
1856  return;
1857  }
1858 
1859  struct mjpeg_requestbuffers breq;
1860 
1861  breq.count = 64;
1862  breq.size = 256 * 1024;
1863 
1864  if (ioctl(fd, MJPIOC_REQBUFS, &breq) < 0)
1865  {
1866  LOG(VB_GENERAL, LOG_DEBUG, LOC + "MJPIOC_REQBUFS: " + ENO);
1867  return;
1868  }
1869 
1870  uint8_t *MJPG_buff = (uint8_t *)mmap(0, breq.count * breq.size,
1871  PROT_READ|PROT_WRITE, MAP_SHARED, fd,
1872  0);
1873 
1874  if (MJPG_buff == MAP_FAILED)
1875  {
1876  LOG(VB_GENERAL, LOG_ERR, LOC + "mapping mjpeg buffers");
1877  return;
1878  }
1879 
1880  struct mjpeg_sync bsync;
1881 
1882  for (unsigned int count = 0; count < breq.count; count++)
1883  {
1884  if (ioctl(fd, MJPIOC_QBUF_CAPT, &count) < 0)
1885  LOG(VB_GENERAL, LOG_ERR, LOC + "MJPIOC_QBUF_CAPT: " + ENO);
1886  }
1887 
1888  while (IsRecordingRequested() && !IsErrored())
1889  {
1890  {
1891  QMutexLocker locker(&pauseLock);
1892  if (request_pause)
1893  {
1894  if (!mainpaused)
1895  {
1896  mainpaused = true;
1897  pauseWait.wakeAll();
1898  if (IsPaused(true) && tvrec)
1899  tvrec->RecorderPaused();
1900  }
1901  unpauseWait.wait(&pauseLock, 100);
1902  if (cleartimeonpause)
1903  gettimeofday(&stm, &tzone);
1904  continue;
1905  }
1906 
1907  if (!request_pause && mainpaused)
1908  {
1909  mainpaused = false;
1910  unpauseWait.wakeAll();
1911  }
1912  }
1913 
1914  if (ioctl(fd, MJPIOC_SYNC, &bsync) < 0)
1915  {
1916  _error = "MJPEG sync error";
1917  LOG(VB_GENERAL, LOG_ERR, LOC + _error + ENO);
1918  break;
1919  }
1920 
1921  BufferIt((unsigned char *)(MJPG_buff + bsync.frame * breq.size),
1922  bsync.length);
1923 
1924  if (ioctl(fd, MJPIOC_QBUF_CAPT, &(bsync.frame)) < 0)
1925  {
1926  _error = "MJPEG Capture error";
1927  LOG(VB_GENERAL, LOG_ERR, LOC + _error + ENO);
1928  }
1929  }
1930 
1931  munmap(MJPG_buff, breq.count * breq.size);
1932  KillChildren();
1933 
1934  FinishRecording();
1935 
1936  close(fd);
1937 }
1938 #else // if !USING_V4L1
1939 void NuppelVideoRecorder::DoMJPEG(void) {}
1940 #endif // !USING_V4L1
1941 
1943 {
1944  {
1945  QMutexLocker locker(&pauseLock);
1946  request_helper = false;
1947  unpauseWait.wakeAll();
1948  }
1949 
1950  if (write_thread)
1951  {
1952  write_thread->wait();
1953  delete write_thread;
1954  write_thread = nullptr;
1955  }
1956 
1957  if (audio_thread)
1958  {
1959  audio_thread->wait();
1960  delete audio_thread;
1961  audio_thread = nullptr;
1962  }
1963 
1964  if (vbi_thread)
1965  {
1966  vbi_thread->wait();
1967  delete vbi_thread;
1968  vbi_thread = nullptr;
1969  CloseVBIDevice();
1970  }
1971 }
1972 
1973 void NuppelVideoRecorder::BufferIt(unsigned char *buf, int len, bool forcekey)
1974 {
1975  int act;
1976  long tcres;
1977  struct timeval now;
1978 
1979  act = act_video_buffer;
1980 
1981  if (!videobuffer[act]->freeToBuffer) {
1982  return;
1983  }
1984 
1985  gettimeofday(&now, &tzone);
1986 
1987  tcres = (now.tv_sec-stm.tv_sec)*1000 + now.tv_usec/1000 - stm.tv_usec/1000;
1988 
1989  usebttv = 0;
1990  // here is the non preferable timecode - drop algorithm - fallback
1991  if (!usebttv)
1992  {
1993  if (tf==0)
1994  tf = 2;
1995  else
1996  {
1997  int fn = tcres - oldtc;
1998 
1999  // the difference should be less than 1,5*timeperframe or we have
2000  // missed at least one frame, this code might be inaccurate!
2001 
2002  if (ntsc_framerate)
2003  fn = (fn+16)/33;
2004  else
2005  fn = (fn+20)/40;
2006  if (fn<1)
2007  fn=1;
2008  tf += 2*fn; // two fields
2009  }
2010  }
2011 
2012  oldtc = tcres;
2013 
2014  if (!videobuffer[act]->freeToBuffer)
2015  {
2016  LOG(VB_GENERAL, LOG_INFO, LOC +
2017  "DROPPED frame due to full buffer in the recorder.");
2018  return; // we can't buffer the current frame
2019  }
2020 
2021  videobuffer[act]->sample = tf;
2022 
2023  // record the time at the start of this frame.
2024  // 'tcres' is at the end of the frame, so subtract the right # of ms
2025  videobuffer[act]->timecode = (ntsc_framerate) ? (tcres - 33) : (tcres - 40);
2026 
2027  memcpy(videobuffer[act]->buffer, buf, len);
2028  videobuffer[act]->bufferlen = len;
2029  videobuffer[act]->forcekey = forcekey;
2030 
2031  videobuffer[act]->freeToBuffer = 0;
2032  act_video_buffer++;
2034  act_video_buffer = 0; // cycle to begin of buffer
2035  videobuffer[act]->freeToEncode = 1; // set last to prevent race
2036  return;
2037 }
2038 
2040 {
2041 #if HAVE_BIGENDIAN
2042  fh->timecode = bswap_32(fh->timecode);
2043  fh->packetlength = bswap_32(fh->packetlength);
2044 #endif
2046 }
2047 
2049 {
2050  if (newaspect == static_cast<double>(video_aspect))
2051  return;
2052 
2053  video_aspect = newaspect;
2054 
2055  struct rtframeheader frameheader;
2056  memset(&frameheader, 0, sizeof(frameheader));
2057 
2058  frameheader.frametype = 'S';
2059  frameheader.comptype = 'M';
2060  frameheader.packetlength = sizeof(struct rtfileheader);
2061 
2062  WriteFrameheader(&frameheader);
2063 
2064  WriteFileHeader();
2065 }
2066 
2068 {
2069  struct rtfileheader fileheader;
2070  static const char finfo[12] = "MythTVVideo";
2071  static const char vers[5] = "0.07";
2072 
2073  memset(&fileheader, 0, sizeof(fileheader));
2074  memcpy(fileheader.finfo, finfo, sizeof(fileheader.finfo));
2075  memcpy(fileheader.version, vers, sizeof(fileheader.version));
2076  fileheader.width = w_out;
2077  fileheader.height = (int)(h_out * height_multiplier);
2078  fileheader.desiredwidth = 0;
2079  fileheader.desiredheight = 0;
2080  fileheader.pimode = 'P';
2081  fileheader.aspect = video_aspect;
2082  fileheader.fps = video_frame_rate;
2083  fileheader.fps *= framerate_multiplier;
2084  fileheader.videoblocks = -1;
2085  fileheader.audioblocks = -1;
2086  fileheader.textsblocks = -1; // TODO: make only -1 if VBI support active?
2087  fileheader.keyframedist = KEYFRAMEDIST;
2088 
2089 #if HAVE_BIGENDIAN
2090  fileheader.width = bswap_32(fileheader.width);
2091  fileheader.height = bswap_32(fileheader.height);
2092  fileheader.desiredwidth = bswap_32(fileheader.desiredwidth);
2093  fileheader.desiredheight = bswap_32(fileheader.desiredheight);
2094  fileheader.aspect = bswap_dbl(fileheader.aspect);
2095  fileheader.fps = bswap_dbl(fileheader.fps);
2096  fileheader.videoblocks = bswap_32(fileheader.videoblocks);
2097  fileheader.audioblocks = bswap_32(fileheader.audioblocks);
2098  fileheader.textsblocks = bswap_32(fileheader.textsblocks);
2099  fileheader.keyframedist = bswap_32(fileheader.keyframedist);
2100 #endif
2101  ringBuffer->Write(&fileheader, FILEHEADERSIZE);
2102 }
2103 
2105 {
2106  struct rtframeheader frameheader;
2107 
2108  if (!videoFilters)
2109  InitFilters();
2110 
2111  WriteFileHeader();
2112 
2113  memset(&frameheader, 0, sizeof(frameheader));
2114  frameheader.frametype = 'D'; // compressor data
2115 
2116  if (useavcodec)
2117  {
2118  frameheader.comptype = 'F';
2119  frameheader.packetlength = mpa_vidctx->extradata_size;
2120 
2121  WriteFrameheader(&frameheader);
2122  ringBuffer->Write(mpa_vidctx->extradata, frameheader.packetlength);
2123  }
2124  else
2125  {
2126  static unsigned long int tbls[128];
2127 
2128  frameheader.comptype = 'R'; // compressor data for RTjpeg
2129  frameheader.packetlength = sizeof(tbls);
2130 
2131  // compression configuration header
2132  WriteFrameheader(&frameheader);
2133 
2134  memset(tbls, 0, sizeof(tbls));
2135  ringBuffer->Write(tbls, sizeof(tbls));
2136  }
2137 
2138  memset(&frameheader, 0, sizeof(frameheader));
2139  frameheader.frametype = 'X'; // extended data
2140  frameheader.packetlength = sizeof(extendeddata);
2141 
2142  // extended data header
2143  WriteFrameheader(&frameheader);
2144 
2145  struct extendeddata moredata;
2146  memset(&moredata, 0, sizeof(extendeddata));
2147 
2148  moredata.version = 1;
2149  if (useavcodec)
2150  {
2151  int vidfcc = 0;
2152  switch(mpa_vidcodec->id)
2153  {
2154  case AV_CODEC_ID_MPEG4: vidfcc = FOURCC_DIVX; break;
2155  case AV_CODEC_ID_WMV1: vidfcc = FOURCC_WMV1; break;
2156  case AV_CODEC_ID_MSMPEG4V3: vidfcc = FOURCC_DIV3; break;
2157  case AV_CODEC_ID_MSMPEG4V2: vidfcc = FOURCC_MP42; break;
2158  case AV_CODEC_ID_MSMPEG4V1: vidfcc = FOURCC_MPG4; break;
2159  case AV_CODEC_ID_MJPEG: vidfcc = FOURCC_MJPG; break;
2160  case AV_CODEC_ID_H263: vidfcc = FOURCC_H263; break;
2161  case AV_CODEC_ID_H263P: vidfcc = FOURCC_H263; break;
2162  case AV_CODEC_ID_H263I: vidfcc = FOURCC_I263; break;
2163  case AV_CODEC_ID_MPEG1VIDEO: vidfcc = FOURCC_MPEG; break;
2164  case AV_CODEC_ID_MPEG2VIDEO: vidfcc = FOURCC_MPG2; break;
2165  case AV_CODEC_ID_HUFFYUV: vidfcc = FOURCC_HFYU; break;
2166  default: break;
2167  }
2168  moredata.video_fourcc = vidfcc;
2169  moredata.lavc_bitrate = mpa_vidctx->bit_rate;
2170  moredata.lavc_qmin = mpa_vidctx->qmin;
2171  moredata.lavc_qmax = mpa_vidctx->qmax;
2172  moredata.lavc_maxqdiff = mpa_vidctx->max_qdiff;
2173  }
2174  else
2175  {
2176  moredata.video_fourcc = FOURCC_RJPG;
2177  moredata.rtjpeg_quality = Q;
2178  moredata.rtjpeg_luma_filter = M1;
2179  moredata.rtjpeg_chroma_filter = M2;
2180  }
2181 
2182  if (compressaudio)
2183  {
2184  moredata.audio_fourcc = FOURCC_LAME;
2185  moredata.audio_compression_ratio = 11;
2186  moredata.audio_quality = mp3quality;
2187  }
2188  else
2189  {
2190  moredata.audio_fourcc = FOURCC_RAWA;
2191  }
2192 
2194  moredata.audio_channels = audio_channels;
2195  moredata.audio_bits_per_sample = audio_bits;
2196 
2198 
2199 #if HAVE_BIGENDIAN
2200  moredata.version = bswap_32(moredata.version);
2201  moredata.video_fourcc = bswap_32(moredata.video_fourcc);
2202  moredata.audio_fourcc = bswap_32(moredata.audio_fourcc);
2203  moredata.audio_sample_rate = bswap_32(moredata.audio_sample_rate);
2204  moredata.audio_bits_per_sample = bswap_32(moredata.audio_bits_per_sample);
2205  moredata.audio_channels = bswap_32(moredata.audio_channels);
2206  moredata.audio_compression_ratio = bswap_32(moredata.audio_compression_ratio);
2207  moredata.audio_quality = bswap_32(moredata.audio_quality);
2208  moredata.rtjpeg_quality = bswap_32(moredata.rtjpeg_quality);
2209  moredata.rtjpeg_luma_filter = bswap_32(moredata.rtjpeg_luma_filter);
2210  moredata.rtjpeg_chroma_filter = bswap_32(moredata.rtjpeg_chroma_filter);
2211  moredata.lavc_bitrate = bswap_32(moredata.lavc_bitrate);
2212  moredata.lavc_qmin = bswap_32(moredata.lavc_qmin);
2213  moredata.lavc_qmax = bswap_32(moredata.lavc_qmax);
2214  moredata.lavc_maxqdiff = bswap_32(moredata.lavc_maxqdiff);
2215  moredata.seektable_offset = bswap_64(moredata.seektable_offset);
2216  moredata.keyframeadjust_offset = bswap_64(moredata.keyframeadjust_offset);
2217 #endif
2218  ringBuffer->Write(&moredata, sizeof(moredata));
2219 
2220  last_block = 0;
2221  lf = 0; // that resets framenumber so that seeking in the
2222  // continues parts works too
2223 }
2224 
2226 {
2227  int numentries = seektable->size();
2228 
2229  struct rtframeheader frameheader;
2230  memset(&frameheader, 0, sizeof(frameheader));
2231  frameheader.frametype = 'Q'; // SeekTable
2232  frameheader.packetlength = sizeof(struct seektable_entry) * numentries;
2233 
2234  long long currentpos = ringBuffer->GetWritePosition();
2235 
2236  ringBuffer->Write(&frameheader, sizeof(frameheader));
2237 
2238  char *seekbuf = new char[frameheader.packetlength];
2239  int offset = 0;
2240 
2241  vector<struct seektable_entry>::iterator it = seektable->begin();
2242  for (; it != seektable->end(); ++it)
2243  {
2244  memcpy(seekbuf + offset, (const void *)&(*it),
2245  sizeof(struct seektable_entry));
2246  offset += sizeof(struct seektable_entry);
2247  }
2248 
2249  ringBuffer->Write(seekbuf, frameheader.packetlength);
2250 
2252  offsetof(struct extendeddata, seektable_offset),
2253  SEEK_SET);
2254 
2255  ringBuffer->Write(&currentpos, sizeof(long long));
2256 
2257  ringBuffer->WriterSeek(0, SEEK_END);
2258 
2259  delete [] seekbuf;
2260 }
2261 
2263  const vector<struct kfatable_entry> &kfa_table)
2264 {
2265  int numentries = kfa_table.size();
2266 
2267  struct rtframeheader frameheader;
2268  memset(&frameheader, 0, sizeof(frameheader));
2269  frameheader.frametype = 'K'; // KFA Table
2270  frameheader.packetlength = sizeof(struct kfatable_entry) * numentries;
2271 
2272  long long currentpos = ringBuffer->GetWritePosition();
2273 
2274  ringBuffer->Write(&frameheader, sizeof(frameheader));
2275 
2276  char *kfa_buf = new char[frameheader.packetlength];
2277  uint offset = 0;
2278 
2279  vector<struct kfatable_entry>::const_iterator it = kfa_table.begin();
2280  for (; it != kfa_table.end() ; ++it)
2281  {
2282  memcpy(kfa_buf + offset, &(*it),
2283  sizeof(struct kfatable_entry));
2284  offset += sizeof(struct kfatable_entry);
2285  }
2286 
2287  ringBuffer->Write(kfa_buf, frameheader.packetlength);
2288 
2289 
2291  offsetof(struct extendeddata, keyframeadjust_offset),
2292  SEEK_SET);
2293 
2294  ringBuffer->Write(&currentpos, sizeof(long long));
2295 
2296  ringBuffer->WriterSeek(0, SEEK_END);
2297 
2298  delete [] kfa_buf;
2299 }
2300 
2301 void NuppelVideoRecorder::UpdateSeekTable(int frame_num, long offset)
2302 {
2303  long long position = ringBuffer->GetWritePosition() + offset;
2304  struct seektable_entry ste;
2305  ste.file_offset = position;
2306  ste.keyframe_number = frame_num;
2307  seektable->push_back(ste);
2308 
2309  positionMapLock.lock();
2310  if (!positionMap.contains(ste.keyframe_number))
2311  {
2312  positionMapDelta[ste.keyframe_number] = position;
2313  positionMap[ste.keyframe_number] = position;
2314  lastPositionMapPos = position;
2315  }
2316  positionMapLock.unlock();
2317 }
2318 
2320 {
2321  framesWritten = 0;
2322 
2323  if (!ringBuffer)
2324  {
2325  LOG(VB_GENERAL, LOG_ERR, LOC +
2326  "No ringbuffer, recorder wasn't initialized.");
2327  return -1;
2328  }
2329 
2330  if (!ringBuffer->IsOpen())
2331  {
2332  LOG(VB_GENERAL, LOG_ERR, LOC + "Ringbuffer isn't open");
2333  return -1;
2334  }
2335 
2336  WriteHeader();
2337 
2338  return 0;
2339 }
2340 
2342 {
2343  ResetForNewFile();
2344 
2345  for (int i = 0; i < video_buffer_count; i++)
2346  {
2347  vidbuffertype *vidbuf = videobuffer[i];
2348  vidbuf->sample = 0;
2349  vidbuf->timecode = 0;
2350  vidbuf->freeToEncode = 0;
2351  vidbuf->freeToBuffer = 1;
2352  vidbuf->forcekey = 0;
2353  }
2354 
2355  for (int i = 0; i < audio_buffer_count; i++)
2356  {
2357  audbuffertype *audbuf = audiobuffer[i];
2358  audbuf->sample = 0;
2359  audbuf->timecode = 0;
2360  audbuf->freeToEncode = 0;
2361  audbuf->freeToBuffer = 1;
2362  }
2363 
2364  for (int i = 0; i < text_buffer_count; i++)
2365  {
2366  txtbuffertype *txtbuf = textbuffer[i];
2367  txtbuf->freeToEncode = 0;
2368  txtbuf->freeToBuffer = 1;
2369  }
2370 
2371  act_video_encode = 0;
2372  act_video_buffer = 0;
2373  act_audio_encode = 0;
2374  act_audio_buffer = 0;
2375  act_audio_sample = 0;
2376  act_text_encode = 0;
2377  act_text_buffer = 0;
2378 
2379  audiobytes = 0;
2380  effectivedsp = 0;
2381 
2382  if (useavcodec)
2384 
2385  if (curRecording)
2387 }
2388 
2390 {
2391  if (!audio_device)
2392  {
2393  LOG(VB_GENERAL, LOG_ERR, LOC +
2394  QString("Invalid audio device (%1), exiting").arg(audiodevice));
2395  return;
2396  }
2397 
2399  {
2400  LOG(VB_GENERAL, LOG_ERR, LOC +
2401  QString("Failed to open audio device %1").arg(audiodevice));
2402  return;
2403  }
2404 
2405  if (!audio_device->Start())
2406  {
2407  LOG(VB_GENERAL, LOG_ERR, LOC +
2408  QString("Failed to start audio capture on %1").arg(audiodevice));
2409  return;
2410  }
2411 
2412  struct timeval anow;
2413  unsigned char *buffer = new unsigned char[audio_buffer_size];
2414  int act = 0, lastread = 0;
2416 
2417  while (IsHelperRequested() && !IsErrored())
2418  {
2419  {
2420  QMutexLocker locker(&pauseLock);
2421  if (request_pause)
2422  {
2423  if (!audiopaused)
2424  {
2425  audiopaused = true;
2426  pauseWait.wakeAll();
2427  if (IsPaused(true) && tvrec)
2428  tvrec->RecorderPaused();
2429  }
2430  unpauseWait.wait(&pauseLock, 100);
2431  continue;
2432  }
2433 
2434  if (!request_pause && audiopaused)
2435  {
2436  audiopaused = false;
2437  unpauseWait.wakeAll();
2438  }
2439  }
2440 
2441  if (!IsHelperRequested() || IsErrored())
2442  break;
2443 
2444  lastread = audio_device->GetSamples(buffer, audio_buffer_size);
2445  if (audio_buffer_size != lastread)
2446  {
2447  LOG(VB_GENERAL, LOG_ERR, LOC +
2448  QString("Short read, %1 of %2 bytes from ")
2449  .arg(lastread).arg(audio_buffer_size) + audiodevice);
2450  }
2451 
2452  /* record the current time */
2453  /* Don't assume that the sound device's record buffer is empty
2454  (like we used to.) Measure to see how much stuff is in there,
2455  and correct for it when calculating the timestamp */
2456  gettimeofday(&anow, &tzone);
2457  int bytes_read = max(audio_device->GetNumReadyBytes(), 0);
2458 
2459  act = act_audio_buffer;
2460 
2461  if (!audiobuffer[act]->freeToBuffer)
2462  {
2463  LOG(VB_GENERAL, LOG_ERR, LOC + "Ran out of free AUDIO buffers :-(");
2464  act_audio_sample++;
2465  continue;
2466  }
2467 
2468  audiobuffer[act]->sample = act_audio_sample;
2469 
2470  /* calculate timecode. First compute the difference
2471  between now and stm (start time) */
2472  audiobuffer[act]->timecode = (anow.tv_sec - stm.tv_sec) * 1000 +
2473  anow.tv_usec / 1000 - stm.tv_usec / 1000;
2474  /* We want the timestamp to point to the start of this
2475  audio chunk. So, subtract off the length of the chunk
2476  and the length of audio still in the capture buffer. */
2477  audiobuffer[act]->timecode -= (int)(
2478  (bytes_read + audio_buffer_size)
2479  * 1000.0 / (audio_samplerate * audio_bytes_per_sample));
2480 
2481  memcpy(audiobuffer[act]->buffer, buffer, audio_buffer_size);
2482 
2483  audiobuffer[act]->freeToBuffer = 0;
2484  act_audio_buffer++;
2486  act_audio_buffer = 0;
2487  audiobuffer[act]->freeToEncode = 1;
2488 
2489  act_audio_sample++;
2490  }
2491 
2492  delete [] buffer;
2493 
2494  if (audio_device->IsOpen())
2495  audio_device->Close();
2496 }
2497 
2498 #ifdef USING_V4L2
2500 {
2501  struct timeval tnow;
2502  gettimeofday(&tnow, &tzone);
2503 
2504  int act = act_text_buffer;
2505  if (!textbuffer[act]->freeToBuffer)
2506  {
2507  LOG(VB_GENERAL, LOG_ERR, LOC +
2508  QString("Teletext #%1: ran out of free TEXT buffers :-(").arg(act));
2509  return;
2510  }
2511 
2512  // calculate timecode:
2513  // compute the difference between now and stm (start time)
2514  textbuffer[act]->timecode = (tnow.tv_sec-stm.tv_sec) * 1000 +
2515  tnow.tv_usec/1000 - stm.tv_usec/1000;
2516  textbuffer[act]->pagenr = (vbidata->teletextpage.pgno << 16) +
2517  vbidata->teletextpage.subno;
2518 
2519  unsigned char *inpos = vbidata->teletextpage.data[0];
2520  unsigned char *outpos = textbuffer[act]->buffer;
2521  *outpos = 0;
2522  struct teletextsubtitle st;
2523  memset(&st, 0, sizeof(struct teletextsubtitle));
2524  unsigned char linebuf[VT_WIDTH + 1];
2525  unsigned char *linebufpos = linebuf;
2526 
2527  for (int y = 0; y < VT_HEIGHT; y++)
2528  {
2529  char c = ' ';
2530  char last_c = ' ';
2531  int hid = 0;
2532  int gfx = 0;
2533  int dbl = 0;
2534  int box = 0;
2535  int sep = 0;
2536  int hold = 0;
2537  int visible = 0;
2538  int fg = 7;
2539  int bg = 0;
2540 
2541  for (int x = 0; x < VT_WIDTH; ++x)
2542  {
2543  c = *inpos++;
2544  switch (c)
2545  {
2546  case 0x00 ... 0x07: /* alpha + fg color */
2547  fg = c & 7;
2548  gfx = 0;
2549  sep = 0;
2550  hid = 0;
2551  goto ctrl;
2552  case 0x08: /* flash */
2553  goto ctrl;
2554  case 0x09: /* steady */
2555  goto ctrl;
2556  case 0x0a: /* end box */
2557  box = 0;
2558  goto ctrl;
2559  case 0x0b: /* start box */
2560  box = 1;
2561  goto ctrl;
2562  case 0x0c: /* normal height */
2563  dbl = 0;
2564  goto ctrl;
2565  case 0x0d: /* double height */
2566  if (y < VT_HEIGHT-2) /* ignored on last 2 lines */
2567  {
2568  dbl = 1;
2569  }
2570  goto ctrl;
2571  case 0x10 ... 0x17: /* gfx + fg color */
2572  fg = c & 7;
2573  gfx = 1;
2574  hid = 0;
2575  goto ctrl;
2576  case 0x18: /* conceal */
2577  hid = 1;
2578  goto ctrl;
2579  case 0x19: /* contiguous gfx */
2580  hid = 0;
2581  sep = 0;
2582  goto ctrl;
2583  case 0x1a: /* separate gfx */
2584  sep = 1;
2585  goto ctrl;
2586  case 0x1c: /* black bf */
2587  bg = 0;
2588  goto ctrl;
2589  case 0x1d: /* new bg */
2590  bg = fg;
2591  goto ctrl;
2592  case 0x1e: /* hold gfx */
2593  hold = 1;
2594  goto ctrl;
2595  case 0x1f: /* release gfx */
2596  hold = 0;
2597  goto ctrl;
2598  case 0x0e: /* SO */
2599  goto ctrl;
2600  case 0x0f: /* SI */
2601  goto ctrl;
2602  case 0x1b: /* ESC */
2603  goto ctrl;
2604 
2605  ctrl:
2606  c = ' ';
2607  if (hold && gfx)
2608  c = last_c;
2609  break;
2610  }
2611  if (gfx)
2612  if ((c & 0xa0) == 0x20)
2613  {
2614  last_c = c;
2615  c += (c & 0x40) ? 32 : -32;
2616  }
2617  if (hid)
2618  c = ' ';
2619 
2620  if (visible || (c != ' '))
2621  {
2622  if (!visible)
2623  {
2624  st.row = y;
2625  st.col = x;
2626  st.dbl = dbl;
2627  st.fg = fg;
2628  st.bg = bg;
2629  linebufpos = linebuf;
2630  *linebufpos = 0;
2631  }
2632  *linebufpos++ = c;
2633  *linebufpos = 0;
2634  visible = 1;
2635  }
2636 
2637  (void) box;
2638  (void) sep;
2639  }
2640  if (visible)
2641  {
2642  st.len = linebufpos - linebuf + 1;;
2643  int max = 200;
2644  int bufsize = ((outpos - textbuffer[act]->buffer + 1) + st.len);
2645  if (bufsize > max)
2646  break;
2647  memcpy(outpos, &st, sizeof(st));
2648  outpos += sizeof(st);
2649  if (st.len < 42)
2650  {
2651  memcpy(outpos, linebuf, st.len);
2652  outpos += st.len;
2653  }
2654  else
2655  {
2656  memcpy(outpos, linebuf, 41);
2657  outpos += 41;
2658  }
2659  *outpos = 0;
2660  }
2661  }
2662 
2663  textbuffer[act]->bufferlen = outpos - textbuffer[act]->buffer + 1;
2664  textbuffer[act]->freeToBuffer = 0;
2665  act_text_buffer++;
2667  act_text_buffer = 0;
2668  textbuffer[act]->freeToEncode = 1;
2669 }
2670 #else // USING_V4L2
2671 void NuppelVideoRecorder::FormatTT(struct VBIData*) {}
2672 #endif // USING_V4L2
2673 
2675 {
2676  struct timeval tnow;
2677  gettimeofday (&tnow, &tzone);
2678 
2679  // calculate timecode:
2680  // compute the difference between now and stm (start time)
2681  int tc = (tnow.tv_sec - stm.tv_sec) * 1000 +
2682  tnow.tv_usec / 1000 - stm.tv_usec / 1000;
2683 
2684  ccd->FormatCC(tc, code1, code2);
2685 }
2686 
2687 void NuppelVideoRecorder::AddTextData(unsigned char *buf, int len,
2688  int64_t timecode, char /*type*/)
2689 {
2690  int act = act_text_buffer;
2691  if (!textbuffer[act]->freeToBuffer)
2692  {
2693  LOG(VB_GENERAL, LOG_ERR, LOC + QString("Teletext#%1").arg(act) +
2694  " ran out of free TEXT buffers :-(");
2695  return;
2696  }
2697 
2698  textbuffer[act]->timecode = timecode;
2699  memcpy(textbuffer[act]->buffer, buf, len);
2700  textbuffer[act]->bufferlen = len + sizeof(ccsubtitle);
2701 
2702  textbuffer[act]->freeToBuffer = 0;
2703  act_text_buffer++;
2705  act_text_buffer = 0;
2706  textbuffer[act]->freeToEncode = 1;
2707 }
2708 
2710 {
2711  while (IsHelperRequested() && !IsErrored())
2712  {
2713  {
2714  QMutexLocker locker(&pauseLock);
2715  if (request_pause)
2716  {
2717  if (!writepaused)
2718  {
2719  writepaused = true;
2720  pauseWait.wakeAll();
2721  if (IsPaused(true) && tvrec)
2722  tvrec->RecorderPaused();
2723  }
2724  unpauseWait.wait(&pauseLock, 100);
2725  continue;
2726  }
2727 
2728  if (!request_pause && writepaused)
2729  {
2730  writepaused = false;
2731  unpauseWait.wakeAll();
2732  }
2733  }
2734 
2735  if (!IsHelperRequested() || IsErrored())
2736  break;
2737 
2739 
2740  enum
2741  { ACTION_NONE,
2742  ACTION_VIDEO,
2743  ACTION_AUDIO,
2744  ACTION_TEXT
2745  } action = ACTION_NONE;
2746  int firsttimecode = -1;
2747 
2748  if (videobuffer[act_video_encode]->freeToEncode)
2749  {
2750  action = ACTION_VIDEO;
2751  firsttimecode = videobuffer[act_video_encode]->timecode;
2752  }
2753 
2754  if (audio_buffer_count &&
2755  audiobuffer[act_audio_encode]->freeToEncode &&
2756  (action == ACTION_NONE ||
2757  (audiobuffer[act_audio_encode]->timecode < firsttimecode)))
2758  {
2759  action = ACTION_AUDIO;
2760  firsttimecode = audiobuffer[act_audio_encode]->timecode;
2761  }
2762 
2763  if (text_buffer_count &&
2764  textbuffer[act_text_encode]->freeToEncode &&
2765  (action == ACTION_NONE ||
2766  (textbuffer[act_text_encode]->timecode < firsttimecode)))
2767  {
2768  action = ACTION_TEXT;
2769  }
2770 
2771  switch (action)
2772  {
2773  case ACTION_VIDEO:
2774  {
2775  VideoFrame frame;
2776  init(&frame,
2778  width, height, videobuffer[act_video_encode]->bufferlen);
2779 
2780  frame.frameNumber = videobuffer[act_video_encode]->sample;
2781  frame.timecode = videobuffer[act_video_encode]->timecode;
2782  frame.forcekey = videobuffer[act_video_encode]->forcekey;
2783 
2784  WriteVideo(&frame);
2785 
2786  videobuffer[act_video_encode]->sample = 0;
2787  videobuffer[act_video_encode]->freeToEncode = 0;
2788  videobuffer[act_video_encode]->freeToBuffer = 1;
2789  videobuffer[act_video_encode]->forcekey = 0;
2790  act_video_encode++;
2792  act_video_encode = 0;
2793  break;
2794  }
2795  case ACTION_AUDIO:
2796  {
2798  audiobuffer[act_audio_encode]->sample,
2799  audiobuffer[act_audio_encode]->timecode);
2800  if (IsErrored()) {
2801  LOG(VB_GENERAL, LOG_ERR, LOC +
2802  "ACTION_AUDIO cannot be completed due to error.");
2803  StopRecording();
2804  break;
2805  }
2806  audiobuffer[act_audio_encode]->sample = 0;
2807  audiobuffer[act_audio_encode]->freeToEncode = 0;
2808  audiobuffer[act_audio_encode]->freeToBuffer = 1;
2809  act_audio_encode++;
2811  act_audio_encode = 0;
2812  break;
2813  }
2814  case ACTION_TEXT:
2815  {
2817  textbuffer[act_text_encode]->bufferlen,
2818  textbuffer[act_text_encode]->timecode,
2819  textbuffer[act_text_encode]->pagenr);
2820  textbuffer[act_text_encode]->freeToEncode = 0;
2821  textbuffer[act_text_encode]->freeToBuffer = 1;
2822  act_text_encode++;
2824  act_text_encode = 0;
2825  break;
2826  }
2827  default:
2828  {
2829  usleep(100);
2830  break;
2831  }
2832  }
2833  }
2834 }
2835 
2837 {
2838  framesWritten = 0;
2839  lf = 0;
2840  last_block = 0;
2841 
2842  seektable->clear();
2843 
2844  ClearStatistics();
2845 
2846  positionMapLock.lock();
2847  positionMap.clear();
2848  positionMapDelta.clear();
2849  positionMapLock.unlock();
2850 
2851  if (go7007)
2852  resetcapture = true;
2853 }
2854 
2856 {
2857  CreateNuppelFile();
2858 }
2859 
2861 {
2863 
2864  WriteSeekTable();
2865 
2867 
2868  positionMapLock.lock();
2869  positionMap.clear();
2870  positionMapDelta.clear();
2871  positionMapLock.unlock();
2872 }
2873 
2874 void NuppelVideoRecorder::WriteVideo(VideoFrame *frame, bool skipsync,
2875  bool forcekey)
2876 {
2877  int tmp = 0;
2878  lzo_uint out_len = OUT_LEN;
2879  struct rtframeheader frameheader;
2880  int raw = 0, compressthis = compression;
2881  // cppcheck-suppress variableScope
2882  uint8_t *planes[3] = {
2883  frame->buf + frame->offsets[0],
2884  frame->buf + frame->offsets[1],
2885  frame->buf + frame->offsets[2] };
2886  int fnum = frame->frameNumber;
2887  long long timecode = frame->timecode;
2888 
2889  memset(&frameheader, 0, sizeof(frameheader));
2890 
2891  if (lf == 0)
2892  { // this will be triggered every new file
2893  lf = fnum;
2894  startnum = fnum;
2895  lasttimecode = 0;
2896  frameofgop = 0;
2897  forcekey = true;
2898  }
2899 
2900  // see if it's time for a seeker header, sync information and a keyframe
2901  frameheader.keyframe = frameofgop; // no keyframe defaulted
2902 
2903  bool wantkeyframe = forcekey;
2904 
2905  bool writesync = false;
2906 
2907  if (!go7007 && (((fnum-startnum)>>1) % keyframedist == 0 && !skipsync))
2908  writesync = true;
2909  else if (go7007 && frame->forcekey)
2910  writesync = true;
2911 
2912  if (writesync)
2913  {
2914  ringBuffer->Write("RTjjjjjjjjjjjjjjjjjjjjjjjj", FRAMEHEADERSIZE);
2915 
2916  UpdateSeekTable(((fnum - startnum) >> 1) / keyframedist);
2917 
2918  frameheader.frametype = 'S'; // sync frame
2919  frameheader.comptype = 'V'; // video sync information
2920  frameheader.filters = 0; // no filters applied
2921  frameheader.packetlength = 0; // no data packet
2922  frameheader.timecode = (fnum-startnum)>>1;
2923  // write video sync info
2924  WriteFrameheader(&frameheader);
2925  frameheader.frametype = 'S'; // sync frame
2926  frameheader.comptype = 'A'; // video sync information
2927  frameheader.filters = 0; // no filters applied
2928  frameheader.packetlength = 0; // no data packet
2929  frameheader.timecode = effectivedsp; // effective dsp frequency
2930  // write audio sync info
2931  WriteFrameheader(&frameheader);
2932 
2933  wantkeyframe = true;
2934  //ringBuffer->Sync();
2935  }
2936 
2937  if (wantkeyframe)
2938  {
2939  frameheader.keyframe=0;
2940  frameofgop=0;
2941  }
2942 
2943  if (videoFilters)
2944  videoFilters->ProcessFrame(frame);
2945 
2946  if (useavcodec)
2947  {
2948  MythAVFrame mpa_picture;
2949  AVPictureFill(mpa_picture, frame);
2950 
2951  if (wantkeyframe)
2952  mpa_picture->pict_type = AV_PICTURE_TYPE_I;
2953  else
2954  mpa_picture->pict_type = AV_PICTURE_TYPE_NONE;
2955 
2956  if (!hardware_encode)
2957  {
2958  AVPacket packet;
2959  av_init_packet(&packet);
2960  packet.data = (uint8_t *)strm;
2961  packet.size = frame->size;
2962 
2963  int got_packet = 0;
2964 
2965  QMutexLocker locker(avcodeclock);
2966  tmp = avcodec_encode_video2(mpa_vidctx, &packet, mpa_picture,
2967  &got_packet);
2968 
2969  if (tmp < 0 || !got_packet)
2970  {
2971  LOG(VB_GENERAL, LOG_ERR, LOC +
2972  "WriteVideo : avcodec_encode_video() failed");
2973  return;
2974  }
2975 
2976  tmp = packet.size;
2977  }
2978  }
2979  else
2980  {
2981  int freecount = 0;
2982  freecount = act_video_buffer > act_video_encode ?
2985 
2986  if (freecount < (video_buffer_count / 3))
2987  compressthis = 0; // speed up the encode process
2988 
2989  if (freecount < 5)
2990  raw = 1; // speed up the encode process
2991 
2992  if (transcoding)
2993  {
2994  raw = 0;
2995  compressthis = 1;
2996  }
2997 
2998  if (!raw)
2999  {
3000  if (wantkeyframe)
3001  rtjc->SetNextKey();
3002  tmp = rtjc->Compress(strm, planes);
3003  }
3004  else
3005  tmp = frame->size;
3006 
3007  // here is lzo compression afterwards
3008  if (compressthis)
3009  {
3010  int r = 0;
3011  if (raw)
3012  r = lzo1x_1_compress(frame->buf, frame->size,
3013  out, &out_len, wrkmem);
3014  else
3015  r = lzo1x_1_compress((unsigned char *)strm, tmp, out,
3016  &out_len, wrkmem);
3017  if (r != LZO_E_OK)
3018  {
3019  LOG(VB_GENERAL, LOG_ERR, LOC + "lzo compression failed");
3020  return;
3021  }
3022  }
3023  }
3024 
3025  frameheader.frametype = 'V'; // video frame
3026  frameheader.timecode = timecode;
3027  lasttimecode = frameheader.timecode;
3028  frameheader.filters = 0; // no filters applied
3029 
3030  // compr ends here
3031  if (useavcodec)
3032  {
3033  if (mpa_vidcodec->id == AV_CODEC_ID_RAWVIDEO)
3034  {
3035  frameheader.comptype = '0';
3036  frameheader.packetlength = frame->size;
3037  WriteFrameheader(&frameheader);
3038  ringBuffer->Write(frame->buf, frame->size);
3039  }
3040  else if (hardware_encode)
3041  {
3042  frameheader.comptype = '4';
3043  frameheader.packetlength = frame->size;
3044  WriteFrameheader(&frameheader);
3045  ringBuffer->Write(frame->buf, frame->size);
3046  }
3047  else
3048  {
3049  frameheader.comptype = '4';
3050  frameheader.packetlength = tmp;
3051  WriteFrameheader(&frameheader);
3052  ringBuffer->Write(strm, tmp);
3053  }
3054  }
3055  else if (compressthis == 0 || (tmp < (int)out_len))
3056  {
3057  if (!raw)
3058  {
3059  frameheader.comptype = '1'; // video compression: RTjpeg only
3060  frameheader.packetlength = tmp;
3061  WriteFrameheader(&frameheader);
3062  ringBuffer->Write(strm, tmp);
3063  }
3064  else
3065  {
3066  frameheader.comptype = '0'; // raw YUV420
3067  frameheader.packetlength = frame->size;
3068  WriteFrameheader(&frameheader);
3069  ringBuffer->Write(frame->buf, frame->size); // we write buf directly
3070  }
3071  }
3072  else
3073  {
3074  if (!raw)
3075  frameheader.comptype = '2'; // video compression: RTjpeg with lzo
3076  else
3077  frameheader.comptype = '3'; // raw YUV420 with lzo
3078  frameheader.packetlength = out_len;
3079  WriteFrameheader(&frameheader);
3080  ringBuffer->Write(out, out_len);
3081  }
3082 
3083  if (framesWritten == 0)
3084  SendMythSystemRecEvent("REC_STARTED_WRITING", curRecording);
3085 
3086  frameofgop++;
3087  framesWritten++;
3088 
3089  // now we reset the last frame number so that we can find out
3090  // how many frames we didn't get next time
3091  lf = fnum;
3092 }
3093 
3094 #if HAVE_BIGENDIAN
3095 static void bswap_16_buf(short int *buf, int buf_cnt, int audio_channels)
3096  __attribute__ ((unused)); /* <- suppress compiler warning */
3097 
3098 static void bswap_16_buf(short int *buf, int buf_cnt, int audio_channels)
3099 {
3100  for (int i = 0; i < audio_channels * buf_cnt; i++)
3101  buf[i] = bswap_16(buf[i]);
3102 }
3103 #endif
3104 
3105 void NuppelVideoRecorder::WriteAudio(unsigned char *buf, int fnum, int timecode)
3106 {
3107  struct rtframeheader frameheader;
3108 
3109  if (last_block == 0)
3110  {
3111  firsttc = -1;
3112  }
3113 
3114  if (last_block != 0)
3115  {
3116  if (fnum != (last_block+1))
3117  {
3118  audio_behind = fnum - (last_block+1);
3119  LOG(VB_RECORD, LOG_INFO, LOC + QString("audio behind %1 %2").
3120  arg(last_block).arg(fnum));
3121  }
3122  }
3123 
3124  frameheader.frametype = 'A'; // audio frame
3125  frameheader.timecode = timecode;
3126 
3127  if (firsttc == -1)
3128  {
3129  firsttc = timecode;
3130 #if 0
3131  LOG(VB_GENERAL, LOG_DEBUG, LOC +
3132  QString("first timecode=%1").arg(firsttc));
3133 #endif
3134  }
3135  else
3136  {
3137  timecode -= firsttc; // this is to avoid the lack between the beginning
3138  // of recording and the first timestamp, maybe we
3139  // can calculate the audio-video +-lack at the
3140  // beginning too
3141  double abytes = (double)audiobytes; // - (double)audio_buffer_size;
3142  // wrong guess ;-)
3143  // need seconds instead of msec's
3144  double mt = (double)timecode;
3145  if (mt > 0.0)
3146  {
3147  double eff = (abytes / mt) * (100000.0 / audio_bytes_per_sample);
3148  effectivedsp = (int)eff;
3149  }
3150  }
3151 
3152  if (compressaudio)
3153  {
3154  char mp3gapless[7200];
3155  int compressedsize = 0;
3156  int gaplesssize = 0;
3157  int lameret = 0;
3158 
3159  int sample_cnt = audio_buffer_size / audio_bytes_per_sample;
3160 
3161 #if HAVE_BIGENDIAN
3162  bswap_16_buf((short int*) buf, sample_cnt, audio_channels);
3163 #endif
3164 
3165  if (audio_channels == 2)
3166  {
3167  lameret = lame_encode_buffer_interleaved(
3168  gf, (short int*) buf, sample_cnt,
3169  (unsigned char*) mp3buf, mp3buf_size);
3170  }
3171  else
3172  {
3173  lameret = lame_encode_buffer(
3174  gf, (short int*) buf, (short int*) buf, sample_cnt,
3175  (unsigned char*) mp3buf, mp3buf_size);
3176  }
3177 
3178  if (lameret < 0)
3179  {
3180  LOG(VB_GENERAL, LOG_ERR, LOC +
3181  QString("lame error '%1'").arg(lameret));
3182  _error = QString("Audio Encoding Error '%1'")
3183  .arg(lameret);
3184  return;
3185  }
3186  compressedsize = lameret;
3187 
3188  lameret = lame_encode_flush_nogap(gf, (unsigned char *)mp3gapless,
3189  7200);
3190  if (lameret < 0)
3191  {
3192  LOG(VB_GENERAL, LOG_ERR, LOC +
3193  QString("lame error '%1'").arg(lameret));
3194  _error = QString("Audio Encoding Error '%1'")
3195  .arg(lameret);
3196  return;
3197  }
3198  gaplesssize = lameret;
3199 
3200  frameheader.comptype = '3'; // audio is compressed
3201  frameheader.packetlength = compressedsize + gaplesssize;
3202 
3203  if (frameheader.packetlength > 0)
3204  {
3205  WriteFrameheader(&frameheader);
3206  ringBuffer->Write(mp3buf, compressedsize);
3207  ringBuffer->Write(mp3gapless, gaplesssize);
3208  }
3210  }
3211  else
3212  {
3213  frameheader.comptype = '0'; // uncompressed audio
3214  frameheader.packetlength = audio_buffer_size;
3215 
3216  WriteFrameheader(&frameheader);
3218  audiobytes += audio_buffer_size; // only audio no header!!
3219  }
3220 
3221  // this will probably never happen and if there would be a
3222  // 'uncountable' video frame drop -> material==worthless
3223  if (audio_behind > 0)
3224  {
3225  LOG(VB_RECORD, LOG_INFO, LOC + "audio behind");
3226  frameheader.frametype = 'A'; // audio frame
3227  frameheader.comptype = 'N'; // output a nullframe with
3228  frameheader.packetlength = 0;
3229  WriteFrameheader(&frameheader);
3231  audio_behind--;
3232  }
3233 
3234  last_block = fnum;
3235 }
3236 
3237 void NuppelVideoRecorder::WriteText(unsigned char *buf, int len, int timecode,
3238  int pagenr)
3239 {
3240  struct rtframeheader frameheader;
3241 
3242  frameheader.frametype = 'T'; // text frame
3243  frameheader.timecode = timecode;
3244 
3245  if (VBIMode::PAL_TT == vbimode)
3246  {
3247  frameheader.comptype = 'T'; // european teletext
3248  frameheader.packetlength = len + 4;
3249  WriteFrameheader(&frameheader);
3250  union page_t {
3251  int32_t val32;
3252  struct { int8_t a,b,c,d; } val8;
3253  } v;
3254  v.val32 = pagenr;
3255  ringBuffer->Write(&v.val8.d, sizeof(int8_t));
3256  ringBuffer->Write(&v.val8.c, sizeof(int8_t));
3257  ringBuffer->Write(&v.val8.b, sizeof(int8_t));
3258  ringBuffer->Write(&v.val8.a, sizeof(int8_t));
3259  ringBuffer->Write(buf, len);
3260  }
3261  else if (VBIMode::NTSC_CC == vbimode)
3262  {
3263  frameheader.comptype = 'C'; // NTSC CC
3264  frameheader.packetlength = len;
3265 
3266  WriteFrameheader(&frameheader);
3267  ringBuffer->Write(buf, len);
3268  }
3269 }
3270 
3271 /* vim: set expandtab tabstop=4 shiftwidth=4: */
QString _error
non-empty iff irrecoverable recording error detected
Definition: dtvrecorder.h:162
int timecode
Definition: format.h:153
bool IsRecording(void) override
Tells whether the StartRecorder() loop is running.
int lavc_qmax
Definition: format.h:112
void start(QThread::Priority=QThread::InheritPriority)
Tell MThread to start running the thread in the near future.
Definition: mthread.cpp:295
#define FOURCC_I263
Definition: fourcc.h:97
lzo_byte out[OUT_LEN]
int audio_bits_per_sample
Definition: format.h:99
NVRWriteThread * write_thread
vector< struct audbuffertype * > audiobuffer
RingBuffer * ringBuffer
Definition: recorderbase.h:297
vector< struct vidbuffertype * > videobuffer
char version[5]
Definition: format.h:15
QWaitCondition unpauseWait
Definition: recorderbase.h:323
int textsblocks
Definition: format.h:26
void SetOption(const QString &name, const QString &value) override
Set an specific option.
Definition: v4lrecorder.cpp:71
void WriteFrameheader(rtframeheader *fh)
unsigned long length
void SetNextKey(void)
Definition: RTjpegN.cpp:3323
virtual int GetNumReadyBytes(void)=0
RecordingInfo * curRecording
Definition: recorderbase.h:316
void ResetForNewFile(void) override
int pgno
Definition: vt.h:38
int lavc_qmin
Definition: format.h:111
int sample
Definition: format.h:152
volatile bool request_helper
Definition: v4lrecorder.h:57
enum go7007_mpeg_video_standard mpeg_video_standard
Definition: go7007_myth.h:58
void AspectChange(uint ratio, long long frame)
Note a change in aspect ratio in the recordedmark table.
QMutex pauseLock
Definition: recorderbase.h:319
unsigned long frame
friend class VBIThread
Definition: v4lrecorder.h:25
bool LiveMode(void) const
Returns true if this RingBuffer has been assigned a LiveTVChain.
void WriterFlush(void)
Calls ThreadedFileWriter::Flush(void)
vbimode
Definition: vbilut.h:20
unsigned char fg
Definition: format.h:174
void WriteKeyFrameAdjustTable(const vector< struct kfatable_entry > &kfa_table)
#define LOC
int lavc_maxqdiff
Definition: format.h:113
struct AVFrame AVFrame
long long file_offset
Definition: format.h:125
#define FOURCC_H263
Definition: fourcc.h:94
#define MJPIOC_SYNC
long long GetFramesWritten(void) override
Returns number of frames written to disk.
int SetIntra(int *key, int *lm, int *cm)
Definition: RTjpegN.cpp:2749
#define VT_WIDTH
Definition: vt.h:4
bool wait(unsigned long time=ULONG_MAX)
Wait for the MThread to exit, with a maximum timeout.
Definition: mthread.cpp:312
virtual void Close(void)=0
void FinishRecording(void) override
Flushes the ringbuffer, and if this is not a live LiveTV recording saves the position map and filesiz...
void SetNewVideoParams(double newaspect)
QWaitCondition pauseWait
Definition: recorderbase.h:322
QString GetFilename(void) const
Returns name of file used by this RingBuffer.
unsigned char * buffer
Definition: format.h:145
char finfo[12]
Definition: format.h:14
int forcekey
Definition: format.h:147
char frametype
Definition: format.h:32
int lavc_bitrate
Definition: format.h:110
#define FOURCC_HFYU
Definition: fourcc.h:96
#define OUT_LEN
QWaitCondition recordingWait
Definition: recorderbase.h:328
void WriteAudio(unsigned char *buf, int fnum, int timecode)
QString videocodec
Definition: recorderbase.h:303
void CloseVBIDevice(void)
vector< struct seektable_entry > * seektable
unsigned int uint
Definition: compat.h:140
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
static RingBuffer * Create(const QString &xfilename, bool write, bool usereadahead=true, int timeout_ms=kDefaultOpenTimeout, bool stream_only=false)
Creates a RingBuffer instance.
Definition: ringbuffer.cpp:112
unsigned long count
unsigned char * buffer
Definition: format.h:165
int forcekey
hardware encoded .nuv
Definition: mythframe.h:60
bool IsErrored(void) override
Tells us whether an unrecoverable error has been encountered.
Definition: dtvrecorder.h:48
long long timecode
Definition: mythframe.h:49
enum FrameType_ VideoFrameType
static AudioInput * CreateDevice(const QByteArray &device)
Definition: audioinput.cpp:37
void WriteVideo(VideoFrame *frame, bool skipsync=false, bool forcekey=false)
Definition: format.h:123
bool MJPEGInit(void)
Determines MJPEG capture resolution.
NuppelVideoRecorder(TVRec *rec, ChannelBase *channel)
void ProcessFrame(VideoFrame *Frame, FrameScanType scan=kScan_Ignore)
int timecode
Definition: format.h:81
virtual void CheckForRingBufferSwitch(void)
If requested, switch to new RingBuffer/ProgramInfo objects.
void WriteText(unsigned char *buf, int len, int timecode, int pagenr)
int freeToBuffer
Definition: format.h:155
static guint32 * tmp
Definition: goom_core.c:35
void AddTextData(unsigned char *, int, int64_t, char) override
virtual bool IsHelperRequested(void) const
Definition: v4lrecorder.cpp:65
unsigned char r
Definition: ParseText.cpp:340
char pimode
Definition: format.h:20
int bufferlen
Definition: format.h:146
unsigned long long audiobytes
int timecode
Definition: format.h:142
void StartNewFile(void) override
char comptype
Definition: format.h:39
QMutex positionMapLock
Definition: recorderbase.h:339
int freeToEncode
Definition: format.h:143
#define FOURCC_MJPG
Definition: fourcc.h:98
unsigned char b
Definition: ParseText.cpp:340
static void init(VideoFrame *vf, VideoFrameType _codec, unsigned char *_buf, int _width, int _height, int _size, const int *p=nullptr, const int *o=nullptr, float _aspect=-1.0f, double _rate=-1.0f, int _aligned=64)
Definition: mythframe.h:109
#define IMAGE_ALIGN
Definition: mythconfig.h:19
#define KEYFRAMEDIST
int offsets[3]
Y, U, & V offsets.
Definition: mythframe.h:64
int audio_quality
Definition: format.h:104
#define GO7007IOC_S_BITRATE
Definition: go7007_myth.h:23
long long seektable_offset
Definition: format.h:115
double toDouble(void) const
Definition: recorderbase.h:40
#define MJPIOC_REQBUFS
int videoblocks
Definition: format.h:24
vector< struct txtbuffertype * > textbuffer
long long WriterSeek(long long pos, int whence, bool has_lock=false)
Calls ThreadedFileWriter::Seek(long long,int).
bool ntsc_framerate
Definition: recorderbase.h:307
#define RTJ_YUV420
Definition: RTjpegN.h:60
int AVPictureFill(AVFrame *pic, const VideoFrame *frame, AVPixelFormat fmt)
AVPictureFill Initialise AVFrame pic with content from VideoFrame frame.
Definition: mythavutil.cpp:65
unsigned char * buffer
Definition: format.h:156
AVContainer m_containerFormat
Definition: recorderbase.h:300
VERBOSE_PREAMBLE false
Definition: verbosedefs.h:85
Abstract base class for Video4Linux based recorders.
Definition: v4lrecorder.h:23
void FinishRecording(void) override
Flushes the ringbuffer, and if this is not a live LiveTV recording saves the position map and filesiz...
int OpenVBIDevice(void)
int version
Definition: format.h:94
TVRec * tvrec
Definition: recorderbase.h:296
#define close
Definition: compat.h:16
void SetOption(const QString &name, int value) override
handles the "wait_for_seqstart" option.
int desiredwidth
Definition: format.h:18
This is the coordinating class of the Recorder Subsystem.
Definition: tv_rec.h:150
bool request_recording
True if API call has requested a recording be [re]started.
Definition: recorderbase.h:325
static void clear(SettingsMap &cache, SettingsMap &overrides, const QString &myKey)
Definition: mythdb.cpp:830
void Initialize(void) override
This is called between SetOptionsFromProfile() and run() to initialize any devices,...
struct teletextsubtitle teletextsubtitle
void SetPositionMapType(MarkTypes type)
Set seektable type.
Definition: recorderbase.h:264
double video_frame_rate
Definition: recorderbase.h:308
static const uint16_t * d
void Reset(void) override
Reset the recorder to the startup state.
char filters
Definition: format.h:71
int Compress(int8_t *sp, uint8_t **planes)
Definition: RTjpegN.cpp:3328
QString audiodevice
Definition: v4lrecorder.h:45
QString GetSetting(const QString &key, const QString &defaultval="")
int freeToBuffer
Definition: format.h:144
void SetVideoFilters(QString &filters) override
Tells recorder which filters to use.
#define GO7007IOC_S_MPEG_PARAMS
Definition: go7007_myth.h:87
int SetSize(int *w, int *h)
Definition: RTjpegN.cpp:2713
void RecorderPaused(void)
This is a callback, called by the "recorder" instance when it has actually paused.
Definition: tv_rec.cpp:2966
FilterChain * LoadFilters(QString filters, VideoFrameType &inpixfmt, VideoFrameType &outpixfmt, int &width, int &height, int &bufsize, int max_threads=1)
#define GO7007_COMP_CLOSED_GOP
Definition: go7007_myth.h:45
long long frameNumber
Definition: mythframe.h:48
double aspect
Definition: format.h:22
virtual bool IsOpen(void) const =0
Returns true if open for either reading or writing.
#define FOURCC_RAWA
Definition: fourcc.h:83
void SendMythSystemRecEvent(const QString &msg, const RecordingInfo *pginfo)
int freeToEncode
Definition: format.h:154
unsigned char len
Definition: format.h:176
int rtjpeg_quality
Definition: format.h:106
#define FOURCC_LAME
Definition: fourcc.h:82
#define FOURCC_WMV1
Definition: fourcc.h:104
void FrameRateChange(uint framerate, long long frame)
Note a change in video frame rate in the recordedmark table.
void run(void) override
Runs the Qt event loop unless we have a QRunnable, in which case we run the runnable run instead.
void FormatCC(uint code1, uint code2) override
long long keyframeadjust_offset
Definition: format.h:117
unsigned char dbl
Definition: format.h:173
virtual int GetBlockSize(void)=0
int GetVideoFd(void) override
Returns file descriptor of recorder device.
const char * name
Definition: ParseText.cpp:339
#define FOURCC_RJPG
Definition: fourcc.h:103
#define ENO
This can be appended to the LOG args with "+".
Definition: mythlogging.h:99
void run(void) override
Runs the Qt event loop unless we have a QRunnable, in which case we run the runnable run instead.
bool isNonzero(void) const
Definition: recorderbase.h:41
int audio_compression_ratio
Definition: format.h:103
#define FOURCC_DIVX
Definition: fourcc.h:92
unsigned char data[VT_HEIGHT][VT_WIDTH]
Definition: vt.h:43
void * av_malloc(unsigned int size)
int audio_channels
Definition: format.h:100
void UpdateSeekTable(int frame_num, long offset=0)
#define FRAMEHEADERSIZE
Definition: format.h:135
void ClearStatistics(void) override
void StopRecording(void) override
StopRecording() signals to the recorder that it should stop recording and exit cleanly.
Definition: v4lrecorder.cpp:58
int SetFormat(int *format)
Definition: RTjpegN.cpp:2707
vt_page teletextpage
Definition: v4lrecorder.h:18
int sample
Definition: format.h:141
#define MJPIOC_QBUF_CAPT
FrameRate m_frameRate
Definition: recorderbase.h:314
void SetOptionsFromProfile(RecordingProfile *profile, const QString &videodev, const QString &audiodev, const QString &vbidev) override
Sets basic recorder options.
Definition: RTjpegN.h:64
int rtjpeg_luma_filter
Definition: format.h:107
int encoding_thread_count
Number of threads to use for MPEG-2 and MPEG-4 encoding.
#define GO7007IOC_S_COMP_PARAMS
Definition: go7007_myth.h:91
bool myth_nice(int val)
virtual bool Retune(void)
Definition: channelbase.h:87
#define VT_HEIGHT
Definition: vt.h:5
long long GetWritePosition(void) const
Returns how far into a ThreadedFileWriter file we have written.
int AudioInit(bool skipdevice=false)
#define FOURCC_MPG2
Definition: fourcc.h:101
#define LOG(_MASK_, _LEVEL_, _STRING_)
Definition: mythlogging.h:41
virtual bool Start(void)=0
void ResolutionChange(uint width, uint height, long long frame)
Note a change in video size in the recordedmark table.
Abstract class providing a generic interface to tuning hardware.
Definition: channelbase.h:31
QMutex * avcodeclock
This global variable is used to makes certain calls to avlib threadsafe.
int keyframedist
Definition: format.h:27
AVPixelFormat picture_format
int video_fourcc
Definition: format.h:95
int SetQuality(int *quality)
Definition: RTjpegN.cpp:2690
uint m_videoAspect
Definition: recorderbase.h:310
frm_pos_map_t positionMap
Definition: recorderbase.h:340
void FormatTT(struct VBIData *) override
lame_global_flags * gf
#define MAX_VIDEO_BUFFERS
char keyframe
Definition: format.h:68
#define FOURCC_MP42
Definition: fourcc.h:99
struct ccsubtitle ccsubtitle
void SetIntOption(RecordingProfile *profile, const QString &name)
Convenience function used to set integer options from a profile.
virtual int GetSamples(void *buf, uint nbytes)=0
#define MJPIOC_G_PARAMS
double fps
Definition: format.h:23
NVRAudioThread * audio_thread
int audio_sample_rate
Definition: format.h:98
void run(void) override
run() starts the recording process, and does not exit until the recording is complete.
AVCodecContext * mpa_vidctx
#define FOURCC_DIV3
Definition: fourcc.h:91
int Write(const void *buf, uint count)
Writes buffer to ThreadedFileWriter::Write(const void*,uint)
MythAVFrame little utility class that act as a safe way to allocate an AVFrame which can then be allo...
Definition: mythavutil.h:42
void av_free(void *ptr)
int audioblocks
Definition: format.h:25
int keyframe_number
Definition: format.h:126
#define FOURCC_MPG4
Definition: fourcc.h:102
static uint buffersize(VideoFrameType type, int width, int height, int _aligned=64)
Definition: mythframe.h:291
int subno
Definition: vt.h:38
struct extendeddata extendeddata
void FormatCC(int tc, int code1, int code2)
VBIThread * vbi_thread
Definition: v4lrecorder.h:54
void BufferIt(unsigned char *buf, int len=-1, bool forcekey=false)
frm_pos_map_t positionMapDelta
Definition: recorderbase.h:341
#define MJPIOC_S_PARAMS
unsigned char bg
Definition: format.h:175
static int comp(const void *va, const void *vb)
Definition: filter_vflip.c:54
unsigned long size
virtual bool Open(uint sample_bits, uint sample_rate, uint channels)=0
int rtjpeg_chroma_filter
Definition: format.h:108
bool IsPaused(bool holding_lock=false) const override
Returns true iff recorder is paused.
unsigned char * buf
Definition: mythframe.h:39
int height
Definition: format.h:17
char APP_data[60]
unsigned char col
Definition: format.h:172
#define FILEHEADERSIZE
Definition: format.h:136
QString videodevice
Definition: recorderbase.h:304
void ClearPositionMap(MarkTypes type) const
Definition: format.h:129
int width
Definition: format.h:16
#define FOURCC_MPEG
Definition: fourcc.h:100
int audio_fourcc
Definition: format.h:96
void Pause(bool clear=true) override
Pause tells recorder to pause, it should not block.
int freeToBuffer
Definition: format.h:164
int freeToEncode
Definition: format.h:163
int desiredheight
Definition: format.h:19
unsigned char row
Definition: format.h:171
int packetlength
Definition: format.h:83
virtual bool IsOpen(void)=0
bool request_pause
Definition: recorderbase.h:320
uint m_videoHeight
Definition: recorderbase.h:312
virtual bool IsRecordingRequested(void)
Tells us if StopRecording() has been called.