00001 #include <cstdio>
00002 #include <cstdlib>
00003 #include <fcntl.h>
00004 #include <unistd.h>
00005 #include <sys/types.h>
00006 #include <sys/stat.h>
00007 #include "mythconfig.h"
00008 #if HAVE_SYS_SOUNDCARD_H
00009 #include <sys/soundcard.h>
00010 #elif HAVE_SOUNDCARD_H
00011 #include <soundcard.h>
00012 #endif
00013 #include <sys/ioctl.h>
00014 #include <sys/mman.h>
00015 #include <cerrno>
00016 #include <cmath>
00017
00018 #include <QStringList>
00019
00020 #include <iostream>
00021 using namespace std;
00022
00023 #include "mythmiscutil.h"
00024 #include "mythcontext.h"
00025 #include "NuppelVideoRecorder.h"
00026 #include "channelbase.h"
00027 #include "filtermanager.h"
00028 #include "recordingprofile.h"
00029 #include "tv_rec.h"
00030 #include "tv_play.h"
00031 #include "audioinput.h"
00032 #include "mythlogging.h"
00033 #include "vbitext/cc.h"
00034 #include "vbitext/vbi.h"
00035
00036 #if HAVE_BIGENDIAN
00037 extern "C" {
00038 #include "byteswap.h"
00039 }
00040 #endif
00041
00042 extern "C" {
00043 #include "libswscale/swscale.h"
00044 }
00045
00046 #ifdef USING_V4L2
00047 #include <linux/videodev2.h>
00048
00049 #include "go7007_myth.h"
00050
00051 #ifdef USING_V4L1
00052 #include <linux/videodev.h>
00053 #endif // USING_V4L1
00054
00055 #ifndef MJPIOC_S_PARAMS
00056 #include "videodev_mjpeg.h"
00057 #endif
00058
00059 #endif // USING_V4L2
00060
00061 #define KEYFRAMEDIST 30
00062
00063 #include "ringbuffer.h"
00064 #include "RTjpegN.h"
00065
00066 #include "programinfo.h"
00067
00068 #define LOC QString("NVR(%1): ").arg(videodevice)
00069
00070 void NVRWriteThread::run(void)
00071 {
00072 RunProlog();
00073 m_parent->doWriteThread();
00074 RunEpilog();
00075 }
00076
00077 void NVRAudioThread::run(void)
00078 {
00079 RunProlog();
00080 m_parent->doAudioThread();
00081 RunEpilog();
00082 }
00083
00084 NuppelVideoRecorder::NuppelVideoRecorder(TVRec *rec, ChannelBase *channel) :
00085 V4LRecorder(rec), audio_device(NULL),
00086 write_thread(NULL), audio_thread(NULL)
00087 {
00088 channelObj = channel;
00089
00090 fd = -1;
00091 channelfd = -1;
00092 lf = tf = 0;
00093 M1 = 0, M2 = 0, Q = 255;
00094 pid = pid2 = 0;
00095 inputchannel = 1;
00096 compression = 1;
00097 compressaudio = 1;
00098 usebttv = 1;
00099 width = 352;
00100 height = 240;
00101 pip_mode = 0;
00102 video_aspect = 1.33333;
00103
00104 skip_btaudio = false;
00105
00106 framerate_multiplier = 1.0;
00107 height_multiplier = 1.0;
00108
00109 mp3quality = 3;
00110 gf = NULL;
00111 rtjc = NULL;
00112 strm = NULL;
00113 mp3buf = NULL;
00114
00115 transcoding = false;
00116
00117 act_video_encode = 0;
00118 act_video_buffer = 0;
00119 video_buffer_count = 0;
00120 video_buffer_size = 0;
00121
00122 act_audio_encode = 0;
00123 act_audio_buffer = 0;
00124 audio_buffer_count = 0;
00125 audio_buffer_size = 0;
00126
00127 act_text_encode = 0;
00128 act_text_buffer = 0;
00129 text_buffer_count = 0;
00130 text_buffer_size = 0;
00131
00132 writepaused = false;
00133 audiopaused = false;
00134 mainpaused = false;
00135
00136 keyframedist = KEYFRAMEDIST;
00137
00138 audiobytes = 0;
00139 audio_bits = 16;
00140 audio_channels = 2;
00141 audio_samplerate = 44100;
00142 audio_bytes_per_sample = audio_channels * audio_bits / 8;
00143
00144 picture_format = PIX_FMT_YUV420P;
00145 v4l2_pixelformat = 0;
00146
00147 avcodec_register_all();
00148
00149 mpa_vidcodec = 0;
00150 mpa_vidctx = NULL;
00151
00152 useavcodec = false;
00153
00154 targetbitrate = 2200;
00155 scalebitrate = 1;
00156 maxquality = 2;
00157 minquality = 31;
00158 qualdiff = 3;
00159 mp4opts = 0;
00160 mb_decision = FF_MB_DECISION_SIMPLE;
00161 encoding_thread_count = 1;
00162
00163 oldtc = 0;
00164 startnum = 0;
00165 frameofgop = 0;
00166 lasttimecode = 0;
00167 audio_behind = 0;
00168
00169 extendeddataOffset = 0;
00170 seektable = new vector<struct seektable_entry>;
00171
00172 hardware_encode = false;
00173 hmjpg_quality = 80;
00174 hmjpg_hdecimation = 2;
00175 hmjpg_vdecimation = 2;
00176 hmjpg_maxw = 640;
00177
00178 videoFilterList = "";
00179 videoFilters = NULL;
00180 FiltMan = new FilterManager;
00181 inpixfmt = FMT_YV12;
00182 correct_bttv = false;
00183
00184 usingv4l2 = false;
00185
00186 prev_bframe_save_pos = -1;
00187
00188 volume = 100;
00189
00190 ccd = new CC608Decoder(this);
00191
00192 go7007 = false;
00193 resetcapture = false;
00194
00195 SetPositionMapType(MARK_KEYFRAME);
00196 }
00197
00198 NuppelVideoRecorder::~NuppelVideoRecorder(void)
00199 {
00200 if (weMadeBuffer && ringBuffer)
00201 {
00202 delete ringBuffer;
00203 ringBuffer = NULL;
00204 }
00205 if (rtjc)
00206 delete rtjc;
00207 if (mp3buf)
00208 delete [] mp3buf;
00209 if (gf)
00210 lame_close(gf);
00211 if (strm)
00212 delete [] strm;
00213 if (audio_device)
00214 {
00215 delete audio_device;
00216 audio_device = NULL;
00217 }
00218 if (fd >= 0)
00219 close(fd);
00220 if (seektable)
00221 {
00222 seektable->clear();
00223 delete seektable;
00224 }
00225
00226 while (videobuffer.size() > 0)
00227 {
00228 struct vidbuffertype *vb = videobuffer.back();
00229 delete [] vb->buffer;
00230 delete vb;
00231 videobuffer.pop_back();
00232 }
00233 while (audiobuffer.size() > 0)
00234 {
00235 struct audbuffertype *ab = audiobuffer.back();
00236 delete [] ab->buffer;
00237 delete ab;
00238 audiobuffer.pop_back();
00239 }
00240 while (textbuffer.size() > 0)
00241 {
00242 struct txtbuffertype *tb = textbuffer.back();
00243 delete [] tb->buffer;
00244 delete tb;
00245 textbuffer.pop_back();
00246 }
00247
00248 if (mpa_vidcodec)
00249 {
00250 QMutexLocker locker(avcodeclock);
00251 avcodec_close(mpa_vidctx);
00252 }
00253
00254 if (mpa_vidctx)
00255 av_free(mpa_vidctx);
00256 mpa_vidctx = NULL;
00257
00258 if (videoFilters)
00259 delete videoFilters;
00260 if (FiltMan)
00261 delete FiltMan;
00262 if (ccd)
00263 delete ccd;
00264 }
00265
00266 void NuppelVideoRecorder::SetOption(const QString &opt, int value)
00267 {
00268 if (opt == "width")
00269 w_out = width = value;
00270 else if (opt == "height")
00271 h_out = height = value;
00272 else if (opt == "rtjpegchromafilter")
00273 M1 = value;
00274 else if (opt == "rtjpeglumafilter")
00275 M2 = value;
00276 else if (opt == "rtjpegquality")
00277 Q = value;
00278 else if ((opt == "mpeg4bitrate") || (opt == "mpeg2bitrate"))
00279 targetbitrate = value;
00280 else if (opt == "scalebitrate")
00281 scalebitrate = value;
00282 else if (opt == "mpeg4maxquality")
00283 {
00284 if (value > 0)
00285 maxquality = value;
00286 else
00287 maxquality = 1;
00288 }
00289 else if (opt == "mpeg4minquality")
00290 minquality = value;
00291 else if (opt == "mpeg4qualdiff")
00292 qualdiff = value;
00293 else if (opt == "encodingthreadcount")
00294 encoding_thread_count = value;
00295 else if (opt == "mpeg4optionvhq")
00296 {
00297 if (value)
00298 mb_decision = FF_MB_DECISION_RD;
00299 else
00300 mb_decision = FF_MB_DECISION_SIMPLE;
00301 }
00302 else if (opt == "mpeg4option4mv")
00303 {
00304 if (value)
00305 mp4opts |= CODEC_FLAG_4MV;
00306 else
00307 mp4opts &= ~CODEC_FLAG_4MV;
00308 }
00309 else if (opt == "mpeg4optionidct")
00310 {
00311 if (value)
00312 mp4opts |= CODEC_FLAG_INTERLACED_DCT;
00313 else
00314 mp4opts &= ~CODEC_FLAG_INTERLACED_DCT;
00315 }
00316 else if (opt == "mpeg4optionime")
00317 {
00318 if (value)
00319 mp4opts |= CODEC_FLAG_INTERLACED_ME;
00320 else
00321 mp4opts &= ~CODEC_FLAG_INTERLACED_ME;
00322 }
00323 else if (opt == "hardwaremjpegquality")
00324 hmjpg_quality = value;
00325 else if (opt == "hardwaremjpeghdecimation")
00326 hmjpg_hdecimation = value;
00327 else if (opt == "hardwaremjpegvdecimation")
00328 hmjpg_vdecimation = value;
00329 else if (opt == "audiocompression")
00330 compressaudio = value;
00331 else if (opt == "mp3quality")
00332 mp3quality = value;
00333 else if (opt == "samplerate")
00334 audio_samplerate = value;
00335 else if (opt == "audioframesize")
00336 audio_buffer_size = value;
00337 else if (opt == "pip_mode")
00338 pip_mode = value;
00339 else if (opt == "inpixfmt")
00340 inpixfmt = (VideoFrameType)value;
00341 else if (opt == "skipbtaudio")
00342 skip_btaudio = value;
00343 else if (opt == "volume")
00344 volume = value;
00345 else
00346 V4LRecorder::SetOption(opt, value);
00347 }
00348
00349 void NuppelVideoRecorder::SetOption(const QString &name, const QString &value)
00350 {
00351 V4LRecorder::SetOption(name, value);
00352 }
00353
00354 void NuppelVideoRecorder::SetOptionsFromProfile(RecordingProfile *profile,
00355 const QString &videodev,
00356 const QString &audiodev,
00357 const QString &vbidev)
00358 {
00359 SetOption("videodevice", videodev);
00360 SetOption("vbidevice", vbidev);
00361 SetOption("tvformat", gCoreContext->GetSetting("TVFormat"));
00362 SetOption("vbiformat", gCoreContext->GetSetting("VbiFormat"));
00363 SetOption("audiodevice", audiodev);
00364
00365 QString setting = QString::null;
00366 const Setting *tmp = profile->byName("videocodec");
00367 if (tmp)
00368 setting = tmp->getValue();
00369
00370 if (setting == "MPEG-4")
00371 {
00372 SetOption("videocodec", "mpeg4");
00373
00374 SetIntOption(profile, "mpeg4bitrate");
00375 SetIntOption(profile, "scalebitrate");
00376 SetIntOption(profile, "mpeg4maxquality");
00377 SetIntOption(profile, "mpeg4minquality");
00378 SetIntOption(profile, "mpeg4qualdiff");
00379 #ifdef USING_FFMPEG_THREADS
00380 SetIntOption(profile, "encodingthreadcount");
00381 #endif
00382 SetIntOption(profile, "mpeg4optionvhq");
00383 SetIntOption(profile, "mpeg4option4mv");
00384 SetIntOption(profile, "mpeg4optionidct");
00385 SetIntOption(profile, "mpeg4optionime");
00386 }
00387 else if (setting == "MPEG-2")
00388 {
00389 SetOption("videocodec", "mpeg2video");
00390
00391 SetIntOption(profile, "mpeg2bitrate");
00392 SetIntOption(profile, "scalebitrate");
00393 #ifdef USING_FFMPEG_THREADS
00394 SetIntOption(profile, "encodingthreadcount");
00395 #endif
00396 }
00397 else if (setting == "RTjpeg")
00398 {
00399 SetOption("videocodec", "rtjpeg");
00400
00401 SetIntOption(profile, "rtjpegquality");
00402 SetIntOption(profile, "rtjpegchromafilter");
00403 SetIntOption(profile, "rtjpeglumafilter");
00404 }
00405 else if (setting == "Hardware MJPEG")
00406 {
00407 SetOption("videocodec", "hardware-mjpeg");
00408
00409 SetIntOption(profile, "hardwaremjpegquality");
00410 SetIntOption(profile, "hardwaremjpeghdecimation");
00411 SetIntOption(profile, "hardwaremjpegvdecimation");
00412 }
00413 else
00414 {
00415 LOG(VB_GENERAL, LOG_ERR, LOC +
00416 "Unknown video codec. "
00417 "Please go into the TV Settings, Recording Profiles and "
00418 "setup the four 'Software Encoders' profiles. "
00419 "Assuming RTjpeg for now.");
00420
00421 SetOption("videocodec", "rtjpeg");
00422
00423 SetIntOption(profile, "rtjpegquality");
00424 SetIntOption(profile, "rtjpegchromafilter");
00425 SetIntOption(profile, "rtjpeglumafilter");
00426 }
00427
00428 setting = QString::null;
00429 if ((tmp = profile->byName("audiocodec")))
00430 setting = tmp->getValue();
00431
00432 if (setting == "MP3")
00433 {
00434 SetOption("audiocompression", 1);
00435 SetIntOption(profile, "mp3quality");
00436 SetIntOption(profile, "samplerate");
00437 }
00438 else if (setting == "Uncompressed")
00439 {
00440 SetOption("audiocompression", 0);
00441 SetIntOption(profile, "samplerate");
00442 }
00443 else
00444 {
00445 LOG(VB_GENERAL, LOG_ERR, LOC + "Unknown audio codec");
00446 SetOption("audiocompression", 0);
00447 }
00448
00449 SetIntOption(profile, "volume");
00450
00451 SetIntOption(profile, "width");
00452 SetIntOption(profile, "height");
00453 }
00454
00455 void NuppelVideoRecorder::Pause(bool clear)
00456 {
00457 QMutexLocker locker(&pauseLock);
00458 cleartimeonpause = clear;
00459 writepaused = audiopaused = mainpaused = false;
00460 request_pause = true;
00461
00462
00463
00464 unpauseWait.wakeAll();
00465 }
00466
00467 bool NuppelVideoRecorder::IsPaused(bool holding_lock) const
00468 {
00469 if (!holding_lock)
00470 pauseLock.lock();
00471 bool ret = audiopaused && mainpaused && writepaused;
00472 if (!holding_lock)
00473 pauseLock.unlock();
00474 return ret;
00475 }
00476
00477 void NuppelVideoRecorder::SetVideoFilters(QString &filters)
00478 {
00479 videoFilterList = filters;
00480 InitFilters();
00481 }
00482
00483 bool NuppelVideoRecorder::IsRecording(void)
00484 {
00485 return recording;
00486 }
00487
00488 long long NuppelVideoRecorder::GetFramesWritten(void)
00489 {
00490 return framesWritten;
00491 }
00492
00493 int NuppelVideoRecorder::GetVideoFd(void)
00494 {
00495 return channelfd;
00496 }
00497
00498 bool NuppelVideoRecorder::SetupAVCodecVideo(void)
00499 {
00500 if (!useavcodec)
00501 useavcodec = true;
00502
00503 if (mpa_vidcodec)
00504 {
00505 QMutexLocker locker(avcodeclock);
00506 avcodec_close(mpa_vidctx);
00507 }
00508
00509 if (mpa_vidctx)
00510 av_free(mpa_vidctx);
00511 mpa_vidctx = NULL;
00512
00513 QByteArray vcodec = videocodec.toAscii();
00514 mpa_vidcodec = avcodec_find_encoder_by_name(vcodec.constData());
00515
00516 if (!mpa_vidcodec)
00517 {
00518 LOG(VB_GENERAL, LOG_ERR, LOC + QString("Video Codec not found: %1")
00519 .arg(vcodec.constData()));
00520 return false;
00521 }
00522
00523 mpa_vidctx = avcodec_alloc_context3(NULL);
00524
00525 avcodec_get_frame_defaults(&mpa_picture);
00526
00527 switch (picture_format)
00528 {
00529 case PIX_FMT_YUV420P:
00530 case PIX_FMT_YUV422P:
00531 case PIX_FMT_YUVJ420P:
00532 mpa_vidctx->pix_fmt = picture_format;
00533 mpa_picture.linesize[0] = w_out;
00534 mpa_picture.linesize[1] = w_out / 2;
00535 mpa_picture.linesize[2] = w_out / 2;
00536 break;
00537 default:
00538 LOG(VB_GENERAL, LOG_ERR, LOC + QString("Unknown picture format: %1")
00539 .arg(picture_format));
00540 }
00541
00542 mpa_vidctx->width = w_out;
00543 mpa_vidctx->height = (int)(height * height_multiplier);
00544
00545 int usebitrate = targetbitrate * 1000;
00546 if (scalebitrate)
00547 {
00548 float diff = (w_out * h_out) / (640.0 * 480.0);
00549 usebitrate = (int)(diff * usebitrate);
00550 }
00551
00552 if (targetbitrate == -1)
00553 usebitrate = -1;
00554
00555 mpa_vidctx->time_base.den = (int)ceil(video_frame_rate * 100 *
00556 framerate_multiplier);
00557 mpa_vidctx->time_base.num = 100;
00558
00559
00560 switch (mpa_vidctx->time_base.den)
00561 {
00562 case 2397:
00563 case 2398: mpa_vidctx->time_base.den = 24000;
00564 mpa_vidctx->time_base.num = 1001;
00565 break;
00566 case 2997:
00567 case 2998: mpa_vidctx->time_base.den = 30000;
00568 mpa_vidctx->time_base.num = 1001;
00569 break;
00570 case 5994:
00571 case 5995: mpa_vidctx->time_base.den = 60000;
00572 mpa_vidctx->time_base.num = 1001;
00573 break;
00574 }
00575
00576 mpa_vidctx->bit_rate = usebitrate;
00577 mpa_vidctx->bit_rate_tolerance = usebitrate * 100;
00578 mpa_vidctx->qmin = maxquality;
00579 mpa_vidctx->qmax = minquality;
00580 mpa_vidctx->max_qdiff = qualdiff;
00581 mpa_vidctx->flags = mp4opts;
00582 mpa_vidctx->mb_decision = mb_decision;
00583
00584 mpa_vidctx->qblur = 0.5;
00585 mpa_vidctx->max_b_frames = 0;
00586 mpa_vidctx->b_quant_factor = 0;
00587 mpa_vidctx->rc_strategy = 2;
00588 mpa_vidctx->b_frame_strategy = 0;
00589 mpa_vidctx->gop_size = 30;
00590 mpa_vidctx->rc_max_rate = 0;
00591 mpa_vidctx->rc_min_rate = 0;
00592 mpa_vidctx->rc_buffer_size = 0;
00593 mpa_vidctx->rc_buffer_aggressivity = 1.0;
00594 mpa_vidctx->rc_override_count = 0;
00595 mpa_vidctx->rc_initial_cplx = 0;
00596 mpa_vidctx->dct_algo = FF_DCT_AUTO;
00597 mpa_vidctx->idct_algo = FF_IDCT_AUTO;
00598 mpa_vidctx->prediction_method = FF_PRED_LEFT;
00599 if (videocodec.toLower() == "huffyuv" || videocodec.toLower() == "mjpeg")
00600 mpa_vidctx->strict_std_compliance = FF_COMPLIANCE_UNOFFICIAL;
00601 mpa_vidctx->thread_count = encoding_thread_count;
00602
00603 QMutexLocker locker(avcodeclock);
00604
00605 if (avcodec_open2(mpa_vidctx, mpa_vidcodec, NULL) < 0)
00606 {
00607 LOG(VB_GENERAL, LOG_ERR, LOC + QString("Unable to open FFMPEG/%1 codec")
00608 .arg(videocodec));
00609 return false;
00610 }
00611
00612
00613 return true;
00614 }
00615
00616 void NuppelVideoRecorder::SetupRTjpeg(void)
00617 {
00618 picture_format = PIX_FMT_YUV420P;
00619
00620 int setval;
00621 rtjc = new RTjpeg();
00622 setval = RTJ_YUV420;
00623 rtjc->SetFormat(&setval);
00624 setval = (int)(h_out * height_multiplier);
00625 rtjc->SetSize(&w_out, &setval);
00626 rtjc->SetQuality(&Q);
00627 setval = 2;
00628 rtjc->SetIntra(&setval, &M1, &M2);
00629 }
00630
00631
00632 void NuppelVideoRecorder::UpdateResolutions(void)
00633 {
00634 int tot_height = (int)(height * height_multiplier);
00635 double aspectnum = w_out / (double)tot_height;
00636 uint aspect;
00637
00638 if (aspectnum == 0.0)
00639 aspect = 0;
00640 else if (fabs(aspectnum - 1.3333333333333333) < 0.001)
00641 aspect = 2;
00642 else if (fabs(aspectnum - 1.7777777777777777) < 0.001)
00643 aspect = 3;
00644 else if (fabs(aspectnum - 2.21) < 0.001)
00645 aspect = 4;
00646 else
00647 aspect = aspectnum * 1000000;
00648
00649 if ((aspect > 0) && (aspect != m_videoAspect))
00650 {
00651 m_videoAspect = aspect;
00652 AspectChange((AspectRatio)aspect, 0);
00653 }
00654
00655 if (w_out && tot_height &&
00656 ((uint)tot_height != m_videoHeight ||
00657 (uint)w_out != m_videoWidth))
00658 {
00659 m_videoHeight = tot_height;
00660 m_videoWidth = w_out;
00661 ResolutionChange(w_out, tot_height, 0);
00662 }
00663
00664 int den = (int)ceil(video_frame_rate * 100 * framerate_multiplier);
00665 int num = 100;
00666
00667
00668 switch (den)
00669 {
00670 case 2397:
00671 case 2398: den = 24000;
00672 num = 1001;
00673 break;
00674 case 2997:
00675 case 2998: den = 30000;
00676 num = 1001;
00677 break;
00678 case 5994:
00679 case 5995: den = 60000;
00680 num = 1001;
00681 break;
00682 }
00683
00684 uint frameRate = (den * 1000) / num;
00685 if (frameRate && frameRate != m_frameRate)
00686 {
00687 m_frameRate = frameRate;
00688 LOG(VB_RECORD, LOG_INFO, LOC + QString("NVR: frame rate = %1")
00689 .arg(frameRate));
00690 FrameRateChange(frameRate, 0);
00691 }
00692 }
00693
00694 void NuppelVideoRecorder::Initialize(void)
00695 {
00696 if (AudioInit() != 0)
00697 {
00698 LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to init audio input device");
00699 }
00700
00701 if (videocodec == "hardware-mjpeg")
00702 {
00703 videocodec = "mjpeg";
00704 hardware_encode = true;
00705
00706 MJPEGInit();
00707
00708 width = hmjpg_maxw / hmjpg_hdecimation;
00709
00710 if (ntsc)
00711 {
00712 switch (hmjpg_vdecimation)
00713 {
00714 case 2: height = 240; break;
00715 case 4: height = 120; break;
00716 default: height = 480; break;
00717 }
00718 }
00719 else
00720 {
00721 switch (hmjpg_vdecimation)
00722 {
00723 case 2: height = 288; break;
00724 case 4: height = 144; break;
00725 default: height = 576; break;
00726 }
00727 }
00728 }
00729
00730 if (!ringBuffer)
00731 {
00732 LOG(VB_GENERAL, LOG_WARNING, LOC + "Warning, old RingBuffer creation");
00733 ringBuffer = RingBuffer::Create("output.nuv", true);
00734 weMadeBuffer = true;
00735 livetv = false;
00736 if (!ringBuffer->IsOpen())
00737 {
00738 _error = "Could not open RingBuffer";
00739 LOG(VB_GENERAL, LOG_ERR, LOC + _error);
00740 return;
00741 }
00742 }
00743 else
00744 livetv = ringBuffer->LiveMode();
00745
00746 audiobytes = 0;
00747
00748 InitBuffers();
00749 InitFilters();
00750 }
00751
00752 int NuppelVideoRecorder::AudioInit(bool skipdevice)
00753 {
00754 int blocksize;
00755 int tmp;
00756
00757 if (!skipdevice)
00758 {
00759 audio_device = AudioInput::CreateDevice(audiodevice.toAscii());
00760 if (!audio_device)
00761 {
00762 LOG(VB_GENERAL, LOG_ERR, LOC +
00763 QString("Failed to create audio device: %1") .arg(audiodevice));
00764 return 1;
00765 }
00766
00767 if (!audio_device->Open(audio_bits, audio_samplerate, audio_channels))
00768 {
00769 LOG(VB_GENERAL, LOG_ERR, LOC +
00770 QString("Failed to open audio device %1").arg(audiodevice));
00771 return 1;
00772 }
00773
00774 if ((blocksize = audio_device->GetBlockSize()) <= 0)
00775 {
00776 blocksize = 1024;
00777 LOG(VB_GENERAL, LOG_ERR, LOC +
00778 QString("Failed to determine audio block size on %1,"
00779 "using default 1024 bytes").arg(audiodevice));
00780 }
00781
00782 audio_device->Close();
00783 audio_buffer_size = blocksize;
00784 }
00785
00786 audio_bytes_per_sample = audio_channels * audio_bits / 8;
00787 LOG(VB_AUDIO, LOG_INFO, LOC +
00788 QString("Audio device %1 buffer size: %1 bytes")
00789 .arg(audio_buffer_size));
00790
00791 if (compressaudio)
00792 {
00793 gf = lame_init();
00794 lame_set_bWriteVbrTag(gf, 0);
00795 lame_set_quality(gf, mp3quality);
00796 lame_set_compression_ratio(gf, 11);
00797 lame_set_mode(gf, audio_channels == 2 ? STEREO : MONO);
00798 lame_set_num_channels(gf, audio_channels);
00799 lame_set_in_samplerate(gf, audio_samplerate);
00800 if ((tmp = lame_init_params(gf)) != 0)
00801 {
00802 LOG(VB_GENERAL, LOG_ERR, LOC +
00803 QString("AudioInit(): lame_init_params error %1").arg(tmp));
00804 compressaudio = false;
00805 }
00806
00807 if (audio_bits != 16)
00808 {
00809 LOG(VB_GENERAL, LOG_ERR, LOC +
00810 "AudioInit(): lame support requires 16bit audio");
00811 compressaudio = false;
00812 }
00813 }
00814 mp3buf_size = (int)(1.25 * 16384 + 7200);
00815 mp3buf = new char[mp3buf_size];
00816
00817 return 0;
00818 }
00819
00829 bool NuppelVideoRecorder::MJPEGInit(void)
00830 {
00831 #ifdef USING_V4L1
00832 bool we_opened_fd = false;
00833 int init_fd = fd;
00834 if (init_fd < 0)
00835 {
00836 QByteArray vdevice = videodevice.toAscii();
00837 init_fd = open(vdevice.constData(), O_RDWR);
00838 we_opened_fd = true;
00839
00840 if (init_fd < 0)
00841 {
00842 LOG(VB_GENERAL, LOG_ERR, LOC + "Can't open video device" + ENO);
00843 return false;
00844 }
00845 }
00846
00847 struct video_capability vc;
00848 memset(&vc, 0, sizeof(vc));
00849 int ret = ioctl(init_fd, VIDIOCGCAP, &vc);
00850
00851 if (ret < 0)
00852 LOG(VB_GENERAL, LOG_ERR, LOC + "Can't query V4L capabilities" + ENO);
00853
00854 if (we_opened_fd)
00855 close(init_fd);
00856
00857 if (ret < 0)
00858 return false;
00859
00860 if (vc.maxwidth != 768 && vc.maxwidth != 640)
00861 vc.maxwidth = 720;
00862
00863 if (vc.type & VID_TYPE_MJPEG_ENCODER)
00864 {
00865 if (vc.maxwidth >= 768)
00866 hmjpg_maxw = 768;
00867 else if (vc.maxwidth >= 704)
00868 hmjpg_maxw = 704;
00869 else
00870 hmjpg_maxw = 640;
00871 return true;
00872 }
00873 #endif // USING_V4L1
00874
00875 LOG(VB_GENERAL, LOG_ERR, LOC + "MJPEG not supported by device");
00876 return false;
00877 }
00878
00879 void NuppelVideoRecorder::InitFilters(void)
00880 {
00881 int btmp = video_buffer_size;
00882 if (videoFilters)
00883 delete videoFilters;
00884
00885 QString tmpVideoFilterList;
00886
00887 w_out = width;
00888 h_out = height;
00889 VideoFrameType tmp = FMT_YV12;
00890
00891 if (correct_bttv && !videoFilterList.contains("adjust"))
00892 {
00893 if (videoFilterList.isEmpty())
00894 tmpVideoFilterList = "adjust";
00895 else
00896 tmpVideoFilterList = "adjust," + videoFilterList;
00897 }
00898 else
00899 tmpVideoFilterList = videoFilterList;
00900
00901 videoFilters = FiltMan->LoadFilters(tmpVideoFilterList, inpixfmt, tmp,
00902 w_out, h_out, btmp);
00903 if (video_buffer_size && btmp != video_buffer_size)
00904 {
00905 video_buffer_size = btmp;
00906 ResizeVideoBuffers();
00907 }
00908 }
00909
00910 void NuppelVideoRecorder::InitBuffers(void)
00911 {
00912 int videomegs;
00913 int audiomegs = 2;
00914
00915 if (!video_buffer_size)
00916 {
00917 if (picture_format == PIX_FMT_YUV422P)
00918 video_buffer_size = w_out * h_out * 2;
00919 else
00920 video_buffer_size = w_out * h_out * 3 / 2;
00921 }
00922
00923 if (width >= 480 || height > 288)
00924 videomegs = 20;
00925 else
00926 videomegs = 12;
00927
00928 video_buffer_count = (videomegs * 1000 * 1000) / video_buffer_size;
00929
00930 if (audio_buffer_size != 0)
00931 audio_buffer_count = (audiomegs * 1000 * 1000) / audio_buffer_size;
00932 else
00933 audio_buffer_count = 0;
00934
00935 text_buffer_size = 8 * (sizeof(teletextsubtitle) + VT_WIDTH);
00936 text_buffer_count = video_buffer_count;
00937
00938 for (int i = 0; i < video_buffer_count; i++)
00939 {
00940 vidbuffertype *vidbuf = new vidbuffertype;
00941 vidbuf->buffer = new unsigned char[video_buffer_size];
00942 vidbuf->sample = 0;
00943 vidbuf->freeToEncode = 0;
00944 vidbuf->freeToBuffer = 1;
00945 vidbuf->bufferlen = 0;
00946 vidbuf->forcekey = 0;
00947
00948 videobuffer.push_back(vidbuf);
00949 }
00950
00951 for (int i = 0; i < audio_buffer_count; i++)
00952 {
00953 audbuffertype *audbuf = new audbuffertype;
00954 audbuf->buffer = new unsigned char[audio_buffer_size];
00955 audbuf->sample = 0;
00956 audbuf->freeToEncode = 0;
00957 audbuf->freeToBuffer = 1;
00958
00959 audiobuffer.push_back(audbuf);
00960 }
00961
00962 for (int i = 0; i < text_buffer_count; i++)
00963 {
00964 txtbuffertype *txtbuf = new txtbuffertype;
00965 txtbuf->buffer = new unsigned char[text_buffer_size];
00966 txtbuf->freeToEncode = 0;
00967 txtbuf->freeToBuffer = 1;
00968
00969 textbuffer.push_back(txtbuf);
00970 }
00971 }
00972
00973 void NuppelVideoRecorder::ResizeVideoBuffers(void)
00974 {
00975 for (unsigned int i = 0; i < videobuffer.size(); i++)
00976 {
00977 delete [] (videobuffer[i]->buffer);
00978 videobuffer[i]->buffer = new unsigned char[video_buffer_size];
00979 }
00980 }
00981
00982 void NuppelVideoRecorder::StreamAllocate(void)
00983 {
00984 strm = new signed char[width * height * 2 + 10];
00985 }
00986
00987 bool NuppelVideoRecorder::Open(void)
00988 {
00989 if (channelfd>0)
00990 return true;
00991
00992 int retries = 0;
00993 QByteArray vdevice = videodevice.toAscii();
00994 fd = open(vdevice.constData(), O_RDWR);
00995 while (fd < 0)
00996 {
00997 usleep(30000);
00998 fd = open(vdevice.constData(), O_RDWR);
00999 if (retries++ > 5)
01000 {
01001 _error = QString("Can't open video device: %1").arg(videodevice);
01002 LOG(VB_GENERAL, LOG_ERR, LOC + _error + ENO);
01003 KillChildren();
01004 return false;
01005 }
01006 }
01007
01008 channelfd = fd;
01009 return true;
01010 }
01011
01012 void NuppelVideoRecorder::ProbeV4L2(void)
01013 {
01014 #ifdef USING_V4L2
01015 usingv4l2 = true;
01016
01017 struct v4l2_capability vcap;
01018 memset(&vcap, 0, sizeof(vcap));
01019
01020 if (ioctl(channelfd, VIDIOC_QUERYCAP, &vcap) < 0)
01021 {
01022 usingv4l2 = false;
01023 }
01024
01025 if (usingv4l2 && !(vcap.capabilities & V4L2_CAP_VIDEO_CAPTURE))
01026 {
01027 LOG(VB_GENERAL, LOG_ERR, LOC +
01028 "Not a v4l2 capture device, falling back to v4l");
01029 usingv4l2 = false;
01030 }
01031
01032 if (usingv4l2 && !(vcap.capabilities & V4L2_CAP_STREAMING))
01033 {
01034 LOG(VB_GENERAL, LOG_ERR, LOC +
01035 "Won't work with the streaming interface, falling back");
01036 usingv4l2 = false;
01037 }
01038
01039 if (vcap.card[0] == 'B' && vcap.card[1] == 'T' &&
01040 vcap.card[2] == '8' && vcap.card[4] == '8')
01041 correct_bttv = true;
01042
01043 QString driver = (char *)vcap.driver;
01044 if (driver == "go7007")
01045 go7007 = true;
01046 #endif // USING_V4L2
01047 }
01048
01049 void NuppelVideoRecorder::run(void)
01050 {
01051 if (lzo_init() != LZO_E_OK)
01052 {
01053 LOG(VB_GENERAL, LOG_ERR, LOC + "lzo_init() failed, exiting");
01054 _error = "lzo_init() failed, exiting";
01055 LOG(VB_GENERAL, LOG_ERR, LOC + _error);
01056 return;
01057 }
01058
01059 if (!Open())
01060 {
01061 _error = "Failed to open device";
01062 LOG(VB_GENERAL, LOG_ERR, LOC + _error);
01063 return;
01064 }
01065
01066 ProbeV4L2();
01067
01068 if (usingv4l2 && !SetFormatV4L2())
01069 {
01070 _error = "Failed to set V4L2 format";
01071 LOG(VB_GENERAL, LOG_ERR, LOC + _error);
01072 return;
01073 }
01074
01075 StreamAllocate();
01076
01077 positionMapLock.lock();
01078 positionMap.clear();
01079 positionMapDelta.clear();
01080 positionMapLock.unlock();
01081
01082 if (videocodec.toLower() == "rtjpeg")
01083 useavcodec = false;
01084 else
01085 useavcodec = true;
01086
01087 if (useavcodec)
01088 useavcodec = SetupAVCodecVideo();
01089
01090 if (!useavcodec)
01091 SetupRTjpeg();
01092
01093 UpdateResolutions();
01094
01095 if (CreateNuppelFile() != 0)
01096 {
01097 _error = QString("Cannot open '%1' for writing")
01098 .arg(ringBuffer->GetFilename());
01099 LOG(VB_GENERAL, LOG_ERR, LOC + _error);
01100 return;
01101 }
01102
01103 if (IsHelperRequested())
01104 {
01105 LOG(VB_GENERAL, LOG_ERR, LOC + "Children are already alive");
01106 _error = "Children are already alive";
01107 return;
01108 }
01109
01110 {
01111 QMutexLocker locker(&pauseLock);
01112 request_recording = true;
01113 request_helper = true;
01114 recording = true;
01115 recordingWait.wakeAll();
01116 }
01117
01118 write_thread = new NVRWriteThread(this);
01119 write_thread->start();
01120
01121 audio_thread = new NVRAudioThread(this);
01122 audio_thread->start();
01123
01124 if ((vbimode != VBIMode::None) && (OpenVBIDevice() >= 0))
01125 vbi_thread = new VBIThread(this);
01126
01127
01128 gettimeofday(&stm, &tzone);
01129
01130
01131 myth_nice(-10);
01132
01133 if (usingv4l2)
01134 {
01135 inpixfmt = FMT_NONE;
01136 InitFilters();
01137 DoV4L2();
01138 }
01139 else
01140 DoV4L1();
01141
01142 {
01143 QMutexLocker locker(&pauseLock);
01144 request_recording = false;
01145 request_helper = false;
01146 recording = false;
01147 recordingWait.wakeAll();
01148 }
01149 }
01150
01151 #ifdef USING_V4L1
01152 void NuppelVideoRecorder::DoV4L1(void)
01153 {
01154 struct video_capability vc;
01155 struct video_mmap mm;
01156 struct video_mbuf vm;
01157 struct video_channel vchan;
01158 struct video_audio va;
01159 struct video_tuner vt;
01160
01161 memset(&mm, 0, sizeof(mm));
01162 memset(&vm, 0, sizeof(vm));
01163 memset(&vchan, 0, sizeof(vchan));
01164 memset(&va, 0, sizeof(va));
01165 memset(&vt, 0, sizeof(vt));
01166 memset(&vc, 0, sizeof(vc));
01167
01168 if (ioctl(fd, VIDIOCGCAP, &vc) < 0)
01169 {
01170 QString tmp = "VIDIOCGCAP: " + ENO;
01171 KillChildren();
01172 LOG(VB_GENERAL, LOG_ERR, tmp);
01173 _error = tmp;
01174 return;
01175 }
01176
01177 int channelinput = 0;
01178
01179 if (channelObj)
01180 channelinput = channelObj->GetCurrentInputNum();
01181
01182 vchan.channel = channelinput;
01183
01184 if (ioctl(fd, VIDIOCGCHAN, &vchan) < 0)
01185 LOG(VB_GENERAL, LOG_ERR, LOC + "VIDIOCGCHAN: " + ENO);
01186
01187
01188 if (!skip_btaudio)
01189 {
01190
01191
01192
01193 if (ioctl(fd, VIDIOCGAUDIO, &va) < 0)
01194 {
01195 bool reports_audio = vchan.flags & VIDEO_VC_AUDIO;
01196 uint err_level = reports_audio ? VB_GENERAL : VB_AUDIO;
01197
01198 LOG(err_level, LOG_ERR, LOC + "Failed to get audio" + ENO);
01199 }
01200 else
01201 {
01202
01203 va.flags &= ~VIDEO_AUDIO_MUTE;
01204 va.volume = volume * 65535 / 100;
01205 if (ioctl(fd, VIDIOCSAUDIO, &va) < 0)
01206 LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to set audio" + ENO);
01207 }
01208 }
01209
01210 if ((vc.type & VID_TYPE_MJPEG_ENCODER) && hardware_encode)
01211 {
01212 DoMJPEG();
01213 _error = "MJPEG requested but not available.";
01214 LOG(VB_GENERAL, LOG_ERR, LOC + _error);
01215 return;
01216 }
01217
01218 inpixfmt = FMT_NONE;
01219 InitFilters();
01220
01221 if (ioctl(fd, VIDIOCGMBUF, &vm) < 0)
01222 {
01223 QString tmp = "VIDIOCGMBUF: " + ENO;
01224 KillChildren();
01225 LOG(VB_GENERAL, LOG_ERR, LOC + tmp);
01226 _error = tmp;
01227 return;
01228 }
01229
01230 if (vm.frames < 2)
01231 {
01232 QString tmp = "need a minimum of 2 capture buffers";
01233 KillChildren();
01234 LOG(VB_GENERAL, LOG_ERR, LOC + tmp);
01235 _error = tmp;
01236 return;
01237 }
01238
01239 int frame;
01240
01241 unsigned char *buf = (unsigned char *)mmap(0, vm.size,
01242 PROT_READ|PROT_WRITE,
01243 MAP_SHARED,
01244 fd, 0);
01245 if (buf <= 0)
01246 {
01247 QString tmp = "mmap: " + ENO;
01248 KillChildren();
01249 LOG(VB_GENERAL, LOG_ERR, LOC + tmp);
01250 _error = tmp;
01251 return;
01252 }
01253
01254 mm.height = height;
01255 mm.width = width;
01256 if (inpixfmt == FMT_YUV422P)
01257 mm.format = VIDEO_PALETTE_YUV422P;
01258 else
01259 mm.format = VIDEO_PALETTE_YUV420P;
01260
01261 mm.frame = 0;
01262 if (ioctl(fd, VIDIOCMCAPTURE, &mm)<0)
01263 LOG(VB_GENERAL, LOG_ERR, LOC + "VIDIOCMCAPTUREi0: " + ENO);
01264 mm.frame = 1;
01265 if (ioctl(fd, VIDIOCMCAPTURE, &mm)<0)
01266 LOG(VB_GENERAL, LOG_ERR, LOC + "VIDIOCMCAPTUREi1: " + ENO);
01267
01268 int syncerrors = 0;
01269
01270 while (IsRecordingRequested() && !IsErrored())
01271 {
01272 {
01273 QMutexLocker locker(&pauseLock);
01274 if (request_pause)
01275 {
01276 if (!mainpaused)
01277 {
01278 mainpaused = true;
01279 pauseWait.wakeAll();
01280 if (IsPaused(true) && tvrec)
01281 tvrec->RecorderPaused();
01282 }
01283 unpauseWait.wait(&pauseLock, 100);
01284 if (cleartimeonpause)
01285 gettimeofday(&stm, &tzone);
01286 continue;
01287 }
01288
01289 if (!request_pause && mainpaused)
01290 {
01291 mainpaused = false;
01292 unpauseWait.wakeAll();
01293 }
01294 }
01295
01296 frame = 0;
01297 mm.frame = 0;
01298 if (ioctl(fd, VIDIOCSYNC, &frame)<0)
01299 {
01300 syncerrors++;
01301 if (syncerrors == 10)
01302 LOG(VB_GENERAL, LOG_ERR, LOC +
01303 "Multiple bttv errors, further messages supressed");
01304 else if (syncerrors < 10)
01305 LOG(VB_GENERAL, LOG_ERR, LOC + "VIDIOCSYNC: " + ENO);
01306 }
01307 else
01308 {
01309 BufferIt(buf+vm.offsets[0], video_buffer_size);
01310
01311 }
01312
01313 if (ioctl(fd, VIDIOCMCAPTURE, &mm)<0)
01314 LOG(VB_GENERAL, LOG_ERR, LOC + "VIDIOCMCAPTURE0: " + ENO);
01315
01316 frame = 1;
01317 mm.frame = 1;
01318 if (ioctl(fd, VIDIOCSYNC, &frame)<0)
01319 {
01320 syncerrors++;
01321 if (syncerrors == 10)
01322 LOG(VB_GENERAL, LOG_ERR, LOC +
01323 "Multiple bttv errors, further messages supressed");
01324 else if (syncerrors < 10)
01325 LOG(VB_GENERAL, LOG_ERR, LOC + "VIDIOCSYNC: " + ENO);
01326 }
01327 else
01328 {
01329 BufferIt(buf+vm.offsets[1], video_buffer_size);
01330
01331 }
01332 if (ioctl(fd, VIDIOCMCAPTURE, &mm)<0)
01333 LOG(VB_GENERAL, LOG_ERR, LOC + "VIDIOCMCAPTURE1: " + ENO);
01334 }
01335
01336 munmap(buf, vm.size);
01337
01338 KillChildren();
01339
01340 FinishRecording();
01341
01342 close(fd);
01343 }
01344 #else // if !USING_V4L1
01345 void NuppelVideoRecorder::DoV4L1(void) {}
01346 #endif // !USING_V4L1
01347
01348 #ifdef USING_V4L2
01349 bool NuppelVideoRecorder::SetFormatV4L2(void)
01350 {
01351 struct v4l2_format vfmt;
01352 memset(&vfmt, 0, sizeof(vfmt));
01353
01354 vfmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
01355
01356 vfmt.fmt.pix.width = width;
01357 vfmt.fmt.pix.height = height;
01358 vfmt.fmt.pix.field = V4L2_FIELD_INTERLACED;
01359
01360 if (go7007)
01361 vfmt.fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG;
01362 else if (inpixfmt == FMT_YUV422P)
01363 vfmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUV422P;
01364 else
01365 vfmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUV420;
01366
01367 if (ioctl(fd, VIDIOC_S_FMT, &vfmt) < 0)
01368 {
01369
01370 vfmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
01371
01372 if (ioctl(fd, VIDIOC_S_FMT, &vfmt) < 0)
01373 {
01374
01375 vfmt.fmt.pix.pixelformat = V4L2_PIX_FMT_UYVY;
01376 if (ioctl(fd, VIDIOC_S_FMT, &vfmt) < 0)
01377 {
01378 LOG(VB_GENERAL, LOG_ERR, LOC +
01379 "v4l2: Unable to set desired format");
01380 return false;
01381 }
01382 else
01383 {
01384
01385
01386 if (inpixfmt == FMT_YUV422P)
01387 {
01388 LOG(VB_GENERAL, LOG_ERR, LOC +
01389 "v4l2: uyvy format supported, but yuv422 requested.");
01390 LOG(VB_GENERAL, LOG_ERR, LOC +
01391 "v4l2: unfortunately, this converter hasn't been "
01392 "written yet, exiting");
01393 return false;
01394 }
01395 LOG(VB_RECORD, LOG_INFO, LOC +
01396 "v4l2: format set, getting uyvy from v4l, converting");
01397 }
01398 }
01399 else
01400 {
01401
01402 if (inpixfmt == FMT_YUV422P)
01403 {
01404 LOG(VB_GENERAL, LOG_ERR, LOC +
01405 "v4l2: yuyv format supported, but yuv422 requested.");
01406 LOG(VB_GENERAL, LOG_ERR, LOC +
01407 "v4l2: unfortunately, this converter hasn't been written "
01408 "yet, exiting");
01409 return false;
01410 }
01411 LOG(VB_RECORD, LOG_INFO, LOC +
01412 "v4l2: format set, getting yuyv from v4l, converting");
01413 }
01414 }
01415 else
01416 LOG(VB_RECORD, LOG_INFO, LOC +
01417 "v4l2: format set, getting yuv420 from v4l");
01418
01419
01420 if (width != (int)vfmt.fmt.pix.width ||
01421 height != (int)vfmt.fmt.pix.height)
01422 {
01423 LOG(VB_RECORD, LOG_INFO, LOC +
01424 QString("v4l2: resolution changed. requested %1x%2, using "
01425 "%3x%4 now")
01426 .arg(width).arg(height)
01427 .arg(vfmt.fmt.pix.width) .arg(vfmt.fmt.pix.height));
01428 w_out = width = vfmt.fmt.pix.width;
01429 h_out = height = vfmt.fmt.pix.height;
01430 }
01431
01432 v4l2_pixelformat = vfmt.fmt.pix.pixelformat;
01433
01434 return true;
01435 }
01436 #else // if !USING_V4L2
01437 bool NuppelVideoRecorder::SetFormatV4L2(void) { return false; }
01438 #endif // !USING_V4L2
01439
01440 #ifdef USING_V4L2
01441 #define MAX_VIDEO_BUFFERS 5
01442 void NuppelVideoRecorder::DoV4L2(void)
01443 {
01444 struct v4l2_buffer vbuf;
01445 struct v4l2_requestbuffers vrbuf;
01446 struct v4l2_control vc;
01447
01448 memset(&vbuf, 0, sizeof(vbuf));
01449 memset(&vrbuf, 0, sizeof(vrbuf));
01450 memset(&vc, 0, sizeof(vc));
01451
01452 vc.id = V4L2_CID_AUDIO_MUTE;
01453 vc.value = 0;
01454
01455 if (ioctl(fd, VIDIOC_S_CTRL, &vc) < 0)
01456 LOG(VB_GENERAL, LOG_ERR, LOC +
01457 "VIDIOC_S_CTRL:V4L2_CID_AUDIO_MUTE: " + ENO);
01458
01459 if (go7007)
01460 {
01461 struct go7007_comp_params comp;
01462 struct go7007_mpeg_params mpeg;
01463
01464 memset(&comp, 0, sizeof(comp));
01465 comp.gop_size = keyframedist;
01466 comp.max_b_frames = 0;
01467
01468 if (fabs(video_aspect - 1.33333) < 0.01f)
01469 {
01470 if (ntsc)
01471 comp.aspect_ratio = GO7007_ASPECT_RATIO_4_3_NTSC;
01472 else
01473 comp.aspect_ratio = GO7007_ASPECT_RATIO_4_3_PAL;
01474 }
01475 else if (fabs(video_aspect - 1.77777) < 0.01f)
01476 {
01477 if (ntsc)
01478 comp.aspect_ratio = GO7007_ASPECT_RATIO_16_9_NTSC;
01479 else
01480 comp.aspect_ratio = GO7007_ASPECT_RATIO_16_9_PAL;
01481 }
01482 else
01483 {
01484 comp.aspect_ratio = GO7007_ASPECT_RATIO_1_1;
01485 }
01486
01487 comp.flags |= GO7007_COMP_CLOSED_GOP;
01488 if (ioctl(fd, GO7007IOC_S_COMP_PARAMS, &comp) < 0)
01489 {
01490 _error = "Unable to set compression params";
01491 LOG(VB_GENERAL, LOG_ERR, LOC + _error);
01492 return;
01493 }
01494
01495 memset(&mpeg, 0, sizeof(mpeg));
01496
01497 if (videocodec == "mpeg2video")
01498 mpeg.mpeg_video_standard = GO7007_MPEG_VIDEO_MPEG2;
01499 else
01500 mpeg.mpeg_video_standard = GO7007_MPEG_VIDEO_MPEG4;
01501
01502 if (ioctl(fd, GO7007IOC_S_MPEG_PARAMS, &mpeg) < 0)
01503 {
01504 _error = "Unable to set MPEG params";
01505 LOG(VB_GENERAL, LOG_ERR, LOC + _error);
01506 return;
01507 }
01508
01509 int usebitrate = targetbitrate * 1000;
01510 if (scalebitrate)
01511 {
01512 float diff = (width * height) / (640.0 * 480.0);
01513 usebitrate = (int)(diff * usebitrate);
01514 }
01515
01516 if (ioctl(fd, GO7007IOC_S_BITRATE, &usebitrate) < 0)
01517 {
01518 _error = "Unable to set bitrate";
01519 LOG(VB_GENERAL, LOG_ERR, LOC + _error);
01520 return;
01521 }
01522
01523 hardware_encode = true;
01524 }
01525
01526 uint numbuffers = MAX_VIDEO_BUFFERS;
01527
01528 vrbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
01529 vrbuf.memory = V4L2_MEMORY_MMAP;
01530 vrbuf.count = numbuffers;
01531
01532 if (ioctl(fd, VIDIOC_REQBUFS, &vrbuf) < 0)
01533 {
01534 _error = "Not able to get any capture buffers, exiting";
01535 LOG(VB_GENERAL, LOG_ERR, LOC + _error);
01536 return;
01537 }
01538
01539 if (vrbuf.count < numbuffers)
01540 {
01541 LOG(VB_GENERAL, LOG_INFO, LOC +
01542 QString("Requested %1 buffers, but only %2 are available. "
01543 "Proceeding anyway").arg(numbuffers).arg(vrbuf.count));
01544 }
01545
01546 numbuffers = vrbuf.count;
01547
01548 unsigned char *buffers[MAX_VIDEO_BUFFERS];
01549 int bufferlen[MAX_VIDEO_BUFFERS];
01550
01551 for (uint i = 0; i < numbuffers; i++)
01552 {
01553 vbuf.type = vrbuf.type;
01554 vbuf.index = i;
01555
01556 if (ioctl(fd, VIDIOC_QUERYBUF, &vbuf) < 0)
01557 {
01558 LOG(VB_GENERAL, LOG_ERR, LOC +
01559 QString("unable to query capture buffer %1").arg(i));
01560 _error = "Unable to query capture buffer";
01561 return;
01562 }
01563
01564 buffers[i] = (unsigned char *)mmap(NULL, vbuf.length,
01565 PROT_READ|PROT_WRITE, MAP_SHARED,
01566 fd, vbuf.m.offset);
01567
01568 if (buffers[i] == MAP_FAILED)
01569 {
01570 LOG(VB_GENERAL, LOG_ERR, LOC + "mmap: " + ENO);
01571 LOG(VB_GENERAL, LOG_ERR, LOC + "Memory map failed");
01572 _error = "Memory map failed";
01573 return;
01574 }
01575 bufferlen[i] = vbuf.length;
01576 }
01577
01578 for (uint i = 0; i < numbuffers; i++)
01579 {
01580 memset(buffers[i], 0, bufferlen[i]);
01581 vbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
01582 vbuf.index = i;
01583 ioctl(fd, VIDIOC_QBUF, &vbuf);
01584 }
01585
01586 int turnon = V4L2_BUF_TYPE_VIDEO_CAPTURE;
01587 ioctl(fd, VIDIOC_STREAMON, &turnon);
01588
01589 struct timeval tv;
01590 fd_set rdset;
01591 int frame = 0;
01592 bool forcekey = false;
01593
01594 resetcapture = false;
01595
01596
01597 uint8_t *output_buffer = NULL;
01598 struct SwsContext *convert_ctx = NULL;
01599 AVPicture img_out;
01600 if (v4l2_pixelformat == V4L2_PIX_FMT_YUYV ||
01601 v4l2_pixelformat == V4L2_PIX_FMT_UYVY)
01602 {
01603 PixelFormat in_pixfmt = v4l2_pixelformat == V4L2_PIX_FMT_YUYV ?
01604 PIX_FMT_YUYV422 :
01605 PIX_FMT_UYVY422;
01606
01607 output_buffer = (uint8_t*)av_malloc(height * width * 3 / 2);
01608 if (!output_buffer)
01609 {
01610 _error = "Cannot initialize image conversion buffer";
01611 LOG(VB_GENERAL, LOG_ERR, LOC + _error);
01612 return;
01613 }
01614
01615 convert_ctx = sws_getCachedContext(convert_ctx, width, height, in_pixfmt,
01616 width, height, PIX_FMT_YUV420P,
01617 SWS_FAST_BILINEAR, NULL, NULL, NULL);
01618 if (!convert_ctx)
01619 {
01620 _error = "Cannot initialize image conversion context";
01621 LOG(VB_GENERAL, LOG_ERR, LOC + _error);
01622 return;
01623 }
01624
01625 avpicture_fill(&img_out, output_buffer, PIX_FMT_YUV420P, width, height);
01626 }
01627
01628 while (IsRecordingRequested() && !IsErrored())
01629 {
01630 again:
01631 {
01632 QMutexLocker locker(&pauseLock);
01633 if (request_pause)
01634 {
01635 if (!mainpaused)
01636 {
01637 mainpaused = true;
01638 pauseWait.wakeAll();
01639 if (IsPaused(true) && tvrec)
01640 tvrec->RecorderPaused();
01641 }
01642 unpauseWait.wait(&pauseLock, 100);
01643 if (cleartimeonpause)
01644 gettimeofday(&stm, &tzone);
01645 continue;
01646 }
01647
01648 if (!request_pause && mainpaused)
01649 {
01650 mainpaused = false;
01651 unpauseWait.wakeAll();
01652 }
01653 }
01654
01655 if (resetcapture)
01656 {
01657 LOG(VB_GENERAL, LOG_ERR, LOC + "Resetting and re-queueing");
01658 turnon = V4L2_BUF_TYPE_VIDEO_CAPTURE;
01659 ioctl(fd, VIDIOC_STREAMOFF, &turnon);
01660
01661 for (uint i = 0; i < numbuffers; i++)
01662 {
01663 memset(buffers[i], 0, bufferlen[i]);
01664 vbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
01665 vbuf.index = i;
01666 ioctl(fd, VIDIOC_QBUF, &vbuf);
01667 }
01668
01669 ioctl(fd, VIDIOC_STREAMON, &turnon);
01670 resetcapture = false;
01671 }
01672
01673 tv.tv_sec = 5;
01674 tv.tv_usec = 0;
01675 FD_ZERO(&rdset);
01676 FD_SET(fd, &rdset);
01677
01678 switch (select(fd+1, &rdset, NULL, NULL, &tv))
01679 {
01680 case -1:
01681 if (errno == EINTR)
01682 goto again;
01683 LOG(VB_GENERAL, LOG_ERR, LOC + "select: " + ENO);
01684 continue;
01685 case 0:
01686 LOG(VB_GENERAL, LOG_INFO, LOC + "select timeout");
01687 continue;
01688 default: break;
01689 }
01690
01691 memset(&vbuf, 0, sizeof(vbuf));
01692 vbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
01693 vbuf.memory = V4L2_MEMORY_MMAP;
01694 if (ioctl(fd, VIDIOC_DQBUF, &vbuf) < 0)
01695 {
01696 LOG(VB_GENERAL, LOG_ERR, LOC + "DQBUF ioctl failed." + ENO);
01697
01698
01699
01700 if (errno == EIO && channelObj)
01701 {
01702 channelObj->Retune();
01703 resetcapture = true;
01704 continue;
01705 }
01706
01707 if (errno == EIO || errno == EINVAL)
01708 {
01709 resetcapture = true;
01710 continue;
01711 }
01712
01713 if (errno == EAGAIN)
01714 continue;
01715 }
01716
01717 frame = vbuf.index;
01718 if (go7007)
01719 forcekey = vbuf.flags & V4L2_BUF_FLAG_KEYFRAME;
01720
01721 if (!request_pause)
01722 {
01723 if (v4l2_pixelformat == V4L2_PIX_FMT_YUYV)
01724 {
01725 AVPicture img_in;
01726 avpicture_fill(&img_in, buffers[frame], PIX_FMT_YUYV422, width, height);
01727 sws_scale(convert_ctx, img_in.data, img_in.linesize,
01728 0, height, img_out.data, img_out.linesize);
01729 BufferIt(output_buffer, video_buffer_size);
01730 }
01731 else if (v4l2_pixelformat == V4L2_PIX_FMT_UYVY)
01732 {
01733 AVPicture img_in;
01734 avpicture_fill(&img_in, buffers[frame], PIX_FMT_UYVY422, width, height);
01735 sws_scale(convert_ctx, img_in.data, img_in.linesize,
01736 0, height, img_out.data, img_out.linesize);
01737 BufferIt(output_buffer, video_buffer_size);
01738 }
01739 else
01740 {
01741
01742 BufferIt(buffers[frame], vbuf.bytesused, forcekey);
01743 }
01744 }
01745
01746 vbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
01747 ioctl(fd, VIDIOC_QBUF, &vbuf);
01748 }
01749
01750 KillChildren();
01751
01752 ioctl(fd, VIDIOC_STREAMOFF, &turnon);
01753
01754 for (uint i = 0; i < numbuffers; i++)
01755 {
01756 munmap(buffers[i], bufferlen[i]);
01757 }
01758
01759 FinishRecording();
01760
01761 av_free(output_buffer);
01762 sws_freeContext(convert_ctx);
01763
01764 close(fd);
01765 close(channelfd);
01766 }
01767 #else // if !USING_V4L2
01768 void NuppelVideoRecorder::DoV4L2(void) {}
01769 #endif // !USING_V4L2
01770
01771 #ifdef USING_V4L1
01772 void NuppelVideoRecorder::DoMJPEG(void)
01773 {
01774 struct mjpeg_params bparm;
01775
01776 if (ioctl(fd, MJPIOC_G_PARAMS, &bparm) < 0)
01777 {
01778 LOG(VB_GENERAL, LOG_ERR, LOC + "MJPIOC_G_PARAMS: " + ENO);
01779 return;
01780 }
01781
01782
01783
01784 bparm.quality = hmjpg_quality;
01785
01786 if (hmjpg_hdecimation == hmjpg_vdecimation)
01787 {
01788 bparm.decimation = hmjpg_hdecimation;
01789 }
01790 else
01791 {
01792 bparm.decimation = 0;
01793 bparm.HorDcm = hmjpg_hdecimation;
01794 bparm.VerDcm = (hmjpg_vdecimation + 1) / 2;
01795
01796 if (hmjpg_vdecimation == 1)
01797 {
01798 bparm.TmpDcm = 1;
01799 bparm.field_per_buff = 2;
01800 }
01801 else
01802 {
01803 bparm.TmpDcm = 2;
01804 bparm.field_per_buff = 1;
01805 }
01806
01807 bparm.img_width = hmjpg_maxw;
01808
01809 if (ntsc)
01810 bparm.img_height = 240;
01811 else
01812 bparm.img_height = 288;
01813
01814 bparm.img_x = 0;
01815 bparm.img_y = 0;
01816 }
01817
01818 bparm.APPn = 0;
01819
01820 if (hmjpg_vdecimation == 1)
01821 bparm.APP_len = 14;
01822 else
01823 bparm.APP_len = 0;
01824
01825 bparm.odd_even = !(hmjpg_vdecimation > 1);
01826
01827 for (int n = 0; n < bparm.APP_len; n++)
01828 bparm.APP_data[n] = 0;
01829
01830 if (ioctl(fd, MJPIOC_S_PARAMS, &bparm) < 0)
01831 {
01832 LOG(VB_GENERAL, LOG_DEBUG, LOC + "MJPIOC_S_PARAMS: " + ENO);
01833 return;
01834 }
01835
01836 struct mjpeg_requestbuffers breq;
01837
01838 breq.count = 64;
01839 breq.size = 256 * 1024;
01840
01841 if (ioctl(fd, MJPIOC_REQBUFS, &breq) < 0)
01842 {
01843 LOG(VB_GENERAL, LOG_DEBUG, LOC + "MJPIOC_REQBUFS: " + ENO);
01844 return;
01845 }
01846
01847 uint8_t *MJPG_buff = (uint8_t *)mmap(0, breq.count * breq.size,
01848 PROT_READ|PROT_WRITE, MAP_SHARED, fd,
01849 0);
01850
01851 if (MJPG_buff == MAP_FAILED)
01852 {
01853 LOG(VB_GENERAL, LOG_ERR, LOC + "mapping mjpeg buffers");
01854 return;
01855 }
01856
01857 struct mjpeg_sync bsync;
01858
01859 for (unsigned int count = 0; count < breq.count; count++)
01860 {
01861 if (ioctl(fd, MJPIOC_QBUF_CAPT, &count) < 0)
01862 LOG(VB_GENERAL, LOG_ERR, LOC + "MJPIOC_QBUF_CAPT: " + ENO);
01863 }
01864
01865 while (IsRecordingRequested() && !IsErrored())
01866 {
01867 {
01868 QMutexLocker locker(&pauseLock);
01869 if (request_pause)
01870 {
01871 if (!mainpaused)
01872 {
01873 mainpaused = true;
01874 pauseWait.wakeAll();
01875 if (IsPaused(true) && tvrec)
01876 tvrec->RecorderPaused();
01877 }
01878 unpauseWait.wait(&pauseLock, 100);
01879 if (cleartimeonpause)
01880 gettimeofday(&stm, &tzone);
01881 continue;
01882 }
01883
01884 if (!request_pause && mainpaused)
01885 {
01886 mainpaused = false;
01887 unpauseWait.wakeAll();
01888 }
01889 }
01890
01891 if (ioctl(fd, MJPIOC_SYNC, &bsync) < 0)
01892 {
01893 _error = "MJPEG sync error";
01894 LOG(VB_GENERAL, LOG_ERR, LOC + _error + ENO);
01895 break;
01896 }
01897
01898 BufferIt((unsigned char *)(MJPG_buff + bsync.frame * breq.size),
01899 bsync.length);
01900
01901 if (ioctl(fd, MJPIOC_QBUF_CAPT, &(bsync.frame)) < 0)
01902 {
01903 _error = "MJPEG Capture error";
01904 LOG(VB_GENERAL, LOG_ERR, LOC + _error + ENO);
01905 }
01906 }
01907
01908 munmap(MJPG_buff, breq.count * breq.size);
01909 KillChildren();
01910
01911 FinishRecording();
01912
01913 close(fd);
01914 }
01915 #else // if !USING_V4L1
01916 void NuppelVideoRecorder::DoMJPEG(void) {}
01917 #endif // !USING_V4L1
01918
01919 void NuppelVideoRecorder::KillChildren(void)
01920 {
01921 {
01922 QMutexLocker locker(&pauseLock);
01923 request_helper = false;
01924 unpauseWait.wakeAll();
01925 }
01926
01927 if (write_thread)
01928 {
01929 write_thread->wait();
01930 delete write_thread;
01931 write_thread = NULL;
01932 }
01933
01934 if (audio_thread)
01935 {
01936 audio_thread->wait();
01937 delete audio_thread;
01938 audio_thread = NULL;
01939 }
01940
01941 if (vbi_thread)
01942 {
01943 vbi_thread->wait();
01944 delete vbi_thread;
01945 vbi_thread = NULL;
01946 CloseVBIDevice();
01947 }
01948 }
01949
01950 void NuppelVideoRecorder::BufferIt(unsigned char *buf, int len, bool forcekey)
01951 {
01952 int act;
01953 long tcres;
01954 int fn;
01955 struct timeval now;
01956
01957 act = act_video_buffer;
01958
01959 if (!videobuffer[act]->freeToBuffer) {
01960 return;
01961 }
01962
01963 gettimeofday(&now, &tzone);
01964
01965 tcres = (now.tv_sec-stm.tv_sec)*1000 + now.tv_usec/1000 - stm.tv_usec/1000;
01966
01967 usebttv = 0;
01968
01969 if (!usebttv)
01970 {
01971 if (tf==0)
01972 tf = 2;
01973 else
01974 {
01975 fn = tcres - oldtc;
01976
01977
01978
01979
01980 if (ntsc_framerate)
01981 fn = (fn+16)/33;
01982 else
01983 fn = (fn+20)/40;
01984 if (fn<1)
01985 fn=1;
01986 tf += 2*fn;
01987 }
01988 }
01989
01990 oldtc = tcres;
01991
01992 if (!videobuffer[act]->freeToBuffer)
01993 {
01994 LOG(VB_GENERAL, LOG_INFO, LOC +
01995 "DROPPED frame due to full buffer in the recorder.");
01996 return;
01997 }
01998
01999 videobuffer[act]->sample = tf;
02000
02001
02002
02003 videobuffer[act]->timecode = (ntsc_framerate) ? (tcres - 33) : (tcres - 40);
02004
02005 memcpy(videobuffer[act]->buffer, buf, len);
02006 videobuffer[act]->bufferlen = len;
02007 videobuffer[act]->forcekey = forcekey;
02008
02009 videobuffer[act]->freeToBuffer = 0;
02010 act_video_buffer++;
02011 if (act_video_buffer >= video_buffer_count)
02012 act_video_buffer = 0;
02013 videobuffer[act]->freeToEncode = 1;
02014 return;
02015 }
02016
02017 inline void NuppelVideoRecorder::WriteFrameheader(rtframeheader *fh)
02018 {
02019 #if HAVE_BIGENDIAN
02020 fh->timecode = bswap_32(fh->timecode);
02021 fh->packetlength = bswap_32(fh->packetlength);
02022 #endif
02023 ringBuffer->Write(fh, FRAMEHEADERSIZE);
02024 }
02025
02026 void NuppelVideoRecorder::SetNewVideoParams(double newaspect)
02027 {
02028 if (newaspect == video_aspect)
02029 return;
02030
02031 video_aspect = newaspect;
02032
02033 struct rtframeheader frameheader;
02034 memset(&frameheader, 0, sizeof(frameheader));
02035
02036 frameheader.frametype = 'S';
02037 frameheader.comptype = 'M';
02038 frameheader.packetlength = sizeof(struct rtfileheader);
02039
02040 WriteFrameheader(&frameheader);
02041
02042 WriteFileHeader();
02043 }
02044
02045 void NuppelVideoRecorder::WriteFileHeader(void)
02046 {
02047 struct rtfileheader fileheader;
02048 static const char finfo[12] = "MythTVVideo";
02049 static const char vers[5] = "0.07";
02050
02051 memset(&fileheader, 0, sizeof(fileheader));
02052 memcpy(fileheader.finfo, finfo, sizeof(fileheader.finfo));
02053 memcpy(fileheader.version, vers, sizeof(fileheader.version));
02054 fileheader.width = w_out;
02055 fileheader.height = (int)(h_out * height_multiplier);
02056 fileheader.desiredwidth = 0;
02057 fileheader.desiredheight = 0;
02058 fileheader.pimode = 'P';
02059 fileheader.aspect = video_aspect;
02060 fileheader.fps = video_frame_rate;
02061 fileheader.fps *= framerate_multiplier;
02062 fileheader.videoblocks = -1;
02063 fileheader.audioblocks = -1;
02064 fileheader.textsblocks = -1;
02065 fileheader.keyframedist = KEYFRAMEDIST;
02066
02067 #if HAVE_BIGENDIAN
02068 fileheader.width = bswap_32(fileheader.width);
02069 fileheader.height = bswap_32(fileheader.height);
02070 fileheader.desiredwidth = bswap_32(fileheader.desiredwidth);
02071 fileheader.desiredheight = bswap_32(fileheader.desiredheight);
02072 fileheader.aspect = bswap_dbl(fileheader.aspect);
02073 fileheader.fps = bswap_dbl(fileheader.fps);
02074 fileheader.videoblocks = bswap_32(fileheader.videoblocks);
02075 fileheader.audioblocks = bswap_32(fileheader.audioblocks);
02076 fileheader.textsblocks = bswap_32(fileheader.textsblocks);
02077 fileheader.keyframedist = bswap_32(fileheader.keyframedist);
02078 #endif
02079 ringBuffer->Write(&fileheader, FILEHEADERSIZE);
02080 }
02081
02082 void NuppelVideoRecorder::WriteHeader(void)
02083 {
02084 struct rtframeheader frameheader;
02085 static unsigned long int tbls[128];
02086
02087 if (!videoFilters)
02088 InitFilters();
02089
02090 WriteFileHeader();
02091
02092 memset(&frameheader, 0, sizeof(frameheader));
02093 frameheader.frametype = 'D';
02094
02095 if (useavcodec)
02096 {
02097 frameheader.comptype = 'F';
02098 frameheader.packetlength = mpa_vidctx->extradata_size;
02099
02100 WriteFrameheader(&frameheader);
02101 ringBuffer->Write(mpa_vidctx->extradata, frameheader.packetlength);
02102 }
02103 else
02104 {
02105 frameheader.comptype = 'R';
02106 frameheader.packetlength = sizeof(tbls);
02107
02108
02109 WriteFrameheader(&frameheader);
02110
02111 memset(tbls, 0, sizeof(tbls));
02112 ringBuffer->Write(tbls, sizeof(tbls));
02113 }
02114
02115 memset(&frameheader, 0, sizeof(frameheader));
02116 frameheader.frametype = 'X';
02117 frameheader.packetlength = sizeof(extendeddata);
02118
02119
02120 WriteFrameheader(&frameheader);
02121
02122 struct extendeddata moredata;
02123 memset(&moredata, 0, sizeof(extendeddata));
02124
02125 moredata.version = 1;
02126 if (useavcodec)
02127 {
02128 int vidfcc = 0;
02129 switch(mpa_vidcodec->id)
02130 {
02131 case CODEC_ID_MPEG4: vidfcc = FOURCC_DIVX; break;
02132 case CODEC_ID_WMV1: vidfcc = FOURCC_WMV1; break;
02133 case CODEC_ID_MSMPEG4V3: vidfcc = FOURCC_DIV3; break;
02134 case CODEC_ID_MSMPEG4V2: vidfcc = FOURCC_MP42; break;
02135 case CODEC_ID_MSMPEG4V1: vidfcc = FOURCC_MPG4; break;
02136 case CODEC_ID_MJPEG: vidfcc = FOURCC_MJPG; break;
02137 case CODEC_ID_H263: vidfcc = FOURCC_H263; break;
02138 case CODEC_ID_H263P: vidfcc = FOURCC_H263; break;
02139 case CODEC_ID_H263I: vidfcc = FOURCC_I263; break;
02140 case CODEC_ID_MPEG1VIDEO: vidfcc = FOURCC_MPEG; break;
02141 case CODEC_ID_MPEG2VIDEO: vidfcc = FOURCC_MPG2; break;
02142 case CODEC_ID_HUFFYUV: vidfcc = FOURCC_HFYU; break;
02143 default: break;
02144 }
02145 moredata.video_fourcc = vidfcc;
02146 moredata.lavc_bitrate = mpa_vidctx->bit_rate;
02147 moredata.lavc_qmin = mpa_vidctx->qmin;
02148 moredata.lavc_qmax = mpa_vidctx->qmax;
02149 moredata.lavc_maxqdiff = mpa_vidctx->max_qdiff;
02150 }
02151 else
02152 {
02153 moredata.video_fourcc = FOURCC_RJPG;
02154 moredata.rtjpeg_quality = Q;
02155 moredata.rtjpeg_luma_filter = M1;
02156 moredata.rtjpeg_chroma_filter = M2;
02157 }
02158
02159 if (compressaudio)
02160 {
02161 moredata.audio_fourcc = FOURCC_LAME;
02162 moredata.audio_compression_ratio = 11;
02163 moredata.audio_quality = mp3quality;
02164 }
02165 else
02166 {
02167 moredata.audio_fourcc = FOURCC_RAWA;
02168 }
02169
02170 moredata.audio_sample_rate = audio_samplerate;
02171 moredata.audio_channels = audio_channels;
02172 moredata.audio_bits_per_sample = audio_bits;
02173
02174 extendeddataOffset = ringBuffer->GetWritePosition();
02175
02176 #if HAVE_BIGENDIAN
02177 moredata.version = bswap_32(moredata.version);
02178 moredata.video_fourcc = bswap_32(moredata.video_fourcc);
02179 moredata.audio_fourcc = bswap_32(moredata.audio_fourcc);
02180 moredata.audio_sample_rate = bswap_32(moredata.audio_sample_rate);
02181 moredata.audio_bits_per_sample = bswap_32(moredata.audio_bits_per_sample);
02182 moredata.audio_channels = bswap_32(moredata.audio_channels);
02183 moredata.audio_compression_ratio = bswap_32(moredata.audio_compression_ratio);
02184 moredata.audio_quality = bswap_32(moredata.audio_quality);
02185 moredata.rtjpeg_quality = bswap_32(moredata.rtjpeg_quality);
02186 moredata.rtjpeg_luma_filter = bswap_32(moredata.rtjpeg_luma_filter);
02187 moredata.rtjpeg_chroma_filter = bswap_32(moredata.rtjpeg_chroma_filter);
02188 moredata.lavc_bitrate = bswap_32(moredata.lavc_bitrate);
02189 moredata.lavc_qmin = bswap_32(moredata.lavc_qmin);
02190 moredata.lavc_qmax = bswap_32(moredata.lavc_qmax);
02191 moredata.lavc_maxqdiff = bswap_32(moredata.lavc_maxqdiff);
02192 moredata.seektable_offset = bswap_64(moredata.seektable_offset);
02193 moredata.keyframeadjust_offset = bswap_64(moredata.keyframeadjust_offset);
02194 #endif
02195 ringBuffer->Write(&moredata, sizeof(moredata));
02196
02197 last_block = 0;
02198 lf = 0;
02199
02200 }
02201
02202 void NuppelVideoRecorder::WriteSeekTable(void)
02203 {
02204 int numentries = seektable->size();
02205
02206 struct rtframeheader frameheader;
02207 memset(&frameheader, 0, sizeof(frameheader));
02208 frameheader.frametype = 'Q';
02209 frameheader.packetlength = sizeof(struct seektable_entry) * numentries;
02210
02211 long long currentpos = ringBuffer->GetWritePosition();
02212
02213 ringBuffer->Write(&frameheader, sizeof(frameheader));
02214
02215 char *seekbuf = new char[frameheader.packetlength];
02216 int offset = 0;
02217
02218 vector<struct seektable_entry>::iterator i = seektable->begin();
02219 for (; i != seektable->end(); i++)
02220 {
02221 memcpy(seekbuf + offset, (const void *)&(*i),
02222 sizeof(struct seektable_entry));
02223 offset += sizeof(struct seektable_entry);
02224 }
02225
02226 ringBuffer->Write(seekbuf, frameheader.packetlength);
02227
02228 ringBuffer->WriterSeek(extendeddataOffset +
02229 offsetof(struct extendeddata, seektable_offset),
02230 SEEK_SET);
02231
02232 ringBuffer->Write(¤tpos, sizeof(long long));
02233
02234 ringBuffer->WriterSeek(0, SEEK_END);
02235
02236 delete [] seekbuf;
02237 }
02238
02239 void NuppelVideoRecorder::WriteKeyFrameAdjustTable(
02240 const vector<struct kfatable_entry> &kfa_table)
02241 {
02242 int numentries = kfa_table.size();
02243
02244 struct rtframeheader frameheader;
02245 memset(&frameheader, 0, sizeof(frameheader));
02246 frameheader.frametype = 'K';
02247 frameheader.packetlength = sizeof(struct kfatable_entry) * numentries;
02248
02249 long long currentpos = ringBuffer->GetWritePosition();
02250
02251 ringBuffer->Write(&frameheader, sizeof(frameheader));
02252
02253 char *kfa_buf = new char[frameheader.packetlength];
02254 uint offset = 0;
02255
02256 vector<struct kfatable_entry>::const_iterator it = kfa_table.begin();
02257 for (; it != kfa_table.end() ; ++it)
02258 {
02259 memcpy(kfa_buf + offset, &(*it),
02260 sizeof(struct kfatable_entry));
02261 offset += sizeof(struct kfatable_entry);
02262 }
02263
02264 ringBuffer->Write(kfa_buf, frameheader.packetlength);
02265
02266
02267 ringBuffer->WriterSeek(extendeddataOffset +
02268 offsetof(struct extendeddata, keyframeadjust_offset),
02269 SEEK_SET);
02270
02271 ringBuffer->Write(¤tpos, sizeof(long long));
02272
02273 ringBuffer->WriterSeek(0, SEEK_END);
02274
02275 delete [] kfa_buf;
02276 }
02277
02278 void NuppelVideoRecorder::UpdateSeekTable(int frame_num, long offset)
02279 {
02280 long long position = ringBuffer->GetWritePosition() + offset;
02281 struct seektable_entry ste;
02282 ste.file_offset = position;
02283 ste.keyframe_number = frame_num;
02284 seektable->push_back(ste);
02285
02286 positionMapLock.lock();
02287 if (!positionMap.contains(ste.keyframe_number))
02288 {
02289 positionMapDelta[ste.keyframe_number] = position;
02290 positionMap[ste.keyframe_number] = position;
02291 lastPositionMapPos = position;
02292 }
02293 positionMapLock.unlock();
02294 }
02295
02296 int NuppelVideoRecorder::CreateNuppelFile(void)
02297 {
02298 framesWritten = 0;
02299
02300 if (!ringBuffer)
02301 {
02302 LOG(VB_GENERAL, LOG_ERR, LOC +
02303 "No ringbuffer, recorder wasn't initialized.");
02304 return -1;
02305 }
02306
02307 if (!ringBuffer->IsOpen())
02308 {
02309 LOG(VB_GENERAL, LOG_ERR, LOC + "Ringbuffer isn't open");
02310 return -1;
02311 }
02312
02313 WriteHeader();
02314
02315 return 0;
02316 }
02317
02318 void NuppelVideoRecorder::Reset(void)
02319 {
02320 ResetForNewFile();
02321
02322 for (int i = 0; i < video_buffer_count; i++)
02323 {
02324 vidbuffertype *vidbuf = videobuffer[i];
02325 vidbuf->sample = 0;
02326 vidbuf->timecode = 0;
02327 vidbuf->freeToEncode = 0;
02328 vidbuf->freeToBuffer = 1;
02329 vidbuf->forcekey = 0;
02330 }
02331
02332 for (int i = 0; i < audio_buffer_count; i++)
02333 {
02334 audbuffertype *audbuf = audiobuffer[i];
02335 audbuf->sample = 0;
02336 audbuf->timecode = 0;
02337 audbuf->freeToEncode = 0;
02338 audbuf->freeToBuffer = 1;
02339 }
02340
02341 for (int i = 0; i < text_buffer_count; i++)
02342 {
02343 txtbuffertype *txtbuf = textbuffer[i];
02344 txtbuf->freeToEncode = 0;
02345 txtbuf->freeToBuffer = 1;
02346 }
02347
02348 act_video_encode = 0;
02349 act_video_buffer = 0;
02350 act_audio_encode = 0;
02351 act_audio_buffer = 0;
02352 act_audio_sample = 0;
02353 act_text_encode = 0;
02354 act_text_buffer = 0;
02355
02356 audiobytes = 0;
02357 effectivedsp = 0;
02358
02359 if (useavcodec)
02360 SetupAVCodecVideo();
02361
02362 if (curRecording)
02363 curRecording->ClearPositionMap(MARK_KEYFRAME);
02364 }
02365
02366 void NuppelVideoRecorder::doAudioThread(void)
02367 {
02368 if (!audio_device)
02369 {
02370 LOG(VB_GENERAL, LOG_ERR, LOC +
02371 QString("Invalid audio device (%1), exiting").arg(audiodevice));
02372 return;
02373 }
02374
02375 if (!audio_device->Open(audio_bits, audio_samplerate, audio_channels))
02376 {
02377 LOG(VB_GENERAL, LOG_ERR, LOC +
02378 QString("Failed to open audio device %1").arg(audiodevice));
02379 return;
02380 }
02381
02382 if (!audio_device->Start())
02383 {
02384 LOG(VB_GENERAL, LOG_ERR, LOC +
02385 QString("Failed to start audio capture on %1").arg(audiodevice));
02386 return;
02387 }
02388
02389 struct timeval anow;
02390 unsigned char *buffer = new unsigned char[audio_buffer_size];
02391 int act = 0, lastread = 0;
02392 audio_bytes_per_sample = audio_channels * audio_bits / 8;
02393
02394 while (IsHelperRequested() && !IsErrored())
02395 {
02396 {
02397 QMutexLocker locker(&pauseLock);
02398 if (request_pause)
02399 {
02400 if (!audiopaused)
02401 {
02402 audiopaused = true;
02403 pauseWait.wakeAll();
02404 if (IsPaused(true) && tvrec)
02405 tvrec->RecorderPaused();
02406 }
02407 unpauseWait.wait(&pauseLock, 100);
02408 continue;
02409 }
02410
02411 if (!request_pause && audiopaused)
02412 {
02413 audiopaused = false;
02414 unpauseWait.wakeAll();
02415 }
02416 }
02417
02418 if (!IsHelperRequested() || IsErrored())
02419 break;
02420
02421 lastread = audio_device->GetSamples(buffer, audio_buffer_size);
02422 if (audio_buffer_size != lastread)
02423 {
02424 LOG(VB_GENERAL, LOG_ERR, LOC +
02425 QString("Short read, %1 of %2 bytes from ")
02426 .arg(lastread).arg(audio_buffer_size) + audiodevice);
02427 }
02428
02429
02430
02431
02432
02433 gettimeofday(&anow, &tzone);
02434 int bytes_read = max(audio_device->GetNumReadyBytes(), 0);
02435
02436 act = act_audio_buffer;
02437
02438 if (!audiobuffer[act]->freeToBuffer)
02439 {
02440 LOG(VB_GENERAL, LOG_ERR, LOC + "Ran out of free AUDIO buffers :-(");
02441 act_audio_sample++;
02442 continue;
02443 }
02444
02445 audiobuffer[act]->sample = act_audio_sample;
02446
02447
02448
02449 audiobuffer[act]->timecode = (anow.tv_sec - stm.tv_sec) * 1000 +
02450 anow.tv_usec / 1000 - stm.tv_usec / 1000;
02451
02452
02453
02454 audiobuffer[act]->timecode -= (int)(
02455 (bytes_read + audio_buffer_size)
02456 * 1000.0 / (audio_samplerate * audio_bytes_per_sample));
02457
02458 memcpy(audiobuffer[act]->buffer, buffer, audio_buffer_size);
02459
02460 audiobuffer[act]->freeToBuffer = 0;
02461 act_audio_buffer++;
02462 if (act_audio_buffer >= audio_buffer_count)
02463 act_audio_buffer = 0;
02464 audiobuffer[act]->freeToEncode = 1;
02465
02466 act_audio_sample++;
02467 }
02468
02469 delete [] buffer;
02470
02471 if (audio_device->IsOpen())
02472 audio_device->Close();
02473 }
02474
02475 #ifdef USING_V4L2
02476 void NuppelVideoRecorder::FormatTT(struct VBIData *vbidata)
02477 {
02478 struct timeval tnow;
02479 gettimeofday(&tnow, &tzone);
02480
02481 int act = act_text_buffer;
02482 if (!textbuffer[act]->freeToBuffer)
02483 {
02484 LOG(VB_GENERAL, LOG_ERR, LOC +
02485 QString("Teletext #%1: ran out of free TEXT buffers :-(").arg(act));
02486 return;
02487 }
02488
02489
02490
02491 textbuffer[act]->timecode = (tnow.tv_sec-stm.tv_sec) * 1000 +
02492 tnow.tv_usec/1000 - stm.tv_usec/1000;
02493 textbuffer[act]->pagenr = (vbidata->teletextpage.pgno << 16) +
02494 vbidata->teletextpage.subno;
02495
02496 unsigned char *inpos = vbidata->teletextpage.data[0];
02497 unsigned char *outpos = textbuffer[act]->buffer;
02498 *outpos = 0;
02499 struct teletextsubtitle st = { 0 };
02500 unsigned char linebuf[VT_WIDTH + 1];
02501 unsigned char *linebufpos = linebuf;
02502
02503 for (int y = 0; y < VT_HEIGHT; y++)
02504 {
02505 char c = ' ';
02506 char last_c = ' ';
02507 int hid = 0;
02508 int gfx = 0;
02509 int dbl = 0;
02510 int box = 0;
02511 int sep = 0;
02512 int hold = 0;
02513 int visible = 0;
02514 int fg = 7;
02515 int bg = 0;
02516
02517 for (int x = 0; x < VT_WIDTH; ++x)
02518 {
02519 c = *inpos++;
02520 switch (c)
02521 {
02522 case 0x00 ... 0x07:
02523 fg = c & 7;
02524 gfx = 0;
02525 sep = 0;
02526 hid = 0;
02527 goto ctrl;
02528 case 0x08:
02529 goto ctrl;
02530 case 0x09:
02531 goto ctrl;
02532 case 0x0a:
02533 box = 0;
02534 goto ctrl;
02535 case 0x0b:
02536 box = 1;
02537 goto ctrl;
02538 case 0x0c:
02539 dbl = 0;
02540 goto ctrl;
02541 case 0x0d:
02542 if (y < VT_HEIGHT-2)
02543 {
02544 dbl = 1;
02545 }
02546 goto ctrl;
02547 case 0x10 ... 0x17:
02548 fg = c & 7;
02549 gfx = 1;
02550 hid = 0;
02551 goto ctrl;
02552 case 0x18:
02553 hid = 1;
02554 goto ctrl;
02555 case 0x19:
02556 hid = 0;
02557 sep = 0;
02558 goto ctrl;
02559 case 0x1a:
02560 sep = 1;
02561 goto ctrl;
02562 case 0x1c:
02563 bg = 0;
02564 goto ctrl;
02565 case 0x1d:
02566 bg = fg;
02567 goto ctrl;
02568 case 0x1e:
02569 hold = 1;
02570 goto ctrl;
02571 case 0x1f:
02572 hold = 0;
02573 goto ctrl;
02574 case 0x0e:
02575 goto ctrl;
02576 case 0x0f:
02577 goto ctrl;
02578 case 0x1b:
02579 goto ctrl;
02580
02581 ctrl:
02582 c = ' ';
02583 if (hold && gfx)
02584 c = last_c;
02585 break;
02586 }
02587 if (gfx)
02588 if ((c & 0xa0) == 0x20)
02589 {
02590 last_c = c;
02591 c += (c & 0x40) ? 32 : -32;
02592 }
02593 if (hid)
02594 c = ' ';
02595
02596 if (visible || (c != ' '))
02597 {
02598 if (!visible)
02599 {
02600 st.row = y;
02601 st.col = x;
02602 st.dbl = dbl;
02603 st.fg = fg;
02604 st.bg = bg;
02605 linebufpos = linebuf;
02606 *linebufpos = 0;
02607 }
02608 *linebufpos++ = c;
02609 *linebufpos = 0;
02610 visible = 1;
02611 }
02612 }
02613 if (visible)
02614 {
02615 st.len = linebufpos - linebuf + 1;;
02616 int max = 200;
02617 int bufsize = ((outpos - textbuffer[act]->buffer + 1) + st.len);
02618 if (bufsize > max)
02619 break;
02620 memcpy(outpos, &st, sizeof(st));
02621 outpos += sizeof(st);
02622 if (st.len < 42)
02623 {
02624 memcpy(outpos, linebuf, st.len);
02625 outpos += st.len;
02626 }
02627 else
02628 {
02629 memcpy(outpos, linebuf, 41);
02630 outpos += 41;
02631 }
02632 *outpos = 0;
02633 }
02634 }
02635
02636 textbuffer[act]->bufferlen = outpos - textbuffer[act]->buffer + 1;
02637 textbuffer[act]->freeToBuffer = 0;
02638 act_text_buffer++;
02639 if (act_text_buffer >= text_buffer_count)
02640 act_text_buffer = 0;
02641 textbuffer[act]->freeToEncode = 1;
02642 }
02643 #else // USING_V4L2
02644 void NuppelVideoRecorder::FormatTT(struct VBIData*) {}
02645 #endif // USING_V4L2
02646
02647 void NuppelVideoRecorder::FormatCC(uint code1, uint code2)
02648 {
02649 struct timeval tnow;
02650 gettimeofday (&tnow, &tzone);
02651
02652
02653
02654 int tc = (tnow.tv_sec - stm.tv_sec) * 1000 +
02655 tnow.tv_usec / 1000 - stm.tv_usec / 1000;
02656
02657 ccd->FormatCC(tc, code1, code2);
02658 }
02659
02660 void NuppelVideoRecorder::AddTextData(unsigned char *buf, int len,
02661 int64_t timecode, char )
02662 {
02663 int act = act_text_buffer;
02664 if (!textbuffer[act]->freeToBuffer)
02665 {
02666 LOG(VB_GENERAL, LOG_ERR, LOC + QString("Teletext#%1").arg(act) +
02667 " ran out of free TEXT buffers :-(");
02668 return;
02669 }
02670
02671 textbuffer[act]->timecode = timecode;
02672 memcpy(textbuffer[act]->buffer, buf, len);
02673 textbuffer[act]->bufferlen = len + sizeof(ccsubtitle);
02674
02675 textbuffer[act]->freeToBuffer = 0;
02676 act_text_buffer++;
02677 if (act_text_buffer >= text_buffer_count)
02678 act_text_buffer = 0;
02679 textbuffer[act]->freeToEncode = 1;
02680 }
02681
02682 void NuppelVideoRecorder::doWriteThread(void)
02683 {
02684 while (IsHelperRequested() && !IsErrored())
02685 {
02686 {
02687 QMutexLocker locker(&pauseLock);
02688 if (request_pause)
02689 {
02690 if (!writepaused)
02691 {
02692 writepaused = true;
02693 pauseWait.wakeAll();
02694 if (IsPaused(true) && tvrec)
02695 tvrec->RecorderPaused();
02696 }
02697 unpauseWait.wait(&pauseLock, 100);
02698 continue;
02699 }
02700
02701 if (!request_pause && writepaused)
02702 {
02703 writepaused = false;
02704 unpauseWait.wakeAll();
02705 }
02706 }
02707
02708 if (!IsHelperRequested() || IsErrored())
02709 break;
02710
02711 CheckForRingBufferSwitch();
02712
02713 enum
02714 { ACTION_NONE,
02715 ACTION_VIDEO,
02716 ACTION_AUDIO,
02717 ACTION_TEXT
02718 } action = ACTION_NONE;
02719 int firsttimecode = -1;
02720
02721 if (videobuffer[act_video_encode]->freeToEncode)
02722 {
02723 action = ACTION_VIDEO;
02724 firsttimecode = videobuffer[act_video_encode]->timecode;
02725 }
02726
02727 if (audio_buffer_count &&
02728 audiobuffer[act_audio_encode]->freeToEncode &&
02729 (action == ACTION_NONE ||
02730 (audiobuffer[act_audio_encode]->timecode < firsttimecode)))
02731 {
02732 action = ACTION_AUDIO;
02733 firsttimecode = audiobuffer[act_audio_encode]->timecode;
02734 }
02735
02736 if (text_buffer_count &&
02737 textbuffer[act_text_encode]->freeToEncode &&
02738 (action == ACTION_NONE ||
02739 (textbuffer[act_text_encode]->timecode < firsttimecode)))
02740 {
02741 action = ACTION_TEXT;
02742 }
02743
02744 switch (action)
02745 {
02746 case ACTION_VIDEO:
02747 {
02748 VideoFrame frame;
02749 init(&frame,
02750 FMT_YV12, videobuffer[act_video_encode]->buffer,
02751 width, height, videobuffer[act_video_encode]->bufferlen);
02752
02753 frame.frameNumber = videobuffer[act_video_encode]->sample;
02754 frame.timecode = videobuffer[act_video_encode]->timecode;
02755 frame.forcekey = videobuffer[act_video_encode]->forcekey;
02756
02757 WriteVideo(&frame);
02758
02759 videobuffer[act_video_encode]->sample = 0;
02760 videobuffer[act_video_encode]->freeToEncode = 0;
02761 videobuffer[act_video_encode]->freeToBuffer = 1;
02762 videobuffer[act_video_encode]->forcekey = 0;
02763 act_video_encode++;
02764 if (act_video_encode >= video_buffer_count)
02765 act_video_encode = 0;
02766 break;
02767 }
02768 case ACTION_AUDIO:
02769 {
02770 WriteAudio(audiobuffer[act_audio_encode]->buffer,
02771 audiobuffer[act_audio_encode]->sample,
02772 audiobuffer[act_audio_encode]->timecode);
02773 if (IsErrored()) {
02774 LOG(VB_GENERAL, LOG_ERR, LOC +
02775 "ACTION_AUDIO cannot be completed due to error.");
02776 StopRecording();
02777 break;
02778 }
02779 audiobuffer[act_audio_encode]->sample = 0;
02780 audiobuffer[act_audio_encode]->freeToEncode = 0;
02781 audiobuffer[act_audio_encode]->freeToBuffer = 1;
02782 act_audio_encode++;
02783 if (act_audio_encode >= audio_buffer_count)
02784 act_audio_encode = 0;
02785 break;
02786 }
02787 case ACTION_TEXT:
02788 {
02789 WriteText(textbuffer[act_text_encode]->buffer,
02790 textbuffer[act_text_encode]->bufferlen,
02791 textbuffer[act_text_encode]->timecode,
02792 textbuffer[act_text_encode]->pagenr);
02793 textbuffer[act_text_encode]->freeToEncode = 0;
02794 textbuffer[act_text_encode]->freeToBuffer = 1;
02795 act_text_encode++;
02796 if (act_text_encode >= text_buffer_count)
02797 act_text_encode = 0;
02798 break;
02799 }
02800 default:
02801 {
02802 usleep(100);
02803 break;
02804 }
02805 }
02806 }
02807 }
02808
02809 void NuppelVideoRecorder::SetNextRecording(const ProgramInfo *progInf,
02810 RingBuffer *rb)
02811 {
02812
02813 SavePositionMap(true);
02814 ringBuffer->WriterFlush();
02815 if (curRecording)
02816 curRecording->SaveFilesize(ringBuffer->GetRealFileSize());
02817
02818
02819 QMutexLocker locker(&nextRingBufferLock);
02820 nextRecording = NULL;
02821 if (progInf)
02822 nextRecording = new ProgramInfo(*progInf);
02823 nextRingBuffer = rb;
02824 }
02825
02826 void NuppelVideoRecorder::ResetForNewFile(void)
02827 {
02828 framesWritten = 0;
02829 lf = 0;
02830 last_block = 0;
02831
02832 seektable->clear();
02833
02834 ClearStatistics();
02835
02836 positionMapLock.lock();
02837 positionMap.clear();
02838 positionMapDelta.clear();
02839 positionMapLock.unlock();
02840
02841 if (go7007)
02842 resetcapture = true;
02843 }
02844
02845 void NuppelVideoRecorder::StartNewFile(void)
02846 {
02847 CreateNuppelFile();
02848 }
02849
02850 void NuppelVideoRecorder::FinishRecording(void)
02851 {
02852 ringBuffer->WriterFlush();
02853
02854 WriteSeekTable();
02855
02856 if (curRecording)
02857 {
02858 curRecording->SaveFilesize(ringBuffer->GetRealFileSize());
02859 SavePositionMap(true);
02860 }
02861 positionMapLock.lock();
02862 positionMap.clear();
02863 positionMapDelta.clear();
02864 positionMapLock.unlock();
02865 }
02866
02867 void NuppelVideoRecorder::WriteVideo(VideoFrame *frame, bool skipsync,
02868 bool forcekey)
02869 {
02870 int tmp = 0;
02871 lzo_uint out_len = OUT_LEN;
02872 struct rtframeheader frameheader;
02873 int raw = 0, compressthis = compression;
02874 uint8_t *planes[3];
02875 int len = frame->size;
02876 int fnum = frame->frameNumber;
02877 long long timecode = frame->timecode;
02878 unsigned char *buf = frame->buf;
02879
02880 memset(&frameheader, 0, sizeof(frameheader));
02881
02882 planes[0] = buf;
02883 planes[1] = planes[0] + frame->width * frame->height;
02884 planes[2] = planes[1] + (frame->width * frame->height) /
02885 (picture_format == PIX_FMT_YUV422P ? 2 : 4);
02886
02887 if (lf == 0)
02888 {
02889 lf = fnum;
02890 startnum = fnum;
02891 lasttimecode = 0;
02892 frameofgop = 0;
02893 forcekey = true;
02894 }
02895
02896
02897 frameheader.keyframe = frameofgop;
02898
02899 bool wantkeyframe = forcekey;
02900
02901 bool writesync = false;
02902
02903 if (!go7007 && (((fnum-startnum)>>1) % keyframedist == 0 && !skipsync))
02904 writesync = true;
02905 else if (go7007 && frame->forcekey)
02906 writesync = true;
02907
02908 if (writesync)
02909 {
02910 ringBuffer->Write("RTjjjjjjjjjjjjjjjjjjjjjjjj", FRAMEHEADERSIZE);
02911
02912 UpdateSeekTable(((fnum - startnum) >> 1) / keyframedist);
02913
02914 frameheader.frametype = 'S';
02915 frameheader.comptype = 'V';
02916 frameheader.filters = 0;
02917 frameheader.packetlength = 0;
02918 frameheader.timecode = (fnum-startnum)>>1;
02919
02920 WriteFrameheader(&frameheader);
02921 frameheader.frametype = 'S';
02922 frameheader.comptype = 'A';
02923 frameheader.filters = 0;
02924 frameheader.packetlength = 0;
02925 frameheader.timecode = effectivedsp;
02926
02927 WriteFrameheader(&frameheader);
02928
02929 wantkeyframe = true;
02930
02931 }
02932
02933 if (wantkeyframe)
02934 {
02935 frameheader.keyframe=0;
02936 frameofgop=0;
02937 }
02938
02939 if (videoFilters)
02940 videoFilters->ProcessFrame(frame);
02941
02942 if (useavcodec)
02943 {
02944 mpa_picture.data[0] = planes[0];
02945 mpa_picture.data[1] = planes[1];
02946 mpa_picture.data[2] = planes[2];
02947 mpa_picture.linesize[0] = frame->width;
02948 mpa_picture.linesize[1] = frame->width / 2;
02949 mpa_picture.linesize[2] = frame->width / 2;
02950 mpa_picture.type = FF_BUFFER_TYPE_SHARED;
02951
02952 if (wantkeyframe)
02953 mpa_picture.pict_type = AV_PICTURE_TYPE_I;
02954 else
02955 mpa_picture.pict_type = AV_PICTURE_TYPE_NONE;
02956
02957 if (!hardware_encode)
02958 {
02959 AVPacket packet;
02960 packet.data = (uint8_t *)strm;
02961 packet.size = len;
02962
02963 int got_packet = 0;
02964
02965 QMutexLocker locker(avcodeclock);
02966 tmp = avcodec_encode_video2(mpa_vidctx, &packet, &mpa_picture,
02967 &got_packet);
02968
02969 if (tmp < 0 || !got_packet)
02970 {
02971 LOG(VB_GENERAL, LOG_ERR, LOC +
02972 "WriteVideo : avcodec_encode_video() failed");
02973 return;
02974 }
02975 }
02976 }
02977 else
02978 {
02979 int freecount = 0;
02980 freecount = act_video_buffer > act_video_encode ?
02981 video_buffer_count - (act_video_buffer - act_video_encode) :
02982 act_video_encode - act_video_buffer;
02983
02984 if (freecount < (video_buffer_count / 3))
02985 compressthis = 0;
02986
02987 if (freecount < 5)
02988 raw = 1;
02989
02990 if (transcoding)
02991 {
02992 raw = 0;
02993 compressthis = 1;
02994 }
02995
02996 if (!raw)
02997 {
02998 if (wantkeyframe)
02999 rtjc->SetNextKey();
03000 tmp = rtjc->Compress(strm, planes);
03001 }
03002 else
03003 tmp = len;
03004
03005
03006 if (compressthis)
03007 {
03008 int r = 0;
03009 if (raw)
03010 r = lzo1x_1_compress((unsigned char*)buf, len,
03011 out, &out_len, wrkmem);
03012 else
03013 r = lzo1x_1_compress((unsigned char *)strm, tmp, out,
03014 &out_len, wrkmem);
03015 if (r != LZO_E_OK)
03016 {
03017 LOG(VB_GENERAL, LOG_ERR, LOC + "lzo compression failed");
03018 return;
03019 }
03020 }
03021 }
03022
03023 frameheader.frametype = 'V';
03024 frameheader.timecode = timecode;
03025 lasttimecode = frameheader.timecode;
03026 frameheader.filters = 0;
03027
03028
03029 if (useavcodec)
03030 {
03031 if (mpa_vidcodec->id == CODEC_ID_RAWVIDEO)
03032 {
03033 frameheader.comptype = '0';
03034 frameheader.packetlength = len;
03035 WriteFrameheader(&frameheader);
03036 ringBuffer->Write(buf, len);
03037 }
03038 else if (hardware_encode)
03039 {
03040 frameheader.comptype = '4';
03041 frameheader.packetlength = len;
03042 WriteFrameheader(&frameheader);
03043 ringBuffer->Write(buf, len);
03044 }
03045 else
03046 {
03047 frameheader.comptype = '4';
03048 frameheader.packetlength = tmp;
03049 WriteFrameheader(&frameheader);
03050 ringBuffer->Write(strm, tmp);
03051 }
03052 }
03053 else if (compressthis == 0 || (tmp < (int)out_len))
03054 {
03055 if (!raw)
03056 {
03057 frameheader.comptype = '1';
03058 frameheader.packetlength = tmp;
03059 WriteFrameheader(&frameheader);
03060 ringBuffer->Write(strm, tmp);
03061 }
03062 else
03063 {
03064 frameheader.comptype = '0';
03065 frameheader.packetlength = len;
03066 WriteFrameheader(&frameheader);
03067 ringBuffer->Write(buf, len);
03068 }
03069 }
03070 else
03071 {
03072 if (!raw)
03073 frameheader.comptype = '2';
03074 else
03075 frameheader.comptype = '3';
03076 frameheader.packetlength = out_len;
03077 WriteFrameheader(&frameheader);
03078 ringBuffer->Write(out, out_len);
03079 }
03080
03081 frameofgop++;
03082 framesWritten++;
03083
03084
03085
03086 lf = fnum;
03087 }
03088
03089 #if HAVE_BIGENDIAN
03090 static void bswap_16_buf(short int *buf, int buf_cnt, int audio_channels)
03091 __attribute__ ((unused));
03092
03093 static void bswap_16_buf(short int *buf, int buf_cnt, int audio_channels)
03094 {
03095 for (int i = 0; i < audio_channels * buf_cnt; i++)
03096 buf[i] = bswap_16(buf[i]);
03097 }
03098 #endif
03099
03100 void NuppelVideoRecorder::WriteAudio(unsigned char *buf, int fnum, int timecode)
03101 {
03102 struct rtframeheader frameheader;
03103 double mt;
03104 double eff;
03105 double abytes;
03106
03107 if (last_block == 0)
03108 {
03109 firsttc = -1;
03110 }
03111
03112 if (last_block != 0)
03113 {
03114 if (fnum != (last_block+1))
03115 {
03116 audio_behind = fnum - (last_block+1);
03117 LOG(VB_RECORD, LOG_INFO, LOC + QString("audio behind %1 %2").
03118 arg(last_block).arg(fnum));
03119 }
03120 }
03121
03122 frameheader.frametype = 'A';
03123 frameheader.timecode = timecode;
03124
03125 if (firsttc == -1)
03126 {
03127 firsttc = timecode;
03128 #if 0
03129 LOG(VB_GENERAL, LOG_DEBUG, LOC +
03130 QString("first timecode=%1").arg(firsttc));
03131 #endif
03132 }
03133 else
03134 {
03135 timecode -= firsttc;
03136
03137
03138
03139 abytes = (double)audiobytes;
03140
03141
03142 mt = (double)timecode;
03143 if (mt > 0.0)
03144 {
03145 eff = (abytes / mt) * (100000.0 / audio_bytes_per_sample);
03146 effectivedsp = (int)eff;
03147 }
03148 }
03149
03150 if (compressaudio)
03151 {
03152 char mp3gapless[7200];
03153 int compressedsize = 0;
03154 int gaplesssize = 0;
03155 int lameret = 0;
03156
03157 int sample_cnt = audio_buffer_size / audio_bytes_per_sample;
03158
03159 #if HAVE_BIGENDIAN
03160 bswap_16_buf((short int*) buf, sample_cnt, audio_channels);
03161 #endif
03162
03163 if (audio_channels == 2)
03164 {
03165 lameret = lame_encode_buffer_interleaved(
03166 gf, (short int*) buf, sample_cnt,
03167 (unsigned char*) mp3buf, mp3buf_size);
03168 }
03169 else
03170 {
03171 lameret = lame_encode_buffer(
03172 gf, (short int*) buf, (short int*) buf, sample_cnt,
03173 (unsigned char*) mp3buf, mp3buf_size);
03174 }
03175
03176 if (lameret < 0)
03177 {
03178 LOG(VB_GENERAL, LOG_ERR, LOC +
03179 QString("lame error '%1'").arg(lameret));
03180 _error = QString("Audio Encoding Error '%1'")
03181 .arg(lameret);
03182 return;
03183 }
03184 compressedsize = lameret;
03185
03186 lameret = lame_encode_flush_nogap(gf, (unsigned char *)mp3gapless,
03187 7200);
03188 if (lameret < 0)
03189 {
03190 LOG(VB_GENERAL, LOG_ERR, LOC +
03191 QString("lame error '%1'").arg(lameret));
03192 _error = QString("Audio Encoding Error '%1'")
03193 .arg(lameret);
03194 return;
03195 }
03196 gaplesssize = lameret;
03197
03198 frameheader.comptype = '3';
03199 frameheader.packetlength = compressedsize + gaplesssize;
03200
03201 if (frameheader.packetlength > 0)
03202 {
03203 WriteFrameheader(&frameheader);
03204 ringBuffer->Write(mp3buf, compressedsize);
03205 ringBuffer->Write(mp3gapless, gaplesssize);
03206 }
03207 audiobytes += audio_buffer_size;
03208 }
03209 else
03210 {
03211 frameheader.comptype = '0';
03212 frameheader.packetlength = audio_buffer_size;
03213
03214 WriteFrameheader(&frameheader);
03215 ringBuffer->Write(buf, audio_buffer_size);
03216 audiobytes += audio_buffer_size;
03217 }
03218
03219
03220
03221 if (audio_behind > 0)
03222 {
03223 LOG(VB_RECORD, LOG_INFO, LOC + "audio behind");
03224 frameheader.frametype = 'A';
03225 frameheader.comptype = 'N';
03226 frameheader.packetlength = 0;
03227 WriteFrameheader(&frameheader);
03228 audiobytes += audio_buffer_size;
03229 audio_behind--;
03230 }
03231
03232 last_block = fnum;
03233 }
03234
03235 void NuppelVideoRecorder::WriteText(unsigned char *buf, int len, int timecode,
03236 int pagenr)
03237 {
03238 struct rtframeheader frameheader;
03239
03240 frameheader.frametype = 'T';
03241 frameheader.timecode = timecode;
03242
03243 if (VBIMode::PAL_TT == vbimode)
03244 {
03245 frameheader.comptype = 'T';
03246 frameheader.packetlength = len + 4;
03247 WriteFrameheader(&frameheader);
03248 union page_t {
03249 int32_t val32;
03250 struct { int8_t a,b,c,d; } val8;
03251 } v;
03252 v.val32 = pagenr;
03253 ringBuffer->Write(&v.val8.d, sizeof(int8_t));
03254 ringBuffer->Write(&v.val8.c, sizeof(int8_t));
03255 ringBuffer->Write(&v.val8.b, sizeof(int8_t));
03256 ringBuffer->Write(&v.val8.a, sizeof(int8_t));
03257 ringBuffer->Write(buf, len);
03258 }
03259 else if (VBIMode::NTSC_CC == vbimode)
03260 {
03261 frameheader.comptype = 'C';
03262 frameheader.packetlength = len;
03263
03264 WriteFrameheader(&frameheader);
03265 ringBuffer->Write(buf, len);
03266 }
03267 }
03268
03269
03270