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