00001 #include <stdint.h>
00002
00003 #include <algorithm>
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();
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
00122
00123
00124
00125
00126
00127
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
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
00408 needToSave |= (positionMap.size() < 30) &&
00409 (delta_size >= 1) && (pm_elapsed >= 1500);
00410
00411 needToSave |= (delta_size >= 1) && (pm_elapsed >= 10000);
00412
00413 if (curRecording && needToSave)
00414 {
00415 positionMapTimer.start();
00416 if (delta_size)
00417 {
00418
00419
00420
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
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
00589
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