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

File 133-hdhr.multirec.8.trunk.patch, 105.4 KB (added by cizek@…, 12 years ago)

Patch against trunk v20018

  • mythtv/libs/libmythtv/cardutil.cpp

    diff -r -u -N -X diff.exclude -x myth.20018.0218a -x myth.20018.0218b myth.20018.0218a/mythtv/libs/libmythtv/cardutil.cpp myth.20018.0218b/mythtv/libs/libmythtv/cardutil.cpp
     
    2929#include "videodev_myth.h"
    3030#endif
    3131
     32#include "hdhomerun_includes.h"
     33
    3234#define LOC      QString("CardUtil: ")
    3335#define LOC_WARN QString("CardUtil, Warning: ")
    3436#define LOC_ERR  QString("CardUtil, Error: ")
     
    210212                devs.push_back(subit->filePath());
    211213        }
    212214    }
     215    else if (rawtype.toUpper() == "HDHOMERUN")
     216    {
     217
     218        uint32_t  target_ip   = 0;
     219        uint32_t  device_type = HDHOMERUN_DEVICE_TYPE_TUNER;
     220        uint32_t  device_id   = HDHOMERUN_DEVICE_ID_WILDCARD;
     221        const int max_count   = 50;
     222        hdhomerun_discover_device_t result_list[max_count];
     223
     224        int result = hdhomerun_discover_find_devices_custom(
     225                            target_ip,
     226                            device_type,
     227                            device_id,
     228                            result_list,
     229                            max_count);
     230
     231        if (result == -1)
     232        {
     233            VERBOSE(VB_IMPORTANT, "CardUtil::ProbeVideoDevices: Error finding HDHomerun devices");
     234            return devs;
     235        }
     236
     237        if (result == 20)
     238            VERBOSE(VB_IMPORTANT, "CardUtil::ProbeVideoDevices: Warning: may be > 20 HDHomerun devices");
     239
     240        // Fixme -- figure out some way to return ip address as well
     241        for (int i = 0; i < result; i++)
     242        {
     243            QString did = QString("%1").arg(result_list[i].device_id,0, 16);
     244            did=did.toUpper();
     245
     246            devs.push_back(did + "-0");
     247            devs.push_back(did + "-1");
     248        }
     249    }
    213250    else
    214251    {
    215252        VERBOSE(VB_IMPORTANT, QString("CardUtil::ProbeVideoDevices: ") +
     
    11461183        uint id = 0;
    11471184        for (uint i = 0; !id && (i < 100); i++)
    11481185        {
    1149             name = QString("DVB%1").arg(dev.toUInt());
     1186            bool ok;
     1187            name = QString("DVB%1").arg(dev.toUInt(&ok));
     1188            if (! ok)
     1189            {
     1190                name = QString("HDHR_%1").arg(dev);
     1191            }
    11501192            name += (i) ? QString(":%1").arg(i) : QString("");
    11511193            id = CardUtil::CreateInputGroup(name);
    11521194        }
     
    17491791    }
    17501792    else if (cardtype == "HDHOMERUN")
    17511793    {
    1752         MSqlQuery query(MSqlQuery::InitCon());
    1753         query.prepare(
    1754             "SELECT dbox2_port "
    1755             "FROM capturecard "
    1756             "WHERE cardid = :CARDID");
    1757         query.bindValue(":CARDID", cardid);
    1758 
    1759         if (!query.exec() || !query.isActive() || !query.next())
    1760             label = "[ DB ERROR ]";
    1761         else
    1762             label = QString("[ HDHomeRun : ID %1 Port %2 ]")
    1763                 .arg(videodevice).arg(query.value(0).toString());
     1794        label = QString("[ HDHomeRun : %1 ]").arg(videodevice);
    17641795    }
    17651796    else
    17661797    {
  • mythtv/libs/libmythtv/cardutil.h

    diff -r -u -N -X diff.exclude -x myth.20018.0218a -x myth.20018.0218b myth.20018.0218a/mythtv/libs/libmythtv/cardutil.h myth.20018.0218b/mythtv/libs/libmythtv/cardutil.h
     
    115115
    116116    static bool         IsTunerSharingCapable(const QString &rawtype)
    117117    {
    118         return (rawtype == "DVB");
     118        return (rawtype == "DVB")   || (rawtype == "HDHOMERUN");
    119119    }
    120120
    121121    static bool         IsTunerShared(uint cardidA, uint cardidB);
  • mythtv/libs/libmythtv/hdhomerun_includes.h

    diff -r -u -N -X diff.exclude -x myth.20018.0218a -x myth.20018.0218b myth.20018.0218a/mythtv/libs/libmythtv/hdhomerun_includes.h myth.20018.0218b/mythtv/libs/libmythtv/hdhomerun_includes.h
     
     1#ifndef __HDHOMERUN_INCLUDES__
     2#define __HDHOMERUN_INCLUDES__
     3
     4#include "hdhomerun.h"
     5
     6#endif /* __HDHOMERUN_INCLUDES__ */
     7
  • mythtv/libs/libmythtv/hdhrchannel.cpp

    diff -r -u -N -X diff.exclude -x myth.20018.0218a -x myth.20018.0218b myth.20018.0218a/mythtv/libs/libmythtv/hdhrchannel.cpp myth.20018.0218b/mythtv/libs/libmythtv/hdhrchannel.cpp
     
    2727#include "channelutil.h"
    2828#include "frequencytables.h"
    2929
     30#include "hdhrstreamhandler.h"
     31
    3032#define DEBUG_PID_FILTERS
    3133
    3234#define LOC     QString("HDHRChan(%1): ").arg(GetDevice())
    3335#define LOC_ERR QString("HDHRChan(%1), Error: ").arg(GetDevice())
    3436
    35 HDHRChannel::HDHRChannel(TVRec *parent, const QString &device, uint tuner)
    36     : DTVChannel(parent),       _control_socket(NULL),
    37       _device_id(0),            _device_ip(0),
    38       _tuner(tuner),            _lock(QMutex::Recursive)
    39 {
    40     bool valid;
    41     _device_id = device.toUInt(&valid, 16);
    42 
    43     if (valid && hdhomerun_discover_validate_device_id(_device_id))
    44         return;
    45 
    46     /* Otherwise, is it a valid IP address? */
    47     struct in_addr address;
    48     if (inet_aton(device.toLatin1().constData(), &address))
    49     {
    50         _device_ip = ntohl(address.s_addr);
    51         return;
    52     }
    53 
    54     /* Invalid, use wildcard device ID. */
    55     VERBOSE(VB_IMPORTANT, LOC_ERR + QString("Invalid DeviceID '%1'")
    56             .arg(device));
    57 
    58     _device_id = HDHOMERUN_DEVICE_ID_WILDCARD;
     37HDHRChannel::HDHRChannel(TVRec *parent, const QString &device)
     38    : DTVChannel(parent),       _stream_handler(NULL),
     39      _device_id(device),       _lock(QMutex::Recursive),
     40      tune_lock(QMutex::Recursive),
     41      hw_lock(QMutex::Recursive)
     42{
    5943}
    6044
    6145HDHRChannel::~HDHRChannel(void)
     
    6549
    6650bool HDHRChannel::Open(void)
    6751{
     52    VERBOSE(VB_CHANNEL, LOC + "Opening HDHR channel");
     53
     54    QMutexLocker locker(&hw_lock);
     55   
    6856    if (IsOpen())
    6957        return true;
    7058
    71     if (!FindDevice())
    72         return false;
     59    _stream_handler = HDHRStreamHandler::Get(_device_id);
    7360
    7461    if (!InitializeInputs())
    75         return false;
    76 
    77     return (_device_ip != 0) && Connect();
    78 }
    79 
    80 void HDHRChannel::Close(void)
    81 {
    82     if (_control_socket)
    83     {
    84         hdhomerun_control_destroy(_control_socket);
    85         _control_socket = NULL;
    86     }
    87 }
    88 
    89 bool HDHRChannel::EnterPowerSavingMode(void)
    90 {
    91     return QString::null != TunerSet("channel", "none", false);
    92 }
    93 
    94 bool HDHRChannel::FindDevice(void)
    95 {
    96     if (!_device_id)
    97         return _device_ip;
    98 
    99     _device_ip = 0;
    100 
    101     /* Discover. */
    102     struct hdhomerun_discover_device_t result;
    103     int ret = hdhomerun_discover_find_devices_custom(
    104                   0, HDHOMERUN_DEVICE_TYPE_WILDCARD, _device_id, &result, 1);
    105     if (ret < 0)
    106     {
    107         VERBOSE(VB_IMPORTANT,
    108                 LOC_ERR + "Unable to send discovery request" + ENO);
    109         return false;
    110     }
    111     if (ret == 0)
    112     {
    113         VERBOSE(VB_IMPORTANT, LOC_ERR + QString("device not found"));
    114         return false;
    115     }
    116 
    117     /* Found. */
    118     _device_ip = result.ip_addr;
    119 
    120     VERBOSE(VB_IMPORTANT, LOC +
    121             QString("device found at address %1.%2.%3.%4")
    122             .arg((_device_ip>>24) & 0xFF).arg((_device_ip>>16) & 0xFF)
    123             .arg((_device_ip>> 8) & 0xFF).arg((_device_ip>> 0) & 0xFF));
    124 
    125     return true;
    126 }
    127 
    128 bool HDHRChannel::Connect(void)
    129 {
    130     _control_socket = hdhomerun_control_create(_device_id, _device_ip);
    131     if (!_control_socket)
    13262    {
    133         VERBOSE(VB_IMPORTANT, LOC_ERR + "Unable to create control socket");
     63        Close();
    13464        return false;
    13565    }
    13666
    137     if (hdhomerun_control_get_local_addr(_control_socket) == 0)
    138     {
    139         VERBOSE(VB_IMPORTANT, LOC_ERR + "Unable to connect to device");
    140         return false;
    141     }
    142 
    143     VERBOSE(VB_CHANNEL, LOC + "Successfully connected to device");
    144     return true;
    145 }
    146 
    147 QString HDHRChannel::DeviceGet(const QString &name, bool report_error_return)
    148 {
    149     QMutexLocker locker(&_lock);
    150 
    151     if (!_control_socket)
    152     {
    153         VERBOSE(VB_IMPORTANT, LOC_ERR + "Get request failed (not connected)");
    154         return QString::null;
    155     }
    156 
    157     char *value = NULL;
    158     char *error = NULL;
    159     if (hdhomerun_control_get(_control_socket, name.toLatin1().constData(),
    160                               &value, &error) < 0)
    161     {
    162         VERBOSE(VB_IMPORTANT, LOC_ERR + "Get request failed" + ENO);
    163         return QString::null;
    164     }
    165 
    166     if (report_error_return && error)
    167     {
    168         VERBOSE(VB_IMPORTANT, LOC_ERR +
    169                 QString("DeviceGet(%1): %2").arg(name).arg(error));
    170 
    171         return QString::null;
    172     }
    173 
    174     return QString(value);
     67    return _stream_handler->Connected();
    17568}
    17669
    177 QString HDHRChannel::DeviceSet(const QString &name, const QString &val,
    178                                bool report_error_return)
     70void HDHRChannel::Close(void)
    17971{
    180     QMutexLocker locker(&_lock);
    181 
    182     if (!_control_socket)
    183     {
    184         VERBOSE(VB_IMPORTANT, LOC_ERR + "Set request failed (not connected)");
    185         return QString::null;
    186     }
    187 
    188     char *value = NULL;
    189     char *error = NULL;
    190     if (hdhomerun_control_set(_control_socket, name.toLatin1().constData(),
    191                               val.toAscii().constData(), &value, &error) < 0)
    192     {
    193         VERBOSE(VB_IMPORTANT, LOC_ERR + "Set request failed" + ENO);
     72    VERBOSE(VB_CHANNEL, LOC + "Closing HDHR channel");
    19473
    195         return QString::null;
    196     }
    197 
    198     if (report_error_return && error)
    199     {
    200         VERBOSE(VB_IMPORTANT, LOC_ERR +
    201                 QString("DeviceSet(%1 %2): %3").arg(name).arg(val).arg(error));
    202 
    203         return QString::null;
    204     }
     74        if (! IsOpen())
     75        return; // this caller didn't have it open in the first place..
    20576
    206     return QString(value);
     77    HDHRStreamHandler::Return(_stream_handler);
    20778}
    20879
    209 QString HDHRChannel::TunerGet(const QString &name, bool report_error_return)
     80bool HDHRChannel::EnterPowerSavingMode(void)
    21081{
    211     return DeviceGet(QString("/tuner%1/%2").arg(_tuner).arg(name),
    212                      report_error_return);
     82    if ( IsOpen())
     83        return _stream_handler->EnterPowerSavingMode();
     84    else
     85        return true;
    21386}
    21487
    215 QString HDHRChannel::TunerSet(const QString &name, const QString &value,
    216                               bool report_error_return)
     88bool HDHRChannel::IsOpen(void) const
    21789{
    218     return DeviceSet(QString("/tuner%1/%2").arg(_tuner).arg(name), value,
    219                      report_error_return);
     90      return (_stream_handler != NULL);
    22091}
    22192
    222 bool HDHRChannel::DeviceSetTarget(unsigned short localPort)
     93bool HDHRChannel::Init(QString &inputname, QString &startchannel, bool setchan)
    22394{
    224     if (localPort == 0)
    225     {
    226         return false;
    227     }
    228 
    229     unsigned long localIP = hdhomerun_control_get_local_addr(_control_socket);
    230     if (localIP == 0)
    231     {
    232         return false;
    233     }
    234 
    235     QString configValue = QString("%1.%2.%3.%4:%5")
    236         .arg((localIP >> 24) & 0xFF).arg((localIP >> 16) & 0xFF)
    237         .arg((localIP >>  8) & 0xFF).arg((localIP >>  0) & 0xFF)
    238         .arg(localPort);
    239 
    240     if (TunerSet("target", configValue).isEmpty())
    241     {
    242         return false;
    243     }
     95    if (setchan && !IsOpen())
     96        Open();
    24497
    245     return true;
    246 }
    247 
    248 bool HDHRChannel::DeviceClearTarget()
    249 {
    250     return !TunerSet("target", "0.0.0.0:0").isEmpty();
     98    return ChannelBase::Init(inputname, startchannel, setchan);
    25199}
    252100
    253101bool HDHRChannel::SetChannelByString(const QString &channum)
     
    281129        return SwitchToInput(inputName, channum);
    282130
    283131    ClearDTVInfo();
    284     _ignore_filters = false;
    285132
    286133    InputMap::const_iterator it = inputs.find(currentInputID);
    287134    if (it == inputs.end())
     
    355202    if (mpeg_prog_num && (GetTuningMode() == "mpeg"))
    356203    {
    357204        QString pnum = QString::number(mpeg_prog_num);
    358         _ignore_filters = QString::null != TunerSet("program", pnum, false);
     205        //_ignore_filters = _stream_handler->TuneProgram(pnum);
     206        _stream_handler->TuneProgram(pnum);
    359207    }
    360208
    361209    return true;
     
    417265
    418266    name.append(':' + QString::number(frequency));
    419267
    420     ok = ! TunerSet("channel", name).isEmpty();
     268    ok = _stream_handler->TuneChannel(name);
    421269
    422270    if (ok)
    423271        SetSIStandard(si_std);
     
    425273    return ok;
    426274}
    427275
    428 bool HDHRChannel::AddPID(uint pid, bool do_update)
    429 {
    430     QMutexLocker locker(&_lock);
    431 
    432     vector<uint>::iterator it;
    433     it = lower_bound(_pids.begin(), _pids.end(), pid);
    434     if (it != _pids.end() && *it == pid)
    435     {
    436 #ifdef DEBUG_PID_FILTERS
    437         VERBOSE(VB_CHANNEL, "AddPID(0x"<<hex<<pid<<dec<<") NOOP");
    438 #endif // DEBUG_PID_FILTERS
    439         return true;
    440     }
    441 
    442     _pids.insert(it, pid);
    443 
    444 #ifdef DEBUG_PID_FILTERS
    445     VERBOSE(VB_CHANNEL, "AddPID(0x"<<hex<<pid<<dec<<")");
    446 #endif // DEBUG_PID_FILTERS
    447 
    448     if (do_update)
    449         return UpdateFilters();
    450     return true;
    451 }
    452 
    453 bool HDHRChannel::DelPID(uint pid, bool do_update)
    454 {
    455     QMutexLocker locker(&_lock);
    456 
    457     vector<uint>::iterator it;
    458     it = lower_bound(_pids.begin(), _pids.end(), pid);
    459     if (it == _pids.end())
    460     {
    461 #ifdef DEBUG_PID_FILTERS
    462         VERBOSE(VB_CHANNEL, "DelPID(0x"<<hex<<pid<<dec<<") NOOP");
    463 #endif // DEBUG_PID_FILTERS
    464 
    465        return true;
    466     }
    467 
    468     if (*it == pid)
    469     {
    470 #ifdef DEBUG_PID_FILTERS
    471         VERBOSE(VB_CHANNEL, "DelPID(0x"<<hex<<pid<<dec<<") -- found");
    472 #endif // DEBUG_PID_FILTERS
    473         _pids.erase(it);
    474     }
    475     else
    476     {
    477 #ifdef DEBUG_PID_FILTERS
    478         VERBOSE(VB_CHANNEL, "DelPID(0x"<<hex<<pid<<dec<<") -- failed");
    479 #endif // DEBUG_PID_FILTERS
    480     }
    481 
    482     if (do_update)
    483         return UpdateFilters();
    484     return true;
    485 }
    486 
    487 bool HDHRChannel::DelAllPIDs(void)
    488 {
    489     QMutexLocker locker(&_lock);
    490 
    491 #ifdef DEBUG_PID_FILTERS
    492     VERBOSE(VB_CHANNEL, "DelAllPID()");
    493 #endif // DEBUG_PID_FILTERS
    494 
    495     _pids.clear();
    496 
    497     return UpdateFilters();
    498 }
    499 
    500 QString filt_str(uint pid)
    501 {
    502     uint pid0 = (pid / (16*16*16)) % 16;
    503     uint pid1 = (pid / (16*16))    % 16;
    504     uint pid2 = (pid / (16))        % 16;
    505     uint pid3 = pid % 16;
    506     return QString("0x%1%2%3%4")
    507         .arg(pid0,0,16).arg(pid1,0,16)
    508         .arg(pid2,0,16).arg(pid3,0,16);
    509 }
    510 
    511 bool HDHRChannel::UpdateFilters(void)
    512 {
    513     QMutexLocker locker(&_lock);
    514 
    515     QString filter = "";
    516 
    517     vector<uint> range_min;
    518     vector<uint> range_max;
    519 
    520     if (_ignore_filters)
    521         return true;
    522 
    523     for (uint i = 0; i < _pids.size(); i++)
    524     {
    525         uint pid_min = _pids[i];
    526         uint pid_max  = pid_min;
    527         for (uint j = i + 1; j < _pids.size(); j++)
    528         {
    529             if (pid_max + 1 != _pids[j])
    530                 break;
    531             pid_max++;
    532             i++;
    533         }
    534         range_min.push_back(pid_min);
    535         range_max.push_back(pid_max);
    536     }
    537 
    538     if (range_min.size() > 16)
    539     {
    540         range_min.resize(16);
    541         uint pid_max = range_max.back();
    542         range_max.resize(15);
    543         range_max.push_back(pid_max);
    544     }
    545 
    546     for (uint i = 0; i < range_min.size(); i++)
    547     {
    548         filter += filt_str(range_min[i]);
    549         if (range_min[i] != range_max[i])
    550             filter += QString("-%1").arg(filt_str(range_max[i]));
    551         filter += " ";
    552     }
    553 
    554     filter = filter.trimmed();
    555 
    556     QString new_filter = TunerSet("filter", filter);
    557 
    558 #ifdef DEBUG_PID_FILTERS
    559     QString msg = QString("Filter: '%1'").arg(filter);
    560     if (filter != new_filter)
    561         msg += QString("\n\t\t\t\t'%2'").arg(new_filter);
    562 
    563     VERBOSE(VB_CHANNEL, msg);
    564 #endif // DEBUG_PID_FILTERS
    565 
    566     return filter == new_filter;
    567 }
  • mythtv/libs/libmythtv/hdhrchannel.cpp.rej.fixed

    diff -r -u -N -X diff.exclude -x myth.20018.0218a -x myth.20018.0218b myth.20018.0218a/mythtv/libs/libmythtv/hdhrchannel.cpp.rej.fixed myth.20018.0218b/mythtv/libs/libmythtv/hdhrchannel.cpp.rej.fixed
     
     1***************
     2*** 26,61 ****
     3  #include "channelutil.h"
     4  #include "frequencytables.h"
     5 
     6  #define DEBUG_PID_FILTERS
     7 
     8  #define LOC QString("HDHRChan(%1): ").arg(GetDevice())
     9  #define LOC_ERR QString("HDHRChan(%1), Error: ").arg(GetDevice())
     10 
     11- HDHRChannel::HDHRChannel(TVRec *parent, const QString &device, uint tuner)
     12-     : DTVChannel(parent),       _control_socket(NULL),
     13-       _device_id(0),            _device_ip(0),
     14-       _tuner(tuner),            _lock(true)
     15- {
     16-     bool valid;
     17-     _device_id = device.toUInt(&valid, 16);
     18-
     19-     if (valid && hdhomerun_discover_validate_device_id(_device_id))
     20-       return;
     21-
     22-     _device_id = HDHOMERUN_DEVICE_ID_WILDCARD;
     23-     /* Otherwise, is it a valid IP address? */
     24-     struct in_addr address;
     25-     if (inet_aton(device, &address))
     26-     {
     27-       _device_ip = ntohl(address.s_addr);
     28-       return;
     29-     }
     30-
     31-     /* Invalid, use wildcard device ID. */
     32-     VERBOSE(VB_IMPORTANT, LOC_ERR + QString("Invalid DeviceID '%1'")
     33-           .arg(device));
     34-
     35-     _device_id = HDHOMERUN_DEVICE_ID_WILDCARD;
     36  }
     37 
     38  HDHRChannel::~HDHRChannel(void)
     39--- 26,43 ----
     40  #include "channelutil.h"
     41  #include "frequencytables.h"
     42 
     43+ #include "hdhrstreamhandler.h"
     44+
     45  #define DEBUG_PID_FILTERS
     46 
     47  #define LOC QString("HDHRChan(%1): ").arg(GetDevice())
     48  #define LOC_ERR QString("HDHRChan(%1), Error: ").arg(GetDevice())
     49 
     50+ HDHRChannel::HDHRChannel(TVRec *parent, const QString &device)
     51+     : DTVChannel(parent),       _stream_handler(NULL),
     52+       _device_id(device),            _lock(true),
     53+       tune_lock(true),          hw_lock(true)
     54+ {
     55  }
     56 
     57  HDHRChannel::~HDHRChannel(void)
     58***************
     59*** 65,249 ****
     60 
     61  bool HDHRChannel::Open(void)
     62  {
     63      if (IsOpen())
     64          return true;
     65 
     66-     if (!FindDevice())
     67-         return false;
     68 
     69      if (!InitializeInputs())
     70-         return false;
     71-
     72-     return (_device_ip != 0) && Connect();
     73- }
     74-
     75- void HDHRChannel::Close(void)
     76- {
     77-     if (_control_socket)
     78-     {
     79-         hdhomerun_control_destroy(_control_socket);
     80-         _control_socket = NULL;
     81-     }
     82- }
     83-
     84- bool HDHRChannel::EnterPowerSavingMode(void)
     85- {
     86-     return QString::null != TunerSet("channel", "none", false);
     87- }
     88-
     89- bool HDHRChannel::FindDevice(void)
     90- {
     91-     if (!_device_id)
     92-         return _device_ip;
     93-
     94-     _device_ip = 0;
     95-
     96-     /* Discover. */
     97-     struct hdhomerun_discover_device_t result;
     98-     int ret = hdhomerun_discover_find_devices_custom(0, HDHOMERUN_DEVICE_TYPE_WILDCARD, _device_id, &result, 1);
     99-     if (ret < 0)
     100-     {
     101-         VERBOSE(VB_IMPORTANT, LOC_ERR + "Unable to send discovery request" + ENO);
     102-         return false;
     103-     }
     104-     if (ret == 0)
     105      {
     106-         VERBOSE(VB_IMPORTANT, LOC_ERR + QString("device not found"));
     107          return false;
     108      }
     109 
     110-     /* Found. */
     111-     _device_ip = result.ip_addr;
     112 
     113-     VERBOSE(VB_IMPORTANT, LOC +
     114-             QString("device found at address %1.%2.%3.%4")
     115-             .arg((_device_ip>>24) & 0xFF).arg((_device_ip>>16) & 0xFF)
     116-             .arg((_device_ip>> 8) & 0xFF).arg((_device_ip>> 0) & 0xFF));
     117 
     118-     return true;
     119  }
     120 
     121- bool HDHRChannel::Connect(void)
     122  {
     123-     _control_socket = hdhomerun_control_create(_device_id, _device_ip);
     124-     if (!_control_socket)
     125-     {
     126-         VERBOSE(VB_IMPORTANT, LOC_ERR + "Unable to create control socket");
     127-         return false;
     128-     }
     129 
     130-     if (hdhomerun_control_get_local_addr(_control_socket) == 0)
     131-     {
     132-         VERBOSE(VB_IMPORTANT, LOC_ERR + "Unable to connect to device");
     133-         return false;
     134-     }
     135 
     136-     VERBOSE(VB_CHANNEL, LOC + "Successfully connected to device");
     137-     return true;
     138  }
     139 
     140- QString HDHRChannel::DeviceGet(const QString &name, bool report_error_return)
     141- {
     142-     QMutexLocker locker(&_lock);
     143-
     144-     if (!_control_socket)
     145-     {
     146-         VERBOSE(VB_IMPORTANT, LOC_ERR + "Get request failed (not connected)");
     147-         return QString::null;
     148-     }
     149-
     150-     char *value = NULL;
     151-     char *error = NULL;
     152-     if (hdhomerun_control_get(_control_socket, name, &value, &error) < 0)
     153-     {
     154-         VERBOSE(VB_IMPORTANT, LOC_ERR + "Get request failed" + ENO);
     155-         return QString::null;
     156-     }
     157-
     158-     if (report_error_return && error)
     159-     {
     160-         VERBOSE(VB_IMPORTANT, LOC_ERR +
     161-                 QString("DeviceGet(%1): %2").arg(name).arg(error));
     162-
     163-         return QString::null;
     164-     }
     165-
     166-     return QString(value);
     167- }
     168-
     169- QString HDHRChannel::DeviceSet(const QString &name, const QString &val,
     170-                                bool report_error_return)
     171  {
     172-     QMutexLocker locker(&_lock);
     173-
     174-     if (!_control_socket)
     175-     {
     176-         VERBOSE(VB_IMPORTANT, LOC_ERR + "Set request failed (not connected)");
     177-         return QString::null;
     178-     }
     179-
     180-     char *value = NULL;
     181-     char *error = NULL;
     182-     if (hdhomerun_control_set(_control_socket, name, val, &value, &error) < 0)
     183-     {
     184-         VERBOSE(VB_IMPORTANT, LOC_ERR + "Set request failed" + ENO);
     185-
     186-         return QString::null;
     187-     }
     188-
     189-     if (report_error_return && error)
     190-     {
     191-         VERBOSE(VB_IMPORTANT, LOC_ERR +
     192-                 QString("DeviceSet(%1 %2): %3").arg(name).arg(val).arg(error));
     193-
     194-         return QString::null;
     195-     }
     196-
     197-     return QString(value);
     198  }
     199 
     200- QString HDHRChannel::TunerGet(const QString &name, bool report_error_return)
     201- {
     202-     return DeviceGet(QString("/tuner%1/%2").arg(_tuner).arg(name),
     203-                      report_error_return);
     204- }
     205 
     206- QString HDHRChannel::TunerSet(const QString &name, const QString &value,
     207-                               bool report_error_return)
     208  {
     209-     return DeviceSet(QString("/tuner%1/%2").arg(_tuner).arg(name), value,
     210-                      report_error_return);
     211  }
     212 
     213- bool HDHRChannel::DeviceSetTarget(unsigned short localPort)
     214  {
     215-     if (localPort == 0)
     216-     {
     217-         return false;
     218-     }
     219 
     220-     unsigned long localIP = hdhomerun_control_get_local_addr(_control_socket);
     221-     if (localIP == 0)
     222-     {
     223-         return false;
     224-     }
     225-
     226-     QString configValue = QString("%1.%2.%3.%4:%5")
     227-         .arg((localIP >> 24) & 0xFF).arg((localIP >> 16) & 0xFF)
     228-         .arg((localIP >>  8) & 0xFF).arg((localIP >>  0) & 0xFF)
     229-         .arg(localPort);
     230-
     231-     if (!TunerSet("target", configValue))
     232-     {
     233-         return false;
     234-     }
     235-
     236-     return true;
     237- }
     238-
     239- bool HDHRChannel::DeviceClearTarget()
     240- {
     241-     return TunerSet("target", "0.0.0.0:0");
     242  }
     243 
     244  bool HDHRChannel::SetChannelByString(const QString &channum)
     245--- 47,103 ----
     246 
     247  bool HDHRChannel::Open(void)
     248  {
     249+     VERBOSE(VB_CHANNEL, LOC + "Opening HDHR channel");
     250+
     251+     QMutexLocker locker(&hw_lock);
     252+
     253      if (IsOpen())
     254          return true;
     255 
     256+     _stream_handler = HDHRStreamHandler::Get(_device_id);
     257 
     258      if (!InitializeInputs())
     259      {
     260+         Close();
     261          return false;
     262      }
     263 
     264+ //  nextInputID = currentInputID;
     265 
     266+     return _stream_handler->Connected();
     267 
     268  }
     269 
     270+ void HDHRChannel::Close()
     271  {
     272+     VERBOSE(VB_CHANNEL, LOC + "Closing HDHR channel");
     273 
     274+     if (! IsOpen())
     275+         return; // this caller didn't have it open in the first place..
     276 
     277+     HDHRStreamHandler::Return(_stream_handler);
     278  }
     279 
     280+ bool HDHRChannel::EnterPowerSavingMode(void)
     281  {
     282+     if ( IsOpen())
     283+         return _stream_handler->EnterPowerSavingMode();
     284+     else
     285+         return true;
     286  }
     287 
     288 
     289+ bool HDHRChannel::IsOpen(void) const
     290  {
     291+       return (_stream_handler != NULL);
     292  }
     293 
     294+ bool HDHRChannel::Init(QString &inputname, QString &startchannel, bool setchan)
     295  {
     296+     if (setchan && !IsOpen())
     297+         Open();
     298 
     299+     return ChannelBase::Init(inputname, startchannel, setchan);
     300  }
     301 
     302  bool HDHRChannel::SetChannelByString(const QString &channum)
     303***************
     304*** 400,554 ****
     305              QString("TuneTo(%1,%2)").arg(frequency).arg(modulation));
     306 
     307      if (modulation == "8vsb")
     308-         ok = TunerSet("channel", QString("8vsb:%1").arg(frequency));
     309      else if (modulation == "qam_64")
     310-         ok = TunerSet("channel", QString("qam64:%1").arg(frequency));
     311      else if (modulation == "qam_256")
     312-         ok = TunerSet("channel", QString("qam256:%1").arg(frequency));
     313 
     314      if (ok)
     315          SetSIStandard(si_std);
     316 
     317      return ok;
     318  }
     319-
     320- bool HDHRChannel::AddPID(uint pid, bool do_update)
     321- {
     322-     QMutexLocker locker(&_lock);
     323-
     324-     vector<uint>::iterator it;
     325-     it = lower_bound(_pids.begin(), _pids.end(), pid);
     326-     if (it != _pids.end() && *it == pid)
     327-     {
     328- #ifdef DEBUG_PID_FILTERS
     329-         VERBOSE(VB_CHANNEL, "AddPID(0x"<<hex<<pid<<dec<<") NOOP");
     330- #endif // DEBUG_PID_FILTERS
     331-         return true;
     332-     }
     333-
     334-     _pids.insert(it, pid);
     335-
     336- #ifdef DEBUG_PID_FILTERS
     337-     VERBOSE(VB_CHANNEL, "AddPID(0x"<<hex<<pid<<dec<<")");
     338- #endif // DEBUG_PID_FILTERS
     339-
     340-     if (do_update)
     341-         return UpdateFilters();
     342-     return true;
     343- }
     344-
     345- bool HDHRChannel::DelPID(uint pid, bool do_update)
     346- {
     347-     QMutexLocker locker(&_lock);
     348-
     349-     vector<uint>::iterator it;
     350-     it = lower_bound(_pids.begin(), _pids.end(), pid);
     351-     if (it == _pids.end())
     352-     {
     353- #ifdef DEBUG_PID_FILTERS
     354-         VERBOSE(VB_CHANNEL, "DelPID(0x"<<hex<<pid<<dec<<") NOOP");
     355- #endif // DEBUG_PID_FILTERS
     356-
     357-        return true;
     358-     }
     359-
     360-     if (*it == pid)
     361-     {
     362- #ifdef DEBUG_PID_FILTERS
     363-         VERBOSE(VB_CHANNEL, "DelPID(0x"<<hex<<pid<<dec<<") -- found");
     364- #endif // DEBUG_PID_FILTERS
     365-         _pids.erase(it);
     366-     }
     367-     else
     368-     {
     369- #ifdef DEBUG_PID_FILTERS
     370-         VERBOSE(VB_CHANNEL, "DelPID(0x"<<hex<<pid<<dec<<") -- failed");
     371- #endif // DEBUG_PID_FILTERS
     372-     }
     373-
     374-     if (do_update)
     375-         return UpdateFilters();
     376-     return true;
     377- }
     378-
     379- bool HDHRChannel::DelAllPIDs(void)
     380- {
     381-     QMutexLocker locker(&_lock);
     382-
     383- #ifdef DEBUG_PID_FILTERS
     384-     VERBOSE(VB_CHANNEL, "DelAllPID()");
     385- #endif // DEBUG_PID_FILTERS
     386-
     387-     _pids.clear();
     388-
     389-     return UpdateFilters();
     390- }
     391-
     392- QString filt_str(uint pid)
     393- {
     394-     uint pid0 = (pid / (16*16*16)) % 16;
     395-     uint pid1 = (pid / (16*16))    % 16;
     396-     uint pid2 = (pid / (16))        % 16;
     397-     uint pid3 = pid % 16;
     398-     return QString("0x%1%2%3%4")
     399-         .arg(pid0,0,16).arg(pid1,0,16)
     400-         .arg(pid2,0,16).arg(pid3,0,16);
     401- }
     402-
     403- bool HDHRChannel::UpdateFilters(void)
     404- {
     405-     QMutexLocker locker(&_lock);
     406-
     407-     QString filter = "";
     408-
     409-     vector<uint> range_min;
     410-     vector<uint> range_max;
     411-
     412-     if (_ignore_filters)
     413-         return true;
     414-
     415-     for (uint i = 0; i < _pids.size(); i++)
     416-     {
     417-         uint pid_min = _pids[i];
     418-         uint pid_max  = pid_min;
     419-         for (uint j = i + 1; j < _pids.size(); j++)
     420-         {
     421-             if (pid_max + 1 != _pids[j])
     422-                 break;
     423-             pid_max++;
     424-             i++;
     425-         }
     426-         range_min.push_back(pid_min);
     427-         range_max.push_back(pid_max);
     428-     }
     429-
     430-     if (range_min.size() > 16)
     431-     {
     432-         range_min.resize(16);
     433-         uint pid_max = range_max.back();
     434-         range_max.resize(15);
     435-         range_max.push_back(pid_max);
     436-     }
     437-
     438-     for (uint i = 0; i < range_min.size(); i++)
     439-     {
     440-         filter += filt_str(range_min[i]);
     441-         if (range_min[i] != range_max[i])
     442-             filter += QString("-%1").arg(filt_str(range_max[i]));
     443-         filter += " ";
     444-     }
     445-
     446-     filter = filter.stripWhiteSpace();
     447-
     448-     QString new_filter = TunerSet("filter", filter);
     449-
     450- #ifdef DEBUG_PID_FILTERS
     451-     QString msg = QString("Filter: '%1'").arg(filter);
     452-     if (filter != new_filter)
     453-         msg += QString("\n\t\t\t\t'%2'").arg(new_filter);
     454-
     455-     VERBOSE(VB_CHANNEL, msg);
     456- #endif // DEBUG_PID_FILTERS
     457-
     458-     return filter == new_filter;
     459- }
     460--- 254,267 ----
     461              QString("TuneTo(%1,%2)").arg(frequency).arg(modulation));
     462 
     463      if (modulation == "8vsb")
     464+         ok = _stream_handler->TuneChannel(QString("8vsb:%1").arg(frequency));
     465      else if (modulation == "qam_64")
     466+         ok = _stream_handler->TuneChannel(QString("qam64:%1").arg(frequency));
     467      else if (modulation == "qam_256")
     468+         ok = _stream_handler->TuneChannel(QString("qam256:%1").arg(frequency));
     469 
     470      if (ok)
     471          SetSIStandard(si_std);
     472 
     473      return ok;
     474  }
  • mythtv/libs/libmythtv/hdhrchannel.h

    diff -r -u -N -X diff.exclude -x myth.20018.0218a -x myth.20018.0218b myth.20018.0218a/mythtv/libs/libmythtv/hdhrchannel.h myth.20018.0218b/mythtv/libs/libmythtv/hdhrchannel.h
     
    1515
    1616// HDHomeRun headers
    1717#ifdef USING_HDHOMERUN
    18 #include "hdhomerun.h"
    19 #else
    20 struct hdhomerun_control_sock_t { int dummy; };
     18#include "hdhomerun_includes.h"
    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{
     
    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 scanning 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/hdhrchannel.h.rej.fixed

    diff -r -u -N -X diff.exclude -x myth.20018.0218a -x myth.20018.0218b myth.20018.0218a/mythtv/libs/libmythtv/hdhrchannel.h.rej.fixed myth.20018.0218b/mythtv/libs/libmythtv/hdhrchannel.h.rej.fixed
     
     1***************
     2*** 15,26 ****
     3 
     4  // HDHomeRun headers
     5  #ifdef USING_HDHOMERUN
     6- #include "hdhomerun/hdhomerun.h"
     7- #else
     8- struct hdhomerun_control_sock_t { int dummy; };
     9  #endif
     10 
     11- typedef struct hdhomerun_control_sock_t hdhr_socket_t;
     12 
     13  class HDHRChannel : public DTVChannel
     14  {
     15--- 15,26 ----
     16 
     17  // HDHomeRun headers
     18  #ifdef USING_HDHOMERUN
     19+ #include "hdhomerun_includes.h"
     20  #endif
     21 
     22+ class HDHRChannel;
     23+ class HDHRStreamHandler;
     24+ class ProgramMapTable;
     25 
     26  class HDHRChannel : public DTVChannel
     27  {
  • mythtv/libs/libmythtv/hdhrrecorder.cpp

    diff -r -u -N -X diff.exclude -x myth.20018.0218a -x myth.20018.0218b myth.20018.0218a/mythtv/libs/libmythtv/hdhrrecorder.cpp myth.20018.0218b/mythtv/libs/libmythtv/hdhrrecorder.cpp
     
    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 "eithelper.h"
    3129#include "tv_rec.h"
    3230
     31// MythTV HDHR includes
     32#include "hdhrchannel.h"
     33#include "hdhrrecorder.h"
     34#include "hdhrstreamhandler.h"
     35
    3336#define LOC QString("HDHRRec(%1): ").arg(tvrec->GetCaptureCardNum())
     37#define LOC_WARN QString("HDHRRec(%1), Warning: ") \
     38                    .arg(tvrec->GetCaptureCardNum())
    3439#define LOC_ERR QString("HDHRRec(%1), Error: ") \
    3540                    .arg(tvrec->GetCaptureCardNum())
    3641
    3742HDHRRecorder::HDHRRecorder(TVRec *rec, HDHRChannel *channel)
    3843    : DTVRecorder(rec),
    39       _channel(channel),        _video_socket(NULL),
     44      _channel(channel),
     45      _stream_handler(NULL),
    4046      _stream_data(NULL),
    41       _input_pat(NULL),         _input_pmt(NULL),
    42       _reset_pid_filters(false),_pid_lock(QMutex::Recursive)
     47      _pid_lock(QMutex::Recursive),
     48      _input_pat(NULL),
     49      _input_pmt(NULL),
     50      _has_no_av(false)
    4351{
    4452}
    4553
     
    9098    // HACK -- end
    9199}
    92100
     101bool HDHRRecorder::IsOpen(void) {
     102    return (_stream_handler != NULL);
     103}
     104
    93105bool HDHRRecorder::Open(void)
    94106{
    95107    VERBOSE(VB_RECORD, LOC + "Open()");
    96     if (_video_socket)
     108    if (IsOpen())
    97109    {
    98110        VERBOSE(VB_RECORD, LOC + "Card already open (recorder)");
    99111        return true;
    100112    }
    101113
    102     /* Calculate buffer size */
    103     uint buffersize = gContext->GetNumSetting(
    104         "HDRingbufferSize", 50 * TSPacket::SIZE) * 1024;
    105     buffersize /= VIDEO_DATA_PACKET_SIZE;
    106     buffersize *= VIDEO_DATA_PACKET_SIZE;
     114    bzero(_stream_id,  sizeof(_stream_id));
     115    bzero(_pid_status, sizeof(_pid_status));
     116    memset(_continuity_counter, 0xff, sizeof(_continuity_counter));
    107117
    108     // Buffer should be at least about 1MB..
    109     buffersize = max(49 * TSPacket::SIZE * 128, buffersize);
     118    _stream_handler = HDHRStreamHandler::Get(_channel->GetDevice());
    110119
    111     /* Create TS socket. */
    112     _video_socket = hdhomerun_video_create(0, buffersize);
    113     if (!_video_socket)
    114     {
    115         VERBOSE(VB_IMPORTANT, LOC + "Open() failed to open socket");
    116         return false;
    117     }
     120    VERBOSE(VB_RECORD, LOC + "HDHR opened successfully");
    118121
    119     /* Success. */
    120122    return true;
    121123}
    122124
    123 /** \fn HDHRRecorder::StartData(void)
    124  *  \brief Configure device to send video.
    125  */
    126 bool HDHRRecorder::StartData(void)
    127 {
    128     VERBOSE(VB_RECORD, LOC + "StartData()");
    129     uint localPort = hdhomerun_video_get_local_port(_video_socket);
    130     return _channel->DeviceSetTarget(localPort);
    131 }
    132 
    133125void HDHRRecorder::Close(void)
    134126{
    135     VERBOSE(VB_RECORD, LOC + "Close()");
    136     if (_video_socket)
    137     {
    138         hdhomerun_video_destroy(_video_socket);
    139         _video_socket = NULL;
    140     }
    141 }
    142 
    143 void HDHRRecorder::ProcessTSData(const uint8_t *buffer, int len)
    144 {
    145     QMutexLocker locker(&_pid_lock);
    146     const uint8_t *data = buffer;
    147     const uint8_t *end = buffer + len;
     127    VERBOSE(VB_RECORD, LOC + "Close() - Begin");
    148128
    149     while (data + 188 <= end)
     129    if (IsOpen())
    150130    {
    151         if (data[0] != 0x47)
    152         {
    153             return;
    154         }
    155 
    156         const TSPacket *tspacket = reinterpret_cast<const TSPacket*>(data);
    157         ProcessTSPacket(*tspacket);
    158 
    159         data += 188;
     131        HDHRStreamHandler::Return(_stream_handler);
    160132    }
     133
     134    VERBOSE(VB_RECORD, LOC + "Close() - End");
    161135}
    162136
    163137void HDHRRecorder::SetStreamData(MPEGStreamData *data)
     
    216190    ProgramAssociationTable *oldpat = _input_pat;
    217191    _input_pat = new ProgramAssociationTable(*_pat);
    218192    delete oldpat;
    219 
    220     _reset_pid_filters = true;
    221193}
    222194
    223195void HDHRRecorder::HandlePMT(uint progNum, const ProgramMapTable *_pmt)
     
    229201        VERBOSE(VB_RECORD, LOC + "SetPMT("<<progNum<<")");
    230202        ProgramMapTable *oldpmt = _input_pmt;
    231203        _input_pmt = new ProgramMapTable(*_pmt);
    232         delete oldpmt;
    233204
    234         _reset_pid_filters = true;
     205        QString sistandard = _channel->GetSIStandard();
     206
     207        bool has_no_av = true;
     208        for (uint i = 0; i < _input_pmt->StreamCount() && has_no_av; i++)
     209        {
     210            has_no_av &= !_input_pmt->IsVideo(i, sistandard);
     211            has_no_av &= !_input_pmt->IsAudio(i, sistandard);
     212        }
     213        _has_no_av = has_no_av;
     214
     215        _channel->SetPMT(_input_pmt);
     216        delete oldpmt;
    235217    }
    236218}
    237219
     
    242224
    243225    int next = (pat->tsheader()->ContinuityCounter()+1)&0xf;
    244226    pat->tsheader()->SetContinuityCounter(next);
    245     BufferedWrite(*(reinterpret_cast<TSPacket*>(pat->tsheader())));
     227    DTVRecorder::BufferedWrite(*(reinterpret_cast<TSPacket*>(pat->tsheader())));
    246228}
    247229
    248230void HDHRRecorder::HandleSingleProgramPMT(ProgramMapTable *pmt)
    249231{
    250232    if (!pmt)
     233    {
     234        VERBOSE(VB_RECORD, LOC + "HandleSingleProgramPMT(NULL)");
     235        return;
     236    }
     237
     238    // collect stream types for H.264 (MPEG-4 AVC) keyframe detection
     239    for (uint i = 0; i < pmt->StreamCount(); i++)
     240        _stream_id[pmt->StreamPID(i)] = pmt->StreamType(i);
     241
     242    if (!ringBuffer)
    251243        return;
    252244
    253245    unsigned char buf[8 * 1024];
     
    255247    pmt->tsheader()->SetContinuityCounter(next_cc);
    256248    uint size = pmt->WriteAsTSPackets(buf, next_cc);
    257249
     250    uint posA[2] = { ringBuffer->GetWritePosition(), _payload_buffer.size() };
     251
    258252    for (uint i = 0; i < size ; i += TSPacket::SIZE)
    259253        DTVRecorder::BufferedWrite(*(reinterpret_cast<TSPacket*>(&buf[i])));
     254
     255    uint posB[2] = { ringBuffer->GetWritePosition(), _payload_buffer.size() };
     256
     257    if (posB[0] + posB[1] * TSPacket::SIZE >
     258        posA[0] + posA[1] * TSPacket::SIZE)
     259    {
     260        VERBOSE(VB_RECORD, LOC + "Wrote PMT @"
     261                << posA[0] << " + " << (posA[1] * TSPacket::SIZE));
     262    }
     263    else
     264    {
     265        VERBOSE(VB_RECORD, LOC + "Saw PMT but did not write to disk yet");
     266    }
    260267}
    261268
    262269/** \fn HDHRRecorder::HandleMGT(const MasterGuideTable*)
     
    276283}
    277284*/
    278285
     286bool HDHRRecorder::ProcessVideoTSPacket(const TSPacket &tspacket)
     287{
     288    uint streamType = _stream_id[tspacket.PID()];
     289
     290    // Check for keyframes and count frames
     291    if (streamType == StreamID::H264Video)
     292    {
     293        _buffer_packets = !FindH264Keyframes(&tspacket);
     294        if (!_seen_sps)
     295            return true;
     296    }
     297    else
     298    {
     299        _buffer_packets = !FindMPEG2Keyframes(&tspacket);
     300    }
     301
     302    return ProcessAVTSPacket(tspacket);
     303}
     304
     305bool HDHRRecorder::ProcessAudioTSPacket(const TSPacket &tspacket)
     306{
     307    _buffer_packets = !FindAudioKeyframes(&tspacket);
     308    return ProcessAVTSPacket(tspacket);
     309}
     310
     311/// Common code for processing either audio or video packets
     312bool HDHRRecorder::ProcessAVTSPacket(const TSPacket &tspacket)
     313{
     314    const uint pid = tspacket.PID();
     315    // Sync recording start to first keyframe
     316    if (_wait_for_keyframe_option && _first_keyframe < 0)
     317        return true;
     318
     319    // Sync streams to the first Payload Unit Start Indicator
     320    // _after_ first keyframe iff _wait_for_keyframe_option is true
     321    if (!(_pid_status[pid] & kPayloadStartSeen) && tspacket.HasPayload())
     322    {
     323        if (!tspacket.PayloadStart())
     324            return true; // not payload start - drop packet
     325
     326        VERBOSE(VB_RECORD,
     327                QString("PID 0x%1 Found Payload Start").arg(pid,0,16));
     328
     329        _pid_status[pid] |= kPayloadStartSeen;
     330    }
     331
     332    BufferedWrite(tspacket);
     333
     334    return true;
     335}
     336
    279337bool HDHRRecorder::ProcessTSPacket(const TSPacket& tspacket)
    280338{
    281     bool ok = !tspacket.TransportError();
    282     if (ok && !tspacket.ScramplingControl())
     339    // Only create fake keyframe[s] if there are no audio/video streams
     340    if (_input_pmt && _has_no_av)
    283341    {
    284         if (tspacket.HasAdaptationField())
    285             GetStreamData()->HandleAdaptationFieldControl(&tspacket);
    286         if (tspacket.HasPayload())
    287         {
    288             const unsigned int lpid = tspacket.PID();
     342        _buffer_packets = !FindOtherKeyframes(&tspacket);
     343    }
     344    else
     345    {
     346        // There are audio/video streams. Only write the packet
     347        // if audio/video key-frames have been found
     348        if (_wait_for_keyframe_option && _first_keyframe < 0)
     349            return true;
    289350
    290             if ((GetStreamData()->VideoPIDSingleProgram() > 0x1fff) &&
    291                 _wait_for_keyframe_option)
    292             {
    293                 _wait_for_keyframe_option = false;
    294             }
    295 
    296             // Pass or reject frames based on PID, and parse info from them
    297             if (lpid == GetStreamData()->VideoPIDSingleProgram())
    298             {
    299                 //cerr<<"v";
    300                 _buffer_packets = !FindMPEG2Keyframes(&tspacket);
    301                 BufferedWrite(tspacket);
    302             }
    303             else if (GetStreamData()->IsAudioPID(lpid))
    304             {
    305                 //cerr<<"a";
    306                 _buffer_packets = !FindAudioKeyframes(&tspacket);
    307                 BufferedWrite(tspacket);
    308             }
    309             else if (GetStreamData()->IsListeningPID(lpid))
    310             {
    311                 //cerr<<"t";
    312                 GetStreamData()->HandleTSTables(&tspacket);
    313             }
    314             else if (GetStreamData()->IsWritingPID(lpid))
    315                 BufferedWrite(tspacket);
    316         }
     351        _buffer_packets = true;
    317352    }
    318     return ok;
     353
     354    BufferedWrite(tspacket);
    319355}
    320356
    321357void HDHRRecorder::StartRecording(void)
     
    333369    _request_recording = true;
    334370    _recording = true;
    335371
    336     if (!StartData())
    337     {
    338         VERBOSE(VB_IMPORTANT, LOC_ERR + "Starting recording "
    339                 "(set target failed). Aborting.");
    340         Close();
    341         _error = true;
    342         VERBOSE(VB_RECORD, LOC + "StartRecording -- end 2");
    343         return;
    344     }
    345 
    346     hdhomerun_video_flush(_video_socket);
     372    // Make sure the first things in the file are a PAT & PMT
     373    bool tmp = _wait_for_keyframe_option;
     374    _wait_for_keyframe_option = false;
     375    HandleSingleProgramPAT(_stream_data->PATSingleProgram());
     376    HandleSingleProgramPMT(_stream_data->PMTSingleProgram());
     377    _wait_for_keyframe_option = tmp;
     378
     379    _stream_data->AddAVListener(this);
     380    _stream_data->AddWritingListener(this);
     381    _stream_handler->AddListener(_stream_data);
     382   
    347383    while (_request_recording && !_error)
    348384    {
     385        usleep(50000);
     386
    349387        if (PauseAndWait())
    350388            continue;
    351389
    352         if (_stream_data)
     390        if (!_input_pmt)
    353391        {
    354             QMutexLocker read_lock(&_pid_lock);
    355             _reset_pid_filters |= _stream_data->HasEITPIDChanges(_eit_pids);
     392            VERBOSE(VB_GENERAL, LOC_WARN +
     393                    "Recording will not commence until a PMT is set.");
     394            usleep(5000);
     395            continue;
    356396        }
    357397
    358         if (_reset_pid_filters)
     398        if (!_stream_handler->IsRunning())
    359399        {
    360             _reset_pid_filters = false;
    361             VERBOSE(VB_RECORD, LOC + "Resetting Demux Filters");
    362             AdjustFilters();
    363         }
     400            _error = true;
    364401
    365         size_t read_size = 64 * 1024; // read about 64KB
    366         read_size /= VIDEO_DATA_PACKET_SIZE;
    367         read_size *= VIDEO_DATA_PACKET_SIZE;
    368 
    369         size_t data_length;
    370         unsigned char *data_buffer =
    371             hdhomerun_video_recv(_video_socket, read_size, &data_length);
    372         if (!data_buffer)
    373         {
    374             usleep(5000);
    375             continue;
    376         }
    377 
    378         ProcessTSData(data_buffer, data_length);
     402            VERBOSE(VB_IMPORTANT, LOC_ERR +
     403                    "Stream handler died unexpectedly.");
     404        }
    379405    }
    380406
    381407    VERBOSE(VB_RECORD, LOC + "StartRecording -- ending...");
    382408
    383     _channel->DeviceClearTarget();
     409    _stream_handler->RemoveListener(_stream_data);
     410    _stream_data->RemoveWritingListener(this);
     411    _stream_data->RemoveAVListener(this);
     412
    384413    Close();
    385414
    386415    FinishRecording();
     
    389418    VERBOSE(VB_RECORD, LOC + "StartRecording -- end");
    390419}
    391420
    392 bool HDHRRecorder::AdjustFilters(void)
     421void HDHRRecorder::ResetForNewFile(void)
    393422{
    394     QMutexLocker change_lock(&_pid_lock);
     423    DTVRecorder::ResetForNewFile();
    395424
    396     if (!_channel)
    397     {
    398         VERBOSE(VB_IMPORTANT, LOC_ERR + "AdjustFilters() no channel");
    399         return false;
    400     }
     425    bzero(_stream_id,  sizeof(_stream_id));
     426    bzero(_pid_status, sizeof(_pid_status));
     427    memset(_continuity_counter, 0xff, sizeof(_continuity_counter));
    401428
    402     if (!_input_pat || !_input_pmt)
    403     {
    404         VERBOSE(VB_IMPORTANT, LOC + "AdjustFilters() no pmt or no pat");
    405         return false;
    406     }
    407 
    408     uint_vec_t add_pid;
     429    // FIXME
     430    // Close and re-open ???
     431    //Close();
     432    //Open();
     433}
    409434
    410     add_pid.push_back(MPEG_PAT_PID);
    411     _stream_data->AddListeningPID(MPEG_PAT_PID);
     435void HDHRRecorder::StopRecording(void)
     436{
     437    _request_recording = false;
     438    while (_recording)
     439        usleep(2000);
     440}
    412441
    413     for (uint i = 0; i < _input_pat->ProgramCount(); i++)
     442bool HDHRRecorder::PauseAndWait(int timeout)
     443{
     444    if (request_pause)
    414445    {
    415         add_pid.push_back(_input_pat->ProgramPID(i));
    416         _stream_data->AddListeningPID(_input_pat->ProgramPID(i));
    417     }
     446        QMutex waitlock;
     447        if (!paused)
     448        {
     449            assert(_stream_handler);
     450            assert(_stream_data);
    418451
    419     // Record the streams in the PMT...
    420     bool need_pcr_pid = true;
    421     for (uint i = 0; i < _input_pmt->StreamCount(); i++)
    422     {
    423         add_pid.push_back(_input_pmt->StreamPID(i));
    424         need_pcr_pid &= (_input_pmt->StreamPID(i) != _input_pmt->PCRPID());
    425         _stream_data->AddWritingPID(_input_pmt->StreamPID(i));
    426     }
     452            _stream_handler->RemoveListener(_stream_data);
    427453
    428     if (need_pcr_pid && (_input_pmt->PCRPID()))
    429     {
    430         add_pid.push_back(_input_pmt->PCRPID());
    431         _stream_data->AddWritingPID(_input_pmt->PCRPID());
     454            paused = true;
     455            pauseWait.wakeAll();
     456            if (tvrec)
     457                tvrec->RecorderPaused();
     458        }
     459        waitlock.lock();
     460        unpauseWait.wait(&waitlock, timeout);
    432461    }
    433462
    434     // Adjust for EIT
    435     AdjustEITPIDs();
    436     for (uint i = 0; i < _eit_pids.size(); i++)
     463    if (!request_pause && paused)
    437464    {
    438         add_pid.push_back(_eit_pids[i]);
    439         _stream_data->AddListeningPID(_eit_pids[i]);
    440     }
     465        paused = false;
    441466
    442     // Delete filters for pids we no longer wish to monitor
    443     vector<uint>::const_iterator it;
    444     vector<uint> pids = _channel->GetPIDs();
    445     for (it = pids.begin(); it != pids.end(); ++it)
    446     {
    447         if (find(add_pid.begin(), add_pid.end(), *it) == add_pid.end())
    448         {
    449             _stream_data->RemoveListeningPID(*it);
    450             _stream_data->RemoveWritingPID(*it);
    451             _channel->DelPID(*it, false);
    452         }
    453     }
     467        assert(_stream_handler);
     468        assert(_stream_data);
    454469
    455     for (it = add_pid.begin(); it != add_pid.end(); ++it)
    456         _channel->AddPID(*it, false);
    457 
    458     _channel->UpdateFilters();
     470        _stream_handler->AddListener(_stream_data);
     471    }
    459472
    460     return add_pid.size();
     473    return paused;
    461474}
    462475
    463 /** \fn HDHRRecorder::AdjustEITPIDs(void)
    464  *  \brief Adjusts EIT PID monitoring to monitor the right number of EIT PIDs.
    465  */
    466 bool HDHRRecorder::AdjustEITPIDs(void)
     476void HDHRRecorder::BufferedWrite(const TSPacket &tspacket)
    467477{
    468     bool changes = false;
    469     uint_vec_t add, del;
    470 
    471     QMutexLocker change_lock(&_pid_lock);
    472 
    473     if (GetStreamData()->HasEITPIDChanges(_eit_pids))
    474         changes = GetStreamData()->GetEITPIDChanges(_eit_pids, add, del);
     478    // Care must be taken to make sure that the packet actually gets written
     479    // as the decision to actually write it has already been made
    475480
    476     if (!changes)
    477         return false;
    478 
    479     for (uint i = 0; i < del.size(); i++)
     481    // Do we have to buffer the packet for exact keyframe detection?
     482    if (_buffer_packets)
    480483    {
    481         uint_vec_t::iterator it;
    482         it = find(_eit_pids.begin(), _eit_pids.end(), del[i]);
    483         if (it != _eit_pids.end())
    484             _eit_pids.erase(it);
     484        int idx = _payload_buffer.size();
     485        _payload_buffer.resize(idx + TSPacket::SIZE);
     486        memcpy(&_payload_buffer[idx], tspacket.data(), TSPacket::SIZE);
     487        return;
    485488    }
    486489
    487     for (uint i = 0; i < add.size(); i++)
    488         _eit_pids.push_back(add[i]);
    489 
    490     return true;
     490    // We are free to write the packet, but if we have buffered packet[s]
     491    // we have to write them first...
     492    if (!_payload_buffer.empty())
     493    {
     494        if (ringBuffer)
     495            ringBuffer->Write(&_payload_buffer[0], _payload_buffer.size());
     496        _payload_buffer.clear();
     497    }
     498    if (ringBuffer)
     499        ringBuffer->Write(tspacket.data(), TSPacket::SIZE);
    491500}
    492501
  • mythtv/libs/libmythtv/hdhrrecorder.cpp.rej.fixed

    diff -r -u -N -X diff.exclude -x myth.20018.0218a -x myth.20018.0218b myth.20018.0218a/mythtv/libs/libmythtv/hdhrrecorder.cpp.rej.fixed myth.20018.0218b/mythtv/libs/libmythtv/hdhrrecorder.cpp.rej.fixed
     
     1***************
     2*** 23,45 ****
     3 
     4  // MythTV includes
     5  #include "RingBuffer.h"
     6- #include "hdhrchannel.h"
     7- #include "hdhrrecorder.h"
     8  #include "atsctables.h"
     9  #include "atscstreamdata.h"
     10  #include "eithelper.h"
     11  #include "tv_rec.h"
     12 
     13  #define LOC QString("HDHRRec(%1): ").arg(tvrec->GetCaptureCardNum())
     14  #define LOC_ERR QString("HDHRRec(%1), Error: ") \
     15                      .arg(tvrec->GetCaptureCardNum())
     16 
     17  HDHRRecorder::HDHRRecorder(TVRec *rec, HDHRChannel *channel)
     18      : DTVRecorder(rec),
     19-       _channel(channel),        _video_socket(NULL),
     20        _stream_data(NULL),
     21-       _input_pat(NULL),         _input_pmt(NULL),
     22-       _reset_pid_filters(false),_pid_lock(true)
     23  {
     24  }
     25 
     26--- 23,53 ----
     27 
     28  // MythTV includes
     29  #include "RingBuffer.h"
     30  #include "atsctables.h"
     31  #include "atscstreamdata.h"
     32  #include "eithelper.h"
     33  #include "tv_rec.h"
     34 
     35+ // MythTV HDHR includes
     36+ #include "hdhrchannel.h"
     37+ #include "hdhrrecorder.h"
     38+ #include "hdhrstreamhandler.h"
     39+
     40  #define LOC QString("HDHRRec(%1): ").arg(tvrec->GetCaptureCardNum())
     41+ #define LOC_WARN QString("HDHRRec(%1), Warning: ") \
     42+                     .arg(tvrec->GetCaptureCardNum())
     43  #define LOC_ERR QString("HDHRRec(%1), Error: ") \
     44                      .arg(tvrec->GetCaptureCardNum())
     45 
     46  HDHRRecorder::HDHRRecorder(TVRec *rec, HDHRChannel *channel)
     47      : DTVRecorder(rec),
     48+       _channel(channel),
     49+       _stream_handler(NULL),
     50        _stream_data(NULL),
     51+       _pid_lock(true),
     52+       _input_pat(NULL),
     53+       _input_pmt(NULL),
     54+       _has_no_av(false)
     55  {
     56  }
     57 
  • mythtv/libs/libmythtv/hdhrrecorder.h

    diff -r -u -N -X diff.exclude -x myth.20018.0218a -x myth.20018.0218b myth.20018.0218a/mythtv/libs/libmythtv/hdhrrecorder.h myth.20018.0218b/mythtv/libs/libmythtv/hdhrrecorder.h
     
    1414
    1515class HDHRChannel;
    1616class ProgramMapTable;
     17class MPEGStreamData;
     18class HDHRStreamHandler;
     19
    1720
    1821typedef vector<uint>        uint_vec_t;
    1922
    2023class HDHRRecorder : public DTVRecorder,
    2124                     public MPEGStreamListener,
    22                      public MPEGSingleProgramStreamListener
     25                     public MPEGSingleProgramStreamListener,
     26                     public TSPacketListener,
     27                     public TSPacketListenerAV
    2328{
    2429    friend class ATSCStreamData;
    2530
     
    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; }
     
    5966    void HandleVCT(uint, const VirtualChannelTable*) {}
    6067    */
    6168
    62   private:
    63     bool AdjustFilters(void);
    64     bool AdjustEITPIDs(void);
     69    // TSPacketListenerAV
     70    bool ProcessVideoTSPacket(const TSPacket& tspacket);
     71    bool ProcessAudioTSPacket(const TSPacket& tspacket);
     72
     73    // Common audio/visual processing
     74    bool ProcessAVTSPacket(const TSPacket &tspacket);
    6575
    66     void ProcessTSData(const unsigned char *buffer, int len);
    6776    bool ProcessTSPacket(const TSPacket& tspacket);
     77
     78    void BufferedWrite(const TSPacket &tspacket);
     79  private:
    6880    void TeardownAll(void);
     81
     82    void ReaderPaused(int fd);
     83    bool PauseAndWait(int timeout = 100);
    6984   
    7085  private:
    7186    HDHRChannel                   *_channel;
    72     struct hdhomerun_video_sock_t *_video_socket;
     87    HDHRStreamHandler             *_stream_handler;
    7388    MPEGStreamData                *_stream_data;
    7489
     90    mutable QMutex                 _pid_lock;
    7591    ProgramAssociationTable       *_input_pat;
    7692    ProgramMapTable               *_input_pmt;
    77     bool                           _reset_pid_filters;
    78     uint_vec_t                     _eit_pids;
    79     mutable QMutex                 _pid_lock;
     93    bool                           _has_no_av;
     94
     95    unsigned char   _stream_id[0x1fff];
     96    unsigned char   _pid_status[0x1fff];
     97    unsigned char   _continuity_counter[0x1fff];
     98
     99    // Constants
     100    static const int TSPACKETS_BETWEEN_PSIP_SYNC;
     101    static const int POLL_INTERVAL;
     102    static const int POLL_WARNING_TIMEOUT;
     103
     104    static const unsigned char kPayloadStartSeen = 0x2;
    80105};
    81106
    82107#endif
  • mythtv/libs/libmythtv/hdhrsignalmonitor.cpp

    diff -r -u -N -X diff.exclude -x myth.20018.0218a -x myth.20018.0218b myth.20018.0218a/mythtv/libs/libmythtv/hdhrsignalmonitor.cpp myth.20018.0218b/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()
     
    5760{
    5861    VERBOSE(VB_CHANNEL, LOC + "dtor");
    5962    Stop();
     63    HDHRStreamHandler::Return(streamHandler);
    6064}
    6165
    6266/** \fn 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()
     
    20198    if (!running || exit)
    20299        return;
    203100
    204     if (dtvMonitorRunning)
     101    if (streamHandlerStarted)
    205102    {
    206103        EmitStatus();
    207104        if (IsAllGood())
     
    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]
     
    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.cpp.rej.fixed

    diff -r -u -N -X diff.exclude -x myth.20018.0218a -x myth.20018.0218b myth.20018.0218a/mythtv/libs/libmythtv/hdhrsignalmonitor.cpp.rej.fixed myth.20018.0218b/mythtv/libs/libmythtv/hdhrsignalmonitor.cpp.rej.fixed
     
     1***************
     2*** 41,55 ****
     3                                       HDHRChannel* _channel,
     4                                       uint64_t _flags, const char *_name)
     5      : DTVSignalMonitor(db_cardnum, _channel, _flags, _name),
     6-       dtvMonitorRunning(false)
     7  {
     8      VERBOSE(VB_CHANNEL, LOC + "ctor");
     9 
     10-     _channel->DelAllPIDs();
     11-
     12      signalStrength.SetThreshold(45);
     13 
     14      AddFlags(kDTVSigMon_WaitForSig);
     15  }
     16 
     17  /** \fn HDHRSignalMonitor::~HDHRSignalMonitor()
     18--- 42,58 ----
     19                                       HDHRChannel* _channel,
     20                                       uint64_t _flags, const char *_name)
     21      : DTVSignalMonitor(db_cardnum, _channel, _flags, _name),
     22+       streamHandlerStarted(false),
     23+       streamHandler(NULL)
     24+
     25  {
     26      VERBOSE(VB_CHANNEL, LOC + "ctor");
     27 
     28      signalStrength.SetThreshold(45);
     29 
     30      AddFlags(kDTVSigMon_WaitForSig);
     31+
     32+     streamHandler = HDHRStreamHandler::Get(_channel->GetDevice());
     33  }
     34 
     35  /** \fn HDHRSignalMonitor::~HDHRSignalMonitor()
     36***************
     37*** 73,190 ****
     38  {
     39      VERBOSE(VB_CHANNEL, LOC + "Stop() -- begin");
     40      SignalMonitor::Stop();
     41-     if (dtvMonitorRunning)
     42-     {
     43-         dtvMonitorRunning = false;
     44-         pthread_join(table_monitor_thread, NULL);
     45-     }
     46-     VERBOSE(VB_CHANNEL, LOC + "Stop() -- end");
     47- }
     48 
     49- void *HDHRSignalMonitor::TableMonitorThread(void *param)
     50- {
     51-     HDHRSignalMonitor *mon = (HDHRSignalMonitor*) param;
     52-     mon->RunTableMonitor();
     53-     return NULL;
     54- }
     55-
     56- bool HDHRSignalMonitor::UpdateFiltersFromStreamData(void)
     57- {
     58-     vector<int> add_pids;
     59-     vector<int> del_pids;
     60-
     61-     if (!GetStreamData())
     62-         return false;
     63-
     64-     UpdateListeningForEIT();
     65-
     66-     const pid_map_t &listening = GetStreamData()->ListeningPIDs();
     67-
     68-     // PIDs that need to be added..
     69-     pid_map_t::const_iterator lit = listening.constBegin();
     70-     for (; lit != listening.constEnd(); ++lit)
     71-         if (lit.data() && (filters.find(lit.key()) == filters.end()))
     72-             add_pids.push_back(lit.key());
     73-
     74-     // PIDs that need to be removed..
     75-     FilterMap::const_iterator fit = filters.constBegin();
     76-     for (; fit != filters.constEnd(); ++fit)
     77-         if (listening.find(fit.key()) == listening.end())
     78-             del_pids.push_back(fit.key());
     79-
     80-     HDHRChannel *hdhr = dynamic_cast<HDHRChannel*>(channel);
     81-     // Remove PIDs
     82-     bool ok = true;
     83-     vector<int>::iterator dit = del_pids.begin();
     84-     for (; dit != del_pids.end(); ++dit)
     85-     {
     86-         ok &= hdhr->DelPID(*dit);
     87-         filters.erase(filters.find(*dit));
     88-     }
     89-
     90-     // Add PIDs
     91-     vector<int>::iterator ait = add_pids.begin();
     92-     for (; ait != add_pids.end(); ++ait)
     93-     {
     94-         ok &= hdhr->AddPID(*ait);
     95-         filters[*ait] = 1;
     96-     }
     97-
     98-     return ok;
     99  }
     100 
     101- void HDHRSignalMonitor::RunTableMonitor(void)
     102  {
     103-     dtvMonitorRunning = true;
     104-
     105-     struct hdhomerun_video_sock_t *_video_socket;
     106-     _video_socket = hdhomerun_video_create(0, VIDEO_DATA_BUFFER_SIZE_1S);
     107-     if (!_video_socket)
     108-     {
     109-         VERBOSE(VB_IMPORTANT, LOC_ERR + "Failed to get video socket");
     110-         return;
     111-     }
     112-
     113-     HDHRChannel *hdrc = dynamic_cast<HDHRChannel*>(channel);
     114-     uint localPort = hdhomerun_video_get_local_port(_video_socket);
     115-     if (!hdrc->DeviceSetTarget(localPort))
     116-     {
     117-         hdhomerun_video_destroy(_video_socket);
     118-         VERBOSE(VB_IMPORTANT, LOC_ERR + "Failed to set target");
     119-         return;
     120-     }
     121-
     122-     VERBOSE(VB_CHANNEL, LOC + "RunTableMonitor(): " +
     123-             QString("begin (# of pids %1)")
     124-             .arg(GetStreamData()->ListeningPIDs().size()));
     125-
     126-     while (dtvMonitorRunning && GetStreamData())
     127-     {
     128-         UpdateFiltersFromStreamData();
     129-
     130-         size_t data_length;
     131-         unsigned char *data_buffer =
     132-             hdhomerun_video_recv(_video_socket,
     133-                                          VIDEO_DATA_BUFFER_SIZE_1S / 5,
     134-                                          &data_length);
     135-
     136-         if (data_buffer)
     137-         {
     138-             GetStreamData()->ProcessData(data_buffer, data_length);
     139-             continue;
     140-         }
     141-
     142-         usleep(2500);
     143-     }
     144-
     145-     hdrc->DeviceClearTarget();
     146-     hdhomerun_video_destroy(_video_socket);
     147-
     148-     VERBOSE(VB_CHANNEL, LOC + "RunTableMonitor(): -- shutdown");
     149-
     150-     // TODO teardown PID filters here
     151-
     152-     VERBOSE(VB_CHANNEL, LOC + "RunTableMonitor(): -- end");
     153  }
     154 
     155  /** \fn HDHRSignalMonitor::UpdateValues()
     156--- 77,93 ----
     157  {
     158      VERBOSE(VB_CHANNEL, LOC + "Stop() -- begin");
     159      SignalMonitor::Stop();
     160+     if (GetStreamData())
     161+         streamHandler->RemoveListener(GetStreamData());
     162+     streamHandlerStarted = false;
     163+     streamHandler->SetRetuneAllowed(false, NULL, NULL);
     164 
     165+     VERBOSE(VB_CHANNEL, LOC + "Stop() -- end");
     166  }
     167 
     168+ HDHRChannel *HDHRSignalMonitor::GetHDHRChannel(void)
     169  {
     170+     return dynamic_cast<HDHRChannel*>(channel);
     171  }
     172 
     173  /** \fn HDHRSignalMonitor::UpdateValues()
  • mythtv/libs/libmythtv/hdhrsignalmonitor.h

    diff -r -u -N -X diff.exclude -x myth.20018.0218a -x myth.20018.0218b myth.20018.0218a/mythtv/libs/libmythtv/hdhrsignalmonitor.h myth.20018.0218b/mythtv/libs/libmythtv/hdhrsignalmonitor.h
     
    77#include "qstringlist.h"
    88
    99class HDHRChannel;
     10class HDHRStreamHandler;
    1011
    1112typedef QMap<uint,int> FilterMap;
    1213
     
    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/hdhrsignalmonitor.h.rej.fixed

    diff -r -u -N -X diff.exclude -x myth.20018.0218a -x myth.20018.0218b myth.20018.0218a/mythtv/libs/libmythtv/hdhrsignalmonitor.h.rej.fixed myth.20018.0218b/mythtv/libs/libmythtv/hdhrsignalmonitor.h.rej.fixed
     
     1***************
     2*** 21,28 ****
     3 
     4      void Stop(void);
     5 
     6-     bool UpdateFiltersFromStreamData(void);
     7-
     8    public slots:
     9      void deleteLater(void);
     10 
     11--- 22,27 ----
     12 
     13      void Stop(void);
     14 
     15    public slots:
     16      void deleteLater(void);
     17 
  • mythtv/libs/libmythtv/hdhrstreamhandler.cpp

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

    diff -r -u -N -X diff.exclude -x myth.20018.0218a -x myth.20018.0218b myth.20018.0218a/mythtv/libs/libmythtv/hdhrstreamhandler.h myth.20018.0218b/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_includes.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 -r -u -N -X diff.exclude -x myth.20018.0218a -x myth.20018.0218b myth.20018.0218a/mythtv/libs/libmythtv/libmythtv.pro myth.20018.0218b/mythtv/libs/libmythtv/libmythtv.pro
     
    494494    using_hdhomerun {
    495495        # MythTV HDHomeRun glue
    496496        HEADERS += hdhrsignalmonitor.h   hdhrchannel.h
    497         HEADERS += hdhrrecorder.h
     497        HEADERS += hdhrrecorder.h        hdhrstreamhandler.h
    498498
    499499        SOURCES += hdhrsignalmonitor.cpp hdhrchannel.cpp
    500         SOURCES += hdhrrecorder.cpp
     500        SOURCES += hdhrrecorder.cpp      hdhrstreamhandler.cpp
    501501
    502502        DEFINES += USING_HDHOMERUN
    503503    }
  • mythtv/libs/libmythtv/scanwizardscanner.cpp

    diff -r -u -N -X diff.exclude -x myth.20018.0218a -x myth.20018.0218b myth.20018.0218a/mythtv/libs/libmythtv/scanwizardscanner.cpp myth.20018.0218b/mythtv/libs/libmythtv/scanwizardscanner.cpp
     
    523523#ifdef USING_HDHOMERUN
    524524    if ("HDHOMERUN" == card_type)
    525525    {
    526         uint tuner = CardUtil::GetHDHRTuner(cardid);
    527         channel = new HDHRChannel(NULL, device, tuner);
     526        channel = new HDHRChannel(NULL, device);
    528527    }
    529528#endif // USING_HDHOMERUN
    530529
  • mythtv/libs/libmythtv/tv_rec.cpp

    diff -r -u -N -X diff.exclude -x myth.20018.0218a -x myth.20018.0218b myth.20018.0218a/mythtv/libs/libmythtv/tv_rec.cpp myth.20018.0218b/mythtv/libs/libmythtv/tv_rec.cpp
     
    177177    else if (genOpt.cardtype == "HDHOMERUN")
    178178    {
    179179#ifdef USING_HDHOMERUN
    180         channel = new HDHRChannel(this, genOpt.videodev, dboxOpt.port);
     180        channel = new HDHRChannel(this, genOpt.videodev);
    181181        if (!channel->Open())
    182182            return false;
    183183        InitChannel(genOpt.defaultinput, startchannel);
     
    35043504            return;
    35053505
    35063506        ClearFlags(kFlagWaitingForRecPause);
    3507 #ifdef USING_HDHOMERUN
    3508         if (GetHDHRRecorder())
    3509         {
    3510             // We currently need to close the file descriptor for
    3511             // HDHomeRun signal monitoring to work.
    3512             GetHDHRRecorder()->Close();
    3513             GetHDHRRecorder()->SetRingBuffer(NULL);
    3514         }
    3515 #endif // USING_HDHOMERUN
    35163507        VERBOSE(VB_RECORD, LOC + "Recorder paused, calling TuningFrequency");
    35173508        TuningFrequency(lastTuningRequest);
    35183509    }
     
    41514142    }
    41524143    recorder->Reset();
    41534144
    4154 #ifdef USING_HDHOMERUN
    4155     if (GetHDHRRecorder())
    4156     {
    4157         pauseNotify = false;
    4158         GetHDHRRecorder()->Close();
    4159         pauseNotify = true;
    4160         GetHDHRRecorder()->Open();
    4161         GetHDHRRecorder()->StartData();
    4162     }
    4163 #endif // USING_HDHOMERUN
    4164 
    41654145    // Set file descriptor of channel from recorder for V4L
    41664146    channel->SetFd(recorder->GetVideoFd());
    41674147
  • mythtv/libs/libmythtv/videosource.cpp

    diff -r -u -N -X diff.exclude -x myth.20018.0218a -x myth.20018.0218b myth.20018.0218a/mythtv/libs/libmythtv/videosource.cpp myth.20018.0218b/mythtv/libs/libmythtv/videosource.cpp
     
    5050
    5151QMutex XMLTVFindGrabbers::list_lock;
    5252
     53#include "hdhomerun_includes.h"
     54
    5355VideoSourceSelector::VideoSourceSelector(uint           _initial_sourceid,
    5456                                         const QString &_card_types,
    5557                                         bool           _must_have_mplexid) :
     
    14061408    CaptureCard &parent;
    14071409 };
    14081410
    1409 class HDHomeRunDeviceID : public LineEditSetting, public CaptureCardDBStorage
     1411class HDHomeRunIP : public TransLabelSetting
     1412{
     1413  public:
     1414    HDHomeRunIP()
     1415    {
     1416        setLabel(QObject::tr("IP Address"));
     1417    };
     1418};
     1419
     1420class HDHomeRunTuner : public TransLabelSetting
     1421{
     1422  public:
     1423    HDHomeRunTuner()
     1424    {
     1425        setLabel(QObject::tr("Tuner"));
     1426    };
     1427};
     1428
     1429class HDHomeRunDeviceID : public ComboBoxSetting, public CaptureCardDBStorage
    14101430{
    14111431  public:
    14121432    HDHomeRunDeviceID(const CaptureCard &parent) :
    1413         LineEditSetting(this),
     1433        ComboBoxSetting(this),
    14141434        CaptureCardDBStorage(this, parent, "videodevice")
    14151435    {
    1416         setValue("FFFFFFFF");
    14171436        setLabel(QObject::tr("Device ID"));
    1418         setHelpText(QObject::tr("IP address or Device ID from the bottom of "
    1419                                 "the HDHomeRun.  You may use "
    1420                                 "'FFFFFFFF' if there is only one unit "
    1421                                 "on your your network."));
     1437        setHelpText(
     1438            QObject::tr("DevicedID and Tuner Number of available HDHomeRun "
     1439                        "devices. "));
     1440        fillSelections("");
     1441    };
     1442
     1443    /// \brief Adds all available device-tuner combinations to list
     1444    /// If current is >= 0 it will be considered available even
     1445    /// if no device exists for it on the network
     1446    void fillSelections(QString current)
     1447    {
     1448        clearSelections();
     1449
     1450        // Get devices from filesystem
     1451        vector<QString> devs = CardUtil::ProbeVideoDevices("HDHOMERUN");
     1452
     1453        // Add current if needed
     1454        if ((current != "") &&
     1455            (find(devs.begin(), devs.end(), current) == devs.end()))
     1456        {
     1457            devs.push_back(current);
     1458            stable_sort(devs.begin(), devs.end());
     1459        }
     1460
     1461        vector<QString> db = CardUtil::GetVideoDevices("HDHOMERUN");
     1462
     1463        QMap<QString, bool> in_use;
     1464        QString sel = current;
     1465        for (uint i = 0; i < devs.size(); i++)
     1466        {
     1467            const QString dev = devs[i];
     1468            in_use[devs[i]] = find(db.begin(), db.end(), dev) != db.end();
     1469            if (sel == "" && !in_use[devs[i]])
     1470                sel = dev;
     1471        }
     1472
     1473        if (sel == "" && devs.size())
     1474            sel = devs[0];
     1475 
     1476        QString usestr = QString(" -- ");
     1477        usestr += QObject::tr("Warning: already in use");
     1478
     1479        for (uint i = 0; i < devs.size(); i++)
     1480        {
     1481            const QString dev = devs[i];
     1482            QString desc = dev + (in_use[devs[i]] ? usestr : "");
     1483            desc = (current == devs[i]) ? dev : desc;
     1484            addSelection(desc, dev, dev == sel);
     1485        }
     1486    }
     1487
     1488    virtual void Load(void)
     1489    {
     1490        clearSelections();
     1491        addSelection("");
     1492
     1493        CaptureCardDBStorage::Load();
     1494
     1495        fillSelections(getValue());
    14221496    }
    14231497};
    14241498
     
    14521526    CaptureCard &parent;
    14531527};
    14541528
    1455 class HDHomeRunTunerIndex : public ComboBoxSetting, public CaptureCardDBStorage
     1529class HDHomeRunExtra : public ConfigurationWizard
    14561530{
    14571531  public:
    1458     HDHomeRunTunerIndex(const CaptureCard &parent) :
    1459         ComboBoxSetting(this),
    1460         CaptureCardDBStorage(this, parent, "dbox2_port")
     1532    HDHomeRunExtra(HDHomeRunConfigurationGroup &parent);
     1533    uint GetInstanceCount(void) const
    14611534    {
    1462         setLabel(QObject::tr("Tuner"));
    1463         addSelection("0");
    1464         addSelection("1");
     1535        return (uint) count->intValue();
    14651536    }
     1537
     1538  private:
     1539    InstanceCount *count;
    14661540};
    14671541
    1468 class HDHomeRunConfigurationGroup : public VerticalConfigurationGroup
     1542HDHomeRunExtra::HDHomeRunExtra(HDHomeRunConfigurationGroup &parent)
     1543    : count(new InstanceCount(parent.parent))
    14691544{
    1470   public:
    1471     HDHomeRunConfigurationGroup(CaptureCard& a_parent) :
    1472         VerticalConfigurationGroup(false, true, false, false),
    1473         parent(a_parent)
    1474     {
    1475         setUseLabel(false);
    1476         addChild(new HDHomeRunDeviceID(parent));
    1477         addChild(new HDHomeRunTunerIndex(parent));
    1478         addChild(new SignalTimeout(parent, 1000, 250));
    1479         addChild(new ChannelTimeout(parent, 3000, 1750));
    1480         addChild(new SingleCardInput(parent));
    1481     };
     1545    VerticalConfigurationGroup* rec = new VerticalConfigurationGroup(false);
     1546    rec->setLabel(QObject::tr("Recorder Options"));
     1547    rec->setUseLabel(false);
     1548
     1549    rec->addChild(count);
     1550
     1551    addChild(rec);
     1552}
     1553
     1554HDHomeRunConfigurationGroup::HDHomeRunConfigurationGroup(CaptureCard& a_parent) :
     1555    VerticalConfigurationGroup(false, true, false, false),
     1556    parent(a_parent)
     1557{
     1558    setUseLabel(false);
     1559    deviceid = new HDHomeRunDeviceID(parent);
     1560    addChild(deviceid);
     1561    cardip = new HDHomeRunIP();
     1562    cardtuner = new HDHomeRunTuner();
     1563
     1564    addChild(cardip);
     1565    addChild(cardtuner);
     1566
     1567    addChild(new SignalTimeout(parent, 1000, 250));
     1568    addChild(new ChannelTimeout(parent, 3000, 1750));
     1569    addChild(new SingleCardInput(parent));
     1570
     1571    TransButtonSetting *buttonRecOpt = new TransButtonSetting();
     1572    buttonRecOpt->setLabel(tr("Recording Options"));   
     1573    addChild(buttonRecOpt);
     1574
     1575    connect(deviceid,     SIGNAL(valueChanged(const QString&)),
     1576            this,         SLOT(  probeCard   (const QString&)));
     1577    connect(buttonRecOpt, SIGNAL(pressed()),
     1578            this,         SLOT(  HDHomeRunExtraPanel()));
     1579
    14821580
    1483   private:
    1484     CaptureCard &parent;
    14851581};
    14861582
     1583void HDHomeRunConfigurationGroup::probeCard(const QString& deviceid)
     1584{
     1585    hdhomerun_device_t* thisdevice = hdhomerun_device_create_from_str(deviceid.toLocal8Bit().constData());
     1586
     1587    if (thisdevice)
     1588    {
     1589        uint device_ip = hdhomerun_device_get_device_ip(thisdevice);
     1590        uint tuner     = hdhomerun_device_get_tuner(thisdevice);
     1591        hdhomerun_device_destroy(thisdevice);
     1592
     1593        QString ip = QString("%1.%2.%3.%4")
     1594                .arg((device_ip>>24) & 0xFF).arg((device_ip>>16) & 0xFF)
     1595                .arg((device_ip>> 8) & 0xFF).arg((device_ip>> 0) & 0xFF);
     1596
     1597        cardip->setValue(ip);
     1598        cardtuner->setValue(QString("%1").arg(tuner));
     1599    }
     1600    else
     1601    {
     1602        cardip->setValue("Unknown");
     1603        cardtuner->setValue("Unknown");
     1604    }
     1605}
     1606
     1607void HDHomeRunConfigurationGroup::HDHomeRunExtraPanel(void)
     1608{
     1609    parent.reload(); // ensure card id is valid
     1610
     1611    HDHomeRunExtra acw(*this);
     1612    acw.exec();
     1613    parent.SetInstanceCount(acw.GetInstanceCount());
     1614}
     1615
     1616
    14871617V4LConfigurationGroup::V4LConfigurationGroup(CaptureCard& a_parent) :
    14881618    VerticalConfigurationGroup(false, true, false, false),
    14891619    parent(a_parent),
     
    16971827        if ((cardtype.toLower() == "dvb") && (1 != ++device_refs[videodevice]))
    16981828            continue;
    16991829
     1830        if ((cardtype.toLower() == "hdhomerun") && (1 != ++device_refs[videodevice]))
     1831            continue;
     1832
    17001833        QString label = CardUtil::GetDeviceLabel(
    17011834            cardid, cardtype, videodevice);
    17021835
     
    28392972        if ((cardtype.toLower() == "dvb") && (1 != ++device_refs[videodevice]))
    28402973            continue;
    28412974
     2975        if ((cardtype.toLower() == "hdhomerun") && (1 != ++device_refs[videodevice]))
     2976            continue;
     2977
    28422978        QStringList        inputLabels;
    28432979        vector<CardInput*> cardInputs;
    28442980
  • mythtv/libs/libmythtv/videosource.h

    diff -r -u -N -X diff.exclude -x myth.20018.0218a -x myth.20018.0218b myth.20018.0218a/mythtv/libs/libmythtv/videosource.h myth.20018.0218b/mythtv/libs/libmythtv/videosource.h
     
    530530    DiSEqCDevTree      *diseqc_tree;
    531531};
    532532
     533class HDHomeRunDeviceID;
     534class HDHomeRunIP;
     535class HDHomeRunTuner;
     536class HDHomeRunConfigurationGroup : public VerticalConfigurationGroup
     537{
     538    friend class HDHomeRunExtra;
     539
     540    Q_OBJECT
     541  public:
     542    HDHomeRunConfigurationGroup(CaptureCard& a_parent);
     543
     544public slots:
     545    void probeCard(const QString& deviceid);
     546    void HDHomeRunExtraPanel(void);
     547
     548  private:
     549    HDHomeRunDeviceID *deviceid;
     550    HDHomeRunIP       *cardip;
     551    HDHomeRunTuner    *cardtuner;
     552
     553    CaptureCard &parent;
     554};
     555
     556
    533557class FirewireGUID;
    534558class FirewireModel : public ComboBoxSetting, public CaptureCardDBStorage
    535559{