Ticket #6138: 133-hdhr.multirec.6.patch

File 133-hdhr.multirec.6.patch, 84.5 KB (added by anonymous, 12 years ago)
  • mythtv/libs/libmythtv/cardutil.cpp

    diff -r -u -N -X diff.exclude -x release.19764.0120a -x release.19757.0120a release.19764.0120a/mythtv/libs/libmythtv/cardutil.cpp release.19757.0120a/mythtv/libs/libmythtv/cardutil.cpp
     
    2828#include "videodev_myth.h"
    2929#endif
    3030
     31#include "hdhomerun_includes.h"
     32
    3133#define LOC      QString("CardUtil: ")
    3234#define LOC_WARN QString("CardUtil, Warning: ")
    3335#define LOC_ERR  QString("CardUtil, Error: ")
     
    197199        for (uint i = 0; i < list.size(); i++)
    198200            devs.push_back(QString::number(list[i]));
    199201    }
     202    else if (rawtype.upper() == "HDHOMERUN")
     203    {
     204
     205        uint32_t  target_ip   = 0;
     206        uint32_t  device_type = HDHOMERUN_DEVICE_TYPE_TUNER;
     207        uint32_t  device_id   = HDHOMERUN_DEVICE_ID_WILDCARD;
     208        const int max_count   = 50;
     209        hdhomerun_discover_device_t result_list[max_count];
     210
     211        int result = hdhomerun_discover_find_devices_custom(
     212                            target_ip,
     213                            device_type,
     214                            device_id,
     215                            result_list,
     216                            max_count);
     217
     218        if (result == -1)
     219        {
     220            VERBOSE(VB_IMPORTANT, "CardUtil::ProbeVideoDevices: Error finding HDHomerun devices");
     221            return devs;
     222        }
     223
     224        if (result == 20)
     225            VERBOSE(VB_IMPORTANT, "CardUtil::ProbeVideoDevices: Warning: may be > 20 HDHomerun devices");
     226
     227        // Fixme -- figure out some way to return ip address as well
     228        for (int i = 0; i < result; i++)
     229        {
     230            QString did = QString("%1").arg(result_list[i].device_id,0, 16);
     231            did=did.upper();
     232
     233            devs.push_back(did + "-0");
     234            devs.push_back(did + "-1");
     235        }
     236    }
    200237    else
    201238    {
    202239        VERBOSE(VB_IMPORTANT, QString("CardUtil::ProbeVideoDevices: ") +
     
    10231060        uint id = 0;
    10241061        for (uint i = 0; !id && (i < 100); i++)
    10251062        {
    1026             name = QString("DVB%1").arg(dev.toUInt());
     1063            bool ok;
     1064            name = QString("DVB%1").arg(dev.toUInt(&ok));
     1065            if (! ok)
     1066            {
     1067                name = QString("HDHR_%1").arg(dev);
     1068            }
    10271069            name += (i) ? QString(":%1").arg(i) : QString("");
    10281070            id = CardUtil::CreateInputGroup(name);
    10291071        }
     
    15481590    }
    15491591    else if (cardtype == "HDHOMERUN")
    15501592    {
    1551         MSqlQuery query(MSqlQuery::InitCon());
    1552         query.prepare(
    1553             "SELECT dbox2_port "
    1554             "FROM capturecard "
    1555             "WHERE cardid = :CARDID");
    1556         query.bindValue(":CARDID", cardid);
    1557 
    1558         if (!query.exec() || !query.isActive() || !query.next())
    1559             label = "[ DB ERROR ]";
    1560         else
    1561             label = QString("[ HDHomeRun : ID %1 Port %2 ]")
    1562                 .arg(videodevice).arg(query.value(0).toString());
     1593        label = QString("[ HDHomeRun : %1 ]").arg(videodevice);
    15631594    }
    15641595    else
    15651596    {
  • mythtv/libs/libmythtv/cardutil.h

    diff -r -u -N -X diff.exclude -x release.19764.0120a -x release.19757.0120a release.19764.0120a/mythtv/libs/libmythtv/cardutil.h release.19757.0120a/mythtv/libs/libmythtv/cardutil.h
     
    106106
    107107    static bool         IsTunerSharingCapable(const QString &rawtype)
    108108    {
    109         return (rawtype == "DVB");
     109        return (rawtype == "DVB")   || (rawtype == "HDHOMERUN");
    110110    }
    111111
    112112    static bool         IsTunerShared(uint cardidA, uint cardidB);
  • mythtv/libs/libmythtv/hdhomerun_includes.h

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

    diff -r -u -N -X diff.exclude -x release.19764.0120a -x release.19757.0120a release.19764.0120a/mythtv/libs/libmythtv/hdhrchannel.cpp release.19757.0120a/mythtv/libs/libmythtv/hdhrchannel.cpp
     
    2626#include "channelutil.h"
    2727#include "frequencytables.h"
    2828
     29#include "hdhrstreamhandler.h"
     30
    2931#define DEBUG_PID_FILTERS
    3032
    3133#define LOC QString("HDHRChan(%1): ").arg(GetDevice())
    3234#define LOC_ERR QString("HDHRChan(%1), Error: ").arg(GetDevice())
    3335
    34 HDHRChannel::HDHRChannel(TVRec *parent, const QString &device, uint tuner)
    35     : DTVChannel(parent),       _control_socket(NULL),
    36       _device_id(0),            _device_ip(0),
    37       _tuner(tuner),            _lock(true)
    38 {
    39     bool valid;
    40     _device_id = device.toUInt(&valid, 16);
    41 
    42     if (valid && hdhomerun_discover_validate_device_id(_device_id))
    43         return;
    44 
    45     _device_id = HDHOMERUN_DEVICE_ID_WILDCARD;
    46     /* Otherwise, is it a valid IP address? */
    47     struct in_addr address;
    48     if (inet_aton(device, &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;
     36HDHRChannel::HDHRChannel(TVRec *parent, const QString &device)
     37    : DTVChannel(parent),       _stream_handler(NULL),
     38      _device_id(device),            _lock(true),
     39      tune_lock(true),          hw_lock(true)
     40{
    5941}
    6042
    6143HDHRChannel::~HDHRChannel(void)
     
    6547
    6648bool HDHRChannel::Open(void)
    6749{
     50    VERBOSE(VB_CHANNEL, LOC + "Opening HDHR channel");
     51
     52    QMutexLocker locker(&hw_lock);
     53
    6854    if (IsOpen())
    6955        return true;
    7056
    71     if (!FindDevice())
    72         return false;
     57    _stream_handler = HDHRStreamHandler::Get(_device_id);
    7358
    7459    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(0, HDHOMERUN_DEVICE_TYPE_WILDCARD, _device_id, &result, 1);
    104     if (ret < 0)
    105     {
    106         VERBOSE(VB_IMPORTANT, LOC_ERR + "Unable to send discovery request" + ENO);
    107         return false;
    108     }
    109     if (ret == 0)
    11060    {
    111         VERBOSE(VB_IMPORTANT, LOC_ERR + QString("device not found"));
     61        Close();
    11262        return false;
    11363    }
    11464
    115     /* Found. */
    116     _device_ip = result.ip_addr;
     65//  nextInputID = currentInputID;
    11766
    118     VERBOSE(VB_IMPORTANT, LOC +
    119             QString("device found at address %1.%2.%3.%4")
    120             .arg((_device_ip>>24) & 0xFF).arg((_device_ip>>16) & 0xFF)
    121             .arg((_device_ip>> 8) & 0xFF).arg((_device_ip>> 0) & 0xFF));
     67    return _stream_handler->Connected();
    12268
    123     return true;
    12469}
    12570
    126 bool HDHRChannel::Connect(void)
     71void HDHRChannel::Close()
    12772{
    128     _control_socket = hdhomerun_control_create(_device_id, _device_ip);
    129     if (!_control_socket)
    130     {
    131         VERBOSE(VB_IMPORTANT, LOC_ERR + "Unable to create control socket");
    132         return false;
    133     }
     73    VERBOSE(VB_CHANNEL, LOC + "Closing HDHR channel");
    13474
    135     if (hdhomerun_control_get_local_addr(_control_socket) == 0)
    136     {
    137         VERBOSE(VB_IMPORTANT, LOC_ERR + "Unable to connect to device");
    138         return false;
    139     }
     75    if (! IsOpen())
     76        return; // this caller didn't have it open in the first place..
    14077
    141     VERBOSE(VB_CHANNEL, LOC + "Successfully connected to device");
    142     return true;
     78    HDHRStreamHandler::Return(_stream_handler);
    14379}
    14480
    145 QString HDHRChannel::DeviceGet(const QString &name, bool report_error_return)
    146 {
    147     QMutexLocker locker(&_lock);
    148 
    149     if (!_control_socket)
    150     {
    151         VERBOSE(VB_IMPORTANT, LOC_ERR + "Get request failed (not connected)");
    152         return QString::null;
    153     }
    154 
    155     char *value = NULL;
    156     char *error = NULL;
    157     if (hdhomerun_control_get(_control_socket, name, &value, &error) < 0)
    158     {
    159         VERBOSE(VB_IMPORTANT, LOC_ERR + "Get request failed" + ENO);
    160         return QString::null;
    161     }
    162 
    163     if (report_error_return && error)
    164     {
    165         VERBOSE(VB_IMPORTANT, LOC_ERR +
    166                 QString("DeviceGet(%1): %2").arg(name).arg(error));
    167 
    168         return QString::null;
    169     }
    170 
    171     return QString(value);
    172 }
    173 
    174 QString HDHRChannel::DeviceSet(const QString &name, const QString &val,
    175                                bool report_error_return)
     81bool HDHRChannel::EnterPowerSavingMode(void)
    17682{
    177     QMutexLocker locker(&_lock);
    178 
    179     if (!_control_socket)
    180     {
    181         VERBOSE(VB_IMPORTANT, LOC_ERR + "Set request failed (not connected)");
    182         return QString::null;
    183     }
    184 
    185     char *value = NULL;
    186     char *error = NULL;
    187     if (hdhomerun_control_set(_control_socket, name, val, &value, &error) < 0)
    188     {
    189         VERBOSE(VB_IMPORTANT, LOC_ERR + "Set request failed" + ENO);
    190 
    191         return QString::null;
    192     }
    193 
    194     if (report_error_return && error)
    195     {
    196         VERBOSE(VB_IMPORTANT, LOC_ERR +
    197                 QString("DeviceSet(%1 %2): %3").arg(name).arg(val).arg(error));
    198 
    199         return QString::null;
    200     }
    201 
    202     return QString(value);
     83    if ( IsOpen())
     84        return _stream_handler->EnterPowerSavingMode();
     85    else
     86        return true;
    20387}
    20488
    205 QString HDHRChannel::TunerGet(const QString &name, bool report_error_return)
    206 {
    207     return DeviceGet(QString("/tuner%1/%2").arg(_tuner).arg(name),
    208                      report_error_return);
    209 }
    21089
    211 QString HDHRChannel::TunerSet(const QString &name, const QString &value,
    212                               bool report_error_return)
     90bool HDHRChannel::IsOpen(void) const
    21391{
    214     return DeviceSet(QString("/tuner%1/%2").arg(_tuner).arg(name), value,
    215                      report_error_return);
     92      return (_stream_handler != NULL);
    21693}
    21794
    218 bool HDHRChannel::DeviceSetTarget(unsigned short localPort)
     95bool HDHRChannel::Init(QString &inputname, QString &startchannel, bool setchan)
    21996{
    220     if (localPort == 0)
    221     {
    222         return false;
    223     }
     97    if (setchan && !IsOpen())
     98        Open();
    22499
    225     unsigned long localIP = hdhomerun_control_get_local_addr(_control_socket);
    226     if (localIP == 0)
    227     {
    228         return false;
    229     }
    230 
    231     QString configValue = QString("%1.%2.%3.%4:%5")
    232         .arg((localIP >> 24) & 0xFF).arg((localIP >> 16) & 0xFF)
    233         .arg((localIP >>  8) & 0xFF).arg((localIP >>  0) & 0xFF)
    234         .arg(localPort);
    235 
    236     if (!TunerSet("target", configValue))
    237     {
    238         return false;
    239     }
    240 
    241     return true;
    242 }
    243 
    244 bool HDHRChannel::DeviceClearTarget()
    245 {
    246     return TunerSet("target", "0.0.0.0:0");
     100    return ChannelBase::Init(inputname, startchannel, setchan);
    247101}
    248102
    249103bool HDHRChannel::SetChannelByString(const QString &channum)
     
    277131        return SwitchToInput(inputName, channum);
    278132
    279133    ClearDTVInfo();
    280     _ignore_filters = false;
    281134
    282135    InputMap::const_iterator it = inputs.find(currentInputID);
    283136    if (it == inputs.end())
     
    349202    if (mpeg_prog_num && (GetTuningMode() == "mpeg"))
    350203    {
    351204        QString pnum = QString::number(mpeg_prog_num);
    352         _ignore_filters = QString::null != TunerSet("program", pnum, false);
     205        //_ignore_filters = _stream_handler->TuneProgram(pnum);
     206        _stream_handler->TuneProgram(pnum);
    353207    }
    354208
    355209    return true;
     
    398252            QString("TuneTo(%1,%2)").arg(frequency).arg(modulation));
    399253
    400254    if (modulation == "8vsb")
    401         ok = TunerSet("channel", QString("8vsb:%1").arg(frequency));
     255        ok = _stream_handler->TuneChannel(QString("8vsb:%1").arg(frequency));
    402256    else if (modulation == "qam_64")
    403         ok = TunerSet("channel", QString("qam64:%1").arg(frequency));
     257        ok = _stream_handler->TuneChannel(QString("qam64:%1").arg(frequency));
    404258    else if (modulation == "qam_256")
    405         ok = TunerSet("channel", QString("qam256:%1").arg(frequency));
     259        ok = _stream_handler->TuneChannel(QString("qam256:%1").arg(frequency));
    406260
    407261    if (ok)
    408262        SetSIStandard(si_std);
    409263
    410264    return ok;
    411265}
    412 
    413 bool HDHRChannel::AddPID(uint pid, bool do_update)
    414 {
    415     QMutexLocker locker(&_lock);
    416 
    417     vector<uint>::iterator it;
    418     it = lower_bound(_pids.begin(), _pids.end(), pid);
    419     if (it != _pids.end() && *it == pid)
    420     {
    421 #ifdef DEBUG_PID_FILTERS
    422         VERBOSE(VB_CHANNEL, "AddPID(0x"<<hex<<pid<<dec<<") NOOP");
    423 #endif // DEBUG_PID_FILTERS
    424         return true;
    425     }
    426 
    427     _pids.insert(it, pid);
    428 
    429 #ifdef DEBUG_PID_FILTERS
    430     VERBOSE(VB_CHANNEL, "AddPID(0x"<<hex<<pid<<dec<<")");
    431 #endif // DEBUG_PID_FILTERS
    432 
    433     if (do_update)
    434         return UpdateFilters();
    435     return true;
    436 }
    437 
    438 bool HDHRChannel::DelPID(uint pid, bool do_update)
    439 {
    440     QMutexLocker locker(&_lock);
    441 
    442     vector<uint>::iterator it;
    443     it = lower_bound(_pids.begin(), _pids.end(), pid);
    444     if (it == _pids.end())
    445     {
    446 #ifdef DEBUG_PID_FILTERS
    447         VERBOSE(VB_CHANNEL, "DelPID(0x"<<hex<<pid<<dec<<") NOOP");
    448 #endif // DEBUG_PID_FILTERS
    449 
    450        return true;
    451     }
    452 
    453     if (*it == pid)
    454     {
    455 #ifdef DEBUG_PID_FILTERS
    456         VERBOSE(VB_CHANNEL, "DelPID(0x"<<hex<<pid<<dec<<") -- found");
    457 #endif // DEBUG_PID_FILTERS
    458         _pids.erase(it);
    459     }
    460     else
    461     {
    462 #ifdef DEBUG_PID_FILTERS
    463         VERBOSE(VB_CHANNEL, "DelPID(0x"<<hex<<pid<<dec<<") -- failed");
    464 #endif // DEBUG_PID_FILTERS
    465     }
    466 
    467     if (do_update)
    468         return UpdateFilters();
    469     return true;
    470 }
    471 
    472 bool HDHRChannel::DelAllPIDs(void)
    473 {
    474     QMutexLocker locker(&_lock);
    475 
    476 #ifdef DEBUG_PID_FILTERS
    477     VERBOSE(VB_CHANNEL, "DelAllPID()");
    478 #endif // DEBUG_PID_FILTERS
    479 
    480     _pids.clear();
    481 
    482     return UpdateFilters();
    483 }
    484 
    485 QString filt_str(uint pid)
    486 {
    487     uint pid0 = (pid / (16*16*16)) % 16;
    488     uint pid1 = (pid / (16*16))    % 16;
    489     uint pid2 = (pid / (16))        % 16;
    490     uint pid3 = pid % 16;
    491     return QString("0x%1%2%3%4")
    492         .arg(pid0,0,16).arg(pid1,0,16)
    493         .arg(pid2,0,16).arg(pid3,0,16);
    494 }
    495 
    496 bool HDHRChannel::UpdateFilters(void)
    497 {
    498     QMutexLocker locker(&_lock);
    499 
    500     QString filter = "";
    501 
    502     vector<uint> range_min;
    503     vector<uint> range_max;
    504 
    505     if (_ignore_filters)
    506         return true;
    507 
    508     for (uint i = 0; i < _pids.size(); i++)
    509     {
    510         uint pid_min = _pids[i];
    511         uint pid_max  = pid_min;
    512         for (uint j = i + 1; j < _pids.size(); j++)
    513         {
    514             if (pid_max + 1 != _pids[j])
    515                 break;
    516             pid_max++;
    517             i++;
    518         }
    519         range_min.push_back(pid_min);
    520         range_max.push_back(pid_max);
    521     }
    522 
    523     if (range_min.size() > 16)
    524     {
    525         range_min.resize(16);
    526         uint pid_max = range_max.back();
    527         range_max.resize(15);
    528         range_max.push_back(pid_max);
    529     }
    530 
    531     for (uint i = 0; i < range_min.size(); i++)
    532     {
    533         filter += filt_str(range_min[i]);
    534         if (range_min[i] != range_max[i])
    535             filter += QString("-%1").arg(filt_str(range_max[i]));
    536         filter += " ";
    537     }
    538 
    539     filter = filter.stripWhiteSpace();
    540 
    541     QString new_filter = TunerSet("filter", filter);
    542 
    543 #ifdef DEBUG_PID_FILTERS
    544     QString msg = QString("Filter: '%1'").arg(filter);
    545     if (filter != new_filter)
    546         msg += QString("\n\t\t\t\t'%2'").arg(new_filter);
    547 
    548     VERBOSE(VB_CHANNEL, msg);
    549 #endif // DEBUG_PID_FILTERS
    550 
    551     return filter == new_filter;
    552 }
  • mythtv/libs/libmythtv/hdhrchannel.h

    diff -r -u -N -X diff.exclude -x release.19764.0120a -x release.19757.0120a release.19764.0120a/mythtv/libs/libmythtv/hdhrchannel.h release.19757.0120a/mythtv/libs/libmythtv/hdhrchannel.h
     
    1515
    1616// HDHomeRun headers
    1717#ifdef USING_HDHOMERUN
    18 #include "hdhomerun/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/hdhrrecorder.cpp

    diff -r -u -N -X diff.exclude -x release.19764.0120a -x release.19757.0120a release.19764.0120a/mythtv/libs/libmythtv/hdhrrecorder.cpp release.19757.0120a/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(true)
     47      _pid_lock(true),
     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        if (!paused)
     447        {
     448            assert(_stream_handler);
     449            assert(_stream_data);
    418450
    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     }
     451            _stream_handler->RemoveListener(_stream_data);
    427452
    428     if (need_pcr_pid && (_input_pmt->PCRPID()))
    429     {
    430         add_pid.push_back(_input_pmt->PCRPID());
    431         _stream_data->AddWritingPID(_input_pmt->PCRPID());
     453            paused = true;
     454            pauseWait.wakeAll();
     455            if (tvrec)
     456                tvrec->RecorderPaused();
     457        }
     458        unpauseWait.wait(timeout);
    432459    }
    433460
    434     // Adjust for EIT
    435     AdjustEITPIDs();
    436     for (uint i = 0; i < _eit_pids.size(); i++)
     461    if (!request_pause && paused)
    437462    {
    438         add_pid.push_back(_eit_pids[i]);
    439         _stream_data->AddListeningPID(_eit_pids[i]);
    440     }
     463        paused = false;
    441464
    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     }
     465        assert(_stream_handler);
     466        assert(_stream_data);
    454467
    455     for (it = add_pid.begin(); it != add_pid.end(); ++it)
    456         _channel->AddPID(*it, false);
    457 
    458     _channel->UpdateFilters();
     468        _stream_handler->AddListener(_stream_data);
     469    }
    459470
    460     return add_pid.size();
     471    return paused;
    461472}
    462473
    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)
     474void HDHRRecorder::BufferedWrite(const TSPacket &tspacket)
    467475{
    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);
     476    // Care must be taken to make sure that the packet actually gets written
     477    // as the decision to actually write it has already been made
    475478
    476     if (!changes)
    477         return false;
    478 
    479     for (uint i = 0; i < del.size(); i++)
     479    // Do we have to buffer the packet for exact keyframe detection?
     480    if (_buffer_packets)
    480481    {
    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);
     482        int idx = _payload_buffer.size();
     483        _payload_buffer.resize(idx + TSPacket::SIZE);
     484        memcpy(&_payload_buffer[idx], tspacket.data(), TSPacket::SIZE);
     485        return;
    485486    }
    486487
    487     for (uint i = 0; i < add.size(); i++)
    488         _eit_pids.push_back(add[i]);
    489 
    490     return true;
     488    // We are free to write the packet, but if we have buffered packet[s]
     489    // we have to write them first...
     490    if (!_payload_buffer.empty())
     491    {
     492        if (ringBuffer)
     493            ringBuffer->Write(&_payload_buffer[0], _payload_buffer.size());
     494        _payload_buffer.clear();
     495    }
     496    if (ringBuffer)
     497        ringBuffer->Write(tspacket.data(), TSPacket::SIZE);
    491498}
    492499
  • mythtv/libs/libmythtv/hdhrrecorder.h

    diff -r -u -N -X diff.exclude -x release.19764.0120a -x release.19757.0120a release.19764.0120a/mythtv/libs/libmythtv/hdhrrecorder.h release.19757.0120a/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 release.19764.0120a -x release.19757.0120a release.19764.0120a/mythtv/libs/libmythtv/hdhrsignalmonitor.cpp release.19757.0120a/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())
     
    4142                                     HDHRChannel* _channel,
    4243                                     uint64_t _flags, const char *_name)
    4344    : DTVSignalMonitor(db_cardnum, _channel, _flags, _name),
    44       dtvMonitorRunning(false)
     45      streamHandlerStarted(false),
     46      streamHandler(NULL)
     47
    4548{
    4649    VERBOSE(VB_CHANNEL, LOC + "ctor");
    4750
    48     _channel->DelAllPIDs();
    49 
    5051    signalStrength.SetThreshold(45);
    5152
    5253    AddFlags(kDTVSigMon_WaitForSig);
     54
     55    streamHandler = HDHRStreamHandler::Get(_channel->GetDevice());
    5356}
    5457
    5558/** \fn HDHRSignalMonitor::~HDHRSignalMonitor()
     
    5962{
    6063    VERBOSE(VB_CHANNEL, LOC + "dtor");
    6164    Stop();
     65    HDHRStreamHandler::Return(streamHandler);
    6266}
    6367
    6468void HDHRSignalMonitor::deleteLater(void)
     
    7579{
    7680    VERBOSE(VB_CHANNEL, LOC + "Stop() -- begin");
    7781    SignalMonitor::Stop();
    78     if (dtvMonitorRunning)
    79     {
    80         dtvMonitorRunning = false;
    81         pthread_join(table_monitor_thread, NULL);
    82     }
    83     VERBOSE(VB_CHANNEL, LOC + "Stop() -- end");
    84 }
     82    if (GetStreamData())
     83        streamHandler->RemoveListener(GetStreamData());
     84    streamHandlerStarted = false;
     85    streamHandler->SetRetuneAllowed(false, NULL, NULL);
    8586
    86 void *HDHRSignalMonitor::TableMonitorThread(void *param)
    87 {
    88     HDHRSignalMonitor *mon = (HDHRSignalMonitor*) param;
    89     mon->RunTableMonitor();
    90     return NULL;
    91 }
    92 
    93 bool HDHRSignalMonitor::UpdateFiltersFromStreamData(void)
    94 {
    95     vector<int> add_pids;
    96     vector<int> del_pids;
    97 
    98     if (!GetStreamData())
    99         return false;
    100 
    101     UpdateListeningForEIT();
    102 
    103     const pid_map_t &listening = GetStreamData()->ListeningPIDs();
    104 
    105     // PIDs that need to be added..
    106     pid_map_t::const_iterator lit = listening.constBegin();
    107     for (; lit != listening.constEnd(); ++lit)
    108         if (lit.data() && (filters.find(lit.key()) == filters.end()))
    109             add_pids.push_back(lit.key());
    110 
    111     // PIDs that need to be removed..
    112     FilterMap::const_iterator fit = filters.constBegin();
    113     for (; fit != filters.constEnd(); ++fit)
    114         if (listening.find(fit.key()) == listening.end())
    115             del_pids.push_back(fit.key());
    116 
    117     HDHRChannel *hdhr = dynamic_cast<HDHRChannel*>(channel);
    118     // Remove PIDs
    119     bool ok = true;
    120     vector<int>::iterator dit = del_pids.begin();
    121     for (; dit != del_pids.end(); ++dit)
    122     {
    123         ok &= hdhr->DelPID(*dit);
    124         filters.erase(filters.find(*dit));
    125     }
    126 
    127     // Add PIDs
    128     vector<int>::iterator ait = add_pids.begin();
    129     for (; ait != add_pids.end(); ++ait)
    130     {
    131         ok &= hdhr->AddPID(*ait);
    132         filters[*ait] = 1;
    133     }
    134 
    135     return ok;
     87    VERBOSE(VB_CHANNEL, LOC + "Stop() -- end");
    13688}
    13789
    138 void HDHRSignalMonitor::RunTableMonitor(void)
     90HDHRChannel *HDHRSignalMonitor::GetHDHRChannel(void)
    13991{
    140     dtvMonitorRunning = true;
    141 
    142     struct hdhomerun_video_sock_t *_video_socket;
    143     _video_socket = hdhomerun_video_create(0, VIDEO_DATA_BUFFER_SIZE_1S);
    144     if (!_video_socket)
    145     {
    146         VERBOSE(VB_IMPORTANT, LOC_ERR + "Failed to get video socket");
    147         return;
    148     }
    149 
    150     HDHRChannel *hdrc = dynamic_cast<HDHRChannel*>(channel);
    151     uint localPort = hdhomerun_video_get_local_port(_video_socket);
    152     if (!hdrc->DeviceSetTarget(localPort))
    153     {
    154         hdhomerun_video_destroy(_video_socket);
    155         VERBOSE(VB_IMPORTANT, LOC_ERR + "Failed to set target");
    156         return;
    157     }
    158 
    159     VERBOSE(VB_CHANNEL, LOC + "RunTableMonitor(): " +
    160             QString("begin (# of pids %1)")
    161             .arg(GetStreamData()->ListeningPIDs().size()));
    162 
    163     while (dtvMonitorRunning && GetStreamData())
    164     {
    165         UpdateFiltersFromStreamData();
    166 
    167         size_t data_length;
    168         unsigned char *data_buffer =
    169             hdhomerun_video_recv(_video_socket,
    170                                          VIDEO_DATA_BUFFER_SIZE_1S / 5,
    171                                          &data_length);
    172 
    173         if (data_buffer)
    174         {
    175             GetStreamData()->ProcessData(data_buffer, data_length);
    176             continue;
    177         }
    178 
    179         usleep(2500);
    180     }
    181 
    182     hdrc->DeviceClearTarget();
    183     hdhomerun_video_destroy(_video_socket);
    184 
    185     VERBOSE(VB_CHANNEL, LOC + "RunTableMonitor(): -- shutdown");
    186 
    187     // TODO teardown PID filters here
    188 
    189     VERBOSE(VB_CHANNEL, LOC + "RunTableMonitor(): -- end");
     92    return dynamic_cast<HDHRChannel*>(channel);
    19093}
    19194
    19295/** \fn HDHRSignalMonitor::UpdateValues()
     
    204107    if (!running || exit)
    205108        return;
    206109
    207     if (dtvMonitorRunning)
     110    if (streamHandlerStarted)
    208111    {
    209112        EmitHDHRSignals();
    210113        if (IsAllGood())
     
    215118        return;
    216119    }
    217120
    218     QString msg = ((HDHRChannel*)channel)->TunerGet("status");
     121    QString msg = streamHandler->GetTunerStatus();
    219122    //ss  = signal strength,        [0,100]
    220123    //snq = signal to noise quality [0,100]
    221124    //seq = signal error quality    [0,100]
     
    253156                   kDTVSigMon_WaitForMGT | kDTVSigMon_WaitForVCT |
    254157                   kDTVSigMon_WaitForNIT | kDTVSigMon_WaitForSDT))
    255158    {
    256         pthread_create(&table_monitor_thread, NULL,
    257                        TableMonitorThread, this);
    258 
    259         VERBOSE(VB_CHANNEL, LOC + "UpdateValues() -- "
    260                 "Waiting for table monitor to start");
    261 
    262         while (!dtvMonitorRunning)
    263             usleep(50);
    264 
    265         VERBOSE(VB_CHANNEL, LOC + "UpdateValues() -- "
    266                 "Table monitor started");
     159        streamHandler->AddListener(GetStreamData());
     160        streamHandlerStarted = true;
    267161    }
    268162
    269163    update_done = true;
  • mythtv/libs/libmythtv/hdhrsignalmonitor.h

    diff -r -u -N -X diff.exclude -x release.19764.0120a -x release.19757.0120a release.19764.0120a/mythtv/libs/libmythtv/hdhrsignalmonitor.h release.19757.0120a/mythtv/libs/libmythtv/hdhrsignalmonitor.h
     
    77#include "qstringlist.h"
    88
    99class HDHRChannel;
     10class HDHRStreamHandler;
    1011
    1112typedef QMap<uint,int> FilterMap;
    1213
     
    2122
    2223    void Stop(void);
    2324
    24     bool UpdateFiltersFromStreamData(void);
    25 
    2625  public slots:
    2726    void deleteLater(void);
    2827
     
    3332    virtual void UpdateValues(void);
    3433    void EmitHDHRSignals(void);
    3534
    36     static void *TableMonitorThread(void *param);
    37     void RunTableMonitor(void);
    38 
    3935    bool SupportsTSMonitoring(void);
    4036
     37    HDHRChannel *GetHDHRChannel(void);
     38
    4139  protected:
    42     bool               dtvMonitorRunning;
    43     pthread_t          table_monitor_thread;
    4440
    45     FilterMap          filters; ///< PID filters for table monitoring
     41    bool               streamHandlerStarted;
     42    HDHRStreamHandler  *streamHandler;
     43
    4644};
    4745
    4846#endif // HDHRSIGNALMONITOR_H
  • mythtv/libs/libmythtv/hdhrstreamhandler.cpp

    diff -r -u -N -X diff.exclude -x release.19764.0120a -x release.19757.0120a release.19764.0120a/mythtv/libs/libmythtv/hdhrstreamhandler.cpp release.19757.0120a/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(true),
     106    _running(false),
     107
     108    _sigmon(NULL),
     109    _channel(NULL),
     110
     111    _pid_lock(true),
     112    _listener_lock(true),
     113    _hdhr_lock(true)
     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);
     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, &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, val, &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    if (!TunerSet("target", configValue))
     290    {
     291        return false;
     292    }
     293
     294    return true;
     295}
     296
     297bool HDHRStreamHandler::DeviceClearTarget()
     298{
     299    return (QString::null != TunerSet("target", "0.0.0.0:0"));
     300}
     301
     302QString HDHRStreamHandler::GetTunerStatus() {
     303    return TunerGet("status");
     304}
     305
     306bool HDHRStreamHandler::Connected() {
     307    // FIXME
     308    return (_control_socket != NULL);
     309}
     310
     311bool HDHRStreamHandler::TuneChannel(QString chn) {
     312    QString current = TunerGet("channel");
     313    if (current == chn)
     314    {
     315        VERBOSE(VB_RECORD, QString(LOC + "Not Re-Tuning channel %1").arg(chn));
     316        return true;
     317    }
     318    VERBOSE(VB_RECORD, QString(LOC + "Tuning channel %1 (was %2)").arg(chn).arg(current));
     319    return (QString::null != TunerSet("channel", chn));
     320}
     321
     322bool HDHRStreamHandler::TuneProgram(QString pnum) {
     323    VERBOSE(VB_RECORD, QString(LOC + "Tuning program %1").arg(pnum));
     324    return (QString::null != TunerSet("program", pnum, false));
     325}
     326
     327void HDHRStreamHandler::AddListener(MPEGStreamData *data)
     328{
     329    VERBOSE(VB_RECORD, LOC + "AddListener("<<data<<") -- begin");
     330    assert(data);
     331
     332    _listener_lock.lock();
     333
     334    VERBOSE(VB_RECORD, LOC + "AddListener("<<data<<") -- locked");
     335
     336    _stream_data_list.push_back(data);
     337
     338    _listener_lock.unlock();
     339
     340    Start();
     341
     342    VERBOSE(VB_RECORD, LOC + "AddListener("<<data<<") -- end");
     343}
     344
     345void HDHRStreamHandler::RemoveListener(MPEGStreamData *data)
     346{
     347    VERBOSE(VB_RECORD, LOC + "RemoveListener("<<data<<") -- begin");
     348    assert(data);
     349
     350    _listener_lock.lock();
     351
     352    VERBOSE(VB_RECORD, LOC + "RemoveListener("<<data<<") -- locked");
     353
     354    vector<MPEGStreamData*>::iterator it =
     355        find(_stream_data_list.begin(), _stream_data_list.end(), data);
     356
     357    if (it != _stream_data_list.end())
     358        _stream_data_list.erase(it);
     359
     360    if (_stream_data_list.empty())
     361    {
     362        _listener_lock.unlock();
     363        Stop();
     364    }
     365    else
     366    {
     367        _listener_lock.unlock();
     368    }
     369
     370    VERBOSE(VB_RECORD, LOC + "RemoveListener("<<data<<") -- end");
     371}
     372
     373void *run_hdhr_stream_handler_thunk(void *param)
     374{
     375    HDHRStreamHandler *mon = (HDHRStreamHandler*) param;
     376    mon->Run();
     377    return NULL;
     378}
     379
     380void HDHRStreamHandler::Start(void)
     381{
     382    QMutexLocker locker(&_start_stop_lock);
     383
     384    _eit_pids.clear();
     385
     386    if (!IsRunning())
     387    {
     388        pthread_create(&_reader_thread, NULL,
     389                       run_hdhr_stream_handler_thunk, this);
     390
     391        while (!IsRunning())
     392            _running_state_changed.wait(100);
     393    }
     394}
     395
     396void HDHRStreamHandler::Stop(void)
     397{
     398    QMutexLocker locker(&_start_stop_lock);
     399
     400    if (IsRunning())
     401    {
     402        SetRunning(false);
     403        pthread_join(_reader_thread, NULL);
     404    }
     405}
     406
     407void HDHRStreamHandler::Run(void)
     408{
     409    SetRunning(true);
     410    RunTS();
     411}
     412
     413/** \fn HDHRStreamHandler::RunTS(void)
     414 *  \brief Uses TS filtering devices to read a DVB device for tables & data
     415 *
     416 *  This supports all types of MPEG based stream data, but is extreemely
     417 *  slow with DVB over USB 1.0 devices which for efficiency reasons buffer
     418 *  a stream until a full block transfer buffer full of the requested
     419 *  tables is available. This takes a very long time when you are just
     420 *  waiting for a PAT or PMT table, and the buffer is hundreds of packets
     421 *  in size.
     422 */
     423void HDHRStreamHandler::RunTS(void)
     424{
     425    int remainder = 0;
     426    VERBOSE(VB_RECORD, LOC + "RunTS()");
     427
     428    /* Calculate buffer size */
     429    uint buffersize = gContext->GetNumSetting(
     430        "HDRingbufferSize", 50 * TSPacket::SIZE) * 1024;
     431    buffersize /= VIDEO_DATA_PACKET_SIZE;
     432    buffersize *= VIDEO_DATA_PACKET_SIZE;
     433
     434    // Buffer should be at least about 1MB..
     435    buffersize = max(49 * TSPacket::SIZE * 128, buffersize);
     436
     437    VERBOSE(VB_GENERAL, QString(LOC + "HD Ringbuffer size = %1 KB").arg(buffersize / 1024));
     438
     439    /* Create TS socket. */
     440    _video_socket = hdhomerun_video_create(0, buffersize);
     441    if (!_video_socket)
     442    {
     443        VERBOSE(VB_IMPORTANT, LOC + "Open() failed to open socket");
     444        return;
     445    }
     446
     447    uint localPort = hdhomerun_video_get_local_port(_video_socket);
     448    if (!DeviceSetTarget(localPort))
     449    {
     450        VERBOSE(VB_IMPORTANT, LOC_ERR + "Starting recording (set target failed). Aborting.");
     451        return;
     452    }
     453    hdhomerun_video_flush(_video_socket);
     454
     455    bool _error = false;
     456
     457    VERBOSE(VB_RECORD, LOC + "RunTS(): begin");
     458
     459    int loopcount=0;
     460    size_t data_count=0;
     461    while (IsRunning() && !_error)
     462    {
     463        loopcount++;
     464        if (0 == (loopcount % 1000)) {
     465            QMutexLocker locker(&_listener_lock);
     466            VERBOSE(VB_RECORD, LOC + QString("RunTS(): loopcount = %1, datacount = %2, listen")
     467                   .arg(loopcount).arg(data_count));
     468            data_count=0;
     469        }
     470        UpdateFiltersFromStreamData();
     471
     472        size_t read_size = 64 * 1024; // read about 64KB
     473        read_size /= VIDEO_DATA_PACKET_SIZE;
     474        read_size *= VIDEO_DATA_PACKET_SIZE;
     475
     476        size_t data_length;
     477        unsigned char *data_buffer =
     478            hdhomerun_video_recv(_video_socket, read_size, &data_length);
     479
     480        if (! data_buffer)
     481        {
     482            usleep(5000);
     483            continue;
     484        }
     485
     486        data_count+=data_length;
     487        // Assume data_length is a multiple of 188 (packet size)
     488        ASSERT(0 == ( data_length % 188) );
     489
     490        _listener_lock.lock();
     491
     492        if (_stream_data_list.empty())
     493        {
     494            _listener_lock.unlock();
     495            continue;
     496        }
     497
     498        for (uint i = 0; i < _stream_data_list.size(); i++)
     499        {
     500            remainder = _stream_data_list[i]->ProcessData(data_buffer, data_length);
     501        }
     502       
     503        _listener_lock.unlock();
     504        if (remainder != 0)
     505            VERBOSE(VB_GENERAL, QString(LOC + "RunTS(): data_length = %1 remainder = %2")
     506                    .arg(data_length).arg(remainder));
     507    }
     508    VERBOSE(VB_RECORD, LOC + "RunTS(): " + "shutdown");
     509
     510    DelAllPIDs();
     511
     512    DeviceClearTarget();
     513    VERBOSE(VB_RECORD, LOC + "RunTS(): " + "end");
     514
     515    hdhomerun_video_sock_t* tmp_video_socket;
     516    {
     517        QMutexLocker locker(&_hdhr_lock);
     518        tmp_video_socket = _video_socket;
     519        _video_socket=NULL;
     520    }
     521     
     522    hdhomerun_video_destroy(tmp_video_socket);
     523
     524    SetRunning(false);
     525}
     526
     527bool HDHRStreamHandler::AddPID(uint pid, bool do_update)
     528{
     529    QMutexLocker locker(&_pid_lock);
     530
     531    vector<uint>::iterator it;
     532    it = lower_bound(_pid_info.begin(), _pid_info.end(), pid);
     533    if (it != _pid_info.end() && *it == pid)
     534    {
     535#ifdef DEBUG_PID_FILTERS
     536        VERBOSE(VB_CHANNEL, "AddPID(0x"<<hex<<pid<<dec<<", " << do_update << ") NOOP");
     537#endif // DEBUG_PID_FILTERS
     538        return true;
     539    }
     540
     541    _pid_info.insert(it, pid);
     542
     543#ifdef DEBUG_PID_FILTERS
     544    VERBOSE(VB_CHANNEL, "AddPID(0x"<<hex<<pid<<dec<<")", " << do_update << ");
     545#endif // DEBUG_PID_FILTERS
     546
     547    if (do_update)
     548        return UpdateFilters();
     549    return true;
     550}
     551
     552bool HDHRStreamHandler::DelPID(uint pid, bool do_update)
     553{
     554    QMutexLocker locker(&_pid_lock);
     555
     556    vector<uint>::iterator it;
     557    it = lower_bound(_pid_info.begin(), _pid_info.end(), pid);
     558    if (it == _pid_info.end())
     559    {
     560#ifdef DEBUG_PID_FILTERS
     561        VERBOSE(VB_CHANNEL, "DelPID(0x"<<hex<<pid<<dec<<", " << do_update << ") NOOP");
     562#endif // DEBUG_PID_FILTERS
     563
     564       return true;
     565    }
     566
     567    if (*it == pid)
     568    {
     569#ifdef DEBUG_PID_FILTERS
     570        VERBOSE(VB_CHANNEL, "DelPID(0x"<<hex<<pid<<dec<<", " << do_update << ") -- found");
     571#endif // DEBUG_PID_FILTERS
     572        _pid_info.erase(it);
     573    }
     574    else
     575    {
     576#ifdef DEBUG_PID_FILTERS
     577        VERBOSE(VB_CHANNEL, "DelPID(0x"<<hex<<pid<<dec<<", " << do_update << ") -- failed");
     578#endif // DEBUG_PID_FILTERS
     579    }
     580
     581    if (do_update)
     582        return UpdateFilters();
     583    return true;
     584}
     585
     586bool HDHRStreamHandler::DelAllPIDs(void)
     587{
     588    QMutexLocker locker(&_pid_lock);
     589
     590#ifdef DEBUG_PID_FILTERS
     591    VERBOSE(VB_CHANNEL, "DelAllPID()");
     592#endif // DEBUG_PID_FILTERS
     593
     594    _pid_info.clear();
     595
     596    return UpdateFilters();
     597}
     598
     599QString filt_str(uint pid)
     600{
     601    uint pid0 = (pid / (16*16*16)) % 16;
     602    uint pid1 = (pid / (16*16))    % 16;
     603    uint pid2 = (pid / (16))        % 16;
     604    uint pid3 = pid % 16;
     605    return QString("0x%1%2%3%4")
     606        .arg(pid0,0,16).arg(pid1,0,16)
     607        .arg(pid2,0,16).arg(pid3,0,16);
     608}
     609
     610bool HDHRStreamHandler::UpdateFilters(void)
     611{
     612#ifdef DEBUG_PID_FILTERS
     613    VERBOSE(VB_CHANNEL, LOC + "UpdateFilters()");
     614#endif // DEBUG_PID_FILTERS
     615    QMutexLocker locker(&_pid_lock);
     616
     617    QString filter = "";
     618
     619    vector<uint> range_min;
     620    vector<uint> range_max;
     621
     622// FIXME
     623//    if (_ignore_filters)
     624 //       return true;
     625
     626    for (uint i = 0; i < _pid_info.size(); i++)
     627    {
     628        uint pid_min = _pid_info[i];
     629        uint pid_max  = pid_min;
     630        for (uint j = i + 1; j < _pid_info.size(); j++)
     631        {
     632            if (pid_max + 1 != _pid_info[j])
     633                break;
     634            pid_max++;
     635            i++;
     636        }
     637        range_min.push_back(pid_min);
     638        range_max.push_back(pid_max);
     639    }
     640    if (range_min.size() > 16)
     641    {
     642        range_min.resize(16);
     643        uint pid_max = range_max.back();
     644        range_max.resize(15);
     645        range_max.push_back(pid_max);
     646    }
     647
     648    for (uint i = 0; i < range_min.size(); i++)
     649    {
     650        filter += filt_str(range_min[i]);
     651        if (range_min[i] != range_max[i])
     652            filter += QString("-%1").arg(filt_str(range_max[i]));
     653        filter += " ";
     654    }
     655
     656    filter = filter.stripWhiteSpace();
     657
     658    QString new_filter = TunerSet("filter", filter);
     659
     660#ifdef DEBUG_PID_FILTERS
     661    QString msg = QString("Filter: '%1'").arg(filter);
     662    if (filter != new_filter)
     663        msg += QString("\n\t\t\t\t'%2'").arg(new_filter);
     664
     665    VERBOSE(VB_CHANNEL, LOC + msg);
     666#endif // DEBUG_PID_FILTERS
     667
     668    return filter == new_filter;
     669}
     670
     671void HDHRStreamHandler::UpdateListeningForEIT(void)
     672{
     673    vector<uint> add_eit, del_eit;
     674
     675    QMutexLocker read_locker(&_listener_lock);
     676
     677    for (uint i = 0; i < _stream_data_list.size(); i++)
     678    {
     679        MPEGStreamData *sd = _stream_data_list[i];
     680        if (sd->HasEITPIDChanges(_eit_pids) &&
     681            sd->GetEITPIDChanges(_eit_pids, add_eit, del_eit))
     682        {
     683            for (uint i = 0; i < del_eit.size(); i++)
     684            {
     685                uint_vec_t::iterator it;
     686                it = find(_eit_pids.begin(), _eit_pids.end(), del_eit[i]);
     687                if (it != _eit_pids.end())
     688                    _eit_pids.erase(it);
     689                sd->RemoveListeningPID(del_eit[i]);
     690            }
     691
     692            for (uint i = 0; i < add_eit.size(); i++)
     693            {
     694                _eit_pids.push_back(add_eit[i]);
     695                sd->AddListeningPID(add_eit[i]);
     696            }
     697        }
     698    }
     699}
     700
     701bool HDHRStreamHandler::UpdateFiltersFromStreamData(void)
     702{
     703
     704    UpdateListeningForEIT();
     705
     706    pid_map_t pids;
     707
     708    {
     709        QMutexLocker read_locker(&_listener_lock);
     710
     711        for (uint i = 0; i < _stream_data_list.size(); i++)
     712            _stream_data_list[i]->GetPIDs(pids);
     713    }
     714
     715    uint_vec_t           add_pids;
     716    vector<uint>         del_pids;
     717
     718    {
     719        QMutexLocker read_locker(&_pid_lock);
     720
     721        // PIDs that need to be added..
     722        pid_map_t::const_iterator lit = pids.constBegin();
     723        for (; lit != pids.constEnd(); ++lit)
     724        {
     725            vector<uint>::iterator it;
     726            it = lower_bound(_pid_info.begin(), _pid_info.end(), lit.key());
     727            if (! (it != _pid_info.end() && *it == lit.key())) {
     728                add_pids.push_back(lit.key());
     729            }
     730        }
     731
     732        // PIDs that need to be removed..
     733        vector<uint>::iterator fit = _pid_info.begin();
     734        for (; fit != _pid_info.end(); ++fit)
     735        {
     736            pid_map_t::const_iterator it = pids.find(*fit);
     737            if(it == pids.end())
     738                del_pids.push_back(*fit);
     739        }
     740    }
     741
     742    bool need_update = false;
     743
     744    // Remove PIDs
     745    bool ok = true;
     746    vector<uint>::iterator dit = del_pids.begin();
     747    for (; dit != del_pids.end(); ++dit)
     748    {
     749        need_update = true;
     750        ok &= DelPID(*dit, false);
     751    }
     752
     753    // Add PIDs
     754    vector<uint>::iterator ait = add_pids.begin();
     755    for (; ait != add_pids.end(); ++ait)
     756    {
     757        need_update = true;
     758        ok &= AddPID(*ait, false);
     759    }
     760
     761    if (need_update)
     762        return UpdateFilters();
     763
     764    return ok;
     765}
     766
     767void HDHRStreamHandler::SetRetuneAllowed(
     768    bool              allow,
     769    DTVSignalMonitor *sigmon,
     770    HDHRChannel       *hdhrchan)
     771{
     772    if (allow && sigmon && hdhrchan)
     773    {
     774        _allow_retune = true;
     775        _sigmon       = sigmon;
     776        _channel   = hdhrchan;
     777    }
     778    else
     779    {
     780        _allow_retune = false;
     781        _sigmon       = NULL;
     782        _channel   = NULL;
     783    }
     784}
     785
     786/** \fn HDHRStreamHandler::SupportsTSMonitoring(void)
     787 *  \brief Returns true if TS monitoring is supported.
     788 *
     789 *   NOTE: If you are using a DEC2000-t device you need to
     790 *   apply the patches provided by Peter Beutner for it, see
     791 *   http://www.gossamer-threads.com/lists/mythtv/dev/166172
     792 *   These patches should make it in to Linux 2.6.15 or 2.6.16.
     793 */
     794bool HDHRStreamHandler::SupportsTSMonitoring(void)
     795{
     796    return false;
     797
     798// FIXME
     799#if 0
     800    const uint pat_pid = 0x0;
     801
     802    {
     803        QMutexLocker locker(&_rec_supports_ts_monitoring_lock);
     804        QMap<uint,bool>::const_iterator it;
     805        it = _rec_supports_ts_monitoring.find(_dvb_dev_num);
     806        if (it != _rec_supports_ts_monitoring.end())
     807            return *it;
     808    }
     809
     810    int dvr_fd = open(_dvr_dev_path.ascii(), O_RDONLY | O_NONBLOCK);
     811    if (dvr_fd < 0)
     812    {
     813        QMutexLocker locker(&_rec_supports_ts_monitoring_lock);
     814        _rec_supports_ts_monitoring[_dvb_dev_num] = false;
     815        return false;
     816    }
     817
     818    bool supports_ts = false;
     819    if (AddPIDFilter(new PIDInfoHDHR(pat_pid)))
     820    {
     821        supports_ts = true;
     822        RemovePIDFilter(pat_pid);
     823    }
     824
     825    close(dvr_fd);
     826
     827    QMutexLocker locker(&_rec_supports_ts_monitoring_lock);
     828    _rec_supports_ts_monitoring[_dvb_dev_num] = supports_ts;
     829
     830    return supports_ts;
     831#endif
     832}
     833
     834void HDHRStreamHandler::SetRunning(bool is_running)
     835{
     836    _running = is_running;
     837    _running_state_changed.wakeAll();
     838}
     839
     840PIDPriority HDHRStreamHandler::GetPIDPriority(uint pid) const
     841{
     842    QMutexLocker reading_locker(&_listener_lock);
     843
     844    PIDPriority tmp = kPIDPriorityNone;
     845
     846    for (uint i = 0; i < _stream_data_list.size(); i++)
     847        tmp = max(tmp, _stream_data_list[i]->GetPIDPriority(pid));
     848
     849    return tmp;
     850}
  • mythtv/libs/libmythtv/hdhrstreamhandler.h

    diff -r -u -N -X diff.exclude -x release.19764.0120a -x release.19757.0120a release.19764.0120a/mythtv/libs/libmythtv/hdhrstreamhandler.h release.19757.0120a/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 release.19764.0120a -x release.19757.0120a release.19764.0120a/mythtv/libs/libmythtv/libmythtv.pro release.19757.0120a/mythtv/libs/libmythtv/libmythtv.pro
     
    451451    using_hdhomerun {
    452452        # MythTV HDHomeRun glue
    453453        HEADERS += hdhrsignalmonitor.h   hdhrchannel.h
    454         HEADERS += hdhrrecorder.h
     454        HEADERS += hdhrrecorder.h        hdhrstreamhandler.h
    455455
    456456        SOURCES += hdhrsignalmonitor.cpp hdhrchannel.cpp
    457         SOURCES += hdhrrecorder.cpp
     457        SOURCES += hdhrrecorder.cpp      hdhrstreamhandler.cpp
    458458
    459459        DEFINES += USING_HDHOMERUN
    460460
  • mythtv/libs/libmythtv/scanwizardscanner.cpp

    diff -r -u -N -X diff.exclude -x release.19764.0120a -x release.19757.0120a release.19764.0120a/mythtv/libs/libmythtv/scanwizardscanner.cpp release.19757.0120a/mythtv/libs/libmythtv/scanwizardscanner.cpp
     
    518518#ifdef USING_HDHOMERUN
    519519    if ("HDHOMERUN" == card_type)
    520520    {
    521         uint tuner = CardUtil::GetHDHRTuner(cardid);
    522         channel = new HDHRChannel(NULL, device, tuner);
     521        channel = new HDHRChannel(NULL, device);
    523522    }
    524523#endif // USING_HDHOMERUN
    525524
  • mythtv/libs/libmythtv/tv_rec.cpp

    diff -r -u -N -X diff.exclude -x release.19764.0120a -x release.19757.0120a release.19764.0120a/mythtv/libs/libmythtv/tv_rec.cpp release.19757.0120a/mythtv/libs/libmythtv/tv_rec.cpp
     
    174174    else if (genOpt.cardtype == "HDHOMERUN")
    175175    {
    176176#ifdef USING_HDHOMERUN
    177         channel = new HDHRChannel(this, genOpt.videodev, dboxOpt.port);
     177        channel = new HDHRChannel(this, genOpt.videodev);
    178178        if (!channel->Open())
    179179            return false;
    180180        InitChannel(genOpt.defaultinput, startchannel);
     
    40804080    }
    40814081    recorder->Reset();
    40824082
    4083 #ifdef USING_HDHOMERUN
    4084     if (GetHDHRRecorder())
    4085     {
    4086         pauseNotify = false;
    4087         GetHDHRRecorder()->Close();
    4088         pauseNotify = true;
    4089         GetHDHRRecorder()->Open();
    4090         GetHDHRRecorder()->StartData();
    4091     }
    4092 #endif // USING_HDHOMERUN
    4093 
    40944083    // Set file descriptor of channel from recorder for V4L
    40954084    channel->SetFd(recorder->GetVideoFd());
    40964085
  • mythtv/libs/libmythtv/videosource.cpp

    diff -r -u -N -X diff.exclude -x release.19764.0120a -x release.19757.0120a release.19764.0120a/mythtv/libs/libmythtv/videosource.cpp release.19757.0120a/mythtv/libs/libmythtv/videosource.cpp
     
    4747#include "videodev_myth.h"
    4848#endif
    4949
     50#include "hdhomerun_includes.h"
     51
    5052VideoSourceSelector::VideoSourceSelector(uint           _initial_sourceid,
    5153                                         const QString &_card_types,
    5254                                         bool           _must_have_mplexid) :
     
    131133class RecorderOptions : public ConfigurationWizard
    132134{
    133135  public:
    134     RecorderOptions(CaptureCard& parent);
     136    RecorderOptions(CaptureCard& parent, QString type);
    135137    uint GetInstanceCount(void) const { return (uint) count->intValue(); }
    136138
    137139  private:
     
    12831285    CaptureCard &parent;
    12841286 };
    12851287
    1286 class HDHomeRunDeviceID : public LineEditSetting, public CaptureCardDBStorage
     1288class HDHomeRunIP : public TransLabelSetting
     1289{
     1290  public:
     1291    HDHomeRunIP()
     1292    {
     1293        setLabel(QObject::tr("IP Address"));
     1294    };
     1295};
     1296
     1297class HDHomeRunTuner : public TransLabelSetting
     1298{
     1299  public:
     1300    HDHomeRunTuner()
     1301    {
     1302        setLabel(QObject::tr("Tuner"));
     1303    };
     1304};
     1305
     1306class HDHomeRunDeviceID : public ComboBoxSetting, public CaptureCardDBStorage
    12871307{
    12881308  public:
    12891309    HDHomeRunDeviceID(const CaptureCard &parent) :
    1290         LineEditSetting(this),
     1310        ComboBoxSetting(this),
    12911311        CaptureCardDBStorage(this, parent, "videodevice")
    12921312    {
    1293         setValue("FFFFFFFF");
    12941313        setLabel(QObject::tr("Device ID"));
    1295         setHelpText(QObject::tr("IP address or Device ID from the bottom of "
    1296                                 "the HDHomeRun.  You may use "
    1297                                 "'FFFFFFFF' if there is only one unit "
    1298                                 "on your your network."));
     1314        setHelpText(
     1315            QObject::tr("DevicedID and Tuner Number of available HDHomeRun "
     1316                        "devices. "));
     1317        fillSelections("");
     1318    };
     1319
     1320    /// \brief Adds all available device-tuner combinations to list
     1321    /// If current is >= 0 it will be considered available even
     1322    /// if no device exists for it on the network
     1323    void fillSelections(QString current)
     1324    {
     1325        clearSelections();
     1326
     1327        // Get devices from filesystem
     1328        vector<QString> devs = CardUtil::ProbeVideoDevices("HDHOMERUN");
     1329
     1330        // Add current if needed
     1331        if ((current != "") &&
     1332            (find(devs.begin(), devs.end(), current) == devs.end()))
     1333        {
     1334            devs.push_back(current);
     1335            stable_sort(devs.begin(), devs.end());
     1336        }
     1337
     1338        vector<QString> db = CardUtil::GetVideoDevices("HDHOMERUN");
     1339
     1340        QMap<QString, bool> in_use;
     1341        QString sel = current;
     1342        for (uint i = 0; i < devs.size(); i++)
     1343        {
     1344            const QString dev = devs[i];
     1345            in_use[devs[i]] = find(db.begin(), db.end(), dev) != db.end();
     1346            if (sel == "" && !in_use[devs[i]])
     1347                sel = dev;
     1348        }
     1349
     1350        if (sel == "" && devs.size())
     1351            sel = devs[0];
     1352 
     1353        QString usestr = QString(" -- ");
     1354        usestr += QObject::tr("Warning: already in use");
     1355
     1356        for (uint i = 0; i < devs.size(); i++)
     1357        {
     1358            const QString dev = devs[i];
     1359            QString desc = dev + (in_use[devs[i]] ? usestr : "");
     1360            desc = (current == devs[i]) ? dev : desc;
     1361            addSelection(desc, dev, dev == sel);
     1362        }
     1363    }
     1364
     1365    virtual void load(void)
     1366    {
     1367        clearSelections();
     1368        addSelection("");
     1369
     1370        CaptureCardDBStorage::load();
     1371
     1372        fillSelections(getValue());
    12991373    }
    13001374};
    13011375
     
    13291403    CaptureCard &parent;
    13301404};
    13311405
    1332 class HDHomeRunTunerIndex : public ComboBoxSetting, public CaptureCardDBStorage
     1406HDHomeRunConfigurationGroup::HDHomeRunConfigurationGroup(CaptureCard& a_parent) :
     1407    VerticalConfigurationGroup(false, true, false, false),
     1408    parent(a_parent)
    13331409{
    1334   public:
    1335     HDHomeRunTunerIndex(const CaptureCard &parent) :
    1336         ComboBoxSetting(this),
    1337         CaptureCardDBStorage(this, parent, "dbox2_port")
    1338     {
    1339         setLabel(QObject::tr("Tuner"));
    1340         addSelection("0");
    1341         addSelection("1");
    1342     }
     1410    setUseLabel(false);
     1411    deviceid = new HDHomeRunDeviceID(parent);
     1412    addChild(deviceid);
     1413    cardip = new HDHomeRunIP();
     1414    cardtuner = new HDHomeRunTuner();
     1415
     1416    addChild(cardip);
     1417    addChild(cardtuner);
     1418
     1419    addChild(new SignalTimeout(parent, 1000, 250));
     1420    addChild(new ChannelTimeout(parent, 3000, 1750));
     1421    addChild(new SingleCardInput(parent));
     1422
     1423    TransButtonSetting *buttonRecOpt = new TransButtonSetting();
     1424    buttonRecOpt->setLabel(tr("Recording Options"));   
     1425    addChild(buttonRecOpt);
     1426
     1427    connect(buttonRecOpt, SIGNAL(pressed()),
     1428        &parent,      SLOT(  recorderOptionsPanelHDHomerun()));
     1429    connect(deviceid,     SIGNAL(valueChanged(const QString&)),
     1430            this,         SLOT(  probeCard   (const QString&)));
     1431
     1432
    13431433};
    13441434
    1345 class HDHomeRunConfigurationGroup : public VerticalConfigurationGroup
     1435void HDHomeRunConfigurationGroup::probeCard(const QString& deviceid)
    13461436{
    1347   public:
    1348     HDHomeRunConfigurationGroup(CaptureCard& a_parent) :
    1349         VerticalConfigurationGroup(false, true, false, false),
    1350         parent(a_parent)
     1437    hdhomerun_device_t* thisdevice = hdhomerun_device_create_from_str(deviceid);
     1438
     1439    if (thisdevice)
    13511440    {
    1352         setUseLabel(false);
    1353         addChild(new HDHomeRunDeviceID(parent));
    1354         addChild(new HDHomeRunTunerIndex(parent));
    1355         addChild(new SignalTimeout(parent, 1000, 250));
    1356         addChild(new ChannelTimeout(parent, 3000, 1750));
    1357         addChild(new SingleCardInput(parent));
    1358     };
     1441        uint device_ip = hdhomerun_device_get_device_ip(thisdevice);
     1442        uint tuner     = hdhomerun_device_get_tuner(thisdevice);
     1443        hdhomerun_device_destroy(thisdevice);
    13591444
    1360   private:
    1361     CaptureCard &parent;
    1362 };
     1445        QString ip = QString("%1.%2.%3.%4")
     1446                .arg((device_ip>>24) & 0xFF).arg((device_ip>>16) & 0xFF)
     1447                .arg((device_ip>> 8) & 0xFF).arg((device_ip>> 0) & 0xFF);
     1448
     1449        cardip->setValue(ip);
     1450        cardtuner->setValue(QString("%1").arg(tuner));
     1451    }
     1452    else
     1453    {
     1454        cardip->setValue("Unknown");
     1455        cardtuner->setValue("Unknown");
     1456    }
     1457}
    13631458
    13641459V4LConfigurationGroup::V4LConfigurationGroup(CaptureCard& a_parent) :
    13651460    VerticalConfigurationGroup(false, true, false, false),
     
    15281623        if ((cardtype.lower() == "dvb") && (1 != ++device_refs[videodevice]))
    15291624            continue;
    15301625
     1626        if ((cardtype.lower() == "hdhomerun") && (1 != ++device_refs[videodevice]))
     1627            continue;
     1628
    15311629        QString label = CardUtil::GetDeviceLabel(
    15321630            cardid, cardtype, videodevice);
    15331631
     
    26672765        if ((cardtype.lower() == "dvb") && (1 != ++device_refs[videodevice]))
    26682766            continue;
    26692767
     2768        if ((cardtype.lower() == "hdhomerun") && (1 != ++device_refs[videodevice]))
     2769            continue;
     2770
    26702771        QStringList        inputLabels;
    26712772        vector<CardInput*> cardInputs;
    26722773
     
    29083009    connect(buttonDiSEqC, SIGNAL(pressed()),
    29093010            this,         SLOT(  DiSEqCPanel()));
    29103011    connect(buttonRecOpt, SIGNAL(pressed()),
    2911             &parent,      SLOT(  recorderOptionsPanel()));
     3012            &parent,      SLOT(  recorderOptionsPanelDVB()));
    29123013}
    29133014
    29143015DVBConfigurationGroup::~DVBConfigurationGroup()
     
    29533054    }
    29543055}
    29553056
    2956 void CaptureCard::recorderOptionsPanel()
     3057void CaptureCard::recorderOptionsPanelHDHomerun()
     3058{
     3059    reload();
     3060
     3061    RecorderOptions acw(*this, "HDHOMERUN");
     3062    acw.exec();
     3063    instance_count = acw.GetInstanceCount();
     3064}
     3065
     3066void CaptureCard::recorderOptionsPanelDVB()
    29573067{
    29583068    reload();
    29593069
    2960     RecorderOptions acw(*this);
     3070    RecorderOptions acw(*this, "DVB");
    29613071    acw.exec();
    29623072    instance_count = acw.GetInstanceCount();
    29633073}
    29643074
    2965 RecorderOptions::RecorderOptions(CaptureCard &parent)
     3075RecorderOptions::RecorderOptions(CaptureCard &parent, QString type)
    29663076    : count(new InstanceCount(parent))
    29673077{
    29683078    VerticalConfigurationGroup* rec = new VerticalConfigurationGroup(false);
     
    29703080    rec->setUseLabel(false);
    29713081
    29723082    rec->addChild(count);
    2973     rec->addChild(new DVBNoSeqStart(parent));
    2974     rec->addChild(new DVBOnDemand(parent));
    2975     rec->addChild(new DVBEITScan(parent));
    2976     rec->addChild(new DVBTuningDelay(parent));
     3083    if (type == "DVB")
     3084    {
     3085        rec->addChild(new DVBNoSeqStart(parent));
     3086        rec->addChild(new DVBOnDemand(parent));
     3087        rec->addChild(new DVBEITScan(parent));
     3088        rec->addChild(new DVBTuningDelay(parent));
     3089    }
    29773090
    29783091    addChild(rec);
    29793092}
     3093
  • mythtv/libs/libmythtv/videosource.h

    diff -r -u -N -X diff.exclude -x release.19764.0120a -x release.19757.0120a release.19764.0120a/mythtv/libs/libmythtv/videosource.h release.19757.0120a/mythtv/libs/libmythtv/videosource.h
     
    418418    DiSEqCDevTree      *diseqc_tree;
    419419};
    420420
     421class HDHomeRunDeviceID;
     422class HDHomeRunIP;
     423class HDHomeRunTuner;
     424class HDHomeRunConfigurationGroup : public VerticalConfigurationGroup
     425{
     426    Q_OBJECT
     427  public:
     428    HDHomeRunConfigurationGroup(CaptureCard& a_parent);
     429
     430public slots:
     431    void probeCard(const QString& deviceid);
     432
     433  private:
     434    HDHomeRunDeviceID *deviceid;
     435    HDHomeRunIP       *cardip;
     436    HDHomeRunTuner    *cardtuner;
     437
     438    CaptureCard &parent;
     439};
     440
     441
    421442class FirewireGUID;
    422443class FirewireModel : public ComboBoxSetting, public CaptureCardDBStorage
    423444{
     
    477498    uint GetInstanceCount(void) const { return instance_count; }
    478499
    479500public slots:
    480     void recorderOptionsPanel();
     501    void recorderOptionsPanelDVB();
     502    void recorderOptionsPanelHDHomerun();
    481503
    482504private:
    483505