|
MythTV
0.26-pre
|
00001 // -*- Mode: c++ -*- 00002 00003 // POSIX headers 00004 #include <fcntl.h> 00005 #include <unistd.h> 00006 #include <sys/select.h> 00007 #include <sys/ioctl.h> 00008 00009 // Qt headers 00010 #include <QString> 00011 00012 // MythTV headers 00013 #include "dvbstreamhandler.h" 00014 #include "dvbchannel.h" 00015 #include "dtvsignalmonitor.h" 00016 #include "streamlisteners.h" 00017 #include "mpegstreamdata.h" 00018 #include "cardutil.h" 00019 #include "dvbtypes.h" // for pid filtering 00020 #include "diseqc.h" // for rotor retune 00021 #include "mythlogging.h" 00022 00023 #define LOC QString("DVBSH(%1): ").arg(_device) 00024 00025 QMap<QString,bool> DVBStreamHandler::_rec_supports_ts_monitoring; 00026 QMutex DVBStreamHandler::_rec_supports_ts_monitoring_lock; 00027 00028 QMap<QString,DVBStreamHandler*> DVBStreamHandler::_handlers; 00029 QMap<QString,uint> DVBStreamHandler::_handlers_refcnt; 00030 QMutex DVBStreamHandler::_handlers_lock; 00031 00032 DVBStreamHandler *DVBStreamHandler::Get(const QString &devname) 00033 { 00034 QMutexLocker locker(&_handlers_lock); 00035 00036 QMap<QString,DVBStreamHandler*>::iterator it = 00037 _handlers.find(devname); 00038 00039 if (it == _handlers.end()) 00040 { 00041 _handlers[devname] = new DVBStreamHandler(devname); 00042 _handlers_refcnt[devname] = 1; 00043 } 00044 else 00045 { 00046 _handlers_refcnt[devname]++; 00047 } 00048 00049 return _handlers[devname]; 00050 } 00051 00052 void DVBStreamHandler::Return(DVBStreamHandler * & ref) 00053 { 00054 QMutexLocker locker(&_handlers_lock); 00055 00056 QString devname = ref->_device; 00057 00058 QMap<QString,uint>::iterator rit = _handlers_refcnt.find(devname); 00059 if (rit == _handlers_refcnt.end()) 00060 return; 00061 00062 if (*rit > 1) 00063 { 00064 ref = NULL; 00065 (*rit)--; 00066 return; 00067 } 00068 00069 QMap<QString,DVBStreamHandler*>::iterator it = _handlers.find(devname); 00070 if ((it != _handlers.end()) && (*it == ref)) 00071 { 00072 delete *it; 00073 _handlers.erase(it); 00074 } 00075 else 00076 { 00077 LOG(VB_GENERAL, LOG_ERR, 00078 QString("DVBSH Error: Couldn't find handler for %1") .arg(devname)); 00079 } 00080 00081 _handlers_refcnt.erase(rit); 00082 ref = NULL; 00083 } 00084 00085 DVBStreamHandler::DVBStreamHandler(const QString &dvb_device) : 00086 StreamHandler(dvb_device), 00087 _dvr_dev_path(CardUtil::GetDeviceName(DVB_DEV_DVR, _device)), 00088 _allow_retune(false), 00089 00090 _sigmon(NULL), 00091 _dvbchannel(NULL), 00092 _drb(NULL) 00093 { 00094 setObjectName("DVBRead"); 00095 } 00096 00097 void DVBStreamHandler::SetRunningDesired(bool desired) 00098 { 00099 if (_drb && _running_desired && !desired) 00100 _drb->Stop(); 00101 StreamHandler::SetRunningDesired(desired); 00102 } 00103 00104 void DVBStreamHandler::run(void) 00105 { 00106 RunProlog(); 00107 LOG(VB_RECORD, LOG_INFO, LOC + "run(): begin"); 00108 00109 if (!SupportsTSMonitoring() && _allow_section_reader) 00110 RunSR(); 00111 else 00112 RunTS(); 00113 00114 LOG(VB_RECORD, LOG_INFO, LOC + "run(): end"); 00115 RunEpilog(); 00116 } 00117 00128 void DVBStreamHandler::RunTS(void) 00129 { 00130 QByteArray dvr_dev_path = _dvr_dev_path.toAscii(); 00131 int dvr_fd; 00132 for (int tries = 1; ; ++tries) 00133 { 00134 dvr_fd = open(dvr_dev_path.constData(), O_RDONLY | O_NONBLOCK); 00135 if (dvr_fd >= 0) 00136 break; 00137 00138 LOG(VB_GENERAL, LOG_WARNING, LOC + 00139 QString("Opening DVR device %1 failed : %2") 00140 .arg(_dvr_dev_path).arg(strerror(errno))); 00141 00142 if (tries >= 20 || (errno != EBUSY && errno != EAGAIN)) 00143 { 00144 LOG(VB_GENERAL, LOG_ERR, LOC + 00145 QString("Failed to open DVR device %1 : %2") 00146 .arg(_dvr_dev_path).arg(strerror(errno))); 00147 _error = true; 00148 return; 00149 } 00150 usleep(50000); 00151 } 00152 00153 int remainder = 0; 00154 int buffer_size = TSPacket::kSize * 15000; 00155 unsigned char *buffer = new unsigned char[buffer_size]; 00156 if (!buffer) 00157 { 00158 LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to allocate memory"); 00159 close(dvr_fd); 00160 _error = true; 00161 return; 00162 } 00163 memset(buffer, 0, buffer_size); 00164 00165 DeviceReadBuffer *drb = NULL; 00166 if (_needs_buffering) 00167 { 00168 drb = new DeviceReadBuffer(this, true, false); 00169 if (!drb->Setup(_device, dvr_fd)) 00170 { 00171 LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to allocate DRB buffer"); 00172 delete drb; 00173 delete[] buffer; 00174 close(dvr_fd); 00175 _error = true; 00176 return; 00177 } 00178 00179 drb->Start(); 00180 } 00181 00182 SetRunning(true, _needs_buffering, false); 00183 { 00184 QMutexLocker locker(&_start_stop_lock); 00185 _drb = drb; 00186 } 00187 00188 LOG(VB_RECORD, LOG_INFO, LOC + "RunTS(): begin"); 00189 00190 fd_set fd_select_set; 00191 FD_ZERO( &fd_select_set); 00192 FD_SET (dvr_fd, &fd_select_set); 00193 while (_running_desired && !_error) 00194 { 00195 RetuneMonitor(); 00196 UpdateFiltersFromStreamData(); 00197 00198 ssize_t len = 0; 00199 00200 if (drb) 00201 { 00202 len = drb->Read( 00203 &(buffer[remainder]), buffer_size - remainder); 00204 00205 // Check for DRB errors 00206 if (drb->IsErrored()) 00207 { 00208 LOG(VB_GENERAL, LOG_ERR, LOC + "Device error detected"); 00209 _error = true; 00210 } 00211 00212 if (drb->IsEOF()) 00213 { 00214 LOG(VB_GENERAL, LOG_ERR, LOC + "Device EOF detected"); 00215 _error = true; 00216 } 00217 } 00218 else 00219 { 00220 // timeout gets reset by select, so we need to create new one 00221 struct timeval timeout = { 0, 50 /* ms */ * 1000 /* -> usec */ }; 00222 int ret = select(dvr_fd+1, &fd_select_set, NULL, NULL, &timeout); 00223 if (ret == -1 && errno != EINTR) 00224 { 00225 LOG(VB_GENERAL, LOG_ERR, LOC + "select() failed" + ENO); 00226 } 00227 else 00228 { 00229 len = read(dvr_fd, &(buffer[remainder]), 00230 buffer_size - remainder); 00231 } 00232 } 00233 00234 if ((0 == len) || (-1 == len)) 00235 { 00236 usleep(100); 00237 continue; 00238 } 00239 00240 len += remainder; 00241 00242 if (len < 10) // 10 bytes = 4 bytes TS header + 6 bytes PES header 00243 { 00244 remainder = len; 00245 continue; 00246 } 00247 00248 _listener_lock.lock(); 00249 00250 if (_stream_data_list.empty()) 00251 { 00252 _listener_lock.unlock(); 00253 continue; 00254 } 00255 00256 StreamDataList::const_iterator sit = _stream_data_list.begin(); 00257 for (; sit != _stream_data_list.end(); ++sit) 00258 remainder = sit.key()->ProcessData(buffer, len); 00259 00260 _listener_lock.unlock(); 00261 00262 if (remainder > 0 && (len > remainder)) // leftover bytes 00263 memmove(buffer, &(buffer[len - remainder]), remainder); 00264 } 00265 LOG(VB_RECORD, LOG_INFO, LOC + "RunTS(): " + "shutdown"); 00266 00267 RemoveAllPIDFilters(); 00268 00269 { 00270 QMutexLocker locker(&_start_stop_lock); 00271 _drb = NULL; 00272 } 00273 00274 if (drb) 00275 { 00276 if (drb->IsRunning()) 00277 drb->Stop(); 00278 delete drb; 00279 } 00280 00281 close(dvr_fd); 00282 delete[] buffer; 00283 00284 LOG(VB_RECORD, LOG_INFO, LOC + "RunTS(): " + "end"); 00285 00286 SetRunning(false, _needs_buffering, false); 00287 } 00288 00295 void DVBStreamHandler::RunSR(void) 00296 { 00297 int buffer_size = 4192; // maximum size of Section we handle 00298 unsigned char *buffer = new unsigned char[buffer_size]; 00299 if (!buffer) 00300 { 00301 _error = true; 00302 return; 00303 } 00304 00305 SetRunning(true, _needs_buffering, true); 00306 00307 LOG(VB_RECORD, LOG_INFO, LOC + "RunSR(): begin"); 00308 00309 while (_running_desired && !_error) 00310 { 00311 RetuneMonitor(); 00312 UpdateFiltersFromStreamData(); 00313 00314 QMutexLocker read_locker(&_pid_lock); 00315 00316 bool readSomething = false; 00317 PIDInfoMap::const_iterator fit = _pid_info.begin(); 00318 for (; fit != _pid_info.end(); ++fit) 00319 { 00320 int len = read((*fit)->filter_fd, buffer, buffer_size); 00321 if (len <= 0) 00322 continue; 00323 00324 readSomething = true; 00325 00326 const PESPacket pes = PESPacket::ViewData(buffer); 00327 const PSIPTable psip(pes); 00328 00329 if (psip.SectionSyntaxIndicator()) 00330 { 00331 _listener_lock.lock(); 00332 StreamDataList::const_iterator sit = _stream_data_list.begin(); 00333 for (; sit != _stream_data_list.end(); ++sit) 00334 sit.key()->HandleTables(fit.key() /* pid */, psip); 00335 _listener_lock.unlock(); 00336 } 00337 } 00338 00339 if (!readSomething) 00340 usleep(3000); 00341 } 00342 LOG(VB_RECORD, LOG_INFO, LOC + "RunSR(): " + "shutdown"); 00343 00344 RemoveAllPIDFilters(); 00345 00346 delete[] buffer; 00347 00348 SetRunning(false, _needs_buffering, true); 00349 00350 LOG(VB_RECORD, LOG_INFO, LOC + "RunSR(): " + "end"); 00351 } 00352 00353 typedef vector<uint> pid_list_t; 00354 00355 static pid_list_t::iterator find( 00356 const PIDInfoMap &map, 00357 pid_list_t &list, 00358 pid_list_t::iterator begin, 00359 pid_list_t::iterator end, bool find_open) 00360 { 00361 pid_list_t::iterator it; 00362 for (it = begin; it != end; ++it) 00363 { 00364 PIDInfoMap::const_iterator mit = map.find(*it); 00365 if ((mit != map.end()) && ((*mit)->IsOpen() == find_open)) 00366 return it; 00367 } 00368 00369 for (it = list.begin(); it != begin; ++it) 00370 { 00371 PIDInfoMap::const_iterator mit = map.find(*it); 00372 if ((mit != map.end()) && ((*mit)->IsOpen() == find_open)) 00373 return it; 00374 } 00375 00376 return list.end(); 00377 } 00378 00379 void DVBStreamHandler::CycleFiltersByPriority(void) 00380 { 00381 QMutexLocker writing_locker(&_pid_lock); 00382 QMap<PIDPriority, pid_list_t> priority_queue; 00383 QMap<PIDPriority, uint> priority_open_cnt; 00384 00385 PIDInfoMap::const_iterator cit = _pid_info.begin(); 00386 for (; cit != _pid_info.end(); ++cit) 00387 { 00388 PIDPriority priority = GetPIDPriority((*cit)->_pid); 00389 priority_queue[priority].push_back(cit.key()); 00390 if ((*cit)->IsOpen()) 00391 priority_open_cnt[priority]++; 00392 } 00393 00394 QMap<PIDPriority, pid_list_t>::iterator it = priority_queue.begin(); 00395 for (; it != priority_queue.end(); ++it) 00396 sort((*it).begin(), (*it).end()); 00397 00398 for (PIDPriority i = kPIDPriorityHigh; i > kPIDPriorityNone; 00399 i = (PIDPriority)((int)i-1)) 00400 { 00401 while (priority_open_cnt[i] < priority_queue[i].size()) 00402 { 00403 // if we can open a filter, just do it 00404 00405 // find first closed filter after first open an filter "k" 00406 pid_list_t::iterator open = find( 00407 _pid_info, priority_queue[i], 00408 priority_queue[i].begin(), priority_queue[i].end(), true); 00409 if (open == priority_queue[i].end()) 00410 open = priority_queue[i].begin(); 00411 00412 pid_list_t::iterator closed = find( 00413 _pid_info, priority_queue[i], 00414 open, priority_queue[i].end(), false); 00415 00416 if (closed == priority_queue[i].end()) 00417 break; // something is broken 00418 00419 if (_pid_info[*closed]->Open(_device, _using_section_reader)) 00420 { 00421 _open_pid_filters++; 00422 priority_open_cnt[i]++; 00423 continue; 00424 } 00425 00426 // if we can't open a filter, try to close a lower priority one 00427 bool freed = false; 00428 for (PIDPriority j = (PIDPriority)((int)i - 1); 00429 (j > kPIDPriorityNone) && !freed; 00430 j = (PIDPriority)((int)j-1)) 00431 { 00432 if (!priority_open_cnt[j]) 00433 continue; 00434 00435 for (uint k = 0; (k < priority_queue[j].size()) && !freed; k++) 00436 { 00437 PIDInfo *info = _pid_info[priority_queue[j][k]]; 00438 if (!info->IsOpen()) 00439 continue; 00440 00441 if (info->Close(_device)) 00442 freed = true; 00443 00444 _open_pid_filters--; 00445 priority_open_cnt[j]--; 00446 } 00447 } 00448 00449 if (freed) 00450 { 00451 // if we can open a filter, just do it 00452 if (_pid_info[*closed]->Open( 00453 _device, _using_section_reader)) 00454 { 00455 _open_pid_filters++; 00456 priority_open_cnt[i]++; 00457 continue; 00458 } 00459 } 00460 00461 // we have to cycle within our priority level 00462 00463 if (_cycle_timer.elapsed() < 1000) 00464 break; // we don't want to cycle too often 00465 00466 if (!_pid_info[*open]->IsOpen()) 00467 break; // nothing to close.. 00468 00469 // close "open" 00470 bool ok = _pid_info[*open]->Close(_device); 00471 _open_pid_filters--; 00472 priority_open_cnt[i]--; 00473 00474 // open "closed" 00475 if (ok && _pid_info[*closed]-> 00476 Open(_device, _using_section_reader)) 00477 { 00478 _open_pid_filters++; 00479 priority_open_cnt[i]++; 00480 } 00481 00482 break; // we only want to cycle once per priority per run 00483 } 00484 } 00485 00486 _cycle_timer.start(); 00487 } 00488 00489 void DVBStreamHandler::SetRetuneAllowed( 00490 bool allow, 00491 DTVSignalMonitor *sigmon, 00492 DVBChannel *dvbchan) 00493 { 00494 if (allow && sigmon && dvbchan) 00495 { 00496 _allow_retune = true; 00497 _sigmon = sigmon; 00498 _dvbchannel = dvbchan; 00499 } 00500 else 00501 { 00502 _allow_retune = false; 00503 _sigmon = NULL; 00504 _dvbchannel = NULL; 00505 } 00506 } 00507 00508 void DVBStreamHandler::RetuneMonitor(void) 00509 { 00510 if (!_allow_retune) 00511 return; 00512 00513 // Rotor position 00514 if (_sigmon->HasFlags(SignalMonitor::kDVBSigMon_WaitForPos)) 00515 { 00516 const DiSEqCDevRotor *rotor = _dvbchannel->GetRotor(); 00517 if (rotor) 00518 { 00519 bool was_moving, is_moving; 00520 _sigmon->GetRotorStatus(was_moving, is_moving); 00521 00522 // Retune if move completes normally 00523 if (was_moving && !is_moving) 00524 { 00525 LOG(VB_CHANNEL, LOG_INFO, 00526 LOC + "Retuning for rotor completion"); 00527 _dvbchannel->Retune(); 00528 00529 // (optionally) No need to wait for SDT anymore... 00530 // RemoveFlags(kDTVSigMon_WaitForSDT); 00531 } 00532 } 00533 else 00534 { 00535 // If no rotor is present, pretend the movement is completed 00536 _sigmon->SetRotorValue(100); 00537 } 00538 } 00539 } 00540 00549 bool DVBStreamHandler::SupportsTSMonitoring(void) 00550 { 00551 const uint pat_pid = 0x0; 00552 00553 { 00554 QMutexLocker locker(&_rec_supports_ts_monitoring_lock); 00555 QMap<QString,bool>::const_iterator it; 00556 it = _rec_supports_ts_monitoring.find(_device); 00557 if (it != _rec_supports_ts_monitoring.end()) 00558 return *it; 00559 } 00560 00561 QByteArray dvr_dev_path = _dvr_dev_path.toAscii(); 00562 int dvr_fd = open(dvr_dev_path.constData(), O_RDONLY | O_NONBLOCK); 00563 if (dvr_fd < 0) 00564 { 00565 QMutexLocker locker(&_rec_supports_ts_monitoring_lock); 00566 _rec_supports_ts_monitoring[_device] = false; 00567 return false; 00568 } 00569 00570 bool supports_ts = false; 00571 if (AddPIDFilter(new DVBPIDInfo(pat_pid))) 00572 { 00573 supports_ts = true; 00574 RemovePIDFilter(pat_pid); 00575 } 00576 00577 close(dvr_fd); 00578 00579 QMutexLocker locker(&_rec_supports_ts_monitoring_lock); 00580 _rec_supports_ts_monitoring[_device] = supports_ts; 00581 00582 return supports_ts; 00583 } 00584 00585 #undef LOC 00586 00587 #define LOC QString("PIDInfo(%1): ").arg(dvb_dev) 00588 00589 bool DVBPIDInfo::Open(const QString &dvb_dev, bool use_section_reader) 00590 { 00591 if (filter_fd >= 0) 00592 { 00593 close(filter_fd); 00594 filter_fd = -1; 00595 } 00596 00597 QString demux_fn = CardUtil::GetDeviceName(DVB_DEV_DEMUX, dvb_dev); 00598 QByteArray demux_ba = demux_fn.toAscii(); 00599 00600 LOG(VB_RECORD, LOG_INFO, LOC + QString("Opening filter for pid 0x%1") 00601 .arg(_pid, 0, 16)); 00602 00603 int mux_fd = open(demux_ba.constData(), O_RDWR | O_NONBLOCK); 00604 if (mux_fd == -1) 00605 { 00606 LOG(VB_GENERAL, LOG_ERR, LOC + QString("Failed to open demux device %1 " 00607 "for filter on pid 0x%2") 00608 .arg(demux_fn).arg(_pid, 0, 16)); 00609 return false; 00610 } 00611 00612 if (!use_section_reader) 00613 { 00614 struct dmx_pes_filter_params pesFilterParams; 00615 memset(&pesFilterParams, 0, sizeof(struct dmx_pes_filter_params)); 00616 pesFilterParams.pid = (__u16) _pid; 00617 pesFilterParams.input = DMX_IN_FRONTEND; 00618 pesFilterParams.output = DMX_OUT_TS_TAP; 00619 pesFilterParams.flags = DMX_IMMEDIATE_START; 00620 pesFilterParams.pes_type = DMX_PES_OTHER; 00621 00622 if (ioctl(mux_fd, DMX_SET_PES_FILTER, &pesFilterParams) < 0) 00623 { 00624 LOG(VB_GENERAL, LOG_ERR, LOC + 00625 QString("Failed to set TS filter (pid 0x%1)") 00626 .arg(_pid, 0, 16)); 00627 00628 close(mux_fd); 00629 return false; 00630 } 00631 } 00632 else 00633 { 00634 struct dmx_sct_filter_params sctFilterParams; 00635 memset(&sctFilterParams, 0, sizeof(struct dmx_sct_filter_params)); 00636 switch ( (__u16) _pid ) 00637 { 00638 case 0x0: // PAT 00639 sctFilterParams.filter.filter[0] = 0; 00640 sctFilterParams.filter.mask[0] = 0xff; 00641 break; 00642 case 0x0010: // assume this is for an NIT, NITo, PMT 00643 // This filter will give us table ids 0x00-0x03, 0x40-0x43 00644 // we expect to see table ids 0x02, 0x40 and 0x41 on this PID 00645 // NOTE: In theory, this will break with ATSC when PID 0x10 00646 // is used for ATSC/MPEG tables. This is frowned upon, 00647 // but PMTs have been seen on in the wild. 00648 sctFilterParams.filter.filter[0] = 0x00; 00649 sctFilterParams.filter.mask[0] = 0xbc; 00650 break; 00651 case 0x0011: // assume this is for an SDT, SDTo, PMT 00652 // This filter will give us table ids 0x02, 0x06, 0x42 and 0x46 00653 // All but 0x06 are ones we want to see. 00654 // NOTE: In theory this will break with ATSC when pid 0x11 00655 // is used for random ATSC tables. In practice only 00656 // video data has been seen on 0x11. 00657 sctFilterParams.filter.filter[0] = 0x02; 00658 sctFilterParams.filter.mask[0] = 0xbb; 00659 break; 00660 case 0x1ffb: // assume this is for various ATSC tables 00661 // MGT 0xC7, Terrestrial VCT 0xC8, Cable VCT 0xC9, RRT 0xCA, 00662 // STT 0xCD, DCCT 0xD3, DCCSCT 0xD4, Caption 0x86 00663 sctFilterParams.filter.filter[0] = 0x80; 00664 sctFilterParams.filter.mask[0] = 0xa0; 00665 break; 00666 default: 00667 // otherwise assume it could be any table 00668 sctFilterParams.filter.filter[0] = 0x00; 00669 sctFilterParams.filter.mask[0] = 0x00; 00670 break; 00671 } 00672 sctFilterParams.pid = (__u16) _pid; 00673 sctFilterParams.timeout = 0; 00674 sctFilterParams.flags = DMX_IMMEDIATE_START; 00675 00676 if (ioctl(mux_fd, DMX_SET_FILTER, &sctFilterParams) < 0) 00677 { 00678 LOG(VB_GENERAL, LOG_ERR, LOC + 00679 "Failed to set \"section\" filter " + 00680 QString("(pid 0x%1) (filter %2)").arg(_pid, 0, 16) 00681 .arg(sctFilterParams.filter.filter[0])); 00682 close(mux_fd); 00683 return false; 00684 } 00685 } 00686 00687 filter_fd = mux_fd; 00688 00689 return true; 00690 } 00691 00692 bool DVBPIDInfo::Close(const QString &dvb_dev) 00693 { 00694 LOG(VB_RECORD, LOG_INFO, LOC + 00695 QString("Closing filter for pid 0x%1").arg(_pid, 0, 16)); 00696 00697 if (!IsOpen()) 00698 return false; 00699 00700 int tmp = filter_fd; 00701 filter_fd = -1; 00702 00703 int err = close(tmp); 00704 if (err < 0) 00705 { 00706 LOG(VB_GENERAL, LOG_ERR, 00707 LOC + QString("Failed to close mux (pid 0x%1)") 00708 .arg(_pid, 0, 16) + ENO); 00709 00710 return false; 00711 } 00712 00713 return true; 00714 } 00715 00716 #if 0 00717 00718 // We don't yet do kernel buffer allocation in dvbstreamhandler.. 00719 00720 int DVBRecorder::OpenFilterFd(uint pid, int pes_type, uint stream_type) 00721 { 00722 if (_open_pid_filters >= _max_pid_filters) 00723 return -1; 00724 00725 // bits per millisecond 00726 uint bpms = (StreamID::IsVideo(stream_type)) ? 19200 : 500; 00727 // msec of buffering we want 00728 uint msec_of_buffering = max(POLL_WARNING_TIMEOUT + 50, 1500); 00729 // actual size of buffer we need 00730 uint pid_buffer_size = ((bpms*msec_of_buffering + 7) / 8); 00731 // rounded up to the nearest page 00732 pid_buffer_size = ((pid_buffer_size + 4095) / 4096) * 4096; 00733 00734 LOG(VB_RECORD, LOG_INFO, LOC + QString("Adding pid 0x%1 size(%2)") 00735 .arg(pid,0,16).arg(pid_buffer_size)); 00736 00737 // Open the demux device 00738 QString dvbdev = CardUtil::GetDeviceName( 00739 DVB_DEV_DEMUX, _card_number_option); 00740 QByteArray dev = dvbdev.toAscii(); 00741 00742 int fd_tmp = open(dev.constData(), O_RDWR); 00743 if (fd_tmp < 0) 00744 { 00745 LOG(VB_GENERAL, LOG_ERR, LOC + "Could not open demux device." + ENO); 00746 _max_pid_filters = _open_pid_filters; 00747 return -1; 00748 } 00749 00750 // Try to make the demux buffer large enough to 00751 // allow for longish disk writes. 00752 uint sz = pid_buffer_size; 00753 uint usecs = msec_of_buffering * 1000; 00754 while (ioctl(fd_tmp, DMX_SET_BUFFER_SIZE, sz) < 0 && sz > 1024*8) 00755 { 00756 LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to set demux buffer size for "+ 00757 QString("pid 0x%1 to %2").arg(pid,0,16).arg(sz) + ENO); 00758 00759 sz /= 2; 00760 sz = ((sz+4095)/4096)*4096; 00761 usecs /= 2; 00762 } 00763 #if 0 00764 LOG(VB_RECORD, LOG_DEBUG, LOC + "Set demux buffer size for " + 00765 QString("pid 0x%1 to %2,\n\t\t\twhich gives us a %3 msec buffer.") 00766 .arg(pid,0,16).arg(sz).arg(usecs/1000)); 00767 #endif 00768 00769 // Set the filter type 00770 struct dmx_pes_filter_params params; 00771 memset(¶ms, 0, sizeof(params)); 00772 params.input = DMX_IN_FRONTEND; 00773 params.output = DMX_OUT_TS_TAP; 00774 params.flags = DMX_IMMEDIATE_START; 00775 params.pid = pid; 00776 params.pes_type = (dmx_pes_type_t) pes_type; 00777 if (ioctl(fd_tmp, DMX_SET_PES_FILTER, ¶ms) < 0) 00778 { 00779 close(fd_tmp); 00780 00781 LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to set demux filter." + ENO); 00782 _max_pid_filters = _open_pid_filters; 00783 return -1; 00784 } 00785 00786 _open_pid_filters++; 00787 return fd_tmp; 00788 } 00789 #endif 00790
1.7.6.1