00001
00002
00003
00004 #include <cmath>
00005
00006 #include <algorithm>
00007 using namespace std;
00008
00009 #include "atscstreamdata.h"
00010 #include "atsctables.h"
00011 #include "RingBuffer.h"
00012 #include "eithelper.h"
00013
00014 #define LOC QString("ATSCStream: ")
00015
00031 ATSCStreamData::ATSCStreamData(int desiredMajorChannel,
00032 int desiredMinorChannel,
00033 bool cacheTables)
00034 : MPEGStreamData(-1, cacheTables),
00035 _GPS_UTC_offset(GPS_LEAP_SECONDS),
00036 _atsc_eit_reset(false),
00037 _mgt_version(-1),
00038 _cached_mgt(NULL),
00039 _desired_major_channel(desiredMajorChannel),
00040 _desired_minor_channel(desiredMinorChannel)
00041 {
00042 AddListeningPID(ATSC_PSIP_PID);
00043 }
00044
00045 ATSCStreamData::~ATSCStreamData()
00046 {
00047 Reset(-1,-1);
00048
00049 QMutexLocker locker(&_listener_lock);
00050 _atsc_main_listeners.clear();
00051 _atsc_aux_listeners.clear();
00052 _atsc_eit_listeners.clear();
00053 }
00054
00055 void ATSCStreamData::SetDesiredChannel(int major, int minor)
00056 {
00057 bool reset = true;
00058 const MasterGuideTable *mgt = GetCachedMGT();
00059 tvct_vec_t tvcts = GetAllCachedTVCTs();
00060 cvct_vec_t cvcts = GetAllCachedCVCTs();
00061
00062 if (mgt && (tvcts.size() || cvcts.size()))
00063 {
00064 const TerrestrialVirtualChannelTable *tvct = NULL;
00065 const CableVirtualChannelTable *cvct = NULL;
00066 int chan_idx = -1;
00067 for (uint i = 0; (i < tvcts.size()) && (chan_idx < 0); i++)
00068 {
00069 tvct = tvcts[i];
00070 chan_idx = tvcts[i]->Find(major, minor);
00071 }
00072 for (uint i = (chan_idx < 0) ? 0 : cvcts.size();
00073 (i < cvcts.size()) && (chan_idx < 0); i++)
00074 {
00075 cvct = cvcts[i];
00076 chan_idx = cvcts[i]->Find(major, minor);
00077 }
00078
00079 if (chan_idx >= 0)
00080 {
00081 _desired_major_channel = major;
00082 _desired_minor_channel = minor;
00083
00084 ProcessMGT(mgt);
00085
00086 if (cvct)
00087 {
00088 ProcessCVCT(cvct->TransportStreamID(), cvct);
00089 SetDesiredProgram(cvct->ProgramNumber(chan_idx));
00090 }
00091 else if (tvct)
00092 {
00093 ProcessTVCT(tvct->TransportStreamID(), tvct);
00094 SetDesiredProgram(tvct->ProgramNumber(chan_idx));
00095 }
00096 reset = false;
00097 }
00098 }
00099
00100 ReturnCachedTable(mgt);
00101 ReturnCachedTVCTTables(tvcts);
00102 ReturnCachedCVCTTables(cvcts);
00103
00104 if (reset)
00105 Reset(major, minor);
00106 }
00107
00108 void ATSCStreamData::Reset(int desiredProgram)
00109 {
00110 MPEGStreamData::Reset(desiredProgram);
00111 AddListeningPID(ATSC_PSIP_PID);
00112 }
00113
00114 void ATSCStreamData::Reset(int major, int minor)
00115 {
00116 _desired_major_channel = major;
00117 _desired_minor_channel = minor;
00118
00119 MPEGStreamData::Reset(-1);
00120 _mgt_version = -1;
00121 _tvct_version.clear();
00122 _cvct_version.clear();
00123 _eit_version.clear();
00124 _eit_section_seen.clear();
00125
00126 _sourceid_to_atsc_maj_min.clear();
00127 _atsc_eit_pids.clear();
00128 _atsc_ett_pids.clear();
00129
00130 {
00131 QMutexLocker locker(&_cache_lock);
00132
00133 DeleteCachedTable(_cached_mgt);
00134 _cached_mgt = NULL;
00135
00136 tvct_cache_t::iterator tit = _cached_tvcts.begin();
00137 for (; tit != _cached_tvcts.end(); ++tit)
00138 DeleteCachedTable(*tit);
00139 _cached_tvcts.clear();
00140
00141 cvct_cache_t::iterator cit = _cached_cvcts.begin();
00142 for (; cit != _cached_cvcts.end(); ++cit)
00143 DeleteCachedTable(*cit);
00144 _cached_cvcts.clear();
00145 }
00146
00147 AddListeningPID(ATSC_PSIP_PID);
00148 }
00149
00157 bool ATSCStreamData::IsRedundant(uint pid, const PSIPTable &psip) const
00158 {
00159 if (MPEGStreamData::IsRedundant(pid, psip))
00160 return true;
00161
00162 const int table_id = psip.TableID();
00163 const int version = psip.Version();
00164
00165 if (TableID::EIT == table_id)
00166 {
00167 if (VersionEIT(pid, psip.TableIDExtension()) != version)
00168 return false;
00169 return EITSectionSeen(pid, psip.TableIDExtension(), psip.Section());
00170 }
00171
00172 if (TableID::ETT == table_id)
00173 return false;
00174
00175 if (TableID::STT == table_id)
00176 return false;
00177
00178 if (TableID::MGT == table_id)
00179 return VersionMGT() == version;
00180
00181 if (TableID::TVCT == table_id)
00182 {
00183 return VersionTVCT(psip.TableIDExtension()) == version;
00184 }
00185
00186 if (TableID::CVCT == table_id)
00187 {
00188 return VersionCVCT(psip.TableIDExtension()) == version;
00189 }
00190
00191 if (TableID::RRT == table_id)
00192 return true;
00193
00194 return false;
00195 }
00196
00197 bool ATSCStreamData::HandleTables(uint pid, const PSIPTable &psip)
00198 {
00199 if (MPEGStreamData::HandleTables(pid, psip))
00200 return true;
00201
00202 if (IsRedundant(pid, psip))
00203 return true;
00204
00205 const int version = psip.Version();
00206
00207
00208 switch (psip.TableID())
00209 {
00210 case TableID::MGT:
00211 {
00212 SetVersionMGT(version);
00213 if (_cache_tables)
00214 {
00215 MasterGuideTable *mgt = new MasterGuideTable(psip);
00216 CacheMGT(mgt);
00217 ProcessMGT(mgt);
00218 }
00219 else
00220 {
00221 MasterGuideTable mgt(psip);
00222 ProcessMGT(&mgt);
00223 }
00224 return true;
00225 }
00226 case TableID::TVCT:
00227 {
00228 uint tsid = psip.TableIDExtension();
00229 SetVersionTVCT(tsid, version);
00230 if (_cache_tables)
00231 {
00232 TerrestrialVirtualChannelTable *vct =
00233 new TerrestrialVirtualChannelTable(psip);
00234 CacheTVCT(pid, vct);
00235 ProcessTVCT(tsid, vct);
00236 }
00237 else
00238 {
00239 TerrestrialVirtualChannelTable vct(psip);
00240 ProcessTVCT(tsid, &vct);
00241 }
00242 return true;
00243 }
00244 case TableID::CVCT:
00245 {
00246 uint tsid = psip.TableIDExtension();
00247 SetVersionCVCT(tsid, version);
00248 if (_cache_tables)
00249 {
00250 CableVirtualChannelTable *vct =
00251 new CableVirtualChannelTable(psip);
00252 CacheCVCT(pid, vct);
00253 ProcessCVCT(tsid, vct);
00254 }
00255 else
00256 {
00257 CableVirtualChannelTable vct(psip);
00258 ProcessCVCT(tsid, &vct);
00259 }
00260 return true;
00261 }
00262 case TableID::RRT:
00263 {
00264 RatingRegionTable rrt(psip);
00265 QMutexLocker locker(&_listener_lock);
00266 for (uint i = 0; i < _atsc_aux_listeners.size(); i++)
00267 _atsc_aux_listeners[i]->HandleRRT(&rrt);
00268 return true;
00269 }
00270 case TableID::EIT:
00271 {
00272 QMutexLocker locker(&_listener_lock);
00273 if (!_atsc_eit_listeners.size() && !_eit_helper)
00274 return true;
00275
00276 if (VersionEIT(pid, psip.TableIDExtension()) != version)
00277 SetVersionEIT(pid, psip.TableIDExtension(), version);
00278 SetEITSectionSeen(pid, psip.TableIDExtension(), psip.Section());
00279
00280 EventInformationTable eit(psip);
00281 for (uint i = 0; i < _atsc_eit_listeners.size(); i++)
00282 _atsc_eit_listeners[i]->HandleEIT(pid, &eit);
00283
00284 const uint mm = GetATSCMajorMinor(eit.SourceID());
00285 if (mm && _eit_helper)
00286 _eit_helper->AddEIT(mm >> 16, mm & 0xffff, &eit);
00287
00288 return true;
00289 }
00290 case TableID::ETT:
00291 {
00292 ExtendedTextTable ett(psip);
00293
00294 QMutexLocker locker(&_listener_lock);
00295 for (uint i = 0; i < _atsc_eit_listeners.size(); i++)
00296 _atsc_eit_listeners[i]->HandleETT(pid, &ett);
00297
00298 if (ett.IsEventETM() && _eit_helper)
00299 {
00300 const uint mm = GetATSCMajorMinor(ett.SourceID());
00301 if (mm)
00302 _eit_helper->AddETT(mm >> 16, mm & 0xffff, &ett);
00303 }
00304
00305 return true;
00306 }
00307 case TableID::STT:
00308 {
00309 SystemTimeTable stt(psip);
00310
00311 UpdateTimeOffset(stt.UTCUnix());
00312
00313
00314 if (stt.GPSOffset() != _GPS_UTC_offset)
00315 _GPS_UTC_offset = stt.GPSOffset();
00316
00317 _listener_lock.lock();
00318 for (uint i = 0; i < _atsc_main_listeners.size(); i++)
00319 _atsc_main_listeners[i]->HandleSTT(&stt);
00320 _listener_lock.unlock();
00321
00322 if (_eit_helper && GPSOffset() != _eit_helper->GetGPSOffset())
00323 _eit_helper->SetGPSOffset(GPSOffset());
00324
00325 return true;
00326 }
00327 case TableID::DCCT:
00328 {
00329 DirectedChannelChangeTable dcct(psip);
00330
00331 QMutexLocker locker(&_listener_lock);
00332 for (uint i = 0; i < _atsc_aux_listeners.size(); i++)
00333 _atsc_aux_listeners[i]->HandleDCCT(&dcct);
00334
00335 return true;
00336 }
00337 case TableID::DCCSCT:
00338 {
00339 DirectedChannelChangeSelectionCodeTable dccsct(psip);
00340
00341 QMutexLocker locker(&_listener_lock);
00342 for (uint i = 0; i < _atsc_aux_listeners.size(); i++)
00343 _atsc_aux_listeners[i]->HandleDCCSCT(&dccsct);
00344
00345 return true;
00346 }
00347 default:
00348 {
00349 VERBOSE(VB_RECORD,
00350 QString("ATSCStreamData::HandleTables(): Unknown "
00351 "table 0x%1").arg(psip.TableID(),0,16));
00352 break;
00353 }
00354 }
00355 return false;
00356 }
00357
00358 void ATSCStreamData::SetEITSectionSeen(uint pid, uint atsc_source_id,
00359 uint section)
00360 {
00361 uint key = (pid<<16) | atsc_source_id;
00362 sections_map_t::iterator it = _eit_section_seen.find(key);
00363 if (it == _eit_section_seen.end())
00364 {
00365 _eit_section_seen[key].resize(32, 0);
00366 it = _eit_section_seen.find(key);
00367 }
00368 (*it)[section>>3] |= bit_sel[section & 0x7];
00369 }
00370
00371 bool ATSCStreamData::EITSectionSeen(uint pid, uint atsc_source_id,
00372 uint section) const
00373 {
00374 uint key = (pid<<16) | atsc_source_id;
00375 sections_map_t::const_iterator it = _eit_section_seen.find(key);
00376 if (it == _eit_section_seen.end())
00377 return false;
00378 return (bool) ((*it)[section>>3] & bit_sel[section & 0x7]);
00379 }
00380
00381 bool ATSCStreamData::HasEITPIDChanges(const uint_vec_t &in_use_pids) const
00382 {
00383 QMutexLocker locker(&_listener_lock);
00384 uint eit_count = (uint) round(_atsc_eit_pids.size() * _eit_rate);
00385 uint ett_count = (uint) round(_atsc_ett_pids.size() * _eit_rate);
00386 return (in_use_pids.size() != (eit_count + ett_count) || _atsc_eit_reset);
00387 }
00388
00389 bool ATSCStreamData::GetEITPIDChanges(const uint_vec_t &cur_pids,
00390 uint_vec_t &add_pids,
00391 uint_vec_t &del_pids) const
00392 {
00393 QMutexLocker locker(&_listener_lock);
00394
00395 _atsc_eit_reset = false;
00396
00397 uint eit_count = (uint) round(_atsc_eit_pids.size() * _eit_rate);
00398 uint ett_count = (uint) round(_atsc_ett_pids.size() * _eit_rate);
00399 uint i;
00400
00401
00402
00403
00404 uint_vec_t add_pids_tmp;
00405 atsc_eit_pid_map_t::const_iterator it = _atsc_eit_pids.begin();
00406 for (i = 0; it != _atsc_eit_pids.end() && (i < eit_count); (++it),(i++))
00407 add_pids_tmp.push_back(*it);
00408
00409 atsc_ett_pid_map_t::const_iterator it2 = _atsc_ett_pids.begin();
00410 for (i = 0; it2 != _atsc_ett_pids.end() && (i < ett_count); (++it2),(i++))
00411 add_pids_tmp.push_back(*it2);
00412
00413 uint_vec_t::const_iterator it3;
00414 for (i = 0; i < cur_pids.size(); i++)
00415 {
00416 it3 = find(add_pids_tmp.begin(), add_pids_tmp.end(), cur_pids[i]);
00417 if (it3 == add_pids_tmp.end())
00418 del_pids.push_back(cur_pids[i]);
00419 }
00420
00421 for (i = 0; i < add_pids_tmp.size(); i++)
00422 {
00423 it3 = find(cur_pids.begin(), cur_pids.end(), add_pids_tmp[i]);
00424 if (it3 == cur_pids.end())
00425 add_pids.push_back(add_pids_tmp[i]);
00426 }
00427
00428 return add_pids.size() || del_pids.size();
00429 }
00430
00431 void ATSCStreamData::ProcessMGT(const MasterGuideTable *mgt)
00432 {
00433 QMutexLocker locker(&_listener_lock);
00434
00435 _atsc_eit_reset = true;
00436 _atsc_eit_pids.clear();
00437 _atsc_ett_pids.clear();
00438
00439 for (uint i = 0 ; i < mgt->TableCount(); i++)
00440 {
00441 const int table_class = mgt->TableClass(i);
00442 const uint pid = mgt->TablePID(i);
00443
00444 if (table_class == TableClass::EIT)
00445 {
00446 const uint num = mgt->TableType(i) - 0x100;
00447 _atsc_eit_pids[num] = pid;
00448 }
00449 else if (table_class == TableClass::ETTe)
00450 {
00451 const uint num = mgt->TableType(i) - 0x200;
00452 _atsc_ett_pids[num] = pid;
00453 }
00454 }
00455
00456 for (uint i = 0; i < _atsc_main_listeners.size(); i++)
00457 _atsc_main_listeners[i]->HandleMGT(mgt);
00458 }
00459
00460 void ATSCStreamData::ProcessVCT(uint tsid, const VirtualChannelTable *vct)
00461 {
00462 for (uint i = 0; i < _atsc_main_listeners.size(); i++)
00463 _atsc_main_listeners[i]->HandleVCT(tsid, vct);
00464
00465 _sourceid_to_atsc_maj_min.clear();
00466 for (uint i = 0; i < vct->ChannelCount() ; i++)
00467 {
00468 if (vct->IsHidden(i) && vct->IsHiddenInGuide(i))
00469 {
00470 VERBOSE(VB_EIT, QString("%1 chan %2-%3 is hidden in guide")
00471 .arg(vct->ModulationMode(i) == 1 ? "NTSC" : "ATSC")
00472 .arg(vct->MajorChannel(i))
00473 .arg(vct->MinorChannel(i)));
00474 continue;
00475 }
00476
00477 if (1 == vct->ModulationMode(i))
00478 {
00479 VERBOSE(VB_EIT, QString("Ignoring NTSC chan %1-%2")
00480 .arg(vct->MajorChannel(i))
00481 .arg(vct->MinorChannel(i)));
00482 continue;
00483 }
00484
00485 VERBOSE(VB_EIT, QString("Adding Source #%1 ATSC chan %2-%3")
00486 .arg(vct->SourceID(i))
00487 .arg(vct->MajorChannel(i))
00488 .arg(vct->MinorChannel(i)));
00489
00490 _sourceid_to_atsc_maj_min[vct->SourceID(i)] =
00491 vct->MajorChannel(i) << 16 | vct->MinorChannel(i);
00492 }
00493 }
00494
00495 void ATSCStreamData::ProcessTVCT(uint tsid,
00496 const TerrestrialVirtualChannelTable *vct)
00497 {
00498 QMutexLocker locker(&_listener_lock);
00499 ProcessVCT(tsid, vct);
00500 for (uint i = 0; i < _atsc_aux_listeners.size(); i++)
00501 _atsc_aux_listeners[i]->HandleTVCT(tsid, vct);
00502 }
00503
00504 void ATSCStreamData::ProcessCVCT(uint tsid,
00505 const CableVirtualChannelTable *vct)
00506 {
00507 QMutexLocker locker(&_listener_lock);
00508 ProcessVCT(tsid, vct);
00509 for (uint i = 0; i < _atsc_aux_listeners.size(); i++)
00510 _atsc_aux_listeners[i]->HandleCVCT(tsid, vct);
00511 }
00512
00513 bool ATSCStreamData::HasCachedMGT(bool current) const
00514 {
00515 if (!current)
00516 VERBOSE(VB_IMPORTANT, "Currently we ignore \'current\' param");
00517
00518 return (bool)(_cached_mgt);
00519 }
00520
00521 bool ATSCStreamData::HasChannel(uint major, uint minor) const
00522 {
00523 bool hasit = false;
00524
00525 {
00526 tvct_vec_t tvct = GetAllCachedTVCTs();
00527 for (uint i = 0; i < tvct.size() && !hasit; i++)
00528 {
00529 if (tvct[i]->Find(major, minor) >= 0)
00530 hasit |= HasProgram(tvct[i]->ProgramNumber(i));
00531 }
00532 ReturnCachedTVCTTables(tvct);
00533 }
00534
00535 if (!hasit)
00536 {
00537 cvct_vec_t cvct = GetAllCachedCVCTs();
00538 for (uint i = 0; i < cvct.size() && !hasit; i++)
00539 {
00540 if (cvct[i]->Find(major, minor) >= 0)
00541 hasit |= HasProgram(cvct[i]->ProgramNumber(i));
00542 }
00543 ReturnCachedCVCTTables(cvct);
00544 }
00545
00546 return hasit;
00547 }
00548
00549 bool ATSCStreamData::HasCachedTVCT(uint pid, bool current) const
00550 {
00551 if (!current)
00552 VERBOSE(VB_IMPORTANT, "Currently we ignore \'current\' param");
00553
00554 _cache_lock.lock();
00555 tvct_cache_t::const_iterator it = _cached_tvcts.find(pid);
00556 bool exists = (it != _cached_tvcts.end());
00557 _cache_lock.unlock();
00558
00559 return exists;
00560 }
00561
00562 bool ATSCStreamData::HasCachedCVCT(uint pid, bool current) const
00563 {
00564 if (!current)
00565 VERBOSE(VB_IMPORTANT, "Currently we ignore \'current\' param");
00566
00567 _cache_lock.lock();
00568 cvct_cache_t::const_iterator it = _cached_cvcts.find(pid);
00569 bool exists = (it != _cached_cvcts.end());
00570 _cache_lock.unlock();
00571
00572 return exists;
00573 }
00574
00575 bool ATSCStreamData::HasCachedAllTVCTs(bool current) const
00576 {
00577 if (!current)
00578 VERBOSE(VB_IMPORTANT, "Currently we ignore \'current\' param");
00579
00580 if (!_cached_mgt)
00581 return false;
00582
00583 _cache_lock.lock();
00584 bool ret = true;
00585 for (uint i = 0; ret && (i < _cached_mgt->TableCount()); ++i)
00586 {
00587 if (TableClass::TVCTc == _cached_mgt->TableClass(i))
00588 ret &= HasCachedTVCT(_cached_mgt->TablePID(i));
00589 }
00590 _cache_lock.unlock();
00591
00592 return ret;
00593 }
00594
00595 bool ATSCStreamData::HasCachedAllCVCTs(bool current) const
00596 {
00597 if (!current)
00598 VERBOSE(VB_IMPORTANT, "Currently we ignore \'current\' param");
00599
00600 if (!_cached_mgt)
00601 return false;
00602
00603 _cache_lock.lock();
00604 bool ret = true;
00605 for (uint i = 0; ret && (i < _cached_mgt->TableCount()); ++i)
00606 {
00607 if (TableClass::CVCTc == _cached_mgt->TableClass(i))
00608 ret &= HasCachedCVCT(_cached_mgt->TablePID(i));
00609 }
00610 _cache_lock.unlock();
00611
00612 return ret;
00613 }
00614
00615 const MasterGuideTable *ATSCStreamData::GetCachedMGT(bool current) const
00616 {
00617 if (!current)
00618 VERBOSE(VB_IMPORTANT, "Currently we ignore \'current\' param");
00619
00620 _cache_lock.lock();
00621 const MasterGuideTable *mgt = _cached_mgt;
00622 IncrementRefCnt(mgt);
00623 _cache_lock.unlock();
00624
00625 return mgt;
00626 }
00627
00628 const tvct_ptr_t ATSCStreamData::GetCachedTVCT(uint pid, bool current) const
00629 {
00630 if (!current)
00631 VERBOSE(VB_IMPORTANT, "Currently we ignore \'current\' param");
00632
00633 TerrestrialVirtualChannelTable *tvct = NULL;
00634
00635 _cache_lock.lock();
00636 tvct_cache_t::const_iterator it = _cached_tvcts.find(pid);
00637 if (it != _cached_tvcts.end())
00638 IncrementRefCnt(tvct = *it);
00639 _cache_lock.unlock();
00640
00641 return tvct;
00642 }
00643
00644 const cvct_ptr_t ATSCStreamData::GetCachedCVCT(uint pid, bool current) const
00645 {
00646 if (!current)
00647 VERBOSE(VB_IMPORTANT, "Currently we ignore \'current\' param");
00648
00649 CableVirtualChannelTable *cvct = NULL;
00650
00651 _cache_lock.lock();
00652 cvct_cache_t::const_iterator it = _cached_cvcts.find(pid);
00653 if (it != _cached_cvcts.end())
00654 IncrementRefCnt(cvct = *it);
00655 _cache_lock.unlock();
00656
00657 return cvct;
00658 }
00659
00660 tvct_vec_t ATSCStreamData::GetAllCachedTVCTs(bool current) const
00661 {
00662 if (!current)
00663 VERBOSE(VB_IMPORTANT, "Currently we ignore \'current\' param");
00664
00665 vector<const TerrestrialVirtualChannelTable*> tvcts;
00666
00667 _cache_lock.lock();
00668 tvct_cache_t::const_iterator it = _cached_tvcts.begin();
00669 for (; it != _cached_tvcts.end(); ++it)
00670 {
00671 TerrestrialVirtualChannelTable* tvct = *it;
00672 IncrementRefCnt(tvct);
00673 tvcts.push_back(tvct);
00674 }
00675 _cache_lock.unlock();
00676
00677 return tvcts;
00678 }
00679
00680 cvct_vec_t ATSCStreamData::GetAllCachedCVCTs(bool current) const
00681 {
00682 if (!current)
00683 VERBOSE(VB_IMPORTANT, "Currently we ignore \'current\' param");
00684
00685 vector<const CableVirtualChannelTable*> cvcts;
00686
00687 _cache_lock.lock();
00688 cvct_cache_t::const_iterator it = _cached_cvcts.begin();
00689 for (; it != _cached_cvcts.end(); ++it)
00690 {
00691 CableVirtualChannelTable* cvct = *it;
00692 IncrementRefCnt(cvct);
00693 cvcts.push_back(cvct);
00694 }
00695 _cache_lock.unlock();
00696
00697 return cvcts;
00698 }
00699
00700 void ATSCStreamData::CacheMGT(MasterGuideTable *mgt)
00701 {
00702 QMutexLocker locker(&_cache_lock);
00703
00704 DeleteCachedTable(_cached_mgt);
00705 _cached_mgt = mgt;
00706 }
00707
00708 void ATSCStreamData::CacheTVCT(uint pid, TerrestrialVirtualChannelTable* tvct)
00709 {
00710 QMutexLocker locker(&_cache_lock);
00711
00712 DeleteCachedTable(_cached_tvcts[pid]);
00713 _cached_tvcts[pid] = tvct;
00714 }
00715
00716 void ATSCStreamData::CacheCVCT(uint pid, CableVirtualChannelTable* cvct)
00717 {
00718 QMutexLocker locker(&_cache_lock);
00719
00720 DeleteCachedTable(_cached_cvcts[pid]);
00721 _cached_cvcts[pid] = cvct;
00722 }
00723
00724 void ATSCStreamData::DeleteCachedTable(PSIPTable *psip) const
00725 {
00726 if (!psip)
00727 return;
00728
00729 QMutexLocker locker(&_cache_lock);
00730 if (_cached_ref_cnt[psip] > 0)
00731 {
00732 _cached_slated_for_deletion[psip] = 1;
00733 return;
00734 }
00735 else if (TableID::MGT == psip->TableID())
00736 {
00737 if (psip == _cached_mgt)
00738 _cached_mgt = NULL;
00739 delete psip;
00740 }
00741 else if ((TableID::TVCT == psip->TableID()) &&
00742 _cached_tvcts[psip->tsheader()->PID()])
00743 {
00744 _cached_tvcts[psip->tsheader()->PID()] = NULL;
00745 delete psip;
00746 }
00747 else if ((TableID::CVCT == psip->TableID()) &&
00748 _cached_cvcts[psip->tsheader()->PID()])
00749 {
00750 _cached_cvcts[psip->tsheader()->PID()] = NULL;
00751 delete psip;
00752 }
00753 else
00754 {
00755 MPEGStreamData::DeleteCachedTable(psip);
00756 return;
00757 }
00758 psip_refcnt_map_t::iterator it;
00759 it = _cached_slated_for_deletion.find(psip);
00760 if (it != _cached_slated_for_deletion.end())
00761 _cached_slated_for_deletion.erase(it);
00762 }
00763
00764 void ATSCStreamData::ReturnCachedTVCTTables(tvct_vec_t &tvcts) const
00765 {
00766 for (tvct_vec_t::iterator it = tvcts.begin(); it != tvcts.end(); ++it)
00767 ReturnCachedTable(*it);
00768 tvcts.clear();
00769 }
00770
00771 void ATSCStreamData::ReturnCachedCVCTTables(cvct_vec_t &cvcts) const
00772 {
00773 for (cvct_vec_t::iterator it = cvcts.begin(); it != cvcts.end(); ++it)
00774 ReturnCachedTable(*it);
00775 cvcts.clear();
00776 }
00777
00778 void ATSCStreamData::AddATSCMainListener(ATSCMainStreamListener *val)
00779 {
00780 QMutexLocker locker(&_listener_lock);
00781
00782 atsc_main_listener_vec_t::iterator it = _atsc_main_listeners.begin();
00783 for (; it != _atsc_main_listeners.end(); ++it)
00784 if (((void*)val) == ((void*)*it))
00785 return;
00786
00787 _atsc_main_listeners.push_back(val);
00788 }
00789
00790 void ATSCStreamData::RemoveATSCMainListener(ATSCMainStreamListener *val)
00791 {
00792 QMutexLocker locker(&_listener_lock);
00793
00794 atsc_main_listener_vec_t::iterator it = _atsc_main_listeners.begin();
00795 for (; it != _atsc_main_listeners.end(); ++it)
00796 {
00797 if (((void*)val) == ((void*)*it))
00798 {
00799 _atsc_main_listeners.erase(it);
00800 return;
00801 }
00802 }
00803 }
00804
00805 void ATSCStreamData::AddATSCAuxListener(ATSCAuxStreamListener *val)
00806 {
00807 QMutexLocker locker(&_listener_lock);
00808
00809 atsc_aux_listener_vec_t::iterator it = _atsc_aux_listeners.begin();
00810 for (; it != _atsc_aux_listeners.end(); ++it)
00811 if (((void*)val) == ((void*)*it))
00812 return;
00813
00814 _atsc_aux_listeners.push_back(val);
00815 }
00816
00817 void ATSCStreamData::RemoveATSCAuxListener(ATSCAuxStreamListener *val)
00818 {
00819 QMutexLocker locker(&_listener_lock);
00820
00821 atsc_aux_listener_vec_t::iterator it = _atsc_aux_listeners.begin();
00822 for (; it != _atsc_aux_listeners.end(); ++it)
00823 {
00824 if (((void*)val) == ((void*)*it))
00825 {
00826 _atsc_aux_listeners.erase(it);
00827 return;
00828 }
00829 }
00830 }
00831
00832 void ATSCStreamData::AddATSCEITListener(ATSCEITStreamListener *val)
00833 {
00834 QMutexLocker locker(&_listener_lock);
00835
00836 atsc_eit_listener_vec_t::iterator it = _atsc_eit_listeners.begin();
00837 for (; it != _atsc_eit_listeners.end(); ++it)
00838 if (((void*)val) == ((void*)*it))
00839 return;
00840
00841 _atsc_eit_listeners.push_back(val);
00842 }
00843
00844 void ATSCStreamData::RemoveATSCEITListener(ATSCEITStreamListener *val)
00845 {
00846 QMutexLocker locker(&_listener_lock);
00847
00848 atsc_eit_listener_vec_t::iterator it = _atsc_eit_listeners.begin();
00849 for (; it != _atsc_eit_listeners.end(); ++it)
00850 {
00851 if (((void*)val) == ((void*)*it))
00852 {
00853 _atsc_eit_listeners.erase(it);
00854 return;
00855 }
00856 }
00857 }