void CPatParser::OnTsPacket(byte* tsPacket) { m_packetsReceived++; if (m_packetsReceived > m_packetsToSkip) { for (int i=0; i < (int)m_pmtParsers.size(); ++i) { CPmtParser* parser = m_pmtParsers[i]; parser->OnTsPacket(tsPacket); } CSectionDecoder::OnTsPacket(tsPacket); } if (m_iState==Parsing && m_pCallback!=NULL) { for (int i=0; i < (int)m_pmtParsers.size(); ++i) { CPmtParser* parser = m_pmtParsers[i]; if (true == parser->IsReady()) { CChannelInfo info; if (GetChannel(i, info)) { m_iState=Idle; info.PatVersion = m_iPatTableVersion; m_pCallback->OnNewChannel(info); m_iState = Parsing; return; } } } } }
void CPatParser::OnNewSection(CSection& section) { if (section.table_id != 0) return; try { //int section_syntax_indicator = (section.Data[1]>>7) & 1; //int transport_stream_id = section.table_id_extension; if (section.version_number != m_iPatTableVersion) { XBMC->Log(LOG_DEBUG, "PatParser: new pat table %d->%d", m_iPatTableVersion, section.version_number); //was commented out CleanUp(); m_iPatTableVersion = section.version_number; m_iState = Parsing; } //XBMC->Log(LOG_DEBUG, "DecodePat %d section:%d lastsection:%d sectionlen:%d", // version_number,section_number,last_section_number,section_length); int loop = (section.section_length - 9) / 4; for(int i=0; i < loop; i++) { int offset = (8 +(i * 4)); int pmtPid = ((section.Data[offset+2] & 0x1F)<<8) + section.Data[offset+3]; if (pmtPid < 0x10 || pmtPid >=0x1fff) { //invalid pmt pid return; } bool found=false; for (int idx=0; idx < (int)m_pmtParsers.size(); idx++) { CPmtParser* pmtParser = m_pmtParsers[idx]; if (pmtParser->GetPid() == pmtPid) { found=true; break; } } if (!found && pmtPid>=0x10) { CPmtParser* pmtParser = new CPmtParser(); pmtParser->SetPid(pmtPid); //pmtParser->SetPmtCallBack(this); m_pmtParsers.push_back( pmtParser ); XBMC->Log(LOG_DEBUG, "PatParser: add pmt# %d pid: %x",m_pmtParsers.size(), pmtPid); } } } catch (...) { XBMC->Log(LOG_DEBUG, "Exception in PatParser"); } }
int CPatParser::Count() { int count = m_pmtParsers.size(); if (count == 0) return 0; for (int i=0; i < (int)m_pmtParsers.size(); ++i) { CPmtParser* parser = m_pmtParsers[i]; if (true == parser->IsReady()) { return count; } } return 0; }
bool CPatParser::GetChannel(int index, CChannelInfo& info) { static CChannelInfo unknownChannel; if (index < 0 || index > Count()) { return false; } CPmtParser* parser = m_pmtParsers[index]; if (false == parser->IsReady()) { return false; } info.PidTable = parser->GetPidInfo(); m_iState = Idle; return true; }
void CPmtGrabber::OnNewSection(CSection& section) { try { // if only service ID given, lookup from PAT if (GetPid() == 0) // PID 0 is the PAT, so look for matching PMT { int PMTPid=m_patgrab.PATRequest(section, m_iServiceId); if (PMTPid>0) { SetPmtPid(PMTPid,m_iServiceId); SetPid(PMTPid); } else { LogDebug("PMT Pid wasn't found on the PAT. Channel may have moved, try a new channel scan."); } } if (section.table_id!=2) return; CEnterCriticalSection enter(m_section); if (section.section_length<0 || section.section_length>=MAX_SECTION_LENGTH) return; long serviceId = section.table_id_extension; if (m_iPmtVersion<0) LogDebug("pmtgrabber: got pmt %x sid:%x",GetPid(), serviceId); if (serviceId != m_iServiceId) { LogDebug("pmtgrabber: serviceid mismatch %x != %x",serviceId,m_iServiceId); return; } m_iPmtLength=section.section_length; // copy pmt data for passing it to tvserver memcpy(m_pmtData,section.Data,m_iPmtLength); // compare the current section data with the previous one if (memcmp(section.Data, m_pmtPrevSection.Data, m_iPmtLength)!=0) { bool pidsChanged = false; CPmtParser prevPmtParser; CPmtParser currPmtParser; prevPmtParser.SetPid(GetPid()); prevPmtParser.DecodePmtPidTable(m_pmtPrevSection); currPmtParser.SetPid(GetPid()); // Check if failed - if corrupted it can crash tv service after the callback if(!currPmtParser.DecodePmtPidTable(section)) { LogDebug("CPmtGrabber::OnNewSection() - Error decoding PMT from new section, bad signal?"); return; } if (!(prevPmtParser.GetPidInfo() == currPmtParser.GetPidInfo())) { LogDebug("pmtgrabber: PMT pids changed from:"); prevPmtParser.GetPidInfo().LogPIDs(); LogDebug("pmtgrabber: PMT pids changed to:"); currPmtParser.GetPidInfo().LogPIDs(); pidsChanged = true; } m_pmtPrevSection=section; // do a callback each time the version number changes. this also allows switching for "regional channels" if (m_pCallback!=NULL && m_iPmtVersion != section.version_number) { LogDebug("pmtgrabber: got new pmt version:%x %x, service_id:%x", section.version_number, m_iPmtVersion, serviceId); // if the pids are different, then a callback is required. if (pidsChanged) { LogDebug("pmtgrabber: do callback pid %x",GetPid()); m_pCallback->OnPMTReceived(GetPid()); } // otherwise no need to callback, i.e. if _only_ version number changes regulary... else { LogDebug("pmtgrabber: NO callback done because a/v pids still the same."); } } } m_iPmtVersion=section.version_number; } catch(...) { LogDebug("CPmtGrabber::OnNewSection exception"); } }