8 #if HAVE_SYS_SOUNDCARD_H 9 #include <sys/soundcard.h> 10 #elif HAVE_SOUNDCARD_H 11 #include <soundcard.h> 13 #include <sys/ioctl.h> 18 #include <QStringList> 45 #include "libswscale/swscale.h" 46 #include "libavutil/imgutils.h" 50 #include <linux/videodev2.h> 55 #include <linux/videodev.h> 58 #ifndef MJPIOC_S_PARAMS 64 #define KEYFRAMEDIST 30 66 #include "ringbuffer.h" 72 #define LOC QString("NVR(%1): ").arg(videodevice) 77 m_parent->doWriteThread();
84 m_parent->doAudioThread();
90 write_thread(nullptr), audio_thread(nullptr), recording(
false)
97 M1 = 0,
M2 = 0,
Q = 255;
175 seektable =
new vector<struct seektable_entry>;
206 memset(&
stm, 0,
sizeof(
struct timeval));
207 memset(&
tzone, 0,
sizeof(
struct timezone));
286 else if (opt ==
"height")
288 else if (opt ==
"rtjpegchromafilter")
290 else if (opt ==
"rtjpeglumafilter")
292 else if (opt ==
"rtjpegquality")
294 else if ((opt ==
"mpeg4bitrate") || (opt ==
"mpeg2bitrate"))
296 else if (opt ==
"scalebitrate")
298 else if (opt ==
"mpeg4maxquality")
305 else if (opt ==
"mpeg4minquality")
307 else if (opt ==
"mpeg4qualdiff")
309 else if (opt ==
"encodingthreadcount")
311 else if (opt ==
"mpeg4optionvhq")
318 else if (opt ==
"mpeg4option4mv")
325 else if (opt ==
"mpeg4optionidct")
328 mp4opts |= AV_CODEC_FLAG_INTERLACED_DCT;
330 mp4opts &= ~AV_CODEC_FLAG_INTERLACED_DCT;
332 else if (opt ==
"mpeg4optionime")
335 mp4opts |= AV_CODEC_FLAG_INTERLACED_ME;
337 mp4opts &= ~AV_CODEC_FLAG_INTERLACED_ME;
339 else if (opt ==
"hardwaremjpegquality")
341 else if (opt ==
"hardwaremjpeghdecimation")
343 else if (opt ==
"hardwaremjpegvdecimation")
345 else if (opt ==
"audiocompression")
347 else if (opt ==
"mp3quality")
349 else if (opt ==
"samplerate")
351 else if (opt ==
"audioframesize")
353 else if (opt ==
"pip_mode")
355 else if (opt ==
"inpixfmt")
357 else if (opt ==
"skipbtaudio")
359 else if (opt ==
"volume")
371 const QString &videodev,
372 const QString &audiodev,
373 const QString &vbidev)
384 setting =
tmp->getValue();
386 if (setting ==
"MPEG-4")
395 #ifdef USING_FFMPEG_THREADS 403 else if (setting ==
"MPEG-2")
409 #ifdef USING_FFMPEG_THREADS 413 else if (setting ==
"RTjpeg")
421 else if (setting ==
"Hardware MJPEG")
423 SetOption(
"videocodec",
"hardware-mjpeg");
431 LOG(VB_GENERAL, LOG_ERR,
LOC +
432 "Unknown video codec. " 433 "Please go into the TV Settings, Recording Profiles and " 434 "setup the four 'Software Encoders' profiles. " 435 "Assuming RTjpeg for now.");
446 setting =
tmp->getValue();
448 if (setting ==
"MP3")
454 else if (setting ==
"Uncompressed")
461 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Unknown audio codec");
526 mpa_vidcodec = avcodec_find_encoder_by_name(vcodec.constData());
530 LOG(VB_GENERAL, LOG_ERR,
LOC + QString(
"Video Codec not found: %1")
531 .arg(vcodec.constData()));
539 case AV_PIX_FMT_YUV420P:
540 case AV_PIX_FMT_YUV422P:
541 case AV_PIX_FMT_YUVJ420P:
545 LOG(VB_GENERAL, LOG_ERR,
LOC + QString(
"Unknown picture format: %1")
555 float diff = (
w_out *
h_out) / (640.0 * 480.0);
556 usebitrate = (int)(diff * usebitrate);
583 AVDictionary *
opts =
nullptr;
586 mpa_vidctx->bit_rate_tolerance = usebitrate * 100;
596 av_dict_set(&
opts,
"rc_strategy",
"2", 0);
597 av_dict_set(&
opts,
"b_strategy",
"0", 0);
605 av_dict_set(&
opts,
"rc_init_cplx",
"0", 0);
608 av_dict_set_int(&
opts,
"pred", FF_PRED_LEFT, 0);
610 mpa_vidctx->strict_std_compliance = FF_COMPLIANCE_UNOFFICIAL;
617 LOG(VB_GENERAL, LOG_ERR,
LOC + QString(
"Unable to open FFMPEG/%1 codec")
645 double aspectnum =
w_out / (double)tot_height;
648 if (aspectnum == 0.0)
650 else if (fabs(aspectnum - 1.3333333333333333) < 0.001)
652 else if (fabs(aspectnum - 1.7777777777777777) < 0.001)
654 else if (fabs(aspectnum - 2.21) < 0.001)
657 aspect = aspectnum * 1000000;
665 if (
w_out && tot_height &&
681 case 2398: den = 24000;
685 case 2998: den = 30000;
689 case 5995: den = 60000;
698 LOG(VB_RECORD, LOG_INFO,
LOC + QString(
"NVR: frame rate = %1")
708 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Failed to init audio input device");
724 case 2:
height = 240;
break;
725 case 4:
height = 120;
break;
726 default:
height = 480;
break;
733 case 2:
height = 288;
break;
734 case 4:
height = 144;
break;
735 default:
height = 576;
break;
742 LOG(VB_GENERAL, LOG_WARNING,
LOC +
"Warning, old RingBuffer creation");
748 _error =
"Could not open RingBuffer";
770 LOG(VB_GENERAL, LOG_ERR,
LOC +
771 QString(
"Failed to create audio device: %1") .arg(
audiodevice));
777 LOG(VB_GENERAL, LOG_ERR,
LOC +
778 QString(
"Failed to open audio device %1").arg(
audiodevice));
785 LOG(VB_GENERAL, LOG_ERR,
LOC +
786 QString(
"Failed to determine audio block size on %1," 795 LOG(VB_AUDIO, LOG_INFO,
LOC +
796 QString(
"Audio device %1 buffer size: %1 bytes")
803 lame_set_bWriteVbrTag(
gf, 0);
805 lame_set_compression_ratio(
gf, 11);
809 if ((
tmp = lame_init_params(
gf)) != 0)
811 LOG(VB_GENERAL, LOG_ERR,
LOC +
812 QString(
"AudioInit(): lame_init_params error %1").arg(
tmp));
818 LOG(VB_GENERAL, LOG_ERR,
LOC +
819 "AudioInit(): lame support requires 16bit audio");
841 bool we_opened_fd =
false;
846 init_fd = open(vdevice.constData(), O_RDWR);
851 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Can't open video device" +
ENO);
856 struct video_capability vc;
857 memset(&vc, 0,
sizeof(vc));
858 int ret = ioctl(init_fd, VIDIOCGCAP, &vc);
861 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Can't query V4L capabilities" +
ENO);
869 if (vc.maxwidth != 768 && vc.maxwidth != 640)
872 if (vc.type & VID_TYPE_MJPEG_ENCODER)
874 if (vc.maxwidth >= 768)
876 else if (vc.maxwidth >= 704)
884 LOG(VB_GENERAL, LOG_ERR,
LOC +
"MJPEG not supported by device");
894 QString tmpVideoFilterList;
903 tmpVideoFilterList =
"adjust";
984 for (
unsigned int i = 0; i <
videobuffer.size(); i++)
1004 fd = open(vdevice.constData(), O_RDWR);
1008 fd = open(vdevice.constData(), O_RDWR);
1027 struct v4l2_capability vcap;
1028 memset(&vcap, 0,
sizeof(vcap));
1030 if (ioctl(
channelfd, VIDIOC_QUERYCAP, &vcap) < 0)
1035 if (
usingv4l2 && !(vcap.capabilities & V4L2_CAP_VIDEO_CAPTURE))
1037 LOG(VB_GENERAL, LOG_ERR,
LOC +
1038 "Not a v4l2 capture device, falling back to v4l");
1042 if (
usingv4l2 && !(vcap.capabilities & V4L2_CAP_STREAMING))
1044 LOG(VB_GENERAL, LOG_ERR,
LOC +
1045 "Won't work with the streaming interface, falling back");
1049 if (vcap.card[0] ==
'B' && vcap.card[1] ==
'T' &&
1050 vcap.card[2] ==
'8' && vcap.card[4] ==
'8')
1053 QString driver = (
char *)vcap.driver;
1054 if (driver ==
"go7007")
1056 #endif // USING_V4L2 1061 if (lzo_init() != LZO_E_OK)
1063 LOG(VB_GENERAL, LOG_ERR,
LOC +
"lzo_init() failed, exiting");
1064 _error =
"lzo_init() failed, exiting";
1071 _error =
"Failed to open device";
1080 _error =
"Failed to set V4L2 format";
1107 _error = QString(
"Cannot open '%1' for writing")
1115 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Children are already alive");
1116 _error =
"Children are already alive";
1164 struct video_capability vc;
1165 struct video_mmap mm;
1166 struct video_mbuf vm;
1167 struct video_channel vchan;
1168 struct video_audio va;
1169 struct video_tuner vt;
1171 memset(&mm, 0,
sizeof(mm));
1172 memset(&vm, 0,
sizeof(vm));
1173 memset(&vchan, 0,
sizeof(vchan));
1174 memset(&va, 0,
sizeof(va));
1175 memset(&vt, 0,
sizeof(vt));
1176 memset(&vc, 0,
sizeof(vc));
1178 if (ioctl(
fd, VIDIOCGCAP, &vc) < 0)
1180 QString
tmp =
"VIDIOCGCAP: " +
ENO;
1182 LOG(VB_GENERAL, LOG_ERR,
tmp);
1187 int channelinput = 0;
1190 channelinput =
channelObj->GetCurrentInputNum();
1192 vchan.channel = channelinput;
1194 if (ioctl(
fd, VIDIOCGCHAN, &vchan) < 0)
1195 LOG(VB_GENERAL, LOG_ERR,
LOC +
"VIDIOCGCHAN: " +
ENO);
1203 if (ioctl(
fd, VIDIOCGAUDIO, &va) < 0)
1205 bool reports_audio = vchan.flags & VIDEO_VC_AUDIO;
1206 uint err_level = reports_audio ? VB_GENERAL : VB_AUDIO;
1208 LOG(err_level, LOG_ERR,
LOC +
"Failed to get audio" +
ENO);
1213 va.flags &= ~VIDEO_AUDIO_MUTE;
1214 va.volume =
volume * 65535 / 100;
1215 if (ioctl(
fd, VIDIOCSAUDIO, &va) < 0)
1216 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Failed to set audio" +
ENO);
1223 _error =
"MJPEG requested but not available.";
1231 if (ioctl(
fd, VIDIOCGMBUF, &vm) < 0)
1233 QString
tmp =
"VIDIOCGMBUF: " +
ENO;
1242 QString
tmp =
"need a minimum of 2 capture buffers";
1251 unsigned char *buf = (
unsigned char *)mmap(0, vm.size,
1252 PROT_READ|PROT_WRITE,
1255 if (buf == MAP_FAILED)
1257 QString
tmp =
"mmap: " +
ENO;
1267 mm.format = VIDEO_PALETTE_YUV422P;
1269 mm.format = VIDEO_PALETTE_YUV420P;
1272 if (ioctl(
fd, VIDIOCMCAPTURE, &mm)<0)
1273 LOG(VB_GENERAL, LOG_ERR,
LOC +
"VIDIOCMCAPTUREi0: " +
ENO);
1275 if (ioctl(
fd, VIDIOCMCAPTURE, &mm)<0)
1276 LOG(VB_GENERAL, LOG_ERR,
LOC +
"VIDIOCMCAPTUREi1: " +
ENO);
1308 if (ioctl(
fd, VIDIOCSYNC, &frame)<0)
1311 if (syncerrors == 10)
1312 LOG(VB_GENERAL, LOG_ERR,
LOC +
1313 "Multiple bttv errors, further messages supressed");
1314 else if (syncerrors < 10)
1315 LOG(VB_GENERAL, LOG_ERR,
LOC +
"VIDIOCSYNC: " +
ENO);
1323 if (ioctl(
fd, VIDIOCMCAPTURE, &mm)<0)
1324 LOG(VB_GENERAL, LOG_ERR,
LOC +
"VIDIOCMCAPTURE0: " +
ENO);
1328 if (ioctl(
fd, VIDIOCSYNC, &frame)<0)
1331 if (syncerrors == 10)
1332 LOG(VB_GENERAL, LOG_ERR,
LOC +
1333 "Multiple bttv errors, further messages supressed");
1334 else if (syncerrors < 10)
1335 LOG(VB_GENERAL, LOG_ERR,
LOC +
"VIDIOCSYNC: " +
ENO);
1342 if (ioctl(
fd, VIDIOCMCAPTURE, &mm)<0)
1343 LOG(VB_GENERAL, LOG_ERR,
LOC +
"VIDIOCMCAPTURE1: " +
ENO);
1346 munmap(buf, vm.size);
1354 #else // if !USING_V4L1 1356 #endif // !USING_V4L1 1361 struct v4l2_format vfmt;
1362 memset(&vfmt, 0,
sizeof(vfmt));
1364 vfmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1366 vfmt.fmt.pix.width =
width;
1367 vfmt.fmt.pix.height =
height;
1368 vfmt.fmt.pix.field = V4L2_FIELD_INTERLACED;
1371 vfmt.fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG;
1373 vfmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUV422P;
1375 vfmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUV420;
1377 if (ioctl(
fd, VIDIOC_S_FMT, &vfmt) < 0)
1380 vfmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
1382 if (ioctl(
fd, VIDIOC_S_FMT, &vfmt) < 0)
1385 vfmt.fmt.pix.pixelformat = V4L2_PIX_FMT_UYVY;
1386 if (ioctl(
fd, VIDIOC_S_FMT, &vfmt) < 0)
1388 LOG(VB_GENERAL, LOG_ERR,
LOC +
1389 "v4l2: Unable to set desired format");
1398 LOG(VB_GENERAL, LOG_ERR,
LOC +
1399 "v4l2: uyvy format supported, but yuv422 requested.");
1400 LOG(VB_GENERAL, LOG_ERR,
LOC +
1401 "v4l2: unfortunately, this converter hasn't been " 1402 "written yet, exiting");
1405 LOG(VB_RECORD, LOG_INFO,
LOC +
1406 "v4l2: format set, getting uyvy from v4l, converting");
1414 LOG(VB_GENERAL, LOG_ERR,
LOC +
1415 "v4l2: yuyv format supported, but yuv422 requested.");
1416 LOG(VB_GENERAL, LOG_ERR,
LOC +
1417 "v4l2: unfortunately, this converter hasn't been written " 1421 LOG(VB_RECORD, LOG_INFO,
LOC +
1422 "v4l2: format set, getting yuyv from v4l, converting");
1426 LOG(VB_RECORD, LOG_INFO,
LOC +
1427 "v4l2: format set, getting yuv420 from v4l");
1430 if (
width != (
int)vfmt.fmt.pix.width ||
1431 height != (
int)vfmt.fmt.pix.height)
1433 LOG(VB_RECORD, LOG_INFO,
LOC +
1434 QString(
"v4l2: resolution changed. requested %1x%2, using " 1437 .arg(vfmt.fmt.pix.width) .arg(vfmt.fmt.pix.height));
1446 #else // if !USING_V4L2 1448 #endif // !USING_V4L2 1451 #define MAX_VIDEO_BUFFERS 5 1454 struct v4l2_buffer vbuf;
1455 struct v4l2_requestbuffers vrbuf;
1456 struct v4l2_control vc;
1458 memset(&vbuf, 0,
sizeof(vbuf));
1459 memset(&vrbuf, 0,
sizeof(vrbuf));
1460 memset(&vc, 0,
sizeof(vc));
1462 vc.id = V4L2_CID_AUDIO_MUTE;
1465 if (ioctl(
fd, VIDIOC_S_CTRL, &vc) < 0)
1466 LOG(VB_GENERAL, LOG_ERR,
LOC +
1467 "VIDIOC_S_CTRL:V4L2_CID_AUDIO_MUTE: " +
ENO);
1476 comp.max_b_frames = 0;
1500 _error =
"Unable to set compression params";
1505 memset(&mpeg, 0,
sizeof(mpeg));
1514 _error =
"Unable to set MPEG params";
1523 usebitrate = (int)(diff * usebitrate);
1528 _error =
"Unable to set bitrate";
1538 vrbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1539 vrbuf.memory = V4L2_MEMORY_MMAP;
1540 vrbuf.count = numbuffers;
1542 if (ioctl(
fd, VIDIOC_REQBUFS, &vrbuf) < 0)
1544 _error =
"Not able to get any capture buffers, exiting";
1549 if (vrbuf.count < numbuffers)
1551 LOG(VB_GENERAL, LOG_INFO,
LOC +
1552 QString(
"Requested %1 buffers, but only %2 are available. " 1553 "Proceeding anyway").arg(numbuffers).arg(vrbuf.count));
1556 numbuffers = vrbuf.count;
1561 for (
uint i = 0; i < numbuffers; i++)
1563 vbuf.type = vrbuf.type;
1566 if (ioctl(
fd, VIDIOC_QUERYBUF, &vbuf) < 0)
1568 LOG(VB_GENERAL, LOG_ERR,
LOC +
1569 QString(
"unable to query capture buffer %1").arg(i));
1570 _error =
"Unable to query capture buffer";
1574 buffers[i] = (
unsigned char *)mmap(
nullptr, vbuf.length,
1575 PROT_READ|PROT_WRITE, MAP_SHARED,
1580 LOG(VB_GENERAL, LOG_ERR,
LOC +
"mmap: " +
ENO);
1581 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Memory map failed");
1582 _error =
"Memory map failed";
1585 bufferlen[i] = vbuf.length;
1588 for (
uint i = 0; i < numbuffers; i++)
1590 memset(
buffers[i], 0, bufferlen[i]);
1591 vbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1593 if (ioctl(
fd, VIDIOC_QBUF, &vbuf) < 0)
1594 LOG(VB_GENERAL, LOG_ERR,
LOC +
"unable to enqueue capture buffer (VIDIOC_QBUF failed) " +
ENO);
1597 int turnon = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1598 if (ioctl(
fd, VIDIOC_STREAMON, &turnon) < 0)
1599 LOG(VB_GENERAL, LOG_ERR,
LOC +
"unable to start capture (VIDIOC_STREAMON failed) " +
ENO);
1604 bool forcekey =
false;
1609 uint8_t *output_buffer =
nullptr;
1610 struct SwsContext *convert_ctx =
nullptr;
1616 AV_PIX_FMT_YUYV422 :
1622 _error =
"Cannot initialize image conversion buffer";
1627 convert_ctx = sws_getCachedContext(convert_ctx,
width,
height, in_pixfmt,
1629 SWS_FAST_BILINEAR,
nullptr,
nullptr,
nullptr);
1632 _error =
"Cannot initialize image conversion context";
1638 av_image_fill_arrays(img_out.data, img_out.linesize,
1671 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Resetting and re-queueing");
1672 turnon = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1673 if (ioctl(
fd, VIDIOC_STREAMOFF, &turnon) < 0)
1674 LOG(VB_GENERAL, LOG_ERR,
LOC +
"unable to stop capture (VIDIOC_STREAMOFF failed) " +
ENO);
1676 for (
uint i = 0; i < numbuffers; i++)
1678 memset(
buffers[i], 0, bufferlen[i]);
1679 vbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1681 if (ioctl(
fd, VIDIOC_QBUF, &vbuf) < 0)
1682 LOG(VB_GENERAL, LOG_ERR,
LOC +
"unable to enqueue capture buffer (VIDIOC_QBUF failed) " +
ENO);
1685 if (ioctl(
fd, VIDIOC_STREAMON, &turnon) < 0)
1686 LOG(VB_GENERAL, LOG_ERR,
LOC +
"unable to start capture (VIDIOC_STREAMON failed) " +
ENO);
1695 switch (select(
fd+1, &rdset,
nullptr,
nullptr, &tv))
1700 LOG(VB_GENERAL, LOG_ERR,
LOC +
"select: " +
ENO);
1703 LOG(VB_GENERAL, LOG_INFO,
LOC +
"select timeout");
1708 memset(&vbuf, 0,
sizeof(vbuf));
1709 vbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1710 vbuf.memory = V4L2_MEMORY_MMAP;
1711 if (ioctl(
fd, VIDIOC_DQBUF, &vbuf) < 0)
1713 LOG(VB_GENERAL, LOG_ERR,
LOC +
"DQBUF ioctl failed." +
ENO);
1724 if (errno == EIO || errno == EINVAL)
1730 if (errno == EAGAIN)
1736 forcekey = vbuf.flags & V4L2_BUF_FLAG_KEYFRAME;
1743 av_image_fill_arrays(img_in.data, img_in.linesize,
1746 sws_scale(convert_ctx, img_in.data, img_in.linesize,
1747 0,
height, img_out.data, img_out.linesize);
1753 av_image_fill_arrays(img_in.data, img_in.linesize,
1756 sws_scale(convert_ctx, img_in.data, img_in.linesize,
1757 0,
height, img_out.data, img_out.linesize);
1767 vbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1768 if (ioctl(
fd, VIDIOC_QBUF, &vbuf) < 0)
1769 LOG(VB_GENERAL, LOG_ERR,
LOC +
"unable to enqueue capture buffer (VIDIOC_QBUF failed) " +
ENO);
1774 if (ioctl(
fd, VIDIOC_STREAMOFF, &turnon) < 0)
1775 LOG(VB_GENERAL, LOG_ERR,
LOC +
"unable to stop capture (VIDIOC_STREAMOFF failed) " +
ENO);
1777 for (
uint i = 0; i < numbuffers; i++)
1779 munmap(
buffers[i], bufferlen[i]);
1785 sws_freeContext(convert_ctx);
1790 #else // if !USING_V4L2 1792 #endif // !USING_V4L2 1801 LOG(VB_GENERAL, LOG_ERR,
LOC +
"MJPIOC_G_PARAMS: " +
ENO);
1850 for (
int n = 0; n < bparm.
APP_len; n++)
1855 LOG(VB_GENERAL, LOG_DEBUG,
LOC +
"MJPIOC_S_PARAMS: " +
ENO);
1862 breq.
size = 256 * 1024;
1866 LOG(VB_GENERAL, LOG_DEBUG,
LOC +
"MJPIOC_REQBUFS: " +
ENO);
1870 uint8_t *MJPG_buff = (uint8_t *)mmap(0, breq.
count * breq.
size,
1871 PROT_READ|PROT_WRITE, MAP_SHARED,
fd,
1874 if (MJPG_buff == MAP_FAILED)
1876 LOG(VB_GENERAL, LOG_ERR,
LOC +
"mapping mjpeg buffers");
1882 for (
unsigned int count = 0; count < breq.
count; count++)
1885 LOG(VB_GENERAL, LOG_ERR,
LOC +
"MJPIOC_QBUF_CAPT: " +
ENO);
1916 _error =
"MJPEG sync error";
1926 _error =
"MJPEG Capture error";
1931 munmap(MJPG_buff, breq.
count * breq.
size);
1938 #else // if !USING_V4L1 1940 #endif // !USING_V4L1 1985 gettimeofday(&now, &
tzone);
1987 tcres = (now.tv_sec-
stm.tv_sec)*1000 + now.tv_usec/1000 -
stm.tv_usec/1000;
1997 int fn = tcres -
oldtc;
2016 LOG(VB_GENERAL, LOG_INFO,
LOC +
2017 "DROPPED frame due to full buffer in the recorder.");
2056 memset(&frameheader, 0,
sizeof(frameheader));
2070 static const char finfo[12] =
"MythTVVideo";
2071 static const char vers[5] =
"0.07";
2073 memset(&fileheader, 0,
sizeof(fileheader));
2090 fileheader.
width = bswap_32(fileheader.
width);
2095 fileheader.
fps = bswap_dbl(fileheader.
fps);
2113 memset(&frameheader, 0,
sizeof(frameheader));
2126 static unsigned long int tbls[128];
2134 memset(tbls, 0,
sizeof(tbls));
2138 memset(&frameheader, 0,
sizeof(frameheader));
2154 case AV_CODEC_ID_MPEG4: vidfcc =
FOURCC_DIVX;
break;
2155 case AV_CODEC_ID_WMV1: vidfcc =
FOURCC_WMV1;
break;
2156 case AV_CODEC_ID_MSMPEG4V3: vidfcc =
FOURCC_DIV3;
break;
2157 case AV_CODEC_ID_MSMPEG4V2: vidfcc =
FOURCC_MP42;
break;
2158 case AV_CODEC_ID_MSMPEG4V1: vidfcc =
FOURCC_MPG4;
break;
2159 case AV_CODEC_ID_MJPEG: vidfcc =
FOURCC_MJPG;
break;
2160 case AV_CODEC_ID_H263: vidfcc =
FOURCC_H263;
break;
2161 case AV_CODEC_ID_H263P: vidfcc =
FOURCC_H263;
break;
2162 case AV_CODEC_ID_H263I: vidfcc =
FOURCC_I263;
break;
2163 case AV_CODEC_ID_MPEG1VIDEO: vidfcc =
FOURCC_MPEG;
break;
2164 case AV_CODEC_ID_MPEG2VIDEO: vidfcc =
FOURCC_MPG2;
break;
2165 case AV_CODEC_ID_HUFFYUV: vidfcc =
FOURCC_HFYU;
break;
2230 memset(&frameheader, 0,
sizeof(frameheader));
2241 vector<struct seektable_entry>::iterator it =
seektable->begin();
2244 memcpy(seekbuf + offset, (
const void *)&(*it),
2263 const vector<struct kfatable_entry> &kfa_table)
2265 int numentries = kfa_table.size();
2268 memset(&frameheader, 0,
sizeof(frameheader));
2279 vector<struct kfatable_entry>::const_iterator it = kfa_table.begin();
2280 for (; it != kfa_table.end() ; ++it)
2282 memcpy(kfa_buf + offset, &(*it),
2325 LOG(VB_GENERAL, LOG_ERR,
LOC +
2326 "No ringbuffer, recorder wasn't initialized.");
2332 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Ringbuffer isn't open");
2393 LOG(VB_GENERAL, LOG_ERR,
LOC +
2394 QString(
"Invalid audio device (%1), exiting").arg(
audiodevice));
2400 LOG(VB_GENERAL, LOG_ERR,
LOC +
2401 QString(
"Failed to open audio device %1").arg(
audiodevice));
2407 LOG(VB_GENERAL, LOG_ERR,
LOC +
2408 QString(
"Failed to start audio capture on %1").arg(
audiodevice));
2412 struct timeval anow;
2414 int act = 0, lastread = 0;
2447 LOG(VB_GENERAL, LOG_ERR,
LOC +
2448 QString(
"Short read, %1 of %2 bytes from ")
2456 gettimeofday(&anow, &
tzone);
2463 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Ran out of free AUDIO buffers :-(");
2473 anow.tv_usec / 1000 -
stm.tv_usec / 1000;
2501 struct timeval tnow;
2502 gettimeofday(&tnow, &
tzone);
2507 LOG(VB_GENERAL, LOG_ERR,
LOC +
2508 QString(
"Teletext #%1: ran out of free TEXT buffers :-(").arg(act));
2514 textbuffer[act]->timecode = (tnow.tv_sec-
stm.tv_sec) * 1000 +
2515 tnow.tv_usec/1000 -
stm.tv_usec/1000;
2520 unsigned char *outpos =
textbuffer[act]->buffer;
2524 unsigned char linebuf[
VT_WIDTH + 1];
2525 unsigned char *linebufpos = linebuf;
2612 if ((c & 0xa0) == 0x20)
2615 c += (c & 0x40) ? 32 : -32;
2620 if (visible || (c !=
' '))
2629 linebufpos = linebuf;
2642 st.
len = linebufpos - linebuf + 1;;
2644 int bufsize = ((outpos -
textbuffer[act]->buffer + 1) + st.
len);
2647 memcpy(outpos, &st,
sizeof(st));
2648 outpos +=
sizeof(st);
2651 memcpy(outpos, linebuf, st.
len);
2656 memcpy(outpos, linebuf, 41);
2672 #endif // USING_V4L2 2676 struct timeval tnow;
2677 gettimeofday (&tnow, &
tzone);
2681 int tc = (tnow.tv_sec -
stm.tv_sec) * 1000 +
2682 tnow.tv_usec / 1000 -
stm.tv_usec / 1000;
2688 int64_t timecode,
char )
2693 LOG(VB_GENERAL, LOG_ERR,
LOC + QString(
"Teletext#%1").arg(act) +
2694 " ran out of free TEXT buffers :-(");
2746 int firsttimecode = -1;
2756 (
action == ACTION_NONE ||
2765 (
action == ACTION_NONE ||
2801 LOG(VB_GENERAL, LOG_ERR,
LOC +
2802 "ACTION_AUDIO cannot be completed due to error.");
2882 uint8_t *planes[3] = {
2889 memset(&frameheader, 0,
sizeof(frameheader));
2903 bool wantkeyframe = forcekey;
2905 bool writesync =
false;
2933 wantkeyframe =
true;
2952 mpa_picture->pict_type = AV_PICTURE_TYPE_I;
2954 mpa_picture->pict_type = AV_PICTURE_TYPE_NONE;
2959 av_init_packet(&packet);
2960 packet.data = (uint8_t *)
strm;
2961 packet.size = frame->
size;
2966 tmp = avcodec_encode_video2(
mpa_vidctx, &packet, mpa_picture,
2969 if (
tmp < 0 || !got_packet)
2971 LOG(VB_GENERAL, LOG_ERR,
LOC +
2972 "WriteVideo : avcodec_encode_video() failed");
3012 r = lzo1x_1_compress(frame->
buf, frame->
size,
3013 out, &out_len, wrkmem);
3015 r = lzo1x_1_compress((
unsigned char *)
strm,
tmp,
out,
3019 LOG(VB_GENERAL, LOG_ERR,
LOC +
"lzo compression failed");
3055 else if (compressthis == 0 || (
tmp < (
int)out_len))
3095 static void bswap_16_buf(
short int *buf,
int buf_cnt,
int audio_channels)
3096 __attribute__ ((unused));
3098 static void bswap_16_buf(
short int *buf,
int buf_cnt,
int audio_channels)
3100 for (
int i = 0; i < audio_channels * buf_cnt; i++)
3101 buf[i] = bswap_16(buf[i]);
3119 LOG(VB_RECORD, LOG_INFO,
LOC + QString(
"audio behind %1 %2").
3131 LOG(VB_GENERAL, LOG_DEBUG,
LOC +
3132 QString(
"first timecode=%1").arg(
firsttc));
3154 char mp3gapless[7200];
3155 int compressedsize = 0;
3156 int gaplesssize = 0;
3167 lameret = lame_encode_buffer_interleaved(
3168 gf, (
short int*) buf, sample_cnt,
3173 lameret = lame_encode_buffer(
3174 gf, (
short int*) buf, (
short int*) buf, sample_cnt,
3180 LOG(VB_GENERAL, LOG_ERR,
LOC +
3181 QString(
"lame error '%1'").arg(lameret));
3182 _error = QString(
"Audio Encoding Error '%1'")
3186 compressedsize = lameret;
3188 lameret = lame_encode_flush_nogap(
gf, (
unsigned char *)mp3gapless,
3192 LOG(VB_GENERAL, LOG_ERR,
LOC +
3193 QString(
"lame error '%1'").arg(lameret));
3194 _error = QString(
"Audio Encoding Error '%1'")
3198 gaplesssize = lameret;
3201 frameheader.
packetlength = compressedsize + gaplesssize;
3225 LOG(VB_RECORD, LOG_INFO,
LOC +
"audio behind");
3252 struct { int8_t a,
b,c,
d; } val8;
QString _error
non-empty iff irrecoverable recording error detected
bool IsRecording(void) override
Tells whether the StartRecorder() loop is running.
friend class NVRWriteThread
void start(QThread::Priority=QThread::InheritPriority)
Tell MThread to start running the thread in the near future.
int audio_bits_per_sample
NVRWriteThread * write_thread
vector< struct audbuffertype * > audiobuffer
vector< struct vidbuffertype * > videobuffer
QWaitCondition unpauseWait
void SetOption(const QString &name, const QString &value) override
Set an specific option.
void WriteFrameheader(rtframeheader *fh)
double framerate_multiplier
RecordingInfo * curRecording
void ResetForNewFile(void) override
volatile bool request_helper
enum go7007_mpeg_video_standard mpeg_video_standard
void AspectChange(uint ratio, long long frame)
Note a change in aspect ratio in the recordedmark table.
int CreateNuppelFile(void)
bool LiveMode(void) const
Returns true if this RingBuffer has been assigned a LiveTVChain.
void WriterFlush(void)
Calls ThreadedFileWriter::Flush(void)
void ResizeVideoBuffers(void)
void WriteKeyFrameAdjustTable(const vector< struct kfatable_entry > &kfa_table)
bool SetupAVCodecVideo(void)
long long prev_bframe_save_pos
long long GetFramesWritten(void) override
Returns number of frames written to disk.
int SetIntra(int *key, int *lm, int *cm)
bool wait(unsigned long time=ULONG_MAX)
Wait for the MThread to exit, with a maximum timeout.
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)
uint32_t v4l2_pixelformat
AudioInput * audio_device
QString GetFilename(void) const
Returns name of file used by this RingBuffer.
QWaitCondition recordingWait
void WriteAudio(unsigned char *buf, int fnum, int timecode)
void CloseVBIDevice(void)
vector< struct seektable_entry > * seektable
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.
int forcekey
hardware encoded .nuv
bool IsErrored(void) override
Tells us whether an unrecoverable error has been encountered.
enum FrameType_ VideoFrameType
void WriteVideo(VideoFrame *frame, bool skipsync=false, bool forcekey=false)
bool MJPEGInit(void)
Determines MJPEG capture resolution.
NuppelVideoRecorder(TVRec *rec, ChannelBase *channel)
void ProcessFrame(VideoFrame *Frame, FrameScanType scan=kScan_Ignore)
friend class NVRAudioThread
virtual void CheckForRingBufferSwitch(void)
If requested, switch to new RingBuffer/ProgramInfo objects.
void WriteText(unsigned char *buf, int len, int timecode, int pagenr)
void AddTextData(unsigned char *, int, int64_t, char) override
virtual bool IsHelperRequested(void) const
unsigned long long audiobytes
long long act_audio_sample
void StartNewFile(void) override
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)
void WriteFileHeader(void)
int offsets[3]
Y, U, & V offsets.
#define GO7007IOC_S_BITRATE
long long seektable_offset
double toDouble(void) const
vector< struct txtbuffertype * > textbuffer
long long WriterSeek(long long pos, int whence, bool has_lock=false)
Calls ThreadedFileWriter::Seek(long long,int).
int AVPictureFill(AVFrame *pic, const VideoFrame *frame, AVPixelFormat fmt)
AVPictureFill Initialise AVFrame pic with content from VideoFrame frame.
AVContainer m_containerFormat
int audio_bytes_per_sample
Abstract base class for Video4Linux based recorders.
void FinishRecording(void) override
Flushes the ringbuffer, and if this is not a live LiveTV recording saves the position map and filesiz...
void SetOption(const QString &name, int value) override
handles the "wait_for_seqstart" option.
This is the coordinating class of the Recorder Subsystem.
bool request_recording
True if API call has requested a recording be [re]started.
static void clear(SettingsMap &cache, SettingsMap &overrides, const QString &myKey)
void Initialize(void) override
This is called between SetOptionsFromProfile() and run() to initialize any devices,...
void SetPositionMapType(MarkTypes type)
Set seektable type.
static const uint16_t * d
void Reset(void) override
Reset the recorder to the startup state.
int Compress(int8_t *sp, uint8_t **planes)
QString GetSetting(const QString &key, const QString &defaultval="")
void SetVideoFilters(QString &filters) override
Tells recorder which filters to use.
#define GO7007IOC_S_MPEG_PARAMS
int SetSize(int *w, int *h)
void RecorderPaused(void)
This is a callback, called by the "recorder" instance when it has actually paused.
FilterChain * LoadFilters(QString filters, VideoFrameType &inpixfmt, VideoFrameType &outpixfmt, int &width, int &height, int &bufsize, int max_threads=1)
#define GO7007_COMP_CLOSED_GOP
virtual bool IsOpen(void) const =0
Returns true if open for either reading or writing.
void SendMythSystemRecEvent(const QString &msg, const RecordingInfo *pginfo)
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
int GetVideoFd(void) override
Returns file descriptor of recorder device.
#define ENO
This can be appended to the LOG args with "+".
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
int audio_compression_ratio
unsigned char data[VT_HEIGHT][VT_WIDTH]
void * av_malloc(unsigned int size)
void UpdateSeekTable(int frame_num, long offset=0)
void ClearStatistics(void) override
void StopRecording(void) override
StopRecording() signals to the recorder that it should stop recording and exit cleanly.
int SetFormat(int *format)
long long lastPositionMapPos
void StreamAllocate(void)
void SetOptionsFromProfile(RecordingProfile *profile, const QString &videodev, const QString &audiodev, const QString &vbidev) override
Sets basic recorder options.
int encoding_thread_count
Number of threads to use for MPEG-2 and MPEG-4 encoding.
#define GO7007IOC_S_COMP_PARAMS
virtual bool Retune(void)
long long GetWritePosition(void) const
Returns how far into a ThreadedFileWriter file we have written.
int AudioInit(bool skipdevice=false)
#define LOG(_MASK_, _LEVEL_, _STRING_)
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.
QMutex * avcodeclock
This global variable is used to makes certain calls to avlib threadsafe.
AVPixelFormat picture_format
int SetQuality(int *quality)
FilterChain * videoFilters
frm_pos_map_t positionMap
void FormatTT(struct VBIData *) override
#define MAX_VIDEO_BUFFERS
void SetIntOption(RecordingProfile *profile, const QString &name)
Convenience function used to set integer options from a profile.
NVRAudioThread * audio_thread
void run(void) override
run() starts the recording process, and does not exit until the recording is complete.
AVCodecContext * mpa_vidctx
int Write(const void *buf, uint count)
Writes buffer to ThreadedFileWriter::Write(const void*,uint)
MythAVFrame little utility class that act as a safe way to allocate an AVFrame which can then be allo...
static uint buffersize(VideoFrameType type, int width, int height, int _aligned=64)
void FormatCC(int tc, int code1, int code2)
void WriteSeekTable(void)
void BufferIt(unsigned char *buf, int len=-1, bool forcekey=false)
frm_pos_map_t positionMapDelta
void UpdateResolutions(void)
static int comp(const void *va, const void *vb)
bool IsPaused(bool holding_lock=false) const override
Returns true iff recorder is paused.
void ClearPositionMap(MarkTypes type) const
long long extendeddataOffset
void Pause(bool clear=true) override
Pause tells recorder to pause, it should not block.
virtual bool IsRecordingRequested(void)
Tells us if StopRecording() has been called.