|
MythTV
0.26-pre
|
00001 // C++ headers 00002 #include <algorithm> 00003 using namespace std; 00004 00005 // MythTV headers 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 // If CheckChannel filled in the inputName then we need to 00206 // change inputs and return, since the act of changing 00207 // inputs will change the channel as well. 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 // Fetch tuning data from the database. 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 // If the frequency is zeroed out, don't use it directly. 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 // If we are tuning to a freqid, rather than an actual frequency, 00267 // we may need to set the frequency table to use. 00268 if (!isFrequency || hasTuneToChan) 00269 SetFreqTable(freqtable); 00270 00271 // Set NTSC, PAL, ATSC, etc. 00272 SetFormat(tvformat); 00273 00274 // If a tuneToChannel is set make sure we're still on it 00275 if (hasTuneToChan) 00276 Tune((*it)->tuneToChannel, 0); 00277 00278 // Clear out any old PAT or PMT & save version info 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 // Initialize basic the tuning parameters 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 // Try to fix any problems with the multiplex 00314 CheckOptions(tuning); 00315 00316 // Tune to proper multiplex 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 // We need to pull the pid_cache since there are no tuning tables 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 // Now we construct the PAT & PMT 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 // Set the current channum to the new channel's channum 00385 m_curchannelname = channum; 00386 00387 // Setup filters & recording picture attributes for framegrabing recorders 00388 // now that the new curchannelname has been established. 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 // MAYBE TODO? need to tell signal monitor to throw out any tables 00401 // it saw on the last mux... 00402 00403 // We do not want to call ChannelBase::HandleScript() as it 00404 // will save the current channel to (*it)->startChanNum 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 }
1.7.6.1