bool DVBStreamHandler::UpdateFiltersFromStreamData(void) { UpdateListeningForEIT(); pid_map_t pids; { QMutexLocker read_locker(&_listener_lock); for (uint i = 0; i < _stream_data_list.size(); i++) _stream_data_list[i]->GetPIDs(pids); } QMap<uint, PIDInfo*> add_pids; vector<uint> del_pids; { QMutexLocker read_locker(&_pid_lock); // PIDs that need to be added.. pid_map_t::const_iterator lit = pids.constBegin(); for (; lit != pids.constEnd(); ++lit) { if (*lit && (_pid_info.find(lit.key()) == _pid_info.end())) { add_pids[lit.key()] = new PIDInfo( lit.key(), StreamID::PrivSec, DMX_PES_OTHER); } } // PIDs that need to be removed.. PIDInfoMap::const_iterator fit = _pid_info.begin(); for (; fit != _pid_info.end(); ++fit) { bool in_pids = pids.find(fit.key()) != pids.end(); if (!in_pids) del_pids.push_back(fit.key()); } } // Remove PIDs bool ok = true; vector<uint>::iterator dit = del_pids.begin(); for (; dit != del_pids.end(); ++dit) ok &= RemovePIDFilter(*dit); // Add PIDs QMap<uint, PIDInfo*>::iterator ait = add_pids.begin(); for (; ait != add_pids.end(); ++ait) ok &= AddPIDFilter(*ait); // Cycle filters if it's been a while if (_cycle_timer.elapsed() > 1000) CycleFiltersByPriority(); return ok; }
/** \fn DVBStreamHandler::RunSR(void) * \brief Uses "Section" reader to read a DVB device for tables * * This currently only supports DVB streams, ATSC and the raw MPEG * streams used by some cable and satelite providers is not supported. */ void DVBStreamHandler::RunSR(void) { int buffer_size = 4192; // maximum size of Section we handle unsigned char *buffer = new unsigned char[buffer_size]; if (!buffer) { _error = true; return; } SetRunning(true, _needs_buffering, true); LOG(VB_RECORD, LOG_INFO, LOC + "RunSR(): begin"); while (_running_desired && !_error) { RetuneMonitor(); UpdateFiltersFromStreamData(); QMutexLocker read_locker(&_pid_lock); bool readSomething = false; PIDInfoMap::const_iterator fit = _pid_info.begin(); for (; fit != _pid_info.end(); ++fit) { int len = read((*fit)->filter_fd, buffer, buffer_size); if (len <= 0) continue; readSomething = true; const PESPacket pes = PESPacket::ViewData(buffer); const PSIPTable psip(pes); if (psip.SectionSyntaxIndicator()) { _listener_lock.lock(); StreamDataList::const_iterator sit = _stream_data_list.begin(); for (; sit != _stream_data_list.end(); ++sit) sit.key()->HandleTables(fit.key() /* pid */, psip); _listener_lock.unlock(); } } if (!readSomething) usleep(3000); } LOG(VB_RECORD, LOG_INFO, LOC + "RunSR(): " + "shutdown"); RemoveAllPIDFilters(); delete[] buffer; SetRunning(false, _needs_buffering, true); LOG(VB_RECORD, LOG_INFO, LOC + "RunSR(): " + "end"); }
/** \fn DVBStreamHandler::RunSR(void) * \brief Uses "Section" reader to read a DVB device for tables * * This currently only supports DVB streams, ATSC and the raw MPEG * streams used by some cable and satelite providers is not supported. */ void DVBStreamHandler::RunSR(void) { int buffer_size = 4192; // maximum size of Section we handle unsigned char *buffer = new unsigned char[buffer_size]; if (!buffer) return; VERBOSE(VB_RECORD, LOC + "RunSR(): begin"); while (IsRunning()) { RetuneMonitor(); UpdateFiltersFromStreamData(); QMutexLocker read_locker(&_pid_lock); bool readSomething = false; PIDInfoMap::const_iterator fit = _pid_info.begin(); for (; fit != _pid_info.end(); ++fit) { int len = read((*fit)->filter_fd, buffer, buffer_size); if (len <= 0) continue; readSomething = true; const PESPacket pes = PESPacket::ViewData(buffer); const PSIPTable psip(pes); if (psip.SectionSyntaxIndicator()) { _listener_lock.lock(); for (uint i = 0; i < _stream_data_list.size(); i++) { _stream_data_list[i]->HandleTables( fit.key() /* pid */, psip); } _listener_lock.unlock(); } } if (!readSomething) usleep(3000); } VERBOSE(VB_RECORD, LOC + "RunSR(): " + "shutdown"); RemoveAllPIDFilters(); delete[] buffer; VERBOSE(VB_RECORD, LOC + "RunSR(): " + "end"); }
void DVBStreamHandler::CycleFiltersByPriority(void) { QMutexLocker writing_locker(&_pid_lock); QMap<PIDPriority, pid_list_t> priority_queue; QMap<PIDPriority, uint> priority_open_cnt; PIDInfoMap::const_iterator cit = _pid_info.begin(); for (; cit != _pid_info.end(); ++cit) { PIDPriority priority = GetPIDPriority((*cit)->_pid); priority_queue[priority].push_back(cit.key()); if ((*cit)->IsOpen()) priority_open_cnt[priority]++; } QMap<PIDPriority, pid_list_t>::iterator it = priority_queue.begin(); for (; it != priority_queue.end(); ++it) sort((*it).begin(), (*it).end()); for (PIDPriority i = kPIDPriorityHigh; i > kPIDPriorityNone; i = (PIDPriority)((int)i-1)) { while (priority_open_cnt[i] < priority_queue[i].size()) { // if we can open a filter, just do it // find first closed filter after first open an filter "k" pid_list_t::iterator open = find( _pid_info, priority_queue[i], priority_queue[i].begin(), priority_queue[i].end(), true); if (open == priority_queue[i].end()) open = priority_queue[i].begin(); pid_list_t::iterator closed = find( _pid_info, priority_queue[i], open, priority_queue[i].end(), false); if (closed == priority_queue[i].end()) break; // something is broken if (_pid_info[*closed]->Open(_dvb_dev, _using_section_reader)) { _open_pid_filters++; priority_open_cnt[i]++; continue; } // if we can't open a filter, try to close a lower priority one bool freed = false; for (PIDPriority j = (PIDPriority)((int)i - 1); (j > kPIDPriorityNone) && !freed; j = (PIDPriority)((int)j-1)) { if (!priority_open_cnt[j]) continue; for (uint k = 0; (k < priority_queue[j].size()) && !freed; k++) { PIDInfo *info = _pid_info[priority_queue[j][k]]; if (!info->IsOpen()) continue; if (info->Close(_dvb_dev)) freed = true; _open_pid_filters--; priority_open_cnt[j]--; } } if (freed) { // if we can open a filter, just do it if (_pid_info[*closed]->Open( _dvb_dev, _using_section_reader)) { _open_pid_filters++; priority_open_cnt[i]++; continue; } } // we have to cycle within our priority level if (_cycle_timer.elapsed() < 1000) break; // we don't want to cycle too often if (!_pid_info[*open]->IsOpen()) break; // nothing to close.. // close "open" bool ok = _pid_info[*open]->Close(_dvb_dev); _open_pid_filters--; priority_open_cnt[i]--; // open "closed" if (ok && _pid_info[*closed]-> Open(_dvb_dev, _using_section_reader)) { _open_pid_filters++; priority_open_cnt[i]++; } break; // we only want to cycle once per priority per run } } _cycle_timer.start(); }
bool HDHRStreamHandler::UpdateFilters(void) { if (_tune_mode == hdhrTuneModeFrequency) _tune_mode = hdhrTuneModeFrequencyPid; if (_tune_mode != hdhrTuneModeFrequencyPid) { LOG(VB_GENERAL, LOG_ERR, LOC + "UpdateFilters called in wrong tune mode"); return false; } #ifdef DEBUG_PID_FILTERS LOG(VB_RECORD, LOG_INFO, LOC + "UpdateFilters()"); #endif // DEBUG_PID_FILTERS QMutexLocker locker(&_pid_lock); QString filter = ""; vector<uint> range_min; vector<uint> range_max; PIDInfoMap::const_iterator it = _pid_info.begin(); for (; it != _pid_info.end(); ++it) { range_min.push_back(it.key()); PIDInfoMap::const_iterator eit = it; for (++eit; (eit != _pid_info.end()) && (it.key() + 1 == eit.key()); ++it, ++eit); range_max.push_back(it.key()); } if (range_min.size() > 16) { range_min.resize(16); uint pid_max = range_max.back(); range_max.resize(15); range_max.push_back(pid_max); } for (uint i = 0; i < range_min.size(); i++) { filter += filt_str(range_min[i]); if (range_min[i] != range_max[i]) filter += QString("-%1").arg(filt_str(range_max[i])); filter += " "; } filter = filter.trimmed(); QString new_filter = TunerSet("filter", filter); #ifdef DEBUG_PID_FILTERS QString msg = QString("Filter: '%1'").arg(filter); if (filter != new_filter) msg += QString("\n\t\t\t\t'%2'").arg(new_filter); LOG(VB_RECORD, LOG_INFO, LOC + msg); #endif // DEBUG_PID_FILTERS return filter == new_filter; }