|
MythTV
0.26-pre
|
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 // The wakeAll is to make sure [write|audio|main]paused are 00463 // set immediately, even if we were already paused previously. 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 // avcodec needs specific settings for mpeg2 compression 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 // avcodec needs specific settings for mpeg2 compression 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 // save the start time 01128 gettimeofday(&stm, &tzone); 01129 01130 // try to get run at higher scheduling priority, ignore failure 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 // Set volume level for audio recording (unless feature is disabled). 01188 if (!skip_btaudio) 01189 { 01190 // v4l1 compat in Linux 2.6.18 does not set VIDEO_VC_AUDIO, 01191 // so we just use VIDIOCGAUDIO unconditionally.. then only 01192 // report a get failure as an error if VIDEO_VC_AUDIO is set. 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 // print at VB_GENERAL if driver reports audio. 01198 LOG(err_level, LOG_ERR, LOC + "Failed to get audio" + ENO); 01199 } 01200 else 01201 { 01202 // if channel has a audio then activate it 01203 va.flags &= ~VIDEO_AUDIO_MUTE; // now this really has to work 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 //memset(buf+vm.offsets[0], 0, video_buffer_size); 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 //memset(buf+vm.offsets[1], 0, video_buffer_size); 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 // this is supported by the cx88 and various ati cards. 01370 vfmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV; 01371 01372 if (ioctl(fd, VIDIOC_S_FMT, &vfmt) < 0) 01373 { 01374 // this is supported by the HVR-950q 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 // we need to convert the buffer - we can't deal with uyvy 01385 // directly. 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 // we need to convert the buffer - we can't deal with yuyv directly. 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 // cool, we can do our preferred format, most likely running on bttv. 01416 LOG(VB_RECORD, LOG_INFO, LOC + 01417 "v4l2: format set, getting yuv420 from v4l"); 01418 01419 // VIDIOC_S_FMT might change the format, check it 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 // setup pixel format conversions for YUYV and UYVY 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 // EIO failed DQBUF de-tunes post 2.6.15.3 for cx88 01699 // EIO or EINVAL on bttv means we need to reset the buffers.. 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 // buffer the frame directly 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 //bparm.input = 2; 01783 //bparm.norm = 1; 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 // here is the non preferable timecode - drop algorithm - fallback 01969 if (!usebttv) 01970 { 01971 if (tf==0) 01972 tf = 2; 01973 else 01974 { 01975 fn = tcres - oldtc; 01976 01977 // the difference should be less than 1,5*timeperframe or we have 01978 // missed at least one frame, this code might be inaccurate! 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; // two fields 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; // we can't buffer the current frame 01997 } 01998 01999 videobuffer[act]->sample = tf; 02000 02001 // record the time at the start of this frame. 02002 // 'tcres' is at the end of the frame, so subtract the right # of ms 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; // cycle to begin of buffer 02013 videobuffer[act]->freeToEncode = 1; // set last to prevent race 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; // TODO: make only -1 if VBI support active? 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'; // compressor data 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'; // compressor data for RTjpeg 02106 frameheader.packetlength = sizeof(tbls); 02107 02108 // compression configuration header 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'; // extended data 02117 frameheader.packetlength = sizeof(extendeddata); 02118 02119 // extended data header 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; // that resets framenumber so that seeking in the 02199 // continues parts works too 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'; // SeekTable 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'; // KFA Table 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 /* record the current time */ 02430 /* Don't assume that the sound device's record buffer is empty 02431 (like we used to.) Measure to see how much stuff is in there, 02432 and correct for it when calculating the timestamp */ 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 /* calculate timecode. First compute the difference 02448 between now and stm (start time) */ 02449 audiobuffer[act]->timecode = (anow.tv_sec - stm.tv_sec) * 1000 + 02450 anow.tv_usec / 1000 - stm.tv_usec / 1000; 02451 /* We want the timestamp to point to the start of this 02452 audio chunk. So, subtract off the length of the chunk 02453 and the length of audio still in the capture buffer. */ 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 // calculate timecode: 02490 // compute the difference between now and stm (start time) 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: /* alpha + fg color */ 02523 fg = c & 7; 02524 gfx = 0; 02525 sep = 0; 02526 hid = 0; 02527 goto ctrl; 02528 case 0x08: /* flash */ 02529 goto ctrl; 02530 case 0x09: /* steady */ 02531 goto ctrl; 02532 case 0x0a: /* end box */ 02533 box = 0; 02534 goto ctrl; 02535 case 0x0b: /* start box */ 02536 box = 1; 02537 goto ctrl; 02538 case 0x0c: /* normal height */ 02539 dbl = 0; 02540 goto ctrl; 02541 case 0x0d: /* double height */ 02542 if (y < VT_HEIGHT-2) /* ignored on last 2 lines */ 02543 { 02544 dbl = 1; 02545 } 02546 goto ctrl; 02547 case 0x10 ... 0x17: /* gfx + fg color */ 02548 fg = c & 7; 02549 gfx = 1; 02550 hid = 0; 02551 goto ctrl; 02552 case 0x18: /* conceal */ 02553 hid = 1; 02554 goto ctrl; 02555 case 0x19: /* contiguous gfx */ 02556 hid = 0; 02557 sep = 0; 02558 goto ctrl; 02559 case 0x1a: /* separate gfx */ 02560 sep = 1; 02561 goto ctrl; 02562 case 0x1c: /* black bf */ 02563 bg = 0; 02564 goto ctrl; 02565 case 0x1d: /* new bg */ 02566 bg = fg; 02567 goto ctrl; 02568 case 0x1e: /* hold gfx */ 02569 hold = 1; 02570 goto ctrl; 02571 case 0x1f: /* release gfx */ 02572 hold = 0; 02573 goto ctrl; 02574 case 0x0e: /* SO */ 02575 goto ctrl; 02576 case 0x0f: /* SI */ 02577 goto ctrl; 02578 case 0x1b: /* ESC */ 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 // calculate timecode: 02653 // compute the difference between now and stm (start time) 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 /*type*/) 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 // First we do some of the time consuming stuff we can do now 02813 SavePositionMap(true); 02814 ringBuffer->WriterFlush(); 02815 if (curRecording) 02816 curRecording->SaveFilesize(ringBuffer->GetRealFileSize()); 02817 02818 // Then we set the next info 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 { // this will be triggered every new file 02889 lf = fnum; 02890 startnum = fnum; 02891 lasttimecode = 0; 02892 frameofgop = 0; 02893 forcekey = true; 02894 } 02895 02896 // see if it's time for a seeker header, sync information and a keyframe 02897 frameheader.keyframe = frameofgop; // no keyframe defaulted 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'; // sync frame 02915 frameheader.comptype = 'V'; // video sync information 02916 frameheader.filters = 0; // no filters applied 02917 frameheader.packetlength = 0; // no data packet 02918 frameheader.timecode = (fnum-startnum)>>1; 02919 // write video sync info 02920 WriteFrameheader(&frameheader); 02921 frameheader.frametype = 'S'; // sync frame 02922 frameheader.comptype = 'A'; // video sync information 02923 frameheader.filters = 0; // no filters applied 02924 frameheader.packetlength = 0; // no data packet 02925 frameheader.timecode = effectivedsp; // effective dsp frequency 02926 // write audio sync info 02927 WriteFrameheader(&frameheader); 02928 02929 wantkeyframe = true; 02930 //ringBuffer->Sync(); 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; // speed up the encode process 02986 02987 if (freecount < 5) 02988 raw = 1; // speed up the encode process 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 // here is lzo compression afterwards 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'; // video frame 03024 frameheader.timecode = timecode; 03025 lasttimecode = frameheader.timecode; 03026 frameheader.filters = 0; // no filters applied 03027 03028 // compr ends here 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'; // video compression: RTjpeg only 03058 frameheader.packetlength = tmp; 03059 WriteFrameheader(&frameheader); 03060 ringBuffer->Write(strm, tmp); 03061 } 03062 else 03063 { 03064 frameheader.comptype = '0'; // raw YUV420 03065 frameheader.packetlength = len; 03066 WriteFrameheader(&frameheader); 03067 ringBuffer->Write(buf, len); // we write buf directly 03068 } 03069 } 03070 else 03071 { 03072 if (!raw) 03073 frameheader.comptype = '2'; // video compression: RTjpeg with lzo 03074 else 03075 frameheader.comptype = '3'; // raw YUV420 with lzo 03076 frameheader.packetlength = out_len; 03077 WriteFrameheader(&frameheader); 03078 ringBuffer->Write(out, out_len); 03079 } 03080 03081 frameofgop++; 03082 framesWritten++; 03083 03084 // now we reset the last frame number so that we can find out 03085 // how many frames we didn't get next time 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)); /* <- suppress compiler warning */ 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'; // audio frame 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; // this is to avoid the lack between the beginning 03136 // of recording and the first timestamp, maybe we 03137 // can calculate the audio-video +-lack at the 03138 // beginning too 03139 abytes = (double)audiobytes; // - (double)audio_buffer_size; 03140 // wrong guess ;-) 03141 // need seconds instead of msec's 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'; // audio is compressed 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'; // uncompressed audio 03212 frameheader.packetlength = audio_buffer_size; 03213 03214 WriteFrameheader(&frameheader); 03215 ringBuffer->Write(buf, audio_buffer_size); 03216 audiobytes += audio_buffer_size; // only audio no header!! 03217 } 03218 03219 // this will probably never happen and if there would be a 03220 // 'uncountable' video frame drop -> material==worthless 03221 if (audio_behind > 0) 03222 { 03223 LOG(VB_RECORD, LOG_INFO, LOC + "audio behind"); 03224 frameheader.frametype = 'A'; // audio frame 03225 frameheader.comptype = 'N'; // output a nullframe with 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'; // text frame 03241 frameheader.timecode = timecode; 03242 03243 if (VBIMode::PAL_TT == vbimode) 03244 { 03245 frameheader.comptype = 'T'; // european teletext 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'; // NTSC CC 03262 frameheader.packetlength = len; 03263 03264 WriteFrameheader(&frameheader); 03265 ringBuffer->Write(buf, len); 03266 } 03267 } 03268 03269 /* vim: set expandtab tabstop=4 shiftwidth=4: */ 03270
1.7.6.1