00001
00002 #include <algorithm>
00003 using namespace std;
00004
00005
00006 #include "mythdb.h"
00007 #include "tv_rec.h"
00008 #include "cardutil.h"
00009 #include "dtvchannel.h"
00010 #include "mpegtables.h"
00011 #include "mythlogging.h"
00012
00013 #define LOC QString("DTVChan(%1): ").arg(GetDevice())
00014
00015 QReadWriteLock DTVChannel::master_map_lock(QReadWriteLock::Recursive);
00016 typedef QMap<QString,QList<DTVChannel*> > MasterMap;
00017 MasterMap DTVChannel::master_map;
00018
00019 DTVChannel::DTVChannel(TVRec *parent)
00020 : ChannelBase(parent),
00021 tunerType(DTVTunerType::kTunerTypeUnknown),
00022 sistandard("mpeg"), tuningMode(QString::null),
00023 currentProgramNum(-1),
00024 currentATSCMajorChannel(0), currentATSCMinorChannel(0),
00025 currentTransportID(0), currentOriginalNetworkID(0),
00026 genPAT(NULL), genPMT(NULL)
00027 {
00028 }
00029
00030 DTVChannel::~DTVChannel()
00031 {
00032 if (genPAT)
00033 {
00034 delete genPAT;
00035 genPAT = NULL;
00036 }
00037
00038 if (genPMT)
00039 {
00040 delete genPMT;
00041 genPMT = NULL;
00042 }
00043 }
00044
00045 void DTVChannel::SetDTVInfo(uint atsc_major, uint atsc_minor,
00046 uint dvb_orig_netid,
00047 uint mpeg_tsid, int mpeg_pnum)
00048 {
00049 QMutexLocker locker(&dtvinfo_lock);
00050 currentProgramNum = mpeg_pnum;
00051 currentATSCMajorChannel = atsc_major;
00052 currentATSCMinorChannel = atsc_minor;
00053 currentTransportID = mpeg_tsid;
00054 currentOriginalNetworkID = dvb_orig_netid;
00055 }
00056
00057 QString DTVChannel::GetSIStandard(void) const
00058 {
00059 QMutexLocker locker(&dtvinfo_lock);
00060 QString tmp = sistandard; tmp.detach();
00061 return tmp;
00062 }
00063
00064 void DTVChannel::SetSIStandard(const QString &si_std)
00065 {
00066 QMutexLocker locker(&dtvinfo_lock);
00067 sistandard = si_std.toLower();
00068 sistandard.detach();
00069 }
00070
00071 QString DTVChannel::GetSuggestedTuningMode(bool is_live_tv) const
00072 {
00073 uint cardid = GetCardID();
00074 QString input = GetCurrentInput();
00075
00076 uint quickTuning = 0;
00077 if (cardid && !input.isEmpty())
00078 quickTuning = CardUtil::GetQuickTuning(cardid, input);
00079
00080 bool useQuickTuning = (quickTuning && is_live_tv) || (quickTuning > 1);
00081
00082 QMutexLocker locker(&dtvinfo_lock);
00083 if (!useQuickTuning && ((sistandard == "atsc") || (sistandard == "dvb")))
00084 {
00085 QString tmp = sistandard; tmp.detach();
00086 return tmp;
00087 }
00088
00089 return "mpeg";
00090 }
00091
00092 QString DTVChannel::GetTuningMode(void) const
00093 {
00094 QMutexLocker locker(&dtvinfo_lock);
00095 QString tmp = tuningMode; tmp.detach();
00096 return tmp;
00097 }
00098
00099 vector<DTVTunerType> DTVChannel::GetTunerTypes(void) const
00100 {
00101 vector<DTVTunerType> tts;
00102 if (tunerType != DTVTunerType::kTunerTypeUnknown)
00103 tts.push_back(tunerType);
00104 return tts;
00105 }
00106
00107 void DTVChannel::SetTuningMode(const QString &tuning_mode)
00108 {
00109 QMutexLocker locker(&dtvinfo_lock);
00110 tuningMode = tuning_mode.toLower();
00111 tuningMode.detach();
00112 }
00113
00118 void DTVChannel::GetCachedPids(pid_cache_t &pid_cache) const
00119 {
00120 int chanid = GetChanID();
00121 if (chanid > 0)
00122 ChannelUtil::GetCachedPids(chanid, pid_cache);
00123 }
00124
00128 void DTVChannel::SaveCachedPids(const pid_cache_t &pid_cache) const
00129 {
00130 int chanid = GetChanID();
00131 if (chanid > 0)
00132 ChannelUtil::SaveCachedPids(chanid, pid_cache);
00133 }
00134
00135 void DTVChannel::RegisterForMaster(const QString &key)
00136 {
00137 master_map_lock.lockForWrite();
00138 master_map[key].push_back(this);
00139 master_map_lock.unlock();
00140 }
00141
00142 void DTVChannel::DeregisterForMaster(const QString &key)
00143 {
00144 master_map_lock.lockForWrite();
00145 MasterMap::iterator mit = master_map.find(key);
00146 if (mit == master_map.end())
00147 mit = master_map.begin();
00148 for (; mit != master_map.end(); ++mit)
00149 {
00150 (*mit).removeAll(this);
00151 if (mit.key() == key)
00152 break;
00153 }
00154 master_map_lock.unlock();
00155 }
00156
00157 DTVChannel *DTVChannel::GetMasterLock(const QString &key)
00158 {
00159 master_map_lock.lockForRead();
00160 MasterMap::iterator mit = master_map.find(key);
00161 if (mit == master_map.end() || (*mit).empty())
00162 {
00163 master_map_lock.unlock();
00164 return NULL;
00165 }
00166 return (*mit).front();
00167 }
00168
00169 void DTVChannel::ReturnMasterLock(DTVChannelP &chan)
00170 {
00171 if (chan != NULL)
00172 {
00173 chan = NULL;
00174 master_map_lock.unlock();
00175 }
00176 }
00177
00178 bool DTVChannel::SetChannelByString(const QString &channum)
00179 {
00180 QString loc = LOC + QString("SetChannelByString(%1): ").arg(channum);
00181 LOG(VB_CHANNEL, LOG_INFO, loc);
00182
00183 ClearDTVInfo();
00184
00185 if (!IsOpen() && !Open())
00186 {
00187 LOG(VB_GENERAL, LOG_ERR, loc + "Channel object "
00188 "will not open, can not change channels.");
00189
00190 return false;
00191 }
00192
00193 if (m_inputs.size() > 1)
00194 {
00195 QString inputName;
00196 if (!CheckChannel(channum, inputName))
00197 {
00198 LOG(VB_GENERAL, LOG_ERR, loc +
00199 "CheckChannel failed.\n\t\t\tPlease verify the channel "
00200 "in the 'mythtv-setup' Channel Editor.");
00201
00202 return false;
00203 }
00204
00205
00206
00207
00208 if (!inputName.isEmpty())
00209 return SwitchToInput(inputName, channum);
00210 }
00211
00212 InputMap::const_iterator it = m_inputs.find(m_currentInputID);
00213 if (it == m_inputs.end())
00214 return false;
00215
00216 uint mplexid_restriction;
00217 if (!IsInputAvailable(m_currentInputID, mplexid_restriction))
00218 {
00219 LOG(VB_GENERAL, LOG_INFO, loc +
00220 QString("Requested channel '%1' is on input '%2' "
00221 "which is in a busy input group")
00222 .arg(channum).arg(m_currentInputID));
00223
00224 return false;
00225 }
00226
00227
00228 QString tvformat, modulation, freqtable, freqid, si_std;
00229 int finetune;
00230 uint64_t frequency;
00231 int mpeg_prog_num;
00232 uint atsc_major, atsc_minor, mplexid, tsid, netid;
00233
00234 if (!ChannelUtil::GetChannelData(
00235 (*it)->sourceid, channum,
00236 tvformat, modulation, freqtable, freqid,
00237 finetune, frequency,
00238 si_std, mpeg_prog_num, atsc_major, atsc_minor, tsid, netid,
00239 mplexid, m_commfree))
00240 {
00241 LOG(VB_GENERAL, LOG_ERR, loc + "Unable to find channel in database.");
00242
00243 return false;
00244 }
00245
00246 if (mplexid_restriction && (mplexid != mplexid_restriction))
00247 {
00248 LOG(VB_GENERAL, LOG_ERR, loc +
00249 QString("Requested channel '%1' is not available because "
00250 "the tuner is currently in use on another transport.")
00251 .arg(channum));
00252
00253 return false;
00254 }
00255
00256
00257 if (frequency == 0)
00258 {
00259 frequency = (freqid.toUInt() + finetune) * 1000;
00260 mplexid = 0;
00261 }
00262 bool isFrequency = (frequency > 10000000);
00263 bool hasTuneToChan =
00264 !(*it)->tuneToChannel.isEmpty() && (*it)->tuneToChannel != "Undefined";
00265
00266
00267
00268 if (!isFrequency || hasTuneToChan)
00269 SetFreqTable(freqtable);
00270
00271
00272 SetFormat(tvformat);
00273
00274
00275 if (hasTuneToChan)
00276 Tune((*it)->tuneToChannel, 0);
00277
00278
00279 uint version = 0;
00280 if (genPAT)
00281 {
00282 version = (genPAT->Version()+1) & 0x1f;
00283 delete genPAT; genPAT = NULL;
00284 delete genPMT; genPMT = NULL;
00285 }
00286
00287 bool ok = true;
00288 if ((*it)->externalChanger.isEmpty())
00289 {
00290 if ((*it)->name.contains("composite", Qt::CaseInsensitive) ||
00291 (*it)->name.contains("s-video", Qt::CaseInsensitive))
00292 {
00293 LOG(VB_GENERAL, LOG_WARNING, loc + "You have not set "
00294 "an external channel changing"
00295 "\n\t\t\tscript for a composite or s-video "
00296 "input. Channel changing will do nothing.");
00297 }
00298 else if (isFrequency && Tune(frequency, ""))
00299 {
00300 }
00301 else if (isFrequency)
00302 {
00303
00304 DTVMultiplex tuning;
00305 if (!mplexid || !tuning.FillFromDB(tunerType, mplexid))
00306 {
00307 LOG(VB_GENERAL, LOG_ERR, loc +
00308 "Failed to initialize multiplex options");
00309 ok = false;
00310 }
00311 else
00312 {
00313
00314 CheckOptions(tuning);
00315
00316
00317 if (!Tune(tuning, (*it)->name))
00318 {
00319 LOG(VB_GENERAL, LOG_ERR, loc + "Tuning to frequency.");
00320
00321 ClearDTVInfo();
00322 ok = false;
00323 }
00324 }
00325 }
00326 else
00327 {
00328 ok = Tune(freqid, finetune);
00329 }
00330 }
00331
00332 LOG(VB_CHANNEL, LOG_INFO, loc + ((ok) ? "success" : "failure"));
00333
00334 if (!ok)
00335 return false;
00336
00337 if (atsc_minor || (mpeg_prog_num>=0))
00338 {
00339 SetSIStandard(si_std);
00340 SetDTVInfo(atsc_major, atsc_minor, netid, tsid, mpeg_prog_num);
00341 }
00342 else if (IsPIDTuningSupported())
00343 {
00344
00345 pid_cache_t pid_cache;
00346 int chanid = ChannelUtil::GetChanID((*it)->sourceid, channum);
00347 ChannelUtil::GetCachedPids(chanid, pid_cache);
00348 if (pid_cache.empty())
00349 {
00350 LOG(VB_GENERAL, LOG_ERR, loc + "PID cache is empty");
00351 return false;
00352 }
00353
00354
00355 vector<uint> pnum; pnum.push_back(1);
00356 vector<uint> pid; pid.push_back(9999);
00357 genPAT = ProgramAssociationTable::Create(0,version,pnum,pid);
00358
00359 int pcrpid = -1;
00360 vector<uint> pids;
00361 vector<uint> types;
00362 pid_cache_t::iterator pit = pid_cache.begin();
00363 for (; pit != pid_cache.end(); ++pit)
00364 {
00365 if (!pit->GetStreamID())
00366 continue;
00367 pids.push_back(pit->GetPID());
00368 types.push_back(pit->GetStreamID());
00369 if (pit->IsPCRPID())
00370 pcrpid = pit->GetPID();
00371 if ((pcrpid < 0) && StreamID::IsVideo(pit->GetStreamID()))
00372 pcrpid = pit->GetPID();
00373 }
00374 if (pcrpid < 0)
00375 pcrpid = pid_cache[0].GetPID();
00376
00377 genPMT = ProgramMapTable::Create(
00378 pnum.back(), pid.back(), pcrpid, version, pids, types);
00379
00380 SetSIStandard("mpeg");
00381 SetDTVInfo(0,0,0,0,-1);
00382 }
00383
00384
00385 m_curchannelname = channum;
00386
00387
00388
00389 if (m_pParent)
00390 m_pParent->SetVideoFiltersForChannel(GetCurrentSourceID(), channum);
00391 InitPictureAttributes();
00392
00393 HandleScript(freqid);
00394
00395 return ok;
00396 }
00397
00398 void DTVChannel::HandleScriptEnd(bool ok)
00399 {
00400
00401
00402
00403
00404
00405 }
00406
00407 bool DTVChannel::TuneMultiplex(uint mplexid, QString inputname)
00408 {
00409 DTVMultiplex tuning;
00410 if (!tuning.FillFromDB(tunerType, mplexid))
00411 return false;
00412
00413 CheckOptions(tuning);
00414
00415 return Tune(tuning, inputname);
00416 }