MythTV  0.26-pre
dvbstreamhandler.cpp
Go to the documentation of this file.
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(&params, 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, &params) < 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 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends