00001 #include <iostream>
00002 using namespace std;
00003
00004 #include "recorderbase.h"
00005 #include "tv_rec.h"
00006 #include "mythcontext.h"
00007 #include "RingBuffer.h"
00008 #include "programinfo.h"
00009 #include "recordingprofile.h"
00010 #include "util.h"
00011
00012 #define TVREC_CARDNUM \
00013 ((tvrec != NULL) ? QString::number(tvrec->GetCaptureCardNum()) : "NULL")
00014
00015 #define LOC QString("RecBase(%1:%2): ") \
00016 .arg(TVREC_CARDNUM).arg(videodevice)
00017 #define LOC_WARN QString("RecBase(%1:%2) Warning: ") \
00018 .arg(TVREC_CARDNUM).arg(videodevice)
00019 #define LOC_ERR QString("RecBase(%1:%2) Error: ") \
00020 .arg(TVREC_CARDNUM).arg(videodevice)
00021
00022 RecorderBase::RecorderBase(TVRec *rec)
00023 : tvrec(rec), ringBuffer(NULL), weMadeBuffer(true), videocodec("rtjpeg"),
00024 audiodevice("/dev/dsp"), videodevice("/dev/video"), vbidevice("/dev/vbi"),
00025 vbimode(0), ntsc(true), ntsc_framerate(true), video_frame_rate(29.97),
00026 curRecording(NULL), request_pause(false), paused(false),
00027 nextRingBuffer(NULL), nextRecording(NULL),
00028 positionMapType(MARK_GOP_BYFRAME), positionMapLock(false)
00029 {
00030 QMutexLocker locker(&avcodeclock);
00031 avcodec_init();
00032 }
00033
00034 RecorderBase::~RecorderBase(void)
00035 {
00036 if (weMadeBuffer && ringBuffer)
00037 {
00038 delete ringBuffer;
00039 ringBuffer = NULL;
00040 }
00041 if (curRecording)
00042 {
00043 delete curRecording;
00044 curRecording = NULL;
00045 }
00046 }
00047
00048 void RecorderBase::SetRingBuffer(RingBuffer *rbuf)
00049 {
00050 if (print_verbose_messages & VB_RECORD)
00051 {
00052 QString msg("");
00053 if (rbuf)
00054 msg = " '" + rbuf->GetFilename() + "'";
00055 VERBOSE(VB_RECORD, LOC + "SetRingBuffer("<<rbuf<<")"<<msg);
00056 }
00057 ringBuffer = rbuf;
00058 weMadeBuffer = false;
00059 }
00060
00061 void RecorderBase::SetRecording(const ProgramInfo *pginfo)
00062 {
00063 if (pginfo)
00064 VERBOSE(VB_RECORD, LOC + "SetRecording(" << pginfo
00065 << QString(") title(%1)").arg(pginfo->title));
00066 else
00067 VERBOSE(VB_RECORD, LOC + "SetRecording(0x0)");
00068
00069 ProgramInfo *oldrec = curRecording;
00070 if (pginfo)
00071 curRecording = new ProgramInfo(*pginfo);
00072 else
00073 curRecording = NULL;
00074
00075 if (oldrec)
00076 delete oldrec;
00077 }
00078
00079 void RecorderBase::SetOption(const QString &name, const QString &value)
00080 {
00081 if (name == "videocodec")
00082 videocodec = value;
00083 else if (name == "audiodevice")
00084 audiodevice = value;
00085 else if (name == "videodevice")
00086 videodevice = value;
00087 else if (name == "vbidevice")
00088 vbidevice = value;
00089 else if (name == "tvformat")
00090 {
00091 ntsc = false;
00092 if (value.lower() == "ntsc" || value.lower() == "ntsc-jp")
00093 {
00094 ntsc = true;
00095 SetFrameRate(29.97);
00096 }
00097 else if (value.lower() == "pal-m")
00098 SetFrameRate(29.97);
00099 else if (value.lower() == "atsc")
00100 {
00101
00102
00103
00104
00105
00106
00107
00108 ntsc = true;
00109 SetFrameRate(29.97);
00110 }
00111 else
00112 SetFrameRate(25.00);
00113 }
00114 else if (name == "vbiformat")
00115 {
00116 if (value.lower() == "pal teletext")
00117 vbimode = 1;
00118 else if (value.lower().left(4) == "ntsc")
00119 vbimode = 2;
00120 else
00121 vbimode = 0;
00122 }
00123 }
00124
00125 void RecorderBase::SetOption(const QString &name, int value)
00126 {
00127 VERBOSE(VB_IMPORTANT, LOC_ERR +
00128 QString("SetOption(): Unknown int option: %1: %2")
00129 .arg(name).arg(value));
00130 }
00131
00132 void RecorderBase::SetIntOption(RecordingProfile *profile, const QString &name)
00133 {
00134 const Setting *setting = profile->byName(name);
00135 if (setting)
00136 SetOption(name, setting->getValue().toInt());
00137 else
00138 VERBOSE(VB_IMPORTANT, LOC_ERR + QString(
00139 "SetIntOption(...%1): Option not in profile.").arg(name));
00140 }
00141
00142 void RecorderBase::SetStrOption(RecordingProfile *profile, const QString &name)
00143 {
00144 const Setting *setting = profile->byName(name);
00145 if (setting)
00146 SetOption(name, setting->getValue());
00147 else
00148 VERBOSE(VB_IMPORTANT, LOC_ERR + QString(
00149 "SetStrOption(...%1): Option not in profile.").arg(name));
00150 }
00151
00158 bool RecorderBase::WaitForPause(int timeout)
00159 {
00160 MythTimer t;
00161 t.start();
00162
00163 while (true)
00164 {
00165 int wait = timeout - t.elapsed();
00166
00167 if (wait <= 0)
00168 return IsPaused();
00169 else if (IsPaused())
00170 return true;
00171
00172 pauseWait.wait(wait);
00173 }
00174 }
00175
00182 bool RecorderBase::PauseAndWait(int timeout)
00183 {
00184 if (request_pause)
00185 {
00186 if (!paused)
00187 {
00188 paused = true;
00189 pauseWait.wakeAll();
00190 if (tvrec)
00191 tvrec->RecorderPaused();
00192 }
00193 unpauseWait.wait(timeout);
00194 }
00195 if (!request_pause)
00196 paused = false;
00197 return paused;
00198 }
00199
00200 void RecorderBase::CheckForRingBufferSwitch(void)
00201 {
00202 nextRingBufferLock.lock();
00203
00204 bool rb_changed = false;
00205
00206 if (nextRingBuffer)
00207 {
00208 FinishRecording();
00209 ResetForNewFile();
00210
00211 if (weMadeBuffer && ringBuffer)
00212 delete ringBuffer;
00213 SetRingBuffer(nextRingBuffer);
00214 nextRingBuffer = NULL;
00215
00216 ProgramInfo *oldrec = curRecording;
00217 curRecording = nextRecording;
00218 nextRecording = NULL;
00219 if (oldrec)
00220 delete oldrec;
00221 rb_changed = true;
00222
00223 StartNewFile();
00224 }
00225 nextRingBufferLock.unlock();
00226
00227 if (rb_changed && tvrec)
00228 tvrec->RingBufferChanged(ringBuffer, curRecording);
00229 }
00230
00238 void RecorderBase::SavePositionMap(bool force)
00239 {
00240 bool needToSave = force;
00241 positionMapLock.lock();
00242
00243
00244 needToSave |= (positionMap.size() < 30) && (positionMap.size() % 5 == 1);
00245
00246 needToSave |= positionMapDelta.size() >= 30;
00247
00248 if (curRecording && needToSave)
00249 {
00250
00251
00252
00253 QMap<long long, long long> deltaCopy(positionMapDelta);
00254 positionMapDelta.clear();
00255 positionMapLock.unlock();
00256
00257 curRecording->SetPositionMapDelta(deltaCopy, positionMapType);
00258
00259 if (ringBuffer)
00260 curRecording->SetFilesize(ringBuffer->GetWritePosition());
00261 }
00262 else
00263 positionMapLock.unlock();
00264 }
00265
00266