MythTV  0.26-pre
dtvchannel.cpp
Go to the documentation of this file.
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 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends