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