Ticket #6138: 133-hdhr.multirec.11.trunk.patch

File 133-hdhr.multirec.11.trunk.patch, 85.4 KB (added by anonymous, 11 years ago)
  • mythtv/libs/libmythhdhomerun/hdhomerun.h

    diff -p -r -u -N -X /tmp/diff.exclude.17976 -x myth.20713.0616a -x myth.20713.0616b myth.20713.0616a/mythtv/libs/libmythhdhomerun/hdhomerun.h myth.20713.0616b/mythtv/libs/libmythhdhomerun/hdhomerun.h
     
     1#ifndef __HDHOMERUN_INCLUDES__
     2#define __HDHOMERUN_INCLUDES__
    13/*
    24 * hdhomerun.h
    35 *
     
    4042#include "hdhomerun_channels.h"
    4143#include "hdhomerun_channelscan.h"
    4244#include "hdhomerun_device.h"
     45
     46#endif /* __HDHOMERUN_INCLUDES__ */
     47
  • mythtv/libs/libmythtv/cardutil.cpp

    diff -p -r -u -N -X /tmp/diff.exclude.17976 -x myth.20713.0616a -x myth.20713.0616b myth.20713.0616a/mythtv/libs/libmythtv/cardutil.cpp myth.20713.0616b/mythtv/libs/libmythtv/cardutil.cpp
    QStringVec CardUtil::ProbeVideoDevices(c 
    214214                devs.push_back(subit->filePath());
    215215        }
    216216    }
     217    else if (rawtype.toUpper() == "HDHOMERUN")
     218    {
     219
     220        uint32_t  target_ip   = 0;
     221        uint32_t  device_type = HDHOMERUN_DEVICE_TYPE_TUNER;
     222        uint32_t  device_id   = HDHOMERUN_DEVICE_ID_WILDCARD;
     223        const int max_count   = 50;
     224        hdhomerun_discover_device_t result_list[max_count];
     225
     226        int result = hdhomerun_discover_find_devices_custom(
     227                            target_ip,
     228                            device_type,
     229                            device_id,
     230                            result_list,
     231                            max_count);
     232
     233        if (result == -1)
     234        {
     235            VERBOSE(VB_IMPORTANT, "CardUtil::ProbeVideoDevices: Error finding HDHomerun devices");
     236            return devs;
     237        }
     238
     239        if (result == 20)
     240            VERBOSE(VB_IMPORTANT, "CardUtil::ProbeVideoDevices: Warning: may be > 20 HDHomerun devices");
     241
     242        // Fixme -- figure out some way to return ip address as well
     243        for (int i = 0; i < result; i++)
     244        {
     245            QString did = QString("%1").arg(result_list[i].device_id,0, 16);
     246            did=did.toUpper();
     247
     248            devs.push_back(did + "-0");
     249            devs.push_back(did + "-1");
     250        }
     251    }
    217252    else
    218253    {
    219254        VERBOSE(VB_IMPORTANT, QString("CardUtil::ProbeVideoDevices: ") +
    bool CardUtil::CreateInputGroupIfNeeded( 
    11501185        uint id = 0;
    11511186        for (uint i = 0; !id && (i < 100); i++)
    11521187        {
    1153             name = QString("DVB%1").arg(dev.toUInt());
     1188            bool ok;
     1189            name = QString("DVB%1").arg(dev.toUInt(&ok));
     1190            if (! ok)
     1191            {
     1192                name = QString("HDHR_%1").arg(dev);
     1193            }
    11541194            name += (i) ? QString(":%1").arg(i) : QString("");
    11551195            id = CardUtil::CreateInputGroup(name);
    11561196        }
    QString CardUtil::GetDeviceLabel(uint ca 
    17531793    }
    17541794    else if (cardtype == "HDHOMERUN")
    17551795    {
    1756         MSqlQuery query(MSqlQuery::InitCon());
    1757         query.prepare(
    1758             "SELECT dbox2_port "
    1759             "FROM capturecard "
    1760             "WHERE cardid = :CARDID");
    1761         query.bindValue(":CARDID", cardid);
    1762 
    1763         if (!query.exec() || !query.isActive() || !query.next())
    1764             label = "[ DB ERROR ]";
    1765         else
    1766             label = QString("[ HDHomeRun : ID %1 Port %2 ]")
    1767                 .arg(videodevice).arg(query.value(0).toString());
     1796        label = QString("[ HDHomeRun : %1 ]").arg(videodevice);
    17681797    }
    17691798    else
    17701799    {
  • mythtv/libs/libmythtv/cardutil.h

    diff -p -r -u -N -X /tmp/diff.exclude.17976 -x myth.20713.0616a -x myth.20713.0616b myth.20713.0616a/mythtv/libs/libmythtv/cardutil.h myth.20713.0616b/mythtv/libs/libmythtv/cardutil.h
    class MPUBLIC CardUtil 
    116116
    117117    static bool         IsTunerSharingCapable(const QString &rawtype)
    118118    {
    119         return (rawtype == "DVB");
     119        return (rawtype == "DVB")   || (rawtype == "HDHOMERUN");
    120120    }
    121121
    122122    static bool         IsTunerShared(uint cardidA, uint cardidB);
  • mythtv/libs/libmythtv/channelscan/channelscanner.cpp

    diff -p -r -u -N -X /tmp/diff.exclude.17976 -x myth.20713.0616a -x myth.20713.0616b myth.20713.0616a/mythtv/libs/libmythtv/channelscan/channelscanner.cpp myth.20713.0616b/mythtv/libs/libmythtv/channelscan/channelscanner.cpp
    void ChannelScanner::PreScanCommon( 
    332332#ifdef USING_HDHOMERUN
    333333    if ("HDHOMERUN" == card_type)
    334334    {
    335         uint tuner = CardUtil::GetHDHRTuner(cardid);
    336         channel = new HDHRChannel(NULL, device, tuner);
     335        channel = new HDHRChannel(NULL, device);
    337336    }
    338337#endif // USING_HDHOMERUN
    339338
  • mythtv/libs/libmythtv/hdhrchannel.cpp

    diff -p -r -u -N -X /tmp/diff.exclude.17976 -x myth.20713.0616a -x myth.20713.0616b myth.20713.0616a/mythtv/libs/libmythtv/hdhrchannel.cpp myth.20713.0616b/mythtv/libs/libmythtv/hdhrchannel.cpp
    using namespace std; 
    2626#include "videosource.h"
    2727#include "channelutil.h"
    2828
     29#include "hdhrstreamhandler.h"
     30
    2931#define DEBUG_PID_FILTERS
    3032
    3133#define LOC     QString("HDHRChan(%1): ").arg(GetDevice())
    3234#define LOC_ERR QString("HDHRChan(%1), Error: ").arg(GetDevice())
    3335
    34 HDHRChannel::HDHRChannel(TVRec *parent, const QString &device, uint tuner)
    35     : DTVChannel(parent),       _control_socket(NULL),
    36       _device_id(0),            _device_ip(0),
    37       _tuner(tuner),            _lock(QMutex::Recursive)
    38 {
    39     bool valid;
    40     _device_id = device.toUInt(&valid, 16);
    41 
    42     if (valid && hdhomerun_discover_validate_device_id(_device_id))
    43         return;
    44 
    45     /* Otherwise, is it a valid IP address? */
    46     struct in_addr address;
    47     if (inet_aton(device.toLatin1().constData(), &address))
    48     {
    49         _device_ip = ntohl(address.s_addr);
    50         return;
    51     }
    52 
    53     /* Invalid, use wildcard device ID. */
    54     VERBOSE(VB_IMPORTANT, LOC_ERR + QString("Invalid DeviceID '%1'")
    55             .arg(device));
    56 
    57     _device_id = HDHOMERUN_DEVICE_ID_WILDCARD;
     36HDHRChannel::HDHRChannel(TVRec *parent, const QString &device)
     37    : DTVChannel(parent),       _stream_handler(NULL),
     38      _device_id(device),       _lock(QMutex::Recursive),
     39      tune_lock(QMutex::Recursive),
     40      hw_lock(QMutex::Recursive)
     41{
    5842}
    5943
    6044HDHRChannel::~HDHRChannel(void)
    HDHRChannel::~HDHRChannel(void) 
    6448
    6549bool HDHRChannel::Open(void)
    6650{
     51    VERBOSE(VB_CHANNEL, LOC + "Opening HDHR channel");
     52
     53    QMutexLocker locker(&hw_lock);
     54   
    6755    if (IsOpen())
    6856        return true;
    6957
    70     if (!FindDevice())
    71         return false;
     58    _stream_handler = HDHRStreamHandler::Get(_device_id);
    7259
    7360    if (!InitializeInputs())
    74         return false;
    75 
    76     return (_device_ip != 0) && Connect();
    77 }
    78 
    79 void HDHRChannel::Close(void)
    80 {
    81     if (_control_socket)
    8261    {
    83         hdhomerun_control_destroy(_control_socket);
    84         _control_socket = NULL;
    85     }
    86 }
    87 
    88 bool HDHRChannel::EnterPowerSavingMode(void)
    89 {
    90     return QString::null != TunerSet("channel", "none", false);
    91 }
    92 
    93 bool HDHRChannel::FindDevice(void)
    94 {
    95     if (!_device_id)
    96         return _device_ip;
    97 
    98     _device_ip = 0;
    99 
    100     /* Discover. */
    101     struct hdhomerun_discover_device_t result;
    102     int ret = hdhomerun_discover_find_devices_custom(
    103                   0, HDHOMERUN_DEVICE_TYPE_WILDCARD, _device_id, &result, 1);
    104     if (ret < 0)
    105     {
    106         VERBOSE(VB_IMPORTANT,
    107                 LOC_ERR + "Unable to send discovery request" + ENO);
    108         return false;
    109     }
    110     if (ret == 0)
    111     {
    112         VERBOSE(VB_IMPORTANT, LOC_ERR + QString("device not found"));
     62        Close();
    11363        return false;
    11464    }
    11565
    116     /* Found. */
    117     _device_ip = result.ip_addr;
    118 
    119     VERBOSE(VB_IMPORTANT, LOC +
    120             QString("device found at address %1.%2.%3.%4")
    121             .arg((_device_ip>>24) & 0xFF).arg((_device_ip>>16) & 0xFF)
    122             .arg((_device_ip>> 8) & 0xFF).arg((_device_ip>> 0) & 0xFF));
    123 
    124     return true;
     66    return _stream_handler->Connected();
    12567}
    12668
    127 bool HDHRChannel::Connect(void)
     69void HDHRChannel::Close(void)
    12870{
    129     _control_socket = hdhomerun_control_create(_device_id, _device_ip);
    130     if (!_control_socket)
    131     {
    132         VERBOSE(VB_IMPORTANT, LOC_ERR + "Unable to create control socket");
    133         return false;
    134     }
     71    VERBOSE(VB_CHANNEL, LOC + "Closing HDHR channel");
    13572
    136     if (hdhomerun_control_get_local_addr(_control_socket) == 0)
    137     {
    138         VERBOSE(VB_IMPORTANT, LOC_ERR + "Unable to connect to device");
    139         return false;
    140     }
     73        if (! IsOpen())
     74        return; // this caller didn't have it open in the first place..
    14175
    142     VERBOSE(VB_CHANNEL, LOC + "Successfully connected to device");
    143     return true;
     76    HDHRStreamHandler::Return(_stream_handler);
    14477}
    14578
    146 QString HDHRChannel::DeviceGet(const QString &name, bool report_error_return)
     79bool HDHRChannel::EnterPowerSavingMode(void)
    14780{
    148     QMutexLocker locker(&_lock);
    149 
    150     if (!_control_socket)
    151     {
    152         VERBOSE(VB_IMPORTANT, LOC_ERR + "Get request failed (not connected)");
    153         return QString::null;
    154     }
    155 
    156     char *value = NULL;
    157     char *error = NULL;
    158     if (hdhomerun_control_get(_control_socket, name.toLatin1().constData(),
    159                               &value, &error) < 0)
    160     {
    161         VERBOSE(VB_IMPORTANT, LOC_ERR + "Get request failed" + ENO);
    162         return QString::null;
    163     }
    164 
    165     if (report_error_return && error)
    166     {
    167         VERBOSE(VB_IMPORTANT, LOC_ERR +
    168                 QString("DeviceGet(%1): %2").arg(name).arg(error));
    169 
    170         return QString::null;
    171     }
    172 
    173     return QString(value);
     81    if ( IsOpen())
     82        return _stream_handler->EnterPowerSavingMode();
     83    else
     84        return true;
    17485}
    17586
    176 QString HDHRChannel::DeviceSet(const QString &name, const QString &val,
    177                                bool report_error_return)
     87bool HDHRChannel::IsOpen(void) const
    17888{
    179     QMutexLocker locker(&_lock);
    180 
    181     if (!_control_socket)
    182     {
    183         VERBOSE(VB_IMPORTANT, LOC_ERR + "Set request failed (not connected)");
    184         return QString::null;
    185     }
    186 
    187     char *value = NULL;
    188     char *error = NULL;
    189     if (hdhomerun_control_set(_control_socket, name.toLatin1().constData(),
    190                               val.toAscii().constData(), &value, &error) < 0)
    191     {
    192         VERBOSE(VB_IMPORTANT, LOC_ERR + "Set request failed" + ENO);
    193 
    194         return QString::null;
    195     }
    196 
    197     if (report_error_return && error)
    198     {
    199         VERBOSE(VB_IMPORTANT, LOC_ERR +
    200                 QString("DeviceSet(%1 %2): %3").arg(name).arg(val).arg(error));
    201 
    202         return QString::null;
    203     }
    204 
    205     return QString(value);
     89      return (_stream_handler != NULL);
    20690}
    20791
    208 QString HDHRChannel::TunerGet(const QString &name, bool report_error_return)
     92bool HDHRChannel::Init(QString &inputname, QString &startchannel, bool setchan)
    20993{
    210     return DeviceGet(QString("/tuner%1/%2").arg(_tuner).arg(name),
    211                      report_error_return);
    212 }
     94    if (setchan && !IsOpen())
     95        Open();
    21396
    214 QString HDHRChannel::TunerSet(const QString &name, const QString &value,
    215                               bool report_error_return)
    216 {
    217     return DeviceSet(QString("/tuner%1/%2").arg(_tuner).arg(name), value,
    218                      report_error_return);
    219 }
    220 
    221 bool HDHRChannel::DeviceSetTarget(unsigned short localPort)
    222 {
    223     if (localPort == 0)
    224     {
    225         return false;
    226     }
    227 
    228     unsigned long localIP = hdhomerun_control_get_local_addr(_control_socket);
    229     if (localIP == 0)
    230     {
    231         return false;
    232     }
    233 
    234     QString configValue = QString("%1.%2.%3.%4:%5")
    235         .arg((localIP >> 24) & 0xFF).arg((localIP >> 16) & 0xFF)
    236         .arg((localIP >>  8) & 0xFF).arg((localIP >>  0) & 0xFF)
    237         .arg(localPort);
    238 
    239     if (TunerSet("target", configValue).isEmpty())
    240     {
    241         return false;
    242     }
    243 
    244     return true;
    245 }
    246 
    247 bool HDHRChannel::DeviceClearTarget()
    248 {
    249     return !TunerSet("target", "0.0.0.0:0").isEmpty();
     97    return ChannelBase::Init(inputname, startchannel, setchan);
    25098}
    25199
    252100bool HDHRChannel::SetChannelByString(const QString &channum)
    bool HDHRChannel::SetChannelByString(con 
    280128        return SwitchToInput(inputName, channum);
    281129
    282130    ClearDTVInfo();
    283     _ignore_filters = false;
    284131
    285132    InputMap::const_iterator it = inputs.find(currentInputID);
    286133    if (it == inputs.end())
    bool HDHRChannel::SetChannelByString(con 
    354201    if (mpeg_prog_num && (GetTuningMode() == "mpeg"))
    355202    {
    356203        QString pnum = QString::number(mpeg_prog_num);
    357         _ignore_filters = QString::null != TunerSet("program", pnum, false);
     204        //_ignore_filters = _stream_handler->TuneProgram(pnum);
     205        _stream_handler->TuneProgram(pnum);
    358206    }
    359207
    360208    return true;
    bool HDHRChannel::Tune(uint frequency, Q 
    409257
    410258    QString chan = modulation + ':' + QString::number(frequency);
    411259
    412     VERBOSE(VB_CHANNEL, LOC + "Tune()ing to " + chan);
     260    VERBOSE(VB_CHANNEL, LOC + "Tuning to " + chan);
    413261
    414     if (TunerSet("channel", chan).length())
     262    if (_stream_handler->TuneChannel(chan))
    415263    {
    416264        SetSIStandard(si_std);
    417265        return true;
    bool HDHRChannel::Tune(uint frequency, Q 
    419267
    420268    return false;
    421269}
    422 
    423 bool HDHRChannel::AddPID(uint pid, bool do_update)
    424 {
    425     QMutexLocker locker(&_lock);
    426 
    427     vector<uint>::iterator it;
    428     it = lower_bound(_pids.begin(), _pids.end(), pid);
    429     if (it != _pids.end() && *it == pid)
    430     {
    431 #ifdef DEBUG_PID_FILTERS
    432         VERBOSE(VB_CHANNEL, "AddPID(0x"<<hex<<pid<<dec<<") NOOP");
    433 #endif // DEBUG_PID_FILTERS
    434         return true;
    435     }
    436 
    437     _pids.insert(it, pid);
    438 
    439 #ifdef DEBUG_PID_FILTERS
    440     VERBOSE(VB_CHANNEL, "AddPID(0x"<<hex<<pid<<dec<<")");
    441 #endif // DEBUG_PID_FILTERS
    442 
    443     if (do_update)
    444         return UpdateFilters();
    445     return true;
    446 }
    447 
    448 bool HDHRChannel::DelPID(uint pid, bool do_update)
    449 {
    450     QMutexLocker locker(&_lock);
    451 
    452     vector<uint>::iterator it;
    453     it = lower_bound(_pids.begin(), _pids.end(), pid);
    454     if (it == _pids.end())
    455     {
    456 #ifdef DEBUG_PID_FILTERS
    457         VERBOSE(VB_CHANNEL, "DelPID(0x"<<hex<<pid<<dec<<") NOOP");
    458 #endif // DEBUG_PID_FILTERS
    459 
    460        return true;
    461     }
    462 
    463     if (*it == pid)
    464     {
    465 #ifdef DEBUG_PID_FILTERS
    466         VERBOSE(VB_CHANNEL, "DelPID(0x"<<hex<<pid<<dec<<") -- found");
    467 #endif // DEBUG_PID_FILTERS
    468         _pids.erase(it);
    469     }
    470     else
    471     {
    472 #ifdef DEBUG_PID_FILTERS
    473         VERBOSE(VB_CHANNEL, "DelPID(0x"<<hex<<pid<<dec<<") -- failed");
    474 #endif // DEBUG_PID_FILTERS
    475     }
    476 
    477     if (do_update)
    478         return UpdateFilters();
    479     return true;
    480 }
    481 
    482 bool HDHRChannel::DelAllPIDs(void)
    483 {
    484     QMutexLocker locker(&_lock);
    485 
    486 #ifdef DEBUG_PID_FILTERS
    487     VERBOSE(VB_CHANNEL, "DelAllPID()");
    488 #endif // DEBUG_PID_FILTERS
    489 
    490     _pids.clear();
    491 
    492     return UpdateFilters();
    493 }
    494 
    495 QString filt_str(uint pid)
    496 {
    497     uint pid0 = (pid / (16*16*16)) % 16;
    498     uint pid1 = (pid / (16*16))    % 16;
    499     uint pid2 = (pid / (16))        % 16;
    500     uint pid3 = pid % 16;
    501     return QString("0x%1%2%3%4")
    502         .arg(pid0,0,16).arg(pid1,0,16)
    503         .arg(pid2,0,16).arg(pid3,0,16);
    504 }
    505 
    506 bool HDHRChannel::UpdateFilters(void)
    507 {
    508     QMutexLocker locker(&_lock);
    509 
    510     QString filter = "";
    511 
    512     vector<uint> range_min;
    513     vector<uint> range_max;
    514 
    515     if (_ignore_filters)
    516         return true;
    517 
    518     for (uint i = 0; i < _pids.size(); i++)
    519     {
    520         uint pid_min = _pids[i];
    521         uint pid_max  = pid_min;
    522         for (uint j = i + 1; j < _pids.size(); j++)
    523         {
    524             if (pid_max + 1 != _pids[j])
    525                 break;
    526             pid_max++;
    527             i++;
    528         }
    529         range_min.push_back(pid_min);
    530         range_max.push_back(pid_max);
    531     }
    532 
    533     if (range_min.size() > 16)
    534     {
    535         range_min.resize(16);
    536         uint pid_max = range_max.back();
    537         range_max.resize(15);
    538         range_max.push_back(pid_max);
    539     }
    540 
    541     for (uint i = 0; i < range_min.size(); i++)
    542     {
    543         filter += filt_str(range_min[i]);
    544         if (range_min[i] != range_max[i])
    545             filter += QString("-%1").arg(filt_str(range_max[i]));
    546         filter += " ";
    547     }
    548 
    549     filter = filter.trimmed();
    550 
    551     QString new_filter = TunerSet("filter", filter);
    552 
    553 #ifdef DEBUG_PID_FILTERS
    554     QString msg = QString("Filter: '%1'").arg(filter);
    555     if (filter != new_filter)
    556         msg += QString("\n\t\t\t\t'%2'").arg(new_filter);
    557 
    558     VERBOSE(VB_CHANNEL, msg);
    559 #endif // DEBUG_PID_FILTERS
    560 
    561     return filter == new_filter;
    562 }
  • mythtv/libs/libmythtv/hdhrchannel.h

    diff -p -r -u -N -X /tmp/diff.exclude.17976 -x myth.20713.0616a -x myth.20713.0616b myth.20713.0616a/mythtv/libs/libmythtv/hdhrchannel.h myth.20713.0616b/mythtv/libs/libmythtv/hdhrchannel.h
     
    1616// HDHomeRun headers
    1717#ifdef USING_HDHOMERUN
    1818#include "hdhomerun.h"
    19 #else
    20 struct hdhomerun_control_sock_t { int dummy; };
    2119#endif
    2220
    23 typedef struct hdhomerun_control_sock_t hdhr_socket_t;
     21class HDHRChannel;
     22class HDHRStreamHandler;
     23class ProgramMapTable;
    2424
    2525class HDHRChannel : public DTVChannel
    2626{
    class HDHRChannel : public DTVChannel 
    2828    friend class HDHRRecorder;
    2929
    3030  public:
    31     HDHRChannel(TVRec *parent, const QString &device, uint tuner);
     31    HDHRChannel(TVRec *parent, const QString &device);
    3232    ~HDHRChannel(void);
    3333
    3434    bool Open(void);
    3535    void Close(void);
    3636    bool EnterPowerSavingMode(void);
    3737
     38    bool Init(QString &inputname, QString &startchannel, bool setchan);
     39
    3840    // Sets
     41    void SetPMT(const ProgramMapTable*) {};
    3942    bool SetChannelByString(const QString &chan);
    4043
    4144    // Gets
    42     bool IsOpen(void) const { return (_control_socket != NULL); }
    43     QString GetDevice(void) const
    44         { return QString("%1/%2").arg(_device_id, 8, 16).arg(_tuner); }
     45    bool IsOpen(void) const;
     46    QString GetDevice(void) const { return _device_id; }
    4547    vector<uint> GetPIDs(void) const
    4648        { QMutexLocker locker(&_lock); return _pids; }
    4749    QString GetSIStandard(void) const { return "atsc"; }
    4850
    49     // Commands
    50     bool AddPID(uint pid, bool do_update = true);
    51     bool DelPID(uint pid, bool do_update = true);
    52     bool DelAllPIDs(void);
    53     bool UpdateFilters(void);
    54 
    5551    // ATSC/DVB scanning/tuning stuff
    5652    bool TuneMultiplex(uint mplexid, QString inputname);
    5753    bool Tune(const DTVMultiplex &tuning, QString inputname);
    5854
    5955  private:
    60     bool FindDevice(void);
    61     bool Connect(void);
    6256    bool Tune(uint frequency, QString inputname,
    6357              QString modulation, QString si_std);
    6458
    65     bool DeviceSetTarget(unsigned short localPort);
    66     bool DeviceClearTarget(void);
     59  private:
     60    HDHRStreamHandler *_stream_handler;
    6761
    68     QString DeviceGet(const QString &name, bool report_error_return = true);
    69     QString DeviceSet(const QString &name, const QString &value,
    70                       bool report_error_return = true);
    71 
    72     QString TunerGet(const QString &name, bool report_error_return = true);
    73     QString TunerSet(const QString &name, const QString &value,
    74                      bool report_error_return = true);
     62    QString         _device_id;
    7563
    76   private:
    77     hdhr_socket_t  *_control_socket;
    78     uint            _device_id;
    79     uint            _device_ip;
    80     uint            _tuner;
    81     bool            _ignore_filters;
    8264    vector<uint>    _pids;
    8365    mutable QMutex  _lock;
     66    mutable QMutex  tune_lock;
     67    mutable QMutex  hw_lock;
    8468};
    8569
    8670#endif
  • mythtv/libs/libmythtv/hdhrrecorder.cpp

    diff -p -r -u -N -X /tmp/diff.exclude.17976 -x myth.20713.0616a -x myth.20713.0616b myth.20713.0616a/mythtv/libs/libmythtv/hdhrrecorder.cpp myth.20713.0616b/mythtv/libs/libmythtv/hdhrrecorder.cpp
    using namespace std; 
    2323
    2424// MythTV includes
    2525#include "RingBuffer.h"
    26 #include "hdhrchannel.h"
    27 #include "hdhrrecorder.h"
    2826#include "atsctables.h"
    2927#include "atscstreamdata.h"
    3028#include "dvbstreamdata.h"
    3129#include "eithelper.h"
    3230#include "tv_rec.h"
    3331
     32// MythTV HDHR includes
     33#include "hdhrchannel.h"
     34#include "hdhrrecorder.h"
     35#include "hdhrstreamhandler.h"
     36
    3437#define LOC QString("HDHRRec(%1): ").arg(tvrec->GetCaptureCardNum())
     38#define LOC_WARN QString("HDHRRec(%1), Warning: ") \
     39                    .arg(tvrec->GetCaptureCardNum())
    3540#define LOC_ERR QString("HDHRRec(%1), Error: ") \
    3641                    .arg(tvrec->GetCaptureCardNum())
    3742
    3843HDHRRecorder::HDHRRecorder(TVRec *rec, HDHRChannel *channel)
    3944    : DTVRecorder(rec),
    40       _channel(channel),        _video_socket(NULL),
     45      _channel(channel),
     46      _stream_handler(NULL),
    4147      _stream_data(NULL),
    42       _input_pat(NULL),         _input_pmt(NULL),
    43       _reset_pid_filters(false),_pid_lock(QMutex::Recursive)
     48      _pid_lock(QMutex::Recursive),
     49      _input_pat(NULL),
     50      _input_pmt(NULL),
     51      _has_no_av(false)
    4452{
    4553}
    4654
    void HDHRRecorder::SetOptionsFromProfile 
    9199    // HACK -- end
    92100}
    93101
     102bool HDHRRecorder::IsOpen(void) {
     103    return (_stream_handler != NULL);
     104}
     105
    94106bool HDHRRecorder::Open(void)
    95107{
    96108    VERBOSE(VB_RECORD, LOC + "Open()");
    97     if (_video_socket)
     109    if (IsOpen())
    98110    {
    99111        VERBOSE(VB_RECORD, LOC + "Card already open (recorder)");
    100112        return true;
    101113    }
    102114
    103     /* Calculate buffer size */
    104     uint buffersize = gContext->GetNumSetting(
    105         "HDRingbufferSize", 50 * TSPacket::SIZE) * 1024;
    106     buffersize /= VIDEO_DATA_PACKET_SIZE;
    107     buffersize *= VIDEO_DATA_PACKET_SIZE;
     115    bzero(_stream_id,  sizeof(_stream_id));
     116    bzero(_pid_status, sizeof(_pid_status));
     117    memset(_continuity_counter, 0xff, sizeof(_continuity_counter));
    108118
    109     // Buffer should be at least about 1MB..
    110     buffersize = max(49 * TSPacket::SIZE * 128, buffersize);
     119    _stream_handler = HDHRStreamHandler::Get(_channel->GetDevice());
    111120
    112     /* Create TS socket. */
    113     _video_socket = hdhomerun_video_create(0, buffersize);
    114     if (!_video_socket)
    115     {
    116         VERBOSE(VB_IMPORTANT, LOC + "Open() failed to open socket");
    117         return false;
    118     }
     121    VERBOSE(VB_RECORD, LOC + "HDHR opened successfully");
    119122
    120     /* Success. */
    121123    return true;
    122124}
    123125
    124 /** \fn HDHRRecorder::StartData(void)
    125  *  \brief Configure device to send video.
    126  */
    127 bool HDHRRecorder::StartData(void)
    128 {
    129     VERBOSE(VB_RECORD, LOC + "StartData()");
    130     uint localPort = hdhomerun_video_get_local_port(_video_socket);
    131     return _channel->DeviceSetTarget(localPort);
    132 }
    133 
    134126void HDHRRecorder::Close(void)
    135127{
    136     VERBOSE(VB_RECORD, LOC + "Close()");
    137     if (_video_socket)
    138     {
    139         hdhomerun_video_destroy(_video_socket);
    140         _video_socket = NULL;
    141     }
    142 }
    143 
    144 void HDHRRecorder::ProcessTSData(const uint8_t *buffer, int len)
    145 {
    146     QMutexLocker locker(&_pid_lock);
    147     const uint8_t *data = buffer;
    148     const uint8_t *end = buffer + len;
     128    VERBOSE(VB_RECORD, LOC + "Close() - Begin");
    149129
    150     while (data + 188 <= end)
     130    if (IsOpen())
    151131    {
    152         if (data[0] != 0x47)
    153         {
    154             return;
    155         }
    156 
    157         const TSPacket *tspacket = reinterpret_cast<const TSPacket*>(data);
    158         ProcessTSPacket(*tspacket);
    159 
    160         data += 188;
     132        HDHRStreamHandler::Return(_stream_handler);
    161133    }
     134
     135    VERBOSE(VB_RECORD, LOC + "Close() - End");
    162136}
    163137
    164138void HDHRRecorder::SetStreamData(MPEGStreamData *data)
    void HDHRRecorder::HandlePAT(const Progr 
    220194    ProgramAssociationTable *oldpat = _input_pat;
    221195    _input_pat = new ProgramAssociationTable(*_pat);
    222196    delete oldpat;
    223 
    224     _reset_pid_filters = true;
    225197}
    226198
    227199void HDHRRecorder::HandlePMT(uint progNum, const ProgramMapTable *_pmt)
    void HDHRRecorder::HandlePMT(uint progNu 
    233205        VERBOSE(VB_RECORD, LOC + "SetPMT("<<progNum<<")");
    234206        ProgramMapTable *oldpmt = _input_pmt;
    235207        _input_pmt = new ProgramMapTable(*_pmt);
    236         delete oldpmt;
    237208
    238         _reset_pid_filters = true;
     209        QString sistandard = _channel->GetSIStandard();
     210
     211        bool has_no_av = true;
     212        for (uint i = 0; i < _input_pmt->StreamCount() && has_no_av; i++)
     213        {
     214            has_no_av &= !_input_pmt->IsVideo(i, sistandard);
     215            has_no_av &= !_input_pmt->IsAudio(i, sistandard);
     216        }
     217        _has_no_av = has_no_av;
     218
     219        _channel->SetPMT(_input_pmt);
     220        delete oldpmt;
    239221    }
    240222}
    241223
    void HDHRRecorder::HandleSingleProgramPA 
    246228
    247229    int next = (pat->tsheader()->ContinuityCounter()+1)&0xf;
    248230    pat->tsheader()->SetContinuityCounter(next);
    249     BufferedWrite(*(reinterpret_cast<TSPacket*>(pat->tsheader())));
     231    DTVRecorder::BufferedWrite(*(reinterpret_cast<TSPacket*>(pat->tsheader())));
    250232}
    251233
    252234void HDHRRecorder::HandleSingleProgramPMT(ProgramMapTable *pmt)
    253235{
    254236    if (!pmt)
     237    {
     238        VERBOSE(VB_RECORD, LOC + "HandleSingleProgramPMT(NULL)");
     239        return;
     240    }
     241
     242    // collect stream types for H.264 (MPEG-4 AVC) keyframe detection
     243    for (uint i = 0; i < pmt->StreamCount(); i++)
     244        _stream_id[pmt->StreamPID(i)] = pmt->StreamType(i);
     245
     246    if (!ringBuffer)
    255247        return;
    256248
    257249    unsigned char buf[8 * 1024];
    void HDHRRecorder::HandleSingleProgramPM 
    259251    pmt->tsheader()->SetContinuityCounter(next_cc);
    260252    uint size = pmt->WriteAsTSPackets(buf, next_cc);
    261253
     254    uint posA[2] = { ringBuffer->GetWritePosition(), _payload_buffer.size() };
     255
    262256    for (uint i = 0; i < size ; i += TSPacket::SIZE)
    263257        DTVRecorder::BufferedWrite(*(reinterpret_cast<TSPacket*>(&buf[i])));
     258
     259    uint posB[2] = { ringBuffer->GetWritePosition(), _payload_buffer.size() };
     260
     261    if (posB[0] + posB[1] * TSPacket::SIZE >
     262        posA[0] + posA[1] * TSPacket::SIZE)
     263    {
     264        VERBOSE(VB_RECORD, LOC + "Wrote PMT @"
     265                << posA[0] << " + " << (posA[1] * TSPacket::SIZE));
     266    }
     267    else
     268    {
     269        VERBOSE(VB_RECORD, LOC + "Saw PMT but did not write to disk yet");
     270    }
    264271}
    265272
    266273/** \fn HDHRRecorder::HandleMGT(const MasterGuideTable*)
    void HDHRRecorder::HandleMGT(const Maste 
    280287}
    281288*/
    282289
     290bool HDHRRecorder::ProcessVideoTSPacket(const TSPacket &tspacket)
     291{
     292    uint streamType = _stream_id[tspacket.PID()];
     293
     294    // Check for keyframes and count frames
     295    if (streamType == StreamID::H264Video)
     296    {
     297        _buffer_packets = !FindH264Keyframes(&tspacket);
     298        if (!_seen_sps)
     299            return true;
     300    }
     301    else
     302    {
     303        _buffer_packets = !FindMPEG2Keyframes(&tspacket);
     304    }
     305
     306    return ProcessAVTSPacket(tspacket);
     307}
     308
     309bool HDHRRecorder::ProcessAudioTSPacket(const TSPacket &tspacket)
     310{
     311    _buffer_packets = !FindAudioKeyframes(&tspacket);
     312    return ProcessAVTSPacket(tspacket);
     313}
     314
     315/// Common code for processing either audio or video packets
     316bool HDHRRecorder::ProcessAVTSPacket(const TSPacket &tspacket)
     317{
     318    const uint pid = tspacket.PID();
     319    // Sync recording start to first keyframe
     320    if (_wait_for_keyframe_option && _first_keyframe < 0)
     321        return true;
     322
     323    // Sync streams to the first Payload Unit Start Indicator
     324    // _after_ first keyframe iff _wait_for_keyframe_option is true
     325    if (!(_pid_status[pid] & kPayloadStartSeen) && tspacket.HasPayload())
     326    {
     327        if (!tspacket.PayloadStart())
     328            return true; // not payload start - drop packet
     329
     330        VERBOSE(VB_RECORD,
     331                QString("PID 0x%1 Found Payload Start").arg(pid,0,16));
     332
     333        _pid_status[pid] |= kPayloadStartSeen;
     334    }
     335
     336    BufferedWrite(tspacket);
     337
     338    return true;
     339}
     340
    283341bool HDHRRecorder::ProcessTSPacket(const TSPacket& tspacket)
    284342{
    285     bool ok = !tspacket.TransportError();
    286     if (ok && !tspacket.ScramplingControl())
     343    // Only create fake keyframe[s] if there are no audio/video streams
     344    if (_input_pmt && _has_no_av)
    287345    {
    288         if (tspacket.HasAdaptationField())
    289             GetStreamData()->HandleAdaptationFieldControl(&tspacket);
    290         if (tspacket.HasPayload())
    291         {
    292             const unsigned int lpid = tspacket.PID();
     346        _buffer_packets = !FindOtherKeyframes(&tspacket);
     347    }
     348    else
     349    {
     350        // There are audio/video streams. Only write the packet
     351        // if audio/video key-frames have been found
     352        if (_wait_for_keyframe_option && _first_keyframe < 0)
     353            return true;
    293354
    294             if ((GetStreamData()->VideoPIDSingleProgram() > 0x1fff) &&
    295                 _wait_for_keyframe_option)
    296             {
    297                 _wait_for_keyframe_option = false;
    298             }
    299 
    300             // Pass or reject frames based on PID, and parse info from them
    301             if (lpid == GetStreamData()->VideoPIDSingleProgram())
    302             {
    303                 //cerr<<"v";
    304                 _buffer_packets = !FindMPEG2Keyframes(&tspacket);
    305                 BufferedWrite(tspacket);
    306             }
    307             else if (GetStreamData()->IsAudioPID(lpid))
    308             {
    309                 //cerr<<"a";
    310                 _buffer_packets = !FindAudioKeyframes(&tspacket);
    311                 BufferedWrite(tspacket);
    312             }
    313             else if (GetStreamData()->IsListeningPID(lpid))
    314             {
    315                 //cerr<<"t";
    316                 GetStreamData()->HandleTSTables(&tspacket);
    317             }
    318             else if (GetStreamData()->IsWritingPID(lpid))
    319                 BufferedWrite(tspacket);
    320         }
     355        _buffer_packets = true;
    321356    }
    322     return ok;
     357
     358    BufferedWrite(tspacket);
    323359}
    324360
    325361void HDHRRecorder::StartRecording(void)
    void HDHRRecorder::StartRecording(void) 
    337373    _request_recording = true;
    338374    _recording = true;
    339375
    340     if (!StartData())
    341     {
    342         VERBOSE(VB_IMPORTANT, LOC_ERR + "Starting recording "
    343                 "(set target failed). Aborting.");
    344         Close();
    345         _error = true;
    346         VERBOSE(VB_RECORD, LOC + "StartRecording -- end 2");
    347         return;
    348     }
    349 
    350     hdhomerun_video_flush(_video_socket);
     376    // Make sure the first things in the file are a PAT & PMT
     377    bool tmp = _wait_for_keyframe_option;
     378    _wait_for_keyframe_option = false;
     379    HandleSingleProgramPAT(_stream_data->PATSingleProgram());
     380    HandleSingleProgramPMT(_stream_data->PMTSingleProgram());
     381    _wait_for_keyframe_option = tmp;
     382
     383    _stream_data->AddAVListener(this);
     384    _stream_data->AddWritingListener(this);
     385    _stream_handler->AddListener(_stream_data);
     386   
    351387    while (_request_recording && !_error)
    352388    {
     389        usleep(50000);
     390
    353391        if (PauseAndWait())
    354392            continue;
    355393
    356         if (_stream_data)
     394        if (!_input_pmt)
    357395        {
    358             QMutexLocker read_lock(&_pid_lock);
    359             _reset_pid_filters |= _stream_data->HasEITPIDChanges(_eit_pids);
     396            VERBOSE(VB_GENERAL, LOC_WARN +
     397                    "Recording will not commence until a PMT is set.");
     398            usleep(5000);
     399            continue;
    360400        }
    361401
    362         if (_reset_pid_filters)
     402        if (!_stream_handler->IsRunning())
    363403        {
    364             _reset_pid_filters = false;
    365             VERBOSE(VB_RECORD, LOC + "Resetting Demux Filters");
    366             AdjustFilters();
    367         }
     404            _error = true;
    368405
    369         size_t read_size = 64 * 1024; // read about 64KB
    370         read_size /= VIDEO_DATA_PACKET_SIZE;
    371         read_size *= VIDEO_DATA_PACKET_SIZE;
    372 
    373         size_t data_length;
    374         unsigned char *data_buffer =
    375             hdhomerun_video_recv(_video_socket, read_size, &data_length);
    376         if (!data_buffer)
    377         {
    378             usleep(5000);
    379             continue;
    380         }
    381 
    382         ProcessTSData(data_buffer, data_length);
     406            VERBOSE(VB_IMPORTANT, LOC_ERR +
     407                    "Stream handler died unexpectedly.");
     408        }
    383409    }
    384410
    385411    VERBOSE(VB_RECORD, LOC + "StartRecording -- ending...");
    386412
    387     _channel->DeviceClearTarget();
     413    _stream_handler->RemoveListener(_stream_data);
     414    _stream_data->RemoveWritingListener(this);
     415    _stream_data->RemoveAVListener(this);
     416
    388417    Close();
    389418
    390419    FinishRecording();
    void HDHRRecorder::StartRecording(void) 
    393422    VERBOSE(VB_RECORD, LOC + "StartRecording -- end");
    394423}
    395424
    396 bool HDHRRecorder::AdjustFilters(void)
     425void HDHRRecorder::ResetForNewFile(void)
    397426{
    398     QMutexLocker change_lock(&_pid_lock);
     427    DTVRecorder::ResetForNewFile();
    399428
    400     if (!_channel)
    401     {
    402         VERBOSE(VB_IMPORTANT, LOC_ERR + "AdjustFilters() no channel");
    403         return false;
    404     }
     429    bzero(_stream_id,  sizeof(_stream_id));
     430    bzero(_pid_status, sizeof(_pid_status));
     431    memset(_continuity_counter, 0xff, sizeof(_continuity_counter));
    405432
    406     if (!_input_pat || !_input_pmt)
    407     {
    408         VERBOSE(VB_IMPORTANT, LOC + "AdjustFilters() no pmt or no pat");
    409         return false;
    410     }
    411 
    412     uint_vec_t add_pid;
     433    // FIXME
     434    // Close and re-open ???
     435    //Close();
     436    //Open();
     437}
    413438
    414     add_pid.push_back(MPEG_PAT_PID);
    415     _stream_data->AddListeningPID(MPEG_PAT_PID);
     439void HDHRRecorder::StopRecording(void)
     440{
     441    _request_recording = false;
     442    while (_recording)
     443        usleep(2000);
     444}
    416445
    417     for (uint i = 0; i < _input_pat->ProgramCount(); i++)
     446bool HDHRRecorder::PauseAndWait(int timeout)
     447{
     448    if (request_pause)
    418449    {
    419         add_pid.push_back(_input_pat->ProgramPID(i));
    420         _stream_data->AddListeningPID(_input_pat->ProgramPID(i));
    421     }
     450        QMutex waitlock;
     451        if (!paused)
     452        {
     453            assert(_stream_handler);
     454            assert(_stream_data);
    422455
    423     // Record the streams in the PMT...
    424     bool need_pcr_pid = true;
    425     for (uint i = 0; i < _input_pmt->StreamCount(); i++)
    426     {
    427         add_pid.push_back(_input_pmt->StreamPID(i));
    428         need_pcr_pid &= (_input_pmt->StreamPID(i) != _input_pmt->PCRPID());
    429         _stream_data->AddWritingPID(_input_pmt->StreamPID(i));
    430     }
     456            _stream_handler->RemoveListener(_stream_data);
    431457
    432     if (need_pcr_pid && (_input_pmt->PCRPID()))
    433     {
    434         add_pid.push_back(_input_pmt->PCRPID());
    435         _stream_data->AddWritingPID(_input_pmt->PCRPID());
     458            paused = true;
     459            pauseWait.wakeAll();
     460            if (tvrec)
     461                tvrec->RecorderPaused();
     462        }
     463        waitlock.lock();
     464        unpauseWait.wait(&waitlock, timeout);
    436465    }
    437466
    438     // Adjust for EIT
    439     AdjustEITPIDs();
    440     for (uint i = 0; i < _eit_pids.size(); i++)
     467    if (!request_pause && paused)
    441468    {
    442         add_pid.push_back(_eit_pids[i]);
    443         _stream_data->AddListeningPID(_eit_pids[i]);
    444     }
     469        paused = false;
    445470
    446     // Delete filters for pids we no longer wish to monitor
    447     vector<uint>::const_iterator it;
    448     vector<uint> pids = _channel->GetPIDs();
    449     for (it = pids.begin(); it != pids.end(); ++it)
    450     {
    451         if (find(add_pid.begin(), add_pid.end(), *it) == add_pid.end())
    452         {
    453             _stream_data->RemoveListeningPID(*it);
    454             _stream_data->RemoveWritingPID(*it);
    455             _channel->DelPID(*it, false);
    456         }
    457     }
     471        assert(_stream_handler);
     472        assert(_stream_data);
    458473
    459     for (it = add_pid.begin(); it != add_pid.end(); ++it)
    460         _channel->AddPID(*it, false);
    461 
    462     _channel->UpdateFilters();
     474        _stream_handler->AddListener(_stream_data);
     475    }
    463476
    464     return add_pid.size();
     477    return paused;
    465478}
    466479
    467 /** \fn HDHRRecorder::AdjustEITPIDs(void)
    468  *  \brief Adjusts EIT PID monitoring to monitor the right number of EIT PIDs.
    469  */
    470 bool HDHRRecorder::AdjustEITPIDs(void)
     480void HDHRRecorder::BufferedWrite(const TSPacket &tspacket)
    471481{
    472     bool changes = false;
    473     uint_vec_t add, del;
    474 
    475     QMutexLocker change_lock(&_pid_lock);
    476 
    477     if (GetStreamData()->HasEITPIDChanges(_eit_pids))
    478         changes = GetStreamData()->GetEITPIDChanges(_eit_pids, add, del);
     482    // Care must be taken to make sure that the packet actually gets written
     483    // as the decision to actually write it has already been made
    479484
    480     if (!changes)
    481         return false;
    482 
    483     for (uint i = 0; i < del.size(); i++)
     485    // Do we have to buffer the packet for exact keyframe detection?
     486    if (_buffer_packets)
    484487    {
    485         uint_vec_t::iterator it;
    486         it = find(_eit_pids.begin(), _eit_pids.end(), del[i]);
    487         if (it != _eit_pids.end())
    488             _eit_pids.erase(it);
     488        int idx = _payload_buffer.size();
     489        _payload_buffer.resize(idx + TSPacket::SIZE);
     490        memcpy(&_payload_buffer[idx], tspacket.data(), TSPacket::SIZE);
     491        return;
    489492    }
    490493
    491     for (uint i = 0; i < add.size(); i++)
    492         _eit_pids.push_back(add[i]);
    493 
    494     return true;
     494    // We are free to write the packet, but if we have buffered packet[s]
     495    // we have to write them first...
     496    if (!_payload_buffer.empty())
     497    {
     498        if (ringBuffer)
     499            ringBuffer->Write(&_payload_buffer[0], _payload_buffer.size());
     500        _payload_buffer.clear();
     501    }
     502    if (ringBuffer)
     503        ringBuffer->Write(tspacket.data(), TSPacket::SIZE);
    495504}
    496505
  • mythtv/libs/libmythtv/hdhrrecorder.h

    diff -p -r -u -N -X /tmp/diff.exclude.17976 -x myth.20713.0616a -x myth.20713.0616b myth.20713.0616a/mythtv/libs/libmythtv/hdhrrecorder.h myth.20713.0616b/mythtv/libs/libmythtv/hdhrrecorder.h
     
    1414
    1515class HDHRChannel;
    1616class ProgramMapTable;
     17class MPEGStreamData;
     18class HDHRStreamHandler;
     19
    1720
    1821typedef vector<uint>        uint_vec_t;
    1922
    class HDHRRecorder : public DTVRecorder, 
    2124                     public DVBMainStreamListener,
    2225                     public ATSCMainStreamListener,
    2326                     public MPEGStreamListener,
    24                      public MPEGSingleProgramStreamListener
     27                     public MPEGSingleProgramStreamListener,
     28                     public TSPacketListener,
     29                     public TSPacketListenerAV
    2530{
    2631  public:
    2732    HDHRRecorder(TVRec *rec, HDHRChannel *channel);
    class HDHRRecorder : public DTVRecorder, 
    3338                               const QString &vbidev);
    3439
    3540    bool Open(void);
    36     bool StartData(void);
     41    bool IsOpen(void);
    3742    void Close(void);
    3843
    3944    void StartRecording(void);
     45    void ResetForNewFile(void);
     46    void StopRecording(void);
    4047
    4148    void SetStreamData(MPEGStreamData*);
    4249    MPEGStreamData *GetStreamData(void) { return _stream_data; }
    class HDHRRecorder : public DTVRecorder, 
    6269    void HandleNIT(const NetworkInformationTable*) {}
    6370    void HandleSDT(uint /*tsid*/, const ServiceDescriptionTable*) {}
    6471
    65   private:
    66     bool AdjustFilters(void);
    67     bool AdjustEITPIDs(void);
     72    // TSPacketListenerAV
     73    bool ProcessVideoTSPacket(const TSPacket& tspacket);
     74    bool ProcessAudioTSPacket(const TSPacket& tspacket);
     75
     76    // Common audio/visual processing
     77    bool ProcessAVTSPacket(const TSPacket &tspacket);
    6878
    69     void ProcessTSData(const unsigned char *buffer, int len);
    7079    bool ProcessTSPacket(const TSPacket& tspacket);
     80
     81    void BufferedWrite(const TSPacket &tspacket);
     82  private:
    7183    void TeardownAll(void);
     84
     85    void ReaderPaused(int fd);
     86    bool PauseAndWait(int timeout = 100);
    7287   
    7388  private:
    7489    HDHRChannel                   *_channel;
    75     struct hdhomerun_video_sock_t *_video_socket;
     90    HDHRStreamHandler             *_stream_handler;
    7691    MPEGStreamData                *_stream_data;
    7792
     93    mutable QMutex                 _pid_lock;
    7894    ProgramAssociationTable       *_input_pat;
    7995    ProgramMapTable               *_input_pmt;
    80     bool                           _reset_pid_filters;
    81     uint_vec_t                     _eit_pids;
    82     mutable QMutex                 _pid_lock;
     96    bool                           _has_no_av;
     97
     98    unsigned char   _stream_id[0x1fff];
     99    unsigned char   _pid_status[0x1fff];
     100    unsigned char   _continuity_counter[0x1fff];
     101
     102    // Constants
     103    static const int TSPACKETS_BETWEEN_PSIP_SYNC;
     104    static const int POLL_INTERVAL;
     105    static const int POLL_WARNING_TIMEOUT;
     106
     107    static const unsigned char kPayloadStartSeen = 0x2;
    83108};
    84109
    85110#endif
  • mythtv/libs/libmythtv/hdhrsignalmonitor.cpp

    diff -p -r -u -N -X /tmp/diff.exclude.17976 -x myth.20713.0616a -x myth.20713.0616b myth.20713.0616a/mythtv/libs/libmythtv/hdhrsignalmonitor.cpp myth.20713.0616b/mythtv/libs/libmythtv/hdhrsignalmonitor.cpp
     
    1818
    1919#include "hdhrchannel.h"
    2020#include "hdhrrecorder.h"
     21#include "hdhrstreamhandler.h"
    2122
    2223#define LOC QString("HDHRSM(%1): ").arg(channel->GetDevice())
    2324#define LOC_ERR QString("HDHRSM(%1), Error: ").arg(channel->GetDevice())
     
    3940HDHRSignalMonitor::HDHRSignalMonitor(
    4041    int db_cardnum, HDHRChannel* _channel, uint64_t _flags) :
    4142    DTVSignalMonitor(db_cardnum, _channel, _flags),
    42     dtvMonitorRunning(false)
     43       streamHandlerStarted(false),
     44       streamHandler(NULL)
     45
    4346{
    4447    VERBOSE(VB_CHANNEL, LOC + "ctor");
    4548
    46     _channel->DelAllPIDs();
    47 
    4849    signalStrength.SetThreshold(45);
    4950
    5051    AddFlags(kSigMon_WaitForSig);
     52
     53    streamHandler = HDHRStreamHandler::Get(_channel->GetDevice());
    5154}
    5255
    5356/** \fn HDHRSignalMonitor::~HDHRSignalMonitor()
    HDHRSignalMonitor::~HDHRSignalMonitor() 
    5760{
    5861    VERBOSE(VB_CHANNEL, LOC + "dtor");
    5962    Stop();
     63    HDHRStreamHandler::Return(streamHandler);
    6064}
    6165
    6266/** \fn HDHRSignalMonitor::Stop(void)
    void HDHRSignalMonitor::Stop(void) 
    6670{
    6771    VERBOSE(VB_CHANNEL, LOC + "Stop() -- begin");
    6872    SignalMonitor::Stop();
    69     if (dtvMonitorRunning)
    70     {
    71         dtvMonitorRunning = false;
    72         pthread_join(table_monitor_thread, NULL);
    73     }
    74     VERBOSE(VB_CHANNEL, LOC + "Stop() -- end");
    75 }
    76 
    77 void *HDHRSignalMonitor::TableMonitorThread(void *param)
    78 {
    79     HDHRSignalMonitor *mon = (HDHRSignalMonitor*) param;
    80     mon->RunTableMonitor();
    81     return NULL;
    82 }
    83 
    84 bool HDHRSignalMonitor::UpdateFiltersFromStreamData(void)
    85 {
    86     vector<int> add_pids;
    87     vector<int> del_pids;
    88 
    89     if (!GetStreamData())
    90         return false;
    91 
    92     UpdateListeningForEIT();
    93 
    94     const pid_map_t &listening = GetStreamData()->ListeningPIDs();
    95 
    96     // PIDs that need to be added..
    97     pid_map_t::const_iterator lit = listening.constBegin();
    98     for (; lit != listening.constEnd(); ++lit)
    99         if (*lit && (filters.find(lit.key()) == filters.end()))
    100             add_pids.push_back(lit.key());
    101 
    102     // PIDs that need to be removed..
    103     FilterMap::const_iterator fit = filters.constBegin();
    104     for (; fit != filters.constEnd(); ++fit)
    105         if (listening.find(fit.key()) == listening.end())
    106             del_pids.push_back(fit.key());
    107 
    108     HDHRChannel *hdhr = dynamic_cast<HDHRChannel*>(channel);
    109     if (!hdhr)
    110         return false;
    111 
    112     // Remove PIDs
    113     bool ok = true;
    114     vector<int>::iterator dit = del_pids.begin();
    115     for (; dit != del_pids.end(); ++dit)
    116     {
    117         ok &= hdhr->DelPID(*dit);
    118         filters.erase(filters.find(*dit));
    119     }
     73    if (GetStreamData())
     74        streamHandler->RemoveListener(GetStreamData());
     75    streamHandlerStarted = false;
     76    streamHandler->SetRetuneAllowed(false, NULL, NULL);
    12077
    121     // Add PIDs
    122     vector<int>::iterator ait = add_pids.begin();
    123     for (; ait != add_pids.end(); ++ait)
    124     {
    125         ok &= hdhr->AddPID(*ait);
    126         filters[*ait] = 1;
    127     }
    128 
    129     return ok;
     78    VERBOSE(VB_CHANNEL, LOC + "Stop() -- end");
    13079}
    13180
    132 void HDHRSignalMonitor::RunTableMonitor(void)
     81HDHRChannel *HDHRSignalMonitor::GetHDHRChannel(void)
    13382{
    134     dtvMonitorRunning = true;
    135 
    136     struct hdhomerun_video_sock_t *_video_socket;
    137     _video_socket = hdhomerun_video_create(0, VIDEO_DATA_BUFFER_SIZE_1S);
    138     if (!_video_socket)
    139     {
    140         VERBOSE(VB_IMPORTANT, LOC_ERR + "Failed to get video socket");
    141         return;
    142     }
    143 
    144     HDHRChannel *hdrc = dynamic_cast<HDHRChannel*>(channel);
    145     if (!hdrc)
    146         return;
    147 
    148     uint localPort = hdhomerun_video_get_local_port(_video_socket);
    149     if (!hdrc->DeviceSetTarget(localPort))
    150     {
    151         hdhomerun_video_destroy(_video_socket);
    152         VERBOSE(VB_IMPORTANT, LOC_ERR + "Failed to set target");
    153         return;
    154     }
    155 
    156     VERBOSE(VB_CHANNEL, LOC + "RunTableMonitor(): " +
    157             QString("begin (# of pids %1)")
    158             .arg(GetStreamData()->ListeningPIDs().size()));
    159 
    160     while (dtvMonitorRunning && GetStreamData())
    161     {
    162         UpdateFiltersFromStreamData();
    163 
    164         size_t data_length;
    165         unsigned char *data_buffer =
    166             hdhomerun_video_recv(_video_socket,
    167                                          VIDEO_DATA_BUFFER_SIZE_1S / 5,
    168                                          &data_length);
    169 
    170         if (data_buffer)
    171         {
    172             GetStreamData()->ProcessData(data_buffer, data_length);
    173             continue;
    174         }
    175 
    176         usleep(2500);
    177     }
    178 
    179     hdrc->DeviceClearTarget();
    180     hdhomerun_video_destroy(_video_socket);
    181 
    182     VERBOSE(VB_CHANNEL, LOC + "RunTableMonitor(): -- shutdown");
    183 
    184     // TODO teardown PID filters here
    185 
    186     VERBOSE(VB_CHANNEL, LOC + "RunTableMonitor(): -- end");
     83    return dynamic_cast<HDHRChannel*>(channel);
    18784}
    18885
    18986/** \fn HDHRSignalMonitor::UpdateValues()
    void HDHRSignalMonitor::UpdateValues(voi 
    20198    if (!running || exit)
    20299        return;
    203100
    204     if (dtvMonitorRunning)
     101    if (streamHandlerStarted)
    205102    {
    206103        EmitStatus();
    207104        if (IsAllGood())
    void HDHRSignalMonitor::UpdateValues(voi 
    212109        return;
    213110    }
    214111
    215     QString msg = ((HDHRChannel*)channel)->TunerGet("status");
     112    QString msg = streamHandler->GetTunerStatus();
    216113    //ss  = signal strength,        [0,100]
    217114    //snq = signal to noise quality [0,100]
    218115    //seq = signal error quality    [0,100]
    void HDHRSignalMonitor::UpdateValues(voi 
    250147                   kDTVSigMon_WaitForMGT | kDTVSigMon_WaitForVCT |
    251148                   kDTVSigMon_WaitForNIT | kDTVSigMon_WaitForSDT))
    252149    {
    253         pthread_create(&table_monitor_thread, NULL,
    254                        TableMonitorThread, this);
    255 
    256         VERBOSE(VB_CHANNEL, LOC + "UpdateValues() -- "
    257                 "Waiting for table monitor to start");
    258 
    259         while (!dtvMonitorRunning)
    260             usleep(50);
    261 
    262         VERBOSE(VB_CHANNEL, LOC + "UpdateValues() -- "
    263                 "Table monitor started");
     150        streamHandler->AddListener(GetStreamData());
     151        streamHandlerStarted = true;
    264152    }
    265153
    266154    update_done = true;
  • mythtv/libs/libmythtv/hdhrsignalmonitor.h

    diff -p -r -u -N -X /tmp/diff.exclude.17976 -x myth.20713.0616a -x myth.20713.0616b myth.20713.0616a/mythtv/libs/libmythtv/hdhrsignalmonitor.h myth.20713.0616b/mythtv/libs/libmythtv/hdhrsignalmonitor.h
     
    77#include "qstringlist.h"
    88
    99class HDHRChannel;
     10class HDHRStreamHandler;
    1011
    1112typedef QMap<uint,int> FilterMap;
    1213
    class HDHRSignalMonitor: public DTVSigna 
    1920
    2021    void Stop(void);
    2122
    22     bool UpdateFiltersFromStreamData(void);
    23 
    2423  protected:
    2524    HDHRSignalMonitor(void);
    2625    HDHRSignalMonitor(const HDHRSignalMonitor&);
    2726
    2827    virtual void UpdateValues(void);
    2928
    30     static void *TableMonitorThread(void *param);
    31     void RunTableMonitor(void);
    32 
    3329    bool SupportsTSMonitoring(void);
    3430
     31    HDHRChannel *GetHDHRChannel(void);
     32
    3533  protected:
    36     bool               dtvMonitorRunning;
    37     pthread_t          table_monitor_thread;
    3834
    39     FilterMap          filters; ///< PID filters for table monitoring
     35    bool               streamHandlerStarted;
     36    HDHRStreamHandler  *streamHandler;
     37
    4038};
    4139
    4240#endif // HDHRSIGNALMONITOR_H
  • mythtv/libs/libmythtv/hdhrstreamhandler.cpp

    diff -p -r -u -N -X /tmp/diff.exclude.17976 -x myth.20713.0616a -x myth.20713.0616b myth.20713.0616a/mythtv/libs/libmythtv/hdhrstreamhandler.cpp myth.20713.0616b/mythtv/libs/libmythtv/hdhrstreamhandler.cpp
     
     1// -*- Mode: c++ -*-
     2
     3#include <cassert> // remove when everything is filled in...
     4
     5// POSIX headers
     6#include <pthread.h>
     7#include <fcntl.h>
     8#include <unistd.h>
     9#include <sys/select.h>
     10#include <sys/ioctl.h>
     11
     12// Qt headers
     13#include <qstring.h>
     14
     15// MythTV headers
     16#include "hdhrstreamhandler.h"
     17#include "hdhrchannel.h"
     18#include "dtvsignalmonitor.h"
     19#include "streamlisteners.h"
     20#include "mpegstreamdata.h"
     21#include "cardutil.h"
     22
     23#define LOC      QString("HDHRSH( %1 ): ").arg(_devicename)
     24#define LOC_WARN QString("HDHRSH( %1 ) Warning: ").arg(_devicename)
     25#define LOC_ERR  QString("HDHRSH( %1 ) Error: ").arg(_devicename)
     26
     27QMap<uint,bool> HDHRStreamHandler::_rec_supports_ts_monitoring;
     28QMutex          HDHRStreamHandler::_rec_supports_ts_monitoring_lock;
     29
     30QMap<QString,HDHRStreamHandler*> HDHRStreamHandler::_handlers;
     31QMap<QString,uint>               HDHRStreamHandler::_handlers_refcnt;
     32QMutex                           HDHRStreamHandler::_handlers_lock;
     33
     34
     35#define DEBUG_PID_FILTERS
     36
     37HDHRStreamHandler *HDHRStreamHandler::Get(QString devicename)
     38{
     39    QMutexLocker locker(&_handlers_lock);
     40
     41    QMap<QString,HDHRStreamHandler*>::iterator it =
     42        _handlers.find(devicename);
     43
     44    if (it == _handlers.end())
     45    {
     46        HDHRStreamHandler *newhandler = new HDHRStreamHandler(devicename);
     47        newhandler->Open();
     48        _handlers[devicename] = newhandler;
     49        _handlers_refcnt[devicename] = 1;
     50        VERBOSE(VB_RECORD, QString("HDHRSH: Creating new stream handler for %1")
     51                .arg(devicename));
     52    }
     53    else
     54    {
     55        _handlers_refcnt[devicename]++;
     56        uint rcount=_handlers_refcnt[devicename];
     57        VERBOSE(VB_RECORD, QString("HDHRSH: Using existing stream handler for %1 (%2 in use)")
     58                .arg(devicename).arg(rcount));
     59    }
     60
     61    return _handlers[devicename];
     62}
     63
     64void HDHRStreamHandler::Return(HDHRStreamHandler * & ref)
     65{
     66    QMutexLocker locker(&_handlers_lock);
     67
     68    QMap<QString,uint>::iterator rit = _handlers_refcnt.find(ref->_devicename);
     69    if (rit == _handlers_refcnt.end())
     70        return;
     71
     72    uint rcount = *rit;
     73    VERBOSE(VB_RECORD, QString("HDHRSH: %1 streams left for %2")
     74            .arg(rcount-1).arg(ref->_devicename));
     75
     76    if (*rit > 1)
     77    {
     78        (*rit)--;
     79        ref=NULL;
     80        return;
     81    }
     82
     83    QMap<QString, HDHRStreamHandler*>::iterator it = _handlers.find(ref->_devicename);
     84    if ((it != _handlers.end()) && (*it == ref))
     85    {
     86        VERBOSE(VB_RECORD, QString("HDHRSH: Closing handler for %1").arg(ref->_devicename));
     87        ref->Close();
     88        delete *it;
     89        _handlers.erase(it);
     90    } else {
     91        VERBOSE(VB_IMPORTANT, QString("HDHRSH: Couldn't find handler for %1").arg(ref->_devicename));
     92    }
     93
     94    _handlers_refcnt.erase(rit);
     95    ref=NULL;
     96}
     97
     98HDHRStreamHandler::HDHRStreamHandler(QString devicename) :
     99    _control_socket(NULL),
     100    _video_socket(NULL),
     101    _devicename(devicename),
     102    _allow_retune(false),
     103
     104    _start_stop_lock(QMutex::Recursive),
     105    _running(false),
     106
     107    _sigmon(NULL),
     108    _channel(NULL),
     109
     110    _pid_lock(QMutex::Recursive),
     111    _listener_lock(QMutex::Recursive),
     112    _hdhr_lock(QMutex::Recursive)
     113{
     114}
     115
     116HDHRStreamHandler::~HDHRStreamHandler()
     117{
     118    assert(_stream_data_list.empty());
     119}
     120
     121bool HDHRStreamHandler::Open()
     122{
     123    if (!FindDevice())
     124        return false;
     125
     126    return Connect();
     127}
     128
     129void HDHRStreamHandler::Close()
     130{
     131    if (_control_socket)
     132    {
     133        TuneChannel("none");
     134        hdhomerun_control_destroy(_control_socket);
     135        _control_socket=NULL;
     136    }
     137}
     138
     139bool HDHRStreamHandler::Connect()
     140{
     141    _control_socket = hdhomerun_control_create(_device_id, _device_ip);
     142
     143    if (!_control_socket)
     144    {
     145        VERBOSE(VB_IMPORTANT, LOC_ERR + "Unable to create control socket");
     146        return false;
     147    }
     148
     149    if (hdhomerun_control_get_local_addr(_control_socket) == 0)
     150    {
     151        VERBOSE(VB_IMPORTANT, LOC_ERR + "Unable to connect to device");
     152        return false;
     153    }
     154
     155    VERBOSE(VB_CHANNEL, LOC + "Successfully connected to device");
     156    return true;
     157}
     158
     159bool HDHRStreamHandler::FindDevice(void)
     160{
     161    hdhomerun_device_t* thisdevice = hdhomerun_device_create_from_str(_devicename.toLocal8Bit().constData());
     162
     163    if (thisdevice)
     164    {
     165        _device_id = hdhomerun_device_get_device_id(thisdevice);
     166        _device_ip = hdhomerun_device_get_device_ip(thisdevice);
     167        _tuner     = hdhomerun_device_get_tuner(thisdevice);
     168        hdhomerun_device_destroy(thisdevice);
     169
     170        VERBOSE(VB_IMPORTANT, LOC +
     171                QString("device %5 found at address %1.%2.%3.%4 tuner %6")
     172                .arg((_device_ip>>24) & 0xFF).arg((_device_ip>>16) & 0xFF)
     173                .arg((_device_ip>> 8) & 0xFF).arg((_device_ip>> 0) & 0xFF)
     174                .arg(_devicename).arg(_tuner));
     175
     176        return true;
     177    }
     178    return false;
     179}
     180
     181
     182bool HDHRStreamHandler::EnterPowerSavingMode(void)
     183{
     184    if (_video_socket)
     185    {
     186        VERBOSE(VB_CHANNEL, LOC + "Ignoring request - video streaming active");
     187        return false;
     188    }
     189    else
     190    {
     191        return TuneChannel("none");
     192        /*  QString::null != TunerSet("channel", "none", false); */
     193    }
     194}
     195
     196QString HDHRStreamHandler::DeviceGet(const QString &name, bool report_error_return)
     197{
     198    QMutexLocker locker(&_hdhr_lock);
     199
     200    if (!_control_socket)
     201    {
     202        VERBOSE(VB_IMPORTANT, LOC_ERR + "Get request failed (not connected)");
     203        return QString::null;
     204    }
     205
     206    char *value = NULL;
     207    char *error = NULL;
     208    if (hdhomerun_control_get(_control_socket, name.toLocal8Bit().constData(), &value, &error) < 0)
     209    {
     210        VERBOSE(VB_IMPORTANT, LOC_ERR + "Get request failed" + ENO);
     211        return QString::null;
     212    }
     213
     214    if (report_error_return && error)
     215    {
     216        VERBOSE(VB_IMPORTANT, LOC_ERR +
     217                QString("DeviceGet(%1): %2").arg(name).arg(error));
     218
     219        return QString::null;
     220    }
     221
     222    return QString(value);
     223}
     224
     225
     226QString HDHRStreamHandler::DeviceSet(const QString &name, const QString &val,
     227                               bool report_error_return)
     228{
     229    QMutexLocker locker(&_hdhr_lock);
     230
     231    if (!_control_socket)
     232    {
     233        VERBOSE(VB_IMPORTANT, LOC_ERR + "Set request failed (not connected)");
     234        return QString::null;
     235    }
     236
     237    char *value = NULL;
     238    char *error = NULL;
     239    if (hdhomerun_control_set(_control_socket, name.toLocal8Bit().constData(), val.toLocal8Bit().constData(), &value, &error) < 0)
     240    {
     241        VERBOSE(VB_IMPORTANT, LOC_ERR + "Set request failed" + ENO);
     242
     243        return QString::null;
     244    }
     245
     246    if (report_error_return && error)
     247    {
     248        VERBOSE(VB_IMPORTANT, LOC_ERR +
     249                QString("DeviceSet(%1 %2): %3").arg(name).arg(val).arg(error));
     250
     251        return QString::null;
     252    }
     253
     254    return QString(value);
     255}
     256
     257QString HDHRStreamHandler::TunerGet(const QString &name, bool report_error_return)
     258{
     259    return DeviceGet(QString("/tuner%1/%2").arg(_tuner).arg(name),
     260                     report_error_return);
     261}
     262
     263QString HDHRStreamHandler::TunerSet(const QString &name, const QString &value,
     264                              bool report_error_return)
     265{
     266    return DeviceSet(QString("/tuner%1/%2").arg(_tuner).arg(name), value,
     267                     report_error_return);
     268}
     269
     270bool HDHRStreamHandler::DeviceSetTarget(unsigned short localPort)
     271{
     272    if (localPort == 0)
     273    {
     274        return false;
     275    }
     276
     277    unsigned long localIP = hdhomerun_control_get_local_addr(_control_socket);
     278    if (localIP == 0)
     279    {
     280        return false;
     281    }
     282
     283    QString configValue = QString("rtp://%1.%2.%3.%4:%5")
     284        .arg((localIP >> 24) & 0xFF).arg((localIP >> 16) & 0xFF)
     285        .arg((localIP >>  8) & 0xFF).arg((localIP >>  0) & 0xFF)
     286        .arg(localPort);
     287
     288    return (QString::null != TunerSet("target", configValue));
     289}
     290
     291bool HDHRStreamHandler::DeviceClearTarget()
     292{
     293    return (QString::null != TunerSet("target", "0.0.0.0:0"));
     294}
     295
     296QString HDHRStreamHandler::GetTunerStatus() {
     297    return TunerGet("status");
     298}
     299
     300bool HDHRStreamHandler::Connected() {
     301    // FIXME
     302    return (_control_socket != NULL);
     303}
     304
     305bool HDHRStreamHandler::TuneChannel(QString chn) {
     306    QString current = TunerGet("channel");
     307    if (current == chn)
     308    {
     309        VERBOSE(VB_RECORD, QString(LOC + "Not Re-Tuning channel %1").arg(chn));
     310        return true;
     311    }
     312    VERBOSE(VB_RECORD, QString(LOC + "Tuning channel %1 (was %2)").arg(chn).arg(current));
     313    return (QString::null != TunerSet("channel", chn));
     314}
     315
     316bool HDHRStreamHandler::TuneProgram(QString pnum) {
     317    VERBOSE(VB_RECORD, QString(LOC + "Tuning program %1").arg(pnum));
     318    return (QString::null != TunerSet("program", pnum, false));
     319}
     320
     321void HDHRStreamHandler::AddListener(MPEGStreamData *data)
     322{
     323    VERBOSE(VB_RECORD, LOC + "AddListener("<<data<<") -- begin");
     324    assert(data);
     325
     326    _listener_lock.lock();
     327
     328    VERBOSE(VB_RECORD, LOC + "AddListener("<<data<<") -- locked");
     329
     330    _stream_data_list.push_back(data);
     331
     332    _listener_lock.unlock();
     333
     334    Start();
     335
     336    VERBOSE(VB_RECORD, LOC + "AddListener("<<data<<") -- end");
     337}
     338
     339void HDHRStreamHandler::RemoveListener(MPEGStreamData *data)
     340{
     341    VERBOSE(VB_RECORD, LOC + "RemoveListener("<<data<<") -- begin");
     342    assert(data);
     343
     344    _listener_lock.lock();
     345
     346    VERBOSE(VB_RECORD, LOC + "RemoveListener("<<data<<") -- locked");
     347
     348    vector<MPEGStreamData*>::iterator it =
     349        find(_stream_data_list.begin(), _stream_data_list.end(), data);
     350
     351    if (it != _stream_data_list.end())
     352        _stream_data_list.erase(it);
     353
     354    if (_stream_data_list.empty())
     355    {
     356        _listener_lock.unlock();
     357        Stop();
     358    }
     359    else
     360    {
     361        _listener_lock.unlock();
     362    }
     363
     364    VERBOSE(VB_RECORD, LOC + "RemoveListener("<<data<<") -- end");
     365}
     366
     367void *run_hdhr_stream_handler_thunk(void *param)
     368{
     369    HDHRStreamHandler *mon = (HDHRStreamHandler*) param;
     370    mon->Run();
     371    return NULL;
     372}
     373
     374void HDHRStreamHandler::Start(void)
     375{
     376    QMutexLocker locker(&_start_stop_lock);
     377
     378    _eit_pids.clear();
     379
     380    if (!IsRunning())
     381    {
     382        QMutex is_running_lock;
     383        int rval = pthread_create(&_reader_thread, NULL,
     384                                  run_hdhr_stream_handler_thunk, this);
     385
     386        if (0 != rval)
     387        {
     388            VERBOSE(VB_IMPORTANT, LOC_ERR +
     389                    "Start: Failed to create thread." + ENO);
     390            return;
     391        }
     392
     393        while (!IsRunning())
     394        {
     395            is_running_lock.lock();
     396            _running_state_changed.wait(&is_running_lock, 100);
     397        }
     398    }
     399}
     400
     401void HDHRStreamHandler::Stop(void)
     402{
     403    QMutexLocker locker(&_start_stop_lock);
     404
     405    if (IsRunning())
     406    {
     407        SetRunning(false);
     408        pthread_join(_reader_thread, NULL);
     409    }
     410}
     411
     412void HDHRStreamHandler::Run(void)
     413{
     414    SetRunning(true);
     415    RunTS();
     416}
     417
     418/** \fn HDHRStreamHandler::RunTS(void)
     419 *  \brief Uses TS filtering devices to read a DVB device for tables & data
     420 *
     421 *  This supports all types of MPEG based stream data, but is extreemely
     422 *  slow with DVB over USB 1.0 devices which for efficiency reasons buffer
     423 *  a stream until a full block transfer buffer full of the requested
     424 *  tables is available. This takes a very long time when you are just
     425 *  waiting for a PAT or PMT table, and the buffer is hundreds of packets
     426 *  in size.
     427 */
     428void HDHRStreamHandler::RunTS(void)
     429{
     430    int remainder = 0;
     431    VERBOSE(VB_RECORD, LOC + "RunTS()");
     432
     433    /* Calculate buffer size */
     434    uint buffersize = gContext->GetNumSetting(
     435        "HDRingbufferSize", 50 * TSPacket::SIZE) * 1024;
     436    buffersize /= VIDEO_DATA_PACKET_SIZE;
     437    buffersize *= VIDEO_DATA_PACKET_SIZE;
     438
     439    // Buffer should be at least about 1MB..
     440    buffersize = max(49 * TSPacket::SIZE * 128, buffersize);
     441
     442    VERBOSE(VB_GENERAL, QString(LOC + "HD Ringbuffer size = %1 KB").arg(buffersize / 1024));
     443
     444    /* Create TS socket. */
     445    _video_socket = hdhomerun_video_create(0, buffersize);
     446    if (!_video_socket)
     447    {
     448        VERBOSE(VB_IMPORTANT, LOC + "Open() failed to open socket");
     449        return;
     450    }
     451
     452    uint localPort = hdhomerun_video_get_local_port(_video_socket);
     453    if (!DeviceSetTarget(localPort))
     454    {
     455        VERBOSE(VB_IMPORTANT, LOC_ERR + "Starting recording (set target failed). Aborting.");
     456        return;
     457    }
     458    hdhomerun_video_flush(_video_socket);
     459
     460    bool _error = false;
     461
     462    VERBOSE(VB_RECORD, LOC + "RunTS(): begin");
     463
     464    while (IsRunning() && !_error)
     465    {
     466        UpdateFiltersFromStreamData();
     467
     468        size_t read_size = 64 * 1024; // read about 64KB
     469        read_size /= VIDEO_DATA_PACKET_SIZE;
     470        read_size *= VIDEO_DATA_PACKET_SIZE;
     471
     472        size_t data_length;
     473        unsigned char *data_buffer =
     474            hdhomerun_video_recv(_video_socket, read_size, &data_length);
     475
     476        if (! data_buffer)
     477        {
     478            usleep(5000);
     479            continue;
     480        }
     481
     482        // Assume data_length is a multiple of 188 (packet size)
     483//        ASSERT(0 == ( data_length % 188) );
     484
     485        _listener_lock.lock();
     486
     487        if (_stream_data_list.empty())
     488        {
     489            _listener_lock.unlock();
     490            continue;
     491        }
     492
     493        for (uint i = 0; i < _stream_data_list.size(); i++)
     494        {
     495            remainder = _stream_data_list[i]->ProcessData(data_buffer, data_length);
     496        }
     497       
     498        _listener_lock.unlock();
     499        if (remainder != 0)
     500            VERBOSE(VB_GENERAL, QString(LOC + "RunTS(): data_length = %1 remainder = %2")
     501                    .arg(data_length).arg(remainder));
     502    }
     503    VERBOSE(VB_RECORD, LOC + "RunTS(): " + "shutdown");
     504
     505    DelAllPIDs();
     506
     507    DeviceClearTarget();
     508    VERBOSE(VB_RECORD, LOC + "RunTS(): " + "end");
     509
     510    hdhomerun_video_sock_t* tmp_video_socket;
     511    {
     512        QMutexLocker locker(&_hdhr_lock);
     513        tmp_video_socket = _video_socket;
     514        _video_socket=NULL;
     515    }
     516     
     517    hdhomerun_video_destroy(tmp_video_socket);
     518
     519    SetRunning(false);
     520}
     521
     522bool HDHRStreamHandler::AddPID(uint pid, bool do_update)
     523{
     524    QMutexLocker locker(&_pid_lock);
     525
     526    vector<uint>::iterator it;
     527    it = lower_bound(_pid_info.begin(), _pid_info.end(), pid);
     528    if (it != _pid_info.end() && *it == pid)
     529    {
     530#ifdef DEBUG_PID_FILTERS
     531        VERBOSE(VB_CHANNEL, "AddPID(0x"<<hex<<pid<<dec<<", " << do_update << ") NOOP");
     532#endif // DEBUG_PID_FILTERS
     533        return true;
     534    }
     535
     536    _pid_info.insert(it, pid);
     537
     538#ifdef DEBUG_PID_FILTERS
     539    VERBOSE(VB_CHANNEL, "AddPID(0x"<<hex<<pid<<dec<<")", " << do_update << ");
     540#endif // DEBUG_PID_FILTERS
     541
     542    if (do_update)
     543        return UpdateFilters();
     544    return true;
     545}
     546
     547bool HDHRStreamHandler::DelPID(uint pid, bool do_update)
     548{
     549    QMutexLocker locker(&_pid_lock);
     550
     551    vector<uint>::iterator it;
     552    it = lower_bound(_pid_info.begin(), _pid_info.end(), pid);
     553    if (it == _pid_info.end())
     554    {
     555#ifdef DEBUG_PID_FILTERS
     556        VERBOSE(VB_CHANNEL, "DelPID(0x"<<hex<<pid<<dec<<", " << do_update << ") NOOP");
     557#endif // DEBUG_PID_FILTERS
     558
     559       return true;
     560    }
     561
     562    if (*it == pid)
     563    {
     564#ifdef DEBUG_PID_FILTERS
     565        VERBOSE(VB_CHANNEL, "DelPID(0x"<<hex<<pid<<dec<<", " << do_update << ") -- found");
     566#endif // DEBUG_PID_FILTERS
     567        _pid_info.erase(it);
     568    }
     569    else
     570    {
     571#ifdef DEBUG_PID_FILTERS
     572        VERBOSE(VB_CHANNEL, "DelPID(0x"<<hex<<pid<<dec<<", " << do_update << ") -- failed");
     573#endif // DEBUG_PID_FILTERS
     574    }
     575
     576    if (do_update)
     577        return UpdateFilters();
     578    return true;
     579}
     580
     581bool HDHRStreamHandler::DelAllPIDs(void)
     582{
     583    QMutexLocker locker(&_pid_lock);
     584
     585#ifdef DEBUG_PID_FILTERS
     586    VERBOSE(VB_CHANNEL, "DelAllPID()");
     587#endif // DEBUG_PID_FILTERS
     588
     589    _pid_info.clear();
     590
     591    return UpdateFilters();
     592}
     593
     594QString filt_str(uint pid)
     595{
     596    uint pid0 = (pid / (16*16*16)) % 16;
     597    uint pid1 = (pid / (16*16))    % 16;
     598    uint pid2 = (pid / (16))        % 16;
     599    uint pid3 = pid % 16;
     600    return QString("0x%1%2%3%4")
     601        .arg(pid0,0,16).arg(pid1,0,16)
     602        .arg(pid2,0,16).arg(pid3,0,16);
     603}
     604
     605bool HDHRStreamHandler::UpdateFilters(void)
     606{
     607#ifdef DEBUG_PID_FILTERS
     608    VERBOSE(VB_CHANNEL, LOC + "UpdateFilters()");
     609#endif // DEBUG_PID_FILTERS
     610    QMutexLocker locker(&_pid_lock);
     611
     612    QString filter = "";
     613
     614    vector<uint> range_min;
     615    vector<uint> range_max;
     616
     617// FIXME
     618//    if (_ignore_filters)
     619 //       return true;
     620
     621    for (uint i = 0; i < _pid_info.size(); i++)
     622    {
     623        uint pid_min = _pid_info[i];
     624        uint pid_max  = pid_min;
     625        for (uint j = i + 1; j < _pid_info.size(); j++)
     626        {
     627            if (pid_max + 1 != _pid_info[j])
     628                break;
     629            pid_max++;
     630            i++;
     631        }
     632        range_min.push_back(pid_min);
     633        range_max.push_back(pid_max);
     634    }
     635    if (range_min.size() > 16)
     636    {
     637        range_min.resize(16);
     638        uint pid_max = range_max.back();
     639        range_max.resize(15);
     640        range_max.push_back(pid_max);
     641    }
     642
     643    for (uint i = 0; i < range_min.size(); i++)
     644    {
     645        filter += filt_str(range_min[i]);
     646        if (range_min[i] != range_max[i])
     647            filter += QString("-%1").arg(filt_str(range_max[i]));
     648        filter += " ";
     649    }
     650
     651    filter = filter.trimmed();
     652
     653    QString new_filter = TunerSet("filter", filter);
     654
     655#ifdef DEBUG_PID_FILTERS
     656    QString msg = QString("Filter: '%1'").arg(filter);
     657    if (filter != new_filter)
     658        msg += QString("\n\t\t\t\t'%2'").arg(new_filter);
     659
     660    VERBOSE(VB_CHANNEL, LOC + msg);
     661#endif // DEBUG_PID_FILTERS
     662
     663    return filter == new_filter;
     664}
     665
     666void HDHRStreamHandler::UpdateListeningForEIT(void)
     667{
     668    vector<uint> add_eit, del_eit;
     669
     670    QMutexLocker read_locker(&_listener_lock);
     671
     672    for (uint i = 0; i < _stream_data_list.size(); i++)
     673    {
     674        MPEGStreamData *sd = _stream_data_list[i];
     675        if (sd->HasEITPIDChanges(_eit_pids) &&
     676            sd->GetEITPIDChanges(_eit_pids, add_eit, del_eit))
     677        {
     678            for (uint i = 0; i < del_eit.size(); i++)
     679            {
     680                uint_vec_t::iterator it;
     681                it = find(_eit_pids.begin(), _eit_pids.end(), del_eit[i]);
     682                if (it != _eit_pids.end())
     683                    _eit_pids.erase(it);
     684                sd->RemoveListeningPID(del_eit[i]);
     685            }
     686
     687            for (uint i = 0; i < add_eit.size(); i++)
     688            {
     689                _eit_pids.push_back(add_eit[i]);
     690                sd->AddListeningPID(add_eit[i]);
     691            }
     692        }
     693    }
     694}
     695
     696bool HDHRStreamHandler::UpdateFiltersFromStreamData(void)
     697{
     698
     699    UpdateListeningForEIT();
     700
     701    pid_map_t pids;
     702
     703    {
     704        QMutexLocker read_locker(&_listener_lock);
     705
     706        for (uint i = 0; i < _stream_data_list.size(); i++)
     707            _stream_data_list[i]->GetPIDs(pids);
     708    }
     709
     710    uint_vec_t           add_pids;
     711    vector<uint>         del_pids;
     712
     713    {
     714        QMutexLocker read_locker(&_pid_lock);
     715
     716        // PIDs that need to be added..
     717        pid_map_t::const_iterator lit = pids.constBegin();
     718        for (; lit != pids.constEnd(); ++lit)
     719        {
     720            vector<uint>::iterator it;
     721            it = lower_bound(_pid_info.begin(), _pid_info.end(), lit.key());
     722            if (! (it != _pid_info.end() && *it == lit.key())) {
     723                add_pids.push_back(lit.key());
     724            }
     725        }
     726
     727        // PIDs that need to be removed..
     728        vector<uint>::iterator fit = _pid_info.begin();
     729        for (; fit != _pid_info.end(); ++fit)
     730        {
     731            pid_map_t::const_iterator it = pids.find(*fit);
     732            if(it == pids.end())
     733                del_pids.push_back(*fit);
     734        }
     735    }
     736
     737    bool need_update = false;
     738
     739    // Remove PIDs
     740    bool ok = true;
     741    vector<uint>::iterator dit = del_pids.begin();
     742    for (; dit != del_pids.end(); ++dit)
     743    {
     744        need_update = true;
     745        ok &= DelPID(*dit, false);
     746    }
     747
     748    // Add PIDs
     749    vector<uint>::iterator ait = add_pids.begin();
     750    for (; ait != add_pids.end(); ++ait)
     751    {
     752        need_update = true;
     753        ok &= AddPID(*ait, false);
     754    }
     755
     756    if (need_update)
     757        return UpdateFilters();
     758
     759    return ok;
     760}
     761
     762void HDHRStreamHandler::SetRetuneAllowed(
     763    bool              allow,
     764    DTVSignalMonitor *sigmon,
     765    HDHRChannel       *hdhrchan)
     766{
     767    if (allow && sigmon && hdhrchan)
     768    {
     769        _allow_retune = true;
     770        _sigmon       = sigmon;
     771        _channel   = hdhrchan;
     772    }
     773    else
     774    {
     775        _allow_retune = false;
     776        _sigmon       = NULL;
     777        _channel   = NULL;
     778    }
     779}
     780
     781/** \fn HDHRStreamHandler::SupportsTSMonitoring(void)
     782 *  \brief Returns true if TS monitoring is supported.
     783 *
     784 *   NOTE: If you are using a DEC2000-t device you need to
     785 *   apply the patches provided by Peter Beutner for it, see
     786 *   http://www.gossamer-threads.com/lists/mythtv/dev/166172
     787 *   These patches should make it in to Linux 2.6.15 or 2.6.16.
     788 */
     789bool HDHRStreamHandler::SupportsTSMonitoring(void)
     790{
     791    return false;
     792
     793// FIXME
     794#if 0
     795    const uint pat_pid = 0x0;
     796
     797    {
     798        QMutexLocker locker(&_rec_supports_ts_monitoring_lock);
     799        QMap<uint,bool>::const_iterator it;
     800        it = _rec_supports_ts_monitoring.find(_dvb_dev_num);
     801        if (it != _rec_supports_ts_monitoring.end())
     802            return *it;
     803    }
     804
     805    int dvr_fd = open(_dvr_dev_path.ascii(), O_RDONLY | O_NONBLOCK);
     806    if (dvr_fd < 0)
     807    {
     808        QMutexLocker locker(&_rec_supports_ts_monitoring_lock);
     809        _rec_supports_ts_monitoring[_dvb_dev_num] = false;
     810        return false;
     811    }
     812
     813    bool supports_ts = false;
     814    if (AddPIDFilter(new PIDInfoHDHR(pat_pid)))
     815    {
     816        supports_ts = true;
     817        RemovePIDFilter(pat_pid);
     818    }
     819
     820    close(dvr_fd);
     821
     822    QMutexLocker locker(&_rec_supports_ts_monitoring_lock);
     823    _rec_supports_ts_monitoring[_dvb_dev_num] = supports_ts;
     824
     825    return supports_ts;
     826#endif
     827}
     828
     829void HDHRStreamHandler::SetRunning(bool is_running)
     830{
     831    _running = is_running;
     832    _running_state_changed.wakeAll();
     833}
     834
     835PIDPriority HDHRStreamHandler::GetPIDPriority(uint pid) const
     836{
     837    QMutexLocker reading_locker(&_listener_lock);
     838
     839    PIDPriority tmp = kPIDPriorityNone;
     840
     841    for (uint i = 0; i < _stream_data_list.size(); i++)
     842        tmp = max(tmp, _stream_data_list[i]->GetPIDPriority(pid));
     843
     844    return tmp;
     845}
  • mythtv/libs/libmythtv/hdhrstreamhandler.h

    diff -p -r -u -N -X /tmp/diff.exclude.17976 -x myth.20713.0616a -x myth.20713.0616b myth.20713.0616a/mythtv/libs/libmythtv/hdhrstreamhandler.h myth.20713.0616b/mythtv/libs/libmythtv/hdhrstreamhandler.h
     
     1// -*- Mode: c++ -*-
     2
     3#ifndef _HDHRSTREAMHANDLER_H_
     4#define _HDHRSTREAMHANDLER_H_
     5
     6#include <vector>
     7using namespace std;
     8
     9#include <qmap.h>
     10#include <qmutex.h>
     11
     12#include "util.h"
     13#include "DeviceReadBuffer.h"
     14#include "mpegstreamdata.h"
     15
     16class QString;
     17class HDHRStreamHandler;
     18class DTVSignalMonitor;
     19class HDHRChannel;
     20class DeviceReadBuffer;
     21
     22// HDHomeRun headers
     23#ifdef USING_HDHOMERUN
     24#include "hdhomerun.h"
     25#else
     26struct hdhomerun_control_sock_t { int dummy; };
     27#endif
     28
     29typedef QMap<uint,int> FilterMap;
     30
     31//#define RETUNE_TIMEOUT 5000
     32
     33class HDHRStreamHandler : public ReaderPausedCB
     34{
     35    friend void *run_hdhr_stream_handler_thunk(void *param);
     36
     37  public:
     38    static HDHRStreamHandler *Get(QString devicename);
     39    static void Return(HDHRStreamHandler * & ref);
     40
     41    void AddListener(MPEGStreamData *data);
     42    void RemoveListener(MPEGStreamData *data);
     43
     44    void RetuneMonitor(void);
     45
     46    bool IsRunning(void) const { return _running; }
     47    bool IsRetuneAllowed(void) const { return _allow_retune; }
     48
     49    void SetRetuneAllowed(bool              allow,
     50                          DTVSignalMonitor *sigmon,
     51                          HDHRChannel       *dvbchan);
     52
     53    // ReaderPausedCB
     54    virtual void ReaderPaused(int fd) { (void) fd; }
     55
     56    QString GetTunerStatus(void);
     57
     58    bool Connected();
     59    bool TuneChannel(QString );
     60    bool TuneProgram(QString );
     61
     62    bool EnterPowerSavingMode();
     63
     64  private:
     65
     66    bool FindDevice();
     67    bool Connect(void);
     68
     69    QString DeviceGet(const QString &name, bool report_error_return = true);
     70    QString DeviceSet(const QString &name, const QString &value,
     71                      bool report_error_return = true);
     72
     73    QString TunerGet(const QString &name, bool report_error_return = true);
     74    QString TunerSet(const QString &name, const QString &value,
     75                     bool report_error_return = true);
     76
     77    bool DeviceSetTarget(short unsigned int);
     78    bool DeviceClearTarget();
     79
     80    HDHRStreamHandler(QString);
     81    ~HDHRStreamHandler();
     82
     83    bool Open(void);
     84    void Close();
     85
     86    void Start(void);
     87    void Stop(void);
     88
     89    void Run(void);
     90    void RunTS(void);
     91
     92    void UpdateListeningForEIT(void);
     93    bool UpdateFiltersFromStreamData(void);
     94
     95    // Commands
     96    bool AddPID(uint pid, bool do_update = true);
     97    bool DelPID(uint pid, bool do_update = true);
     98    bool DelAllPIDs(void);
     99    bool UpdateFilters(void);
     100
     101    void SetRunning(bool);
     102
     103    PIDPriority GetPIDPriority(uint pid) const;
     104    bool SupportsTSMonitoring(void);
     105
     106  private:
     107    hdhomerun_control_sock_t  *_control_socket;
     108    hdhomerun_video_sock_t    *_video_socket;
     109    uint                       _device_id;
     110    uint                       _device_ip;
     111    uint                       _tuner;
     112    QString                    _devicename;
     113
     114    bool              _allow_retune;
     115
     116    mutable QMutex     _start_stop_lock;
     117    bool              _running;
     118    QWaitCondition    _running_state_changed;
     119    pthread_t         _reader_thread;
     120    DTVSignalMonitor *_sigmon;
     121    HDHRChannel       *_channel;
     122
     123    mutable QMutex    _pid_lock;
     124    vector<uint>      _eit_pids;
     125    vector<uint>      _pid_info;
     126    uint              _open_pid_filters;
     127    MythTimer         _cycle_timer;
     128
     129    mutable QMutex          _listener_lock;
     130    vector<MPEGStreamData*> _stream_data_list;
     131
     132    mutable QMutex          _hdhr_lock;
     133
     134    // for caching TS monitoring supported value.
     135    static QMutex          _rec_supports_ts_monitoring_lock;
     136    static QMap<uint,bool> _rec_supports_ts_monitoring;
     137
     138    // for implementing Get & Return
     139    static QMutex                       _handlers_lock;
     140    static QMap<QString, HDHRStreamHandler*> _handlers;
     141    static QMap<QString, uint>              _handlers_refcnt;
     142};
     143
     144#endif // _HDHRSTREAMHANDLER_H_
  • mythtv/libs/libmythtv/libmythtv.pro

    diff -p -r -u -N -X /tmp/diff.exclude.17976 -x myth.20713.0616a -x myth.20713.0616b myth.20713.0616a/mythtv/libs/libmythtv/libmythtv.pro myth.20713.0616b/mythtv/libs/libmythtv/libmythtv.pro
    using_backend { 
    528528    using_hdhomerun {
    529529        # MythTV HDHomeRun glue
    530530        HEADERS += hdhrsignalmonitor.h   hdhrchannel.h
    531         HEADERS += hdhrrecorder.h
     531        HEADERS += hdhrrecorder.h        hdhrstreamhandler.h
    532532
    533533        SOURCES += hdhrsignalmonitor.cpp hdhrchannel.cpp
    534         SOURCES += hdhrrecorder.cpp
     534        SOURCES += hdhrrecorder.cpp      hdhrstreamhandler.cpp
    535535
    536536        DEFINES += USING_HDHOMERUN
    537537    }
  • mythtv/libs/libmythtv/tv_rec.cpp

    diff -p -r -u -N -X /tmp/diff.exclude.17976 -x myth.20713.0616a -x myth.20713.0616b myth.20713.0616a/mythtv/libs/libmythtv/tv_rec.cpp myth.20713.0616b/mythtv/libs/libmythtv/tv_rec.cpp
    bool TVRec::CreateChannel(const QString  
    181181    else if (genOpt.cardtype == "HDHOMERUN")
    182182    {
    183183#ifdef USING_HDHOMERUN
    184         channel = new HDHRChannel(this, genOpt.videodev, dboxOpt.port);
     184        channel = new HDHRChannel(this, genOpt.videodev);
    185185        if (!channel->Open())
    186186            return false;
    187187        InitChannel(genOpt.defaultinput, startchannel);
    void TVRec::HandleTuning(void) 
    35033503            return;
    35043504
    35053505        ClearFlags(kFlagWaitingForRecPause);
    3506 #ifdef USING_HDHOMERUN
    3507         if (GetHDHRRecorder())
    3508         {
    3509             // We currently need to close the file descriptor for
    3510             // HDHomeRun signal monitoring to work.
    3511             GetHDHRRecorder()->Close();
    3512             GetHDHRRecorder()->SetRingBuffer(NULL);
    3513         }
    3514 #endif // USING_HDHOMERUN
    35153506        VERBOSE(VB_RECORD, LOC + "Recorder paused, calling TuningFrequency");
    35163507        TuningFrequency(lastTuningRequest);
    35173508    }
    void TVRec::TuningRestartRecorder(void) 
    41504141    }
    41514142    recorder->Reset();
    41524143
    4153 #ifdef USING_HDHOMERUN
    4154     if (GetHDHRRecorder())
    4155     {
    4156         pauseNotify = false;
    4157         GetHDHRRecorder()->Close();
    4158         pauseNotify = true;
    4159         GetHDHRRecorder()->Open();
    4160         GetHDHRRecorder()->StartData();
    4161     }
    4162 #endif // USING_HDHOMERUN
    4163 
    41644144    // Set file descriptor of channel from recorder for V4L
    41654145    channel->SetFd(recorder->GetVideoFd());
    41664146
  • mythtv/libs/libmythtv/videosource.cpp

    diff -p -r -u -N -X /tmp/diff.exclude.17976 -x myth.20713.0616a -x myth.20713.0616b myth.20713.0616a/mythtv/libs/libmythtv/videosource.cpp myth.20713.0616b/mythtv/libs/libmythtv/videosource.cpp
    using namespace std; 
    5050
    5151QMutex XMLTVFindGrabbers::list_lock;
    5252
     53// HDHomeRun headers
     54#ifdef USING_HDHOMERUN
     55#include "hdhomerun.h"
     56#endif
     57
    5358VideoSourceSelector::VideoSourceSelector(uint           _initial_sourceid,
    5459                                         const QString &_card_types,
    5560                                         bool           _must_have_mplexid) :
    class DBOX2ConfigurationGroup : public V 
    14071412    CaptureCard &parent;
    14081413 };
    14091414
    1410 class HDHomeRunDeviceID : public LineEditSetting, public CaptureCardDBStorage
     1415class HDHomeRunIP : public TransLabelSetting
     1416{
     1417  public:
     1418    HDHomeRunIP()
     1419    {
     1420        setLabel(QObject::tr("IP Address"));
     1421    };
     1422};
     1423
     1424class HDHomeRunTuner : public TransLabelSetting
     1425{
     1426  public:
     1427    HDHomeRunTuner()
     1428    {
     1429        setLabel(QObject::tr("Tuner"));
     1430    };
     1431};
     1432
     1433class HDHomeRunDeviceID : public ComboBoxSetting, public CaptureCardDBStorage
    14111434{
    14121435  public:
    14131436    HDHomeRunDeviceID(const CaptureCard &parent) :
    1414         LineEditSetting(this),
     1437        ComboBoxSetting(this),
    14151438        CaptureCardDBStorage(this, parent, "videodevice")
    14161439    {
    1417         setValue("FFFFFFFF");
    14181440        setLabel(QObject::tr("Device ID"));
    1419         setHelpText(QObject::tr("IP address or Device ID from the bottom of "
    1420                                 "the HDHomeRun.  You may use "
    1421                                 "'FFFFFFFF' if there is only one unit "
    1422                                 "on your your network."));
     1441        setHelpText(
     1442            QObject::tr("DevicedID and Tuner Number of available HDHomeRun "
     1443                        "devices. "));
     1444        fillSelections("");
     1445    };
     1446
     1447    /// \brief Adds all available device-tuner combinations to list
     1448    /// If current is >= 0 it will be considered available even
     1449    /// if no device exists for it on the network
     1450    void fillSelections(QString current)
     1451    {
     1452        clearSelections();
     1453
     1454        // Get devices from filesystem
     1455        vector<QString> devs = CardUtil::ProbeVideoDevices("HDHOMERUN");
     1456
     1457        // Add current if needed
     1458        if ((current != "") &&
     1459            (find(devs.begin(), devs.end(), current) == devs.end()))
     1460        {
     1461            devs.push_back(current);
     1462            stable_sort(devs.begin(), devs.end());
     1463        }
     1464
     1465        vector<QString> db = CardUtil::GetVideoDevices("HDHOMERUN");
     1466
     1467        QMap<QString, bool> in_use;
     1468        QString sel = current;
     1469        for (uint i = 0; i < devs.size(); i++)
     1470        {
     1471            const QString dev = devs[i];
     1472            in_use[devs[i]] = find(db.begin(), db.end(), dev) != db.end();
     1473            if (sel == "" && !in_use[devs[i]])
     1474                sel = dev;
     1475        }
     1476
     1477        if (sel == "" && devs.size())
     1478            sel = devs[0];
     1479 
     1480        QString usestr = QString(" -- ");
     1481        usestr += QObject::tr("Warning: already in use");
     1482
     1483        for (uint i = 0; i < devs.size(); i++)
     1484        {
     1485            const QString dev = devs[i];
     1486            QString desc = dev + (in_use[devs[i]] ? usestr : "");
     1487            desc = (current == devs[i]) ? dev : desc;
     1488            addSelection(desc, dev, dev == sel);
     1489        }
     1490    }
     1491
     1492    virtual void Load(void)
     1493    {
     1494        clearSelections();
     1495        addSelection("");
     1496
     1497        CaptureCardDBStorage::Load();
     1498
     1499        fillSelections(getValue());
    14231500    }
    14241501};
    14251502
    class IPTVConfigurationGroup : public Ve 
    14531530    CaptureCard &parent;
    14541531};
    14551532
    1456 class HDHomeRunTunerIndex : public ComboBoxSetting, public CaptureCardDBStorage
     1533class HDHomeRunExtra : public ConfigurationWizard
    14571534{
    14581535  public:
    1459     HDHomeRunTunerIndex(const CaptureCard &parent) :
    1460         ComboBoxSetting(this),
    1461         CaptureCardDBStorage(this, parent, "dbox2_port")
     1536    HDHomeRunExtra(HDHomeRunConfigurationGroup &parent);
     1537    uint GetInstanceCount(void) const
    14621538    {
    1463         setLabel(QObject::tr("Tuner"));
    1464         addSelection("0");
    1465         addSelection("1");
     1539        return (uint) count->intValue();
    14661540    }
     1541
     1542  private:
     1543    InstanceCount *count;
    14671544};
    14681545
     1546HDHomeRunExtra::HDHomeRunExtra(HDHomeRunConfigurationGroup &parent)
     1547    : count(new InstanceCount(parent.parent))
     1548{
     1549    VerticalConfigurationGroup* rec = new VerticalConfigurationGroup(false);
     1550    rec->setLabel(QObject::tr("Recorder Options"));
     1551    rec->setUseLabel(false);
     1552
     1553    rec->addChild(count);
     1554
     1555    addChild(rec);
     1556}
     1557
     1558
    14691559HDHomeRunConfigurationGroup::HDHomeRunConfigurationGroup
    14701560        (CaptureCard& a_parent) :
    14711561    VerticalConfigurationGroup(false, true, false, false),
    14721562    parent(a_parent)
    14731563{
    1474     HDHomeRunDeviceID *device = new HDHomeRunDeviceID(parent);
     1564    setUseLabel(false);
     1565    deviceid = new HDHomeRunDeviceID(parent);
     1566    addChild(deviceid);
     1567    cardip = new HDHomeRunIP();
     1568    cardtuner = new HDHomeRunTuner();
    14751569
    1476     desc = new TransLabelSetting();
     1570    addChild(cardip);
     1571    addChild(cardtuner);
    14771572
    1478     setUseLabel(false);
    1479     addChild(device);
    1480     addChild(desc);
    1481     addChild(new HDHomeRunTunerIndex(parent));
    14821573    addChild(new SignalTimeout(parent, 1000, 250));
    14831574    addChild(new ChannelTimeout(parent, 3000, 1750));
    14841575    addChild(new SingleCardInput(parent));
    14851576
     1577    TransButtonSetting *buttonRecOpt = new TransButtonSetting();
     1578    buttonRecOpt->setLabel(tr("Recording Options"));
     1579    addChild(buttonRecOpt);
    14861580
    14871581    // Wish we could use something like editingFinished() here...
    1488     connect(device, SIGNAL(valueChanged(const QString&)),
    1489             this,   SLOT(  probeCard(   const QString&)));
     1582    connect(deviceid,     SIGNAL(valueChanged(const QString&)),
     1583            this,         SLOT(  probeCard   (const QString&)));
     1584    connect(buttonRecOpt, SIGNAL(pressed()),
     1585            this,         SLOT(  HDHomeRunExtraPanel()));
     1586
     1587//    addChild(desc);
    14901588};
    14911589
    1492 void HDHomeRunConfigurationGroup::probeCard(const QString &device)
     1590void HDHomeRunConfigurationGroup::probeCard(const QString &deviceid)
    14931591{
    1494     if (device.contains('.') || device.contains(QRegExp("^[0-9a-fA-F]{8}$")))
    1495         desc->setValue(CardUtil::GetHDHRdesc(device));
     1592    hdhomerun_device_t* thisdevice = hdhomerun_device_create_from_str(deviceid.toLocal8Bit().constData());
     1593
     1594    if (thisdevice)
     1595    {
     1596        uint device_ip = hdhomerun_device_get_device_ip(thisdevice);
     1597        uint tuner     = hdhomerun_device_get_tuner(thisdevice);
     1598        hdhomerun_device_destroy(thisdevice);
     1599
     1600        QString ip = QString("%1.%2.%3.%4")
     1601                .arg((device_ip>>24) & 0xFF).arg((device_ip>>16) & 0xFF)
     1602                .arg((device_ip>> 8) & 0xFF).arg((device_ip>> 0) & 0xFF);
     1603
     1604        cardip->setValue(ip);
     1605        cardtuner->setValue(QString("%1").arg(tuner));
     1606    }
    14961607    else
    1497         desc->setValue(tr("Badly formatted Device ID"));
     1608    {
     1609        cardip->setValue("Unknown");
     1610        cardtuner->setValue("Unknown");
     1611    }
     1612}
     1613
     1614void HDHomeRunConfigurationGroup::HDHomeRunExtraPanel(void)
     1615{
     1616    parent.reload(); // ensure card id is valid
     1617
     1618    HDHomeRunExtra acw(*this);
     1619    acw.exec();
     1620    parent.SetInstanceCount(acw.GetInstanceCount());
    14981621}
    14991622
    15001623V4LConfigurationGroup::V4LConfigurationGroup(CaptureCard& a_parent) :
    void CaptureCard::fillSelections(SelectS 
    17101833        if ((cardtype.toLower() == "dvb") && (1 != ++device_refs[videodevice]))
    17111834            continue;
    17121835
     1836        if ((cardtype.toLower() == "hdhomerun") && (1 != ++device_refs[videodevice]))
     1837            continue;
     1838
    17131839        QString label = CardUtil::GetDeviceLabel(
    17141840            cardid, cardtype, videodevice);
    17151841
    void CardInputEditor::Load(void) 
    28532979        if ((cardtype.toLower() == "dvb") && (1 != ++device_refs[videodevice]))
    28542980            continue;
    28552981
     2982        if ((cardtype.toLower() == "hdhomerun") && (1 != ++device_refs[videodevice]))
     2983            continue;
     2984
    28562985        QStringList        inputLabels;
    28572986        vector<CardInput*> cardInputs;
    28582987
  • mythtv/libs/libmythtv/videosource.h

    diff -p -r -u -N -X /tmp/diff.exclude.17976 -x myth.20713.0616a -x myth.20713.0616b myth.20713.0616a/mythtv/libs/libmythtv/videosource.h myth.20713.0616b/mythtv/libs/libmythtv/videosource.h
    public: 
    442442    static void fillSelections(SelectSetting* setting);
    443443};
    444444
     445class HDHomeRunDeviceID;
     446class HDHomeRunIP;
     447class HDHomeRunTuner;
    445448class HDHomeRunConfigurationGroup : public VerticalConfigurationGroup
    446449{
    447450    Q_OBJECT
    448451
     452    friend class HDHomeRunExtra;
     453
    449454  public:
    450455    HDHomeRunConfigurationGroup(CaptureCard &parent);
    451456
    452457  public slots:
    453458    void probeCard(const QString &device);
     459    void HDHomeRunExtraPanel(void);
    454460
    455461  private:
     462    HDHomeRunDeviceID *deviceid;
     463    HDHomeRunIP       *cardip;
     464    HDHomeRunTuner    *cardtuner;
     465
    456466    CaptureCard       &parent;
    457467    TransLabelSetting *desc;
    458468};