|
MythTV
0.26-pre
|
00001 #include <stdint.h> 00002 00003 #include <algorithm> // for min 00004 using namespace std; 00005 00006 #include "NuppelVideoRecorder.h" 00007 #include "firewirerecorder.h" 00008 #include "recordingprofile.h" 00009 #include "firewirechannel.h" 00010 #include "importrecorder.h" 00011 #include "cetonrecorder.h" 00012 #include "dummychannel.h" 00013 #include "hdhrrecorder.h" 00014 #include "iptvrecorder.h" 00015 #include "mpegrecorder.h" 00016 #include "recorderbase.h" 00017 #include "cetonchannel.h" 00018 #include "asirecorder.h" 00019 #include "dvbrecorder.h" 00020 #include "hdhrchannel.h" 00021 #include "iptvchannel.h" 00022 #include "mythlogging.h" 00023 #include "programinfo.h" 00024 #include "asichannel.h" 00025 #include "dtvchannel.h" 00026 #include "dvbchannel.h" 00027 #include "v4lchannel.h" 00028 #include "ringbuffer.h" 00029 #include "cardutil.h" 00030 #include "tv_rec.h" 00031 #include "mythmiscutil.h" 00032 00033 #define TVREC_CARDNUM \ 00034 ((tvrec != NULL) ? QString::number(tvrec->GetCaptureCardNum()) : "NULL") 00035 00036 #define LOC QString("RecBase(%1:%2): ") \ 00037 .arg(TVREC_CARDNUM).arg(videodevice) 00038 00039 const uint RecorderBase::kTimeOfLatestDataIntervalTarget = 5000; 00040 00041 RecorderBase::RecorderBase(TVRec *rec) 00042 : tvrec(rec), ringBuffer(NULL), 00043 weMadeBuffer(true), videocodec("rtjpeg"), 00044 ntsc(true), ntsc_framerate(true), 00045 video_frame_rate(29.97), 00046 m_videoAspect(0), m_videoHeight(0), 00047 m_videoWidth(0), m_frameRate(0.0), 00048 curRecording(NULL), 00049 request_pause(false), paused(false), 00050 request_recording(false), recording(false), 00051 nextRingBuffer(NULL), nextRecording(NULL), 00052 positionMapType(MARK_GOP_BYFRAME) 00053 { 00054 ClearStatistics(); 00055 QMutexLocker locker(avcodeclock); 00056 #if 0 00057 avcodec_init(); // init CRC's 00058 #endif 00059 } 00060 00061 RecorderBase::~RecorderBase(void) 00062 { 00063 if (weMadeBuffer && ringBuffer) 00064 { 00065 delete ringBuffer; 00066 ringBuffer = NULL; 00067 } 00068 SetRecording(NULL); 00069 } 00070 00071 void RecorderBase::SetRingBuffer(RingBuffer *rbuf) 00072 { 00073 if (VERBOSE_LEVEL_CHECK(VB_RECORD, LOG_INFO)) 00074 { 00075 QString msg(""); 00076 if (rbuf) 00077 msg = " '" + rbuf->GetFilename() + "'"; 00078 LOG(VB_RECORD, LOG_INFO, LOC + QString("SetRingBuffer(0x%1)") 00079 .arg((uint64_t)rbuf,0,16) + msg); 00080 } 00081 ringBuffer = rbuf; 00082 weMadeBuffer = false; 00083 } 00084 00085 void RecorderBase::SetRecording(const ProgramInfo *pginfo) 00086 { 00087 if (pginfo) 00088 LOG(VB_RECORD, LOG_INFO, LOC + QString("SetRecording(0x%1) title(%2)") 00089 .arg((uint64_t)pginfo,0,16).arg(pginfo->GetTitle())); 00090 else 00091 LOG(VB_RECORD, LOG_INFO, LOC + "SetRecording(0x0)"); 00092 00093 ProgramInfo *oldrec = curRecording; 00094 if (pginfo) 00095 curRecording = new ProgramInfo(*pginfo); 00096 else 00097 curRecording = NULL; 00098 00099 if (oldrec) 00100 delete oldrec; 00101 } 00102 00103 void RecorderBase::SetOption(const QString &name, const QString &value) 00104 { 00105 if (name == "videocodec") 00106 videocodec = value; 00107 else if (name == "videodevice") 00108 videodevice = value; 00109 else if (name == "tvformat") 00110 { 00111 ntsc = false; 00112 if (value.toLower() == "ntsc" || value.toLower() == "ntsc-jp") 00113 { 00114 ntsc = true; 00115 SetFrameRate(29.97); 00116 } 00117 else if (value.toLower() == "pal-m") 00118 SetFrameRate(29.97); 00119 else if (value.toLower() == "atsc") 00120 { 00121 // Here we set the TV format values for ATSC. ATSC isn't really 00122 // NTSC, but users who configure a non-ATSC-recorder as ATSC 00123 // are far more likely to be using a mix of ATSC and NTSC than 00124 // a mix of ATSC and PAL or SECAM. The atsc recorder itself 00125 // does not care about these values, except in so much as tv_rec 00126 // cares anout video_frame_rate which should be neither 29.97 00127 // nor 25.0, but based on the actual video. 00128 ntsc = true; 00129 SetFrameRate(29.97); 00130 } 00131 else 00132 SetFrameRate(25.00); 00133 } 00134 else 00135 { 00136 LOG(VB_GENERAL, LOG_WARNING, LOC + 00137 QString("SetOption(%1,%2): Option not recognized") 00138 .arg(name).arg(value)); 00139 } 00140 } 00141 00142 void RecorderBase::SetOption(const QString &name, int value) 00143 { 00144 LOG(VB_GENERAL, LOG_ERR, LOC + 00145 QString("SetOption(): Unknown int option: %1: %2") 00146 .arg(name).arg(value)); 00147 } 00148 00149 void RecorderBase::SetIntOption(RecordingProfile *profile, const QString &name) 00150 { 00151 const Setting *setting = profile->byName(name); 00152 if (setting) 00153 SetOption(name, setting->getValue().toInt()); 00154 else 00155 LOG(VB_GENERAL, LOG_ERR, LOC + 00156 QString("SetIntOption(...%1): Option not in profile.").arg(name)); 00157 } 00158 00159 void RecorderBase::SetStrOption(RecordingProfile *profile, const QString &name) 00160 { 00161 const Setting *setting = profile->byName(name); 00162 if (setting) 00163 SetOption(name, setting->getValue()); 00164 else 00165 LOG(VB_GENERAL, LOG_ERR, LOC + 00166 QString("SetStrOption(...%1): Option not in profile.").arg(name)); 00167 } 00168 00174 void RecorderBase::StopRecording(void) 00175 { 00176 QMutexLocker locker(&pauseLock); 00177 request_recording = false; 00178 unpauseWait.wakeAll(); 00179 while (recording) 00180 { 00181 recordingWait.wait(&pauseLock, 100); 00182 if (request_recording) 00183 { 00184 LOG(VB_GENERAL, LOG_ERR, LOC + 00185 "Programmer Error: Recorder started while we were in " 00186 "StopRecording"); 00187 request_recording = false; 00188 } 00189 } 00190 } 00191 00193 bool RecorderBase::IsRecording(void) 00194 { 00195 QMutexLocker locker(&pauseLock); 00196 return recording; 00197 } 00198 00200 bool RecorderBase::IsRecordingRequested(void) 00201 { 00202 QMutexLocker locker(&pauseLock); 00203 return request_recording; 00204 } 00205 00213 void RecorderBase::Pause(bool clear) 00214 { 00215 (void) clear; 00216 QMutexLocker locker(&pauseLock); 00217 request_pause = true; 00218 } 00219 00224 void RecorderBase::Unpause(void) 00225 { 00226 QMutexLocker locker(&pauseLock); 00227 request_pause = false; 00228 unpauseWait.wakeAll(); 00229 } 00230 00232 bool RecorderBase::IsPaused(bool holding_lock) const 00233 { 00234 if (!holding_lock) 00235 pauseLock.lock(); 00236 bool ret = paused; 00237 if (!holding_lock) 00238 pauseLock.unlock(); 00239 return ret; 00240 } 00241 00248 bool RecorderBase::WaitForPause(int timeout) 00249 { 00250 MythTimer t; 00251 t.start(); 00252 00253 QMutexLocker locker(&pauseLock); 00254 while (!IsPaused(true) && request_pause) 00255 { 00256 int wait = timeout - t.elapsed(); 00257 if (wait <= 0) 00258 return false; 00259 pauseWait.wait(&pauseLock, wait); 00260 } 00261 return true; 00262 } 00263 00276 bool RecorderBase::PauseAndWait(int timeout) 00277 { 00278 QMutexLocker locker(&pauseLock); 00279 if (request_pause) 00280 { 00281 if (!IsPaused(true)) 00282 { 00283 paused = true; 00284 pauseWait.wakeAll(); 00285 if (tvrec) 00286 tvrec->RecorderPaused(); 00287 } 00288 00289 unpauseWait.wait(&pauseLock, timeout); 00290 } 00291 00292 if (!request_pause && IsPaused(true)) 00293 { 00294 paused = false; 00295 unpauseWait.wakeAll(); 00296 } 00297 00298 return IsPaused(true); 00299 } 00300 00301 void RecorderBase::CheckForRingBufferSwitch(void) 00302 { 00303 nextRingBufferLock.lock(); 00304 00305 RecordingQuality *recq = NULL; 00306 00307 if (nextRingBuffer) 00308 { 00309 FinishRecording(); 00310 00311 recq = GetRecordingQuality(); 00312 00313 ResetForNewFile(); 00314 00315 m_videoAspect = m_videoWidth = m_videoHeight = 0; 00316 m_frameRate = 0.0; 00317 00318 SetRingBuffer(nextRingBuffer); 00319 SetRecording(nextRecording); 00320 00321 nextRingBuffer = NULL; 00322 nextRecording = NULL; 00323 00324 StartNewFile(); 00325 } 00326 nextRingBufferLock.unlock(); 00327 00328 if (recq && tvrec) 00329 tvrec->RingBufferChanged(ringBuffer, curRecording, recq); 00330 } 00331 00332 void RecorderBase::ClearStatistics(void) 00333 { 00334 QMutexLocker locker(&statisticsLock); 00335 timeOfFirstData = QDateTime(); 00336 timeOfFirstDataIsSet.fetchAndStoreRelaxed(0); 00337 timeOfLatestData = QDateTime(); 00338 timeOfLatestDataCount.fetchAndStoreRelaxed(0); 00339 timeOfLatestDataPacketInterval.fetchAndStoreRelaxed(2000); 00340 recordingGaps.clear(); 00341 } 00342 00343 RecordingQuality *RecorderBase::GetRecordingQuality(void) const 00344 { 00345 QMutexLocker locker(&statisticsLock); 00346 return new RecordingQuality( 00347 curRecording, recordingGaps, 00348 timeOfFirstData, timeOfLatestData); 00349 } 00350 00351 int64_t RecorderBase::GetKeyframePosition(uint64_t desired) const 00352 { 00353 QMutexLocker locker(&positionMapLock); 00354 long long ret = -1; 00355 00356 if (positionMap.empty()) 00357 return ret; 00358 00359 // find closest exact or previous keyframe position... 00360 frm_pos_map_t::const_iterator it = positionMap.lowerBound(desired); 00361 if (it == positionMap.end()) 00362 ret = *positionMap.begin(); 00363 else if (it.key() == desired) 00364 ret = *it; 00365 else if (--it != positionMap.end()) 00366 ret = *it; 00367 00368 return ret; 00369 } 00370 00371 bool RecorderBase::GetKeyframePositions( 00372 int64_t start, int64_t end, frm_pos_map_t &map) const 00373 { 00374 map.clear(); 00375 00376 QMutexLocker locker(&positionMapLock); 00377 if (positionMap.empty()) 00378 return true; 00379 00380 frm_pos_map_t::const_iterator it = positionMap.lowerBound(start); 00381 end = (end < 0) ? INT64_MAX : end; 00382 for (; (it != positionMap.end()) && 00383 (it.key() <= (uint64_t)end); ++it) 00384 map[it.key()] = *it; 00385 00386 LOG(VB_GENERAL, LOG_INFO, LOC + 00387 QString("GetKeyframePositions(%1,%2,#%3) out of %4") 00388 .arg(start).arg(end).arg(map.size()).arg(positionMap.size())); 00389 00390 return true; 00391 } 00392 00400 void RecorderBase::SavePositionMap(bool force) 00401 { 00402 bool needToSave = force; 00403 positionMapLock.lock(); 00404 00405 uint delta_size = positionMapDelta.size(); 00406 uint pm_elapsed = positionMapTimer.elapsed(); 00407 // save on every 1.5 seconds if in the first few frames of a recording 00408 needToSave |= (positionMap.size() < 30) && 00409 (delta_size >= 1) && (pm_elapsed >= 1500); 00410 // save every 10 seconds later on 00411 needToSave |= (delta_size >= 1) && (pm_elapsed >= 10000); 00412 00413 if (curRecording && needToSave) 00414 { 00415 positionMapTimer.start(); 00416 if (delta_size) 00417 { 00418 // copy the delta map because most times we are called it will be in 00419 // another thread and we don't want to lock the main recorder thread 00420 // which is populating the delta map 00421 frm_pos_map_t deltaCopy(positionMapDelta); 00422 positionMapDelta.clear(); 00423 positionMapLock.unlock(); 00424 00425 curRecording->SavePositionMapDelta(deltaCopy, positionMapType); 00426 } 00427 else 00428 { 00429 positionMapLock.unlock(); 00430 } 00431 00432 if (ringBuffer) 00433 { 00434 curRecording->SaveFilesize(ringBuffer->GetWritePosition()); 00435 } 00436 } 00437 else 00438 { 00439 positionMapLock.unlock(); 00440 } 00441 } 00442 00443 void RecorderBase::AspectChange(uint aspect, long long frame) 00444 { 00445 MarkTypes mark = MARK_ASPECT_4_3; 00446 uint customAspect = 0; 00447 if (aspect == ASPECT_1_1 || aspect >= ASPECT_CUSTOM) 00448 { 00449 if (aspect > 0x0F) 00450 customAspect = aspect; 00451 else if (m_videoWidth && m_videoHeight) 00452 customAspect = m_videoWidth * 1000000 / m_videoHeight; 00453 00454 mark = (customAspect) ? MARK_ASPECT_CUSTOM : mark; 00455 } 00456 if (aspect == ASPECT_4_3) 00457 mark = MARK_ASPECT_4_3; 00458 if (aspect == ASPECT_16_9) 00459 mark = MARK_ASPECT_16_9; 00460 if (aspect == ASPECT_2_21_1) 00461 mark = MARK_ASPECT_2_21_1; 00462 00463 if (curRecording) 00464 curRecording->SaveAspect(frame, mark, customAspect); 00465 } 00466 00467 void RecorderBase::ResolutionChange(uint width, uint height, long long frame) 00468 { 00469 if (curRecording) 00470 curRecording->SaveResolution(frame, width, height); 00471 } 00472 00473 void RecorderBase::FrameRateChange(uint framerate, long long frame) 00474 { 00475 if (curRecording) 00476 curRecording->SaveFrameRate(frame, framerate); 00477 } 00478 00479 void RecorderBase::SetDuration(uint64_t duration) 00480 { 00481 if (curRecording) 00482 curRecording->SaveTotalDuration(duration); 00483 } 00484 00485 void RecorderBase::SetTotalFrames(uint64_t total_frames) 00486 { 00487 if (curRecording) 00488 curRecording->SaveTotalFrames(total_frames); 00489 } 00490 00491 00492 RecorderBase *RecorderBase::CreateRecorder( 00493 TVRec *tvrec, 00494 ChannelBase *channel, 00495 const RecordingProfile &profile, 00496 const GeneralDBOptions &genOpt, 00497 const DVBDBOptions &dvbOpt) 00498 { 00499 if (!channel) 00500 return NULL; 00501 00502 RecorderBase *recorder = NULL; 00503 if (genOpt.cardtype == "MPEG") 00504 { 00505 #ifdef USING_IVTV 00506 recorder = new MpegRecorder(tvrec); 00507 #endif // USING_IVTV 00508 } 00509 else if (genOpt.cardtype == "HDPVR") 00510 { 00511 #ifdef USING_HDPVR 00512 recorder = new MpegRecorder(tvrec); 00513 #endif // USING_HDPVR 00514 } 00515 else if (genOpt.cardtype == "FIREWIRE") 00516 { 00517 #ifdef USING_FIREWIRE 00518 recorder = new FirewireRecorder( 00519 tvrec, dynamic_cast<FirewireChannel*>(channel)); 00520 #endif // USING_FIREWIRE 00521 } 00522 else if (genOpt.cardtype == "HDHOMERUN") 00523 { 00524 #ifdef USING_HDHOMERUN 00525 recorder = new HDHRRecorder( 00526 tvrec, dynamic_cast<HDHRChannel*>(channel)); 00527 recorder->SetOption("wait_for_seqstart", genOpt.wait_for_seqstart); 00528 #endif // USING_HDHOMERUN 00529 } 00530 else if (genOpt.cardtype == "CETON") 00531 { 00532 #ifdef USING_CETON 00533 recorder = new CetonRecorder( 00534 tvrec, dynamic_cast<CetonChannel*>(channel)); 00535 recorder->SetOption("wait_for_seqstart", genOpt.wait_for_seqstart); 00536 #endif // USING_CETON 00537 } 00538 else if (genOpt.cardtype == "DVB") 00539 { 00540 #ifdef USING_DVB 00541 recorder = new DVBRecorder( 00542 tvrec, dynamic_cast<DVBChannel*>(channel)); 00543 recorder->SetOption("wait_for_seqstart", genOpt.wait_for_seqstart); 00544 #endif // USING_DVB 00545 } 00546 else if (genOpt.cardtype == "FREEBOX") 00547 { 00548 #ifdef USING_IPTV 00549 recorder = new IPTVRecorder( 00550 tvrec, dynamic_cast<IPTVChannel*>(channel)); 00551 recorder->SetOption("mrl", genOpt.videodev); 00552 #endif // USING_IPTV 00553 } 00554 else if (genOpt.cardtype == "ASI") 00555 { 00556 #ifdef USING_ASI 00557 recorder = new ASIRecorder( 00558 tvrec, dynamic_cast<ASIChannel*>(channel)); 00559 recorder->SetOption("wait_for_seqstart", genOpt.wait_for_seqstart); 00560 #endif // USING_ASI 00561 } 00562 else if (genOpt.cardtype == "IMPORT") 00563 { 00564 recorder = new ImportRecorder(tvrec); 00565 } 00566 else if (genOpt.cardtype == "DEMO") 00567 { 00568 #ifdef USING_IVTV 00569 recorder = new MpegRecorder(tvrec); 00570 #else 00571 recorder = new ImportRecorder(tvrec); 00572 #endif 00573 } 00574 else if (CardUtil::IsV4L(genOpt.cardtype)) 00575 { 00576 #ifdef USING_V4L2 00577 // V4L/MJPEG/GO7007 from here on 00578 recorder = new NuppelVideoRecorder(tvrec, channel); 00579 recorder->SetOption("skipbtaudio", genOpt.skip_btaudio); 00580 #endif // USING_V4L2 00581 } 00582 00583 if (recorder) 00584 { 00585 recorder->SetOptionsFromProfile( 00586 const_cast<RecordingProfile*>(&profile), 00587 genOpt.videodev, genOpt.audiodev, genOpt.vbidev); 00588 // Override the samplerate defined in the profile if this card 00589 // was configured with a fixed rate. 00590 if (genOpt.audiosamplerate) 00591 recorder->SetOption("samplerate", genOpt.audiosamplerate); 00592 } 00593 else 00594 { 00595 QString msg = "Need %1 recorder, but compiled without %2 support!"; 00596 msg = msg.arg(genOpt.cardtype).arg(genOpt.cardtype); 00597 LOG(VB_GENERAL, LOG_ERR, 00598 "RecorderBase::CreateRecorder() Error, " + msg); 00599 } 00600 00601 return recorder; 00602 } 00603 00604 /* vim: set expandtab tabstop=4 shiftwidth=4: */
1.7.6.1