Ticket #6138: 133-release.19703.0116.multirec.bc.2.patch

File 133-release.19703.0116.multirec.bc.2.patch, 81.2 KB (added by anonymous, 15 years ago)

multirec patch

  • mythtv/libs/libmythtv/cardutil.cpp

    diff -r -u -N -X diff.exclude -x release.19703.0116b -x release.19703.0116c release.19703.0116b/mythtv/libs/libmythtv/cardutil.cpp release.19703.0116c/mythtv/libs/libmythtv/cardutil.cpp
     
    3838            .arg(cardidA).arg(cardidB));
    3939
    4040    MSqlQuery query(MSqlQuery::InitCon());
    41     query.prepare("SELECT videodevice, hostname, cardtype "
     41    query.prepare("SELECT videodevice, hostname, cardtype, dbox2_port "
    4242                  "FROM capturecard "
    4343                  "WHERE ( (cardid = :CARDID_A) OR "
    4444                  "        (cardid = :CARDID_B) )");
     
    5757    const QString vdevice  = query.value(0).toString();
    5858    const QString hostname = query.value(1).toString();
    5959    const QString cardtype = query.value(2).toString();
     60    const QString hdhrTuner = query.value(3).toString();
    6061
    6162    if (!IsTunerSharingCapable(cardtype.upper()))
    6263        return false;
     
    6768    bool ret = ((vdevice  == query.value(0).toString()) &&
    6869                (hostname == query.value(1).toString()) &&
    6970                (cardtype == query.value(2).toString()));
     71    if (cardtype.upper() == "HDHOMERUN")
     72        ret = ret && (hdhrTuner == query.value(3).toString());
    7073
    7174    VERBOSE(VB_RECORD, QString("IsTunerShared(%1,%2) -> %3")
    7275            .arg(cardidA).arg(cardidB).arg(ret));
     
    417420    return list;
    418421}
    419422
     423/** \fn CardUtil::GetCardIDs(const QString&, uint hdhrTuner, QString)
     424 *  \brief Returns all cardids of cards that uses the specified
     425 *         videodevice, and optionally rawtype and a non-local
     426 *         hostname. The result is ordered from smallest to largest.
     427 *  \param videodevice Video device we want card ids for
     428 *  \param hdhrTuner   tuner for this card
     429 *  \param hostname    Host on which device resides, only
     430 *                     required if said host is not the localhost
     431 */
     432vector<uint> CardUtil::GetCardIDs(const QString &videodevice,
     433                                  uint           hdhrTuner,
     434                                  QString        hostname)
     435{
     436    vector<uint> list;
     437
     438    if (hostname.isEmpty())
     439        hostname = gContext->GetHostName();
     440
     441    MSqlQuery query(MSqlQuery::InitCon());
     442    QString qstr =
     443        "SELECT cardid "
     444        "FROM capturecard "
     445        "WHERE videodevice = :DEVICE AND "
     446        "      dbox2_port  = :HDHRTUNER AND "
     447        "      hostname    = :HOSTNAME";
     448
     449    qstr += " ORDER BY cardid";
     450
     451    query.prepare(qstr);
     452
     453    query.bindValue(":DEVICE",   videodevice);
     454    query.bindValue(":HDHRTUNER",   hdhrTuner);
     455    query.bindValue(":HOSTNAME", hostname);
     456
     457    if (!query.exec())
     458        MythContext::DBError("CardUtil::GetCardIDs(videodevice...)", query);
     459    else
     460    {
     461        while (query.next())
     462            list.push_back(query.value(0).toUInt());
     463    }
     464
     465    return list;
     466}
     467
    420468static uint clone_capturecard(uint src_cardid, uint orig_dst_cardid)
    421469{
    422470    uint dst_cardid = orig_dst_cardid;
     
    468516        "SELECT videodevice,           cardtype,       defaultinput,     "
    469517        "       hostname,              signal_timeout, channel_timeout,  "
    470518        "       dvb_wait_for_seqstart, dvb_on_demand,  dvb_tuning_delay, "
    471         "       dvb_diseqc_type,       diseqcid,       dvb_eitscan "
     519        "       dvb_diseqc_type,       diseqcid,       dvb_eitscan,      "
     520        "       dbox2_port "
    472521        "FROM capturecard "
    473522        "WHERE cardid = :CARDID");
    474523    query.bindValue(":CARDID", src_cardid);
     
    498547        "    dvb_tuning_delay      = :V8, "
    499548        "    dvb_diseqc_type       = :V9, "
    500549        "    diseqcid              = :V10,"
    501         "    dvb_eitscan           = :V11 "
     550        "    dvb_eitscan           = :V11,"
     551        "    dbox2_port            = :V12 "
    502552        "WHERE cardid = :CARDID");
    503553    for (uint i = 0; i < 12; i++)
    504554        query2.bindValue(QString(":V%1").arg(i), query.value(i).toString());
     555    query2.bindValue(":V12", query.value(12).toUInt());
    505556    query2.bindValue(":CARDID", dst_cardid);
    506557
    507558    if (!query2.exec())
     
    10231074        uint id = 0;
    10241075        for (uint i = 0; !id && (i < 100); i++)
    10251076        {
    1026             name = QString("DVB%1").arg(dev.toUInt());
     1077            bool ok;
     1078            name = QString("DVB%1").arg(dev.toUInt(&ok));
     1079            if (! ok)
     1080            {
     1081                uint hdhrTuner = CardUtil::GetHDHRTuner(cardid);
     1082                name = QString("HDHR%1").arg(hdhrTuner);
     1083            }
    10271084            name += (i) ? QString(":%1").arg(i) : QString("");
    10281085            id = CardUtil::CreateInputGroup(name);
    10291086        }
  • mythtv/libs/libmythtv/cardutil.h

    diff -r -u -N -X diff.exclude -x release.19703.0116b -x release.19703.0116c release.19703.0116b/mythtv/libs/libmythtv/cardutil.h release.19703.0116c/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);
     
    135135                                   QString rawtype  = QString::null,
    136136                                   QString hostname = QString::null);
    137137
     138    static vector<uint> GetCardIDs(const QString &videodevice,
     139                                   uint           hdhrTuner,
     140                                   QString hostname = QString::null);
     141
    138142    static bool         IsCardTypePresent(const QString &rawtype,
    139143                                          QString hostname = QString::null);
    140144    static QStringVec   GetVideoDevices(const QString &rawtype,
  • mythtv/libs/libmythtv/hdhomerun_includes.h

    diff -r -u -N -X diff.exclude -x release.19703.0116b -x release.19703.0116c release.19703.0116b/mythtv/libs/libmythtv/hdhomerun_includes.h release.19703.0116c/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.19703.0116b -x release.19703.0116c release.19703.0116b/mythtv/libs/libmythtv/hdhrchannel.cpp release.19703.0116c/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
    3436HDHRChannel::HDHRChannel(TVRec *parent, const QString &device, uint tuner)
    35     : DTVChannel(parent),       _control_socket(NULL),
     37    : DTVChannel(parent),       _stream_handler(NULL),
    3638      _device_id(0),            _device_ip(0),
    37       _tuner(tuner),            _lock(true)
     39      _tuner(tuner),            _lock(true),
     40      tune_lock(true),          hw_lock(true)
    3841{
    3942    bool valid;
    4043    _device_id = device.toUInt(&valid, 16);
     
    6568
    6669bool HDHRChannel::Open(void)
    6770{
     71    VERBOSE(VB_CHANNEL, LOC + "Opening HDHR channel");
     72
     73    QMutexLocker locker(&hw_lock);
     74
    6875    if (IsOpen())
    6976        return true;
    7077
    71     if (!FindDevice())
    72         return false;
     78    _stream_handler = HDHRStreamHandler::Get(_device_id, _tuner, GetDevice());
    7379
    7480    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)
    10581    {
    106         VERBOSE(VB_IMPORTANT, LOC_ERR + "Unable to send discovery request" + ENO);
     82        Close();
    10783        return false;
    10884    }
    109     if (ret == 0)
    110     {
    111         VERBOSE(VB_IMPORTANT, LOC_ERR + QString("device not found"));
    112         return false;
    113     }
    114 
    115     /* Found. */
    116     _device_ip = result.ip_addr;
    11785
    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));
     86//  nextInputID = currentInputID;
    12287
    123     return true;
    124 }
    125 
    126 bool HDHRChannel::Connect(void)
    127 {
    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     }
    134 
    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     }
     88    return _stream_handler->Connected();
    14089
    141     VERBOSE(VB_CHANNEL, LOC + "Successfully connected to device");
    142     return true;
    14390}
    14491
    145 QString HDHRChannel::DeviceGet(const QString &name, bool report_error_return)
     92void HDHRChannel::Close()
    14693{
    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     }
     94    VERBOSE(VB_CHANNEL, LOC + "Closing HDHR channel");
    15495
    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));
     96    if (! IsOpen())
     97        return; // this caller didn't have it open in the first place..
    16798
    168         return QString::null;
    169     }
    170 
    171     return QString(value);
     99    HDHRStreamHandler::Return(_stream_handler);
    172100}
    173101
    174 QString HDHRChannel::DeviceSet(const QString &name, const QString &val,
    175                                bool report_error_return)
     102bool HDHRChannel::EnterPowerSavingMode(void)
    176103{
    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);
     104    if ( IsOpen())
     105        return _stream_handler->EnterPowerSavingMode();
     106    else
     107        return true;
    203108}
    204109
    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 }
    210110
    211 QString HDHRChannel::TunerSet(const QString &name, const QString &value,
    212                               bool report_error_return)
     111bool HDHRChannel::IsOpen(void) const
    213112{
    214     return DeviceSet(QString("/tuner%1/%2").arg(_tuner).arg(name), value,
    215                      report_error_return);
     113      return (_stream_handler != NULL);
    216114}
    217115
    218 bool HDHRChannel::DeviceSetTarget(unsigned short localPort)
     116bool HDHRChannel::Init(QString &inputname, QString &startchannel, bool setchan)
    219117{
    220     if (localPort == 0)
    221     {
    222         return false;
    223     }
    224 
    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);
     118    if (setchan && !IsOpen())
     119        Open();
    235120
    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");
     121    return ChannelBase::Init(inputname, startchannel, setchan);
    247122}
    248123
    249124bool HDHRChannel::SetChannelByString(const QString &channum)
     
    277152        return SwitchToInput(inputName, channum);
    278153
    279154    ClearDTVInfo();
    280     _ignore_filters = false;
    281155
    282156    InputMap::const_iterator it = inputs.find(currentInputID);
    283157    if (it == inputs.end())
     
    349223    if (mpeg_prog_num && (GetTuningMode() == "mpeg"))
    350224    {
    351225        QString pnum = QString::number(mpeg_prog_num);
    352         _ignore_filters = QString::null != TunerSet("program", pnum, false);
     226        //_ignore_filters = _stream_handler->TuneProgram(pnum);
     227        _stream_handler->TuneProgram(pnum);
    353228    }
    354229
    355230    return true;
     
    398273            QString("TuneTo(%1,%2)").arg(frequency).arg(modulation));
    399274
    400275    if (modulation == "8vsb")
    401         ok = TunerSet("channel", QString("8vsb:%1").arg(frequency));
     276        ok = _stream_handler->TuneChannel(QString("8vsb:%1").arg(frequency));
    402277    else if (modulation == "qam_64")
    403         ok = TunerSet("channel", QString("qam64:%1").arg(frequency));
     278        ok = _stream_handler->TuneChannel(QString("qam64:%1").arg(frequency));
    404279    else if (modulation == "qam_256")
    405         ok = TunerSet("channel", QString("qam256:%1").arg(frequency));
     280        ok = _stream_handler->TuneChannel(QString("qam256:%1").arg(frequency));
    406281
    407282    if (ok)
    408283        SetSIStandard(si_std);
    409284
    410285    return ok;
    411286}
    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.19703.0116b -x release.19703.0116c release.19703.0116b/mythtv/libs/libmythtv/hdhrchannel.h release.19703.0116c/mythtv/libs/libmythtv/hdhrchannel.h
     
    1515
    1616// HDHomeRun headers
    1717#ifdef USING_HDHOMERUN
    18 #include "hdhomerun/hdhomerun.h"
     18#include "hdhomerun_includes.h"
    1919#else
    2020struct hdhomerun_control_sock_t { int dummy; };
    2121#endif
    2222
    2323typedef struct hdhomerun_control_sock_t hdhr_socket_t;
    2424
     25class HDHRChannel;
     26class HDHRStreamHandler;
     27class ProgramMapTable;
     28
    2529class HDHRChannel : public DTVChannel
    2630{
    2731    friend class HDHRSignalMonitor;
     
    3539    void Close(void);
    3640    bool EnterPowerSavingMode(void);
    3741
     42    bool Init(QString &inputname, QString &startchannel, bool setchan);
     43
    3844    // Sets
     45    void SetPMT(const ProgramMapTable*) {};
    3946    bool SetChannelByString(const QString &chan);
    4047
    4148    // Gets
    42     bool IsOpen(void) const { return (_control_socket != NULL); }
     49    bool IsOpen(void) const;
    4350    QString GetDevice(void) const
    4451        { return QString("%1/%2").arg(_device_id, 8, 16).arg(_tuner); }
     52    uint GetDeviceId(void) const { return _device_id; }
     53    uint GetTuner(void) const { return _tuner; }
    4554    vector<uint> GetPIDs(void) const
    4655        { QMutexLocker locker(&_lock); return _pids; }
    4756    QString GetSIStandard(void) const { return "atsc"; }
    4857
    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 
    5558    // ATSC scanning stuff
    5659    bool TuneMultiplex(uint mplexid, QString inputname);
    5760    bool Tune(const DTVMultiplex &tuning, QString inputname);
    5861
    5962  private:
    60     bool FindDevice(void);
    61     bool Connect(void);
    6263    bool Tune(uint frequency, QString inputname,
    6364              QString modulation, QString si_std);
    6465
    65     bool DeviceSetTarget(unsigned short localPort);
    66     bool DeviceClearTarget(void);
    67 
    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);
    75 
    7666  private:
    77     hdhr_socket_t  *_control_socket;
     67    HDHRStreamHandler *_stream_handler;
     68
    7869    uint            _device_id;
    7970    uint            _device_ip;
    8071    uint            _tuner;
    81     bool            _ignore_filters;
    8272    vector<uint>    _pids;
    8373    mutable QMutex  _lock;
     74    mutable QMutex  tune_lock;
     75    mutable QMutex  hw_lock;
    8476};
    8577
    8678#endif
  • mythtv/libs/libmythtv/hdhrrecorder.cpp

    diff -r -u -N -X diff.exclude -x release.19703.0116b -x release.19703.0116c release.19703.0116b/mythtv/libs/libmythtv/hdhrrecorder.cpp release.19703.0116c/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->GetDeviceId(), _channel->GetTuner(), _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)
     127    VERBOSE(VB_RECORD, LOC + "Close() - Begin");
     128
     129    if (IsOpen())
    137130    {
    138         hdhomerun_video_destroy(_video_socket);
    139         _video_socket = NULL;
     131        HDHRStreamHandler::Return(_stream_handler);
    140132    }
    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;
    148 
    149     while (data + 188 <= end)
     133    else
    150134    {
    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;
     135        VERBOSE(VB_IMPORTANT,QString( LOC + " Trying to Close HDHR But it's not open"));
    160136    }
     137
     138    VERBOSE(VB_RECORD, LOC + "Close() - End");
    161139}
    162140
    163141void HDHRRecorder::SetStreamData(MPEGStreamData *data)
     
    216194    ProgramAssociationTable *oldpat = _input_pat;
    217195    _input_pat = new ProgramAssociationTable(*_pat);
    218196    delete oldpat;
    219 
    220     _reset_pid_filters = true;
    221197}
    222198
    223199void HDHRRecorder::HandlePMT(uint progNum, const ProgramMapTable *_pmt)
     
    229205        VERBOSE(VB_RECORD, LOC + "SetPMT("<<progNum<<")");
    230206        ProgramMapTable *oldpmt = _input_pmt;
    231207        _input_pmt = new ProgramMapTable(*_pmt);
    232         delete oldpmt;
    233208
    234         _reset_pid_filters = true;
     209        QString sistandard = _channel->GetSIStandard();
     210
     211        bool has_no_av = true;
     212        for (uint i = 0; i < _input_pmt->StreamCount() && has_no_av; i++)
     213        {
     214            has_no_av &= !_input_pmt->IsVideo(i, sistandard);
     215            has_no_av &= !_input_pmt->IsAudio(i, sistandard);
     216        }
     217        _has_no_av = has_no_av;
     218
     219        _channel->SetPMT(_input_pmt);
     220        delete oldpmt;
    235221    }
    236222}
    237223
     
    242228
    243229    int next = (pat->tsheader()->ContinuityCounter()+1)&0xf;
    244230    pat->tsheader()->SetContinuityCounter(next);
    245     BufferedWrite(*(reinterpret_cast<TSPacket*>(pat->tsheader())));
     231    DTVRecorder::BufferedWrite(*(reinterpret_cast<TSPacket*>(pat->tsheader())));
    246232}
    247233
    248234void HDHRRecorder::HandleSingleProgramPMT(ProgramMapTable *pmt)
    249235{
    250236    if (!pmt)
     237    {
     238        VERBOSE(VB_RECORD, LOC + "HandleSingleProgramPMT(NULL)");
     239        return;
     240    }
     241
     242    // collect stream types for H.264 (MPEG-4 AVC) keyframe detection
     243    for (uint i = 0; i < pmt->StreamCount(); i++)
     244        _stream_id[pmt->StreamPID(i)] = pmt->StreamType(i);
     245
     246    if (!ringBuffer)
    251247        return;
    252248
    253249    unsigned char buf[8 * 1024];
     
    255251    pmt->tsheader()->SetContinuityCounter(next_cc);
    256252    uint size = pmt->WriteAsTSPackets(buf, next_cc);
    257253
     254    uint posA[2] = { ringBuffer->GetWritePosition(), _payload_buffer.size() };
     255
    258256    for (uint i = 0; i < size ; i += TSPacket::SIZE)
    259257        DTVRecorder::BufferedWrite(*(reinterpret_cast<TSPacket*>(&buf[i])));
     258
     259    uint posB[2] = { ringBuffer->GetWritePosition(), _payload_buffer.size() };
     260
     261    if (posB[0] + posB[1] * TSPacket::SIZE >
     262        posA[0] + posA[1] * TSPacket::SIZE)
     263    {
     264        VERBOSE(VB_RECORD, LOC + "Wrote PMT @"
     265                << posA[0] << " + " << (posA[1] * TSPacket::SIZE));
     266    }
     267    else
     268    {
     269        VERBOSE(VB_RECORD, LOC + "Saw PMT but did not write to disk yet");
     270    }
    260271}
    261272
    262273/** \fn HDHRRecorder::HandleMGT(const MasterGuideTable*)
     
    276287}
    277288*/
    278289
     290bool HDHRRecorder::ProcessVideoTSPacket(const TSPacket &tspacket)
     291{
     292    uint streamType = _stream_id[tspacket.PID()];
     293
     294    // Check for keyframes and count frames
     295    if (streamType == StreamID::H264Video)
     296    {
     297        _buffer_packets = !FindH264Keyframes(&tspacket);
     298        if (!_seen_sps)
     299            return true;
     300    }
     301    else
     302    {
     303        _buffer_packets = !FindMPEG2Keyframes(&tspacket);
     304    }
     305
     306    return ProcessAVTSPacket(tspacket);
     307}
     308
     309bool HDHRRecorder::ProcessAudioTSPacket(const TSPacket &tspacket)
     310{
     311    _buffer_packets = !FindAudioKeyframes(&tspacket);
     312    return ProcessAVTSPacket(tspacket);
     313}
     314
     315/// Common code for processing either audio or video packets
     316bool HDHRRecorder::ProcessAVTSPacket(const TSPacket &tspacket)
     317{
     318    const uint pid = tspacket.PID();
     319    // Sync recording start to first keyframe
     320    if (_wait_for_keyframe_option && _first_keyframe < 0)
     321        return true;
     322
     323    // Sync streams to the first Payload Unit Start Indicator
     324    // _after_ first keyframe iff _wait_for_keyframe_option is true
     325    if (!(_pid_status[pid] & kPayloadStartSeen) && tspacket.HasPayload())
     326    {
     327        if (!tspacket.PayloadStart())
     328            return true; // not payload start - drop packet
     329
     330        VERBOSE(VB_RECORD,
     331                QString("PID 0x%1 Found Payload Start").arg(pid,0,16));
     332
     333        _pid_status[pid] |= kPayloadStartSeen;
     334    }
     335
     336    BufferedWrite(tspacket);
     337
     338    return true;
     339}
     340
    279341bool HDHRRecorder::ProcessTSPacket(const TSPacket& tspacket)
    280342{
    281     bool ok = !tspacket.TransportError();
    282     if (ok && !tspacket.ScramplingControl())
     343    // Only create fake keyframe[s] if there are no audio/video streams
     344    if (_input_pmt && _has_no_av)
    283345    {
    284         if (tspacket.HasAdaptationField())
    285             GetStreamData()->HandleAdaptationFieldControl(&tspacket);
    286         if (tspacket.HasPayload())
    287         {
    288             const unsigned int lpid = tspacket.PID();
     346        _buffer_packets = !FindOtherKeyframes(&tspacket);
     347    }
     348    else
     349    {
     350        // There are audio/video streams. Only write the packet
     351        // if audio/video key-frames have been found
     352        if (_wait_for_keyframe_option && _first_keyframe < 0)
     353            return true;
    289354
    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         }
     355        _buffer_packets = true;
    317356    }
    318     return ok;
     357
     358    BufferedWrite(tspacket);
    319359}
    320360
    321361void HDHRRecorder::StartRecording(void)
     
    333373    _request_recording = true;
    334374    _recording = true;
    335375
    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);
     376    // Make sure the first things in the file are a PAT & PMT
     377    bool tmp = _wait_for_keyframe_option;
     378    _wait_for_keyframe_option = false;
     379    HandleSingleProgramPAT(_stream_data->PATSingleProgram());
     380    HandleSingleProgramPMT(_stream_data->PMTSingleProgram());
     381    _wait_for_keyframe_option = tmp;
     382
     383    _stream_data->AddAVListener(this);
     384    _stream_data->AddWritingListener(this);
     385    _stream_handler->AddListener(_stream_data);
     386   
    347387    while (_request_recording && !_error)
    348388    {
     389        usleep(50000);
     390
    349391        if (PauseAndWait())
    350392            continue;
    351393
    352         if (_stream_data)
     394        if (!_input_pmt)
    353395        {
    354             QMutexLocker read_lock(&_pid_lock);
    355             _reset_pid_filters |= _stream_data->HasEITPIDChanges(_eit_pids);
     396            VERBOSE(VB_GENERAL, LOC_WARN +
     397                    "Recording will not commence until a PMT is set.");
     398            usleep(5000);
     399            continue;
    356400        }
    357401
    358         if (_reset_pid_filters)
     402        if (!_stream_handler->IsRunning())
    359403        {
    360             _reset_pid_filters = false;
    361             VERBOSE(VB_RECORD, LOC + "Resetting Demux Filters");
    362             AdjustFilters();
    363         }
     404            _error = true;
    364405
    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);
     406            VERBOSE(VB_IMPORTANT, LOC_ERR +
     407                    "Stream handler died unexpectedly.");
     408        }
    379409    }
    380410
    381411    VERBOSE(VB_RECORD, LOC + "StartRecording -- ending...");
    382412
    383     _channel->DeviceClearTarget();
     413    _stream_handler->RemoveListener(_stream_data);
     414    _stream_data->RemoveWritingListener(this);
     415    _stream_data->RemoveAVListener(this);
     416
    384417    Close();
    385418
    386419    FinishRecording();
     
    389422    VERBOSE(VB_RECORD, LOC + "StartRecording -- end");
    390423}
    391424
    392 bool HDHRRecorder::AdjustFilters(void)
     425void HDHRRecorder::ResetForNewFile(void)
    393426{
    394     QMutexLocker change_lock(&_pid_lock);
     427    DTVRecorder::ResetForNewFile();
    395428
    396     if (!_channel)
    397     {
    398         VERBOSE(VB_IMPORTANT, LOC_ERR + "AdjustFilters() no channel");
    399         return false;
    400     }
     429    bzero(_stream_id,  sizeof(_stream_id));
     430    bzero(_pid_status, sizeof(_pid_status));
     431    memset(_continuity_counter, 0xff, sizeof(_continuity_counter));
    401432
    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;
     433    // FIXME
     434    // Close and re-open ???
     435    //Close();
     436    //Open();
     437}
    409438
    410     add_pid.push_back(MPEG_PAT_PID);
    411     _stream_data->AddListeningPID(MPEG_PAT_PID);
     439void HDHRRecorder::StopRecording(void)
     440{
     441    _request_recording = false;
     442    while (_recording)
     443        usleep(2000);
     444}
    412445
    413     for (uint i = 0; i < _input_pat->ProgramCount(); i++)
     446bool HDHRRecorder::PauseAndWait(int timeout)
     447{
     448    if (request_pause)
    414449    {
    415         add_pid.push_back(_input_pat->ProgramPID(i));
    416         _stream_data->AddListeningPID(_input_pat->ProgramPID(i));
    417     }
     450        if (!paused)
     451        {
     452            assert(_stream_handler);
     453            assert(_stream_data);
    418454
    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     }
     455            _stream_handler->RemoveListener(_stream_data);
    427456
    428     if (need_pcr_pid && (_input_pmt->PCRPID()))
    429     {
    430         add_pid.push_back(_input_pmt->PCRPID());
    431         _stream_data->AddWritingPID(_input_pmt->PCRPID());
     457            paused = true;
     458            pauseWait.wakeAll();
     459            if (tvrec)
     460                tvrec->RecorderPaused();
     461        }
     462        unpauseWait.wait(timeout);
    432463    }
    433464
    434     // Adjust for EIT
    435     AdjustEITPIDs();
    436     for (uint i = 0; i < _eit_pids.size(); i++)
     465    if (!request_pause && paused)
    437466    {
    438         add_pid.push_back(_eit_pids[i]);
    439         _stream_data->AddListeningPID(_eit_pids[i]);
    440     }
     467        paused = false;
    441468
    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     }
     469        assert(_stream_handler);
     470        assert(_stream_data);
    454471
    455     for (it = add_pid.begin(); it != add_pid.end(); ++it)
    456         _channel->AddPID(*it, false);
    457 
    458     _channel->UpdateFilters();
     472        _stream_handler->AddListener(_stream_data);
     473    }
    459474
    460     return add_pid.size();
     475    return paused;
    461476}
    462477
    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)
     478void HDHRRecorder::BufferedWrite(const TSPacket &tspacket)
    467479{
    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);
     480    // Care must be taken to make sure that the packet actually gets written
     481    // as the decision to actually write it has already been made
    475482
    476     if (!changes)
    477         return false;
    478 
    479     for (uint i = 0; i < del.size(); i++)
     483    // Do we have to buffer the packet for exact keyframe detection?
     484    if (_buffer_packets)
    480485    {
    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);
     486        int idx = _payload_buffer.size();
     487        _payload_buffer.resize(idx + TSPacket::SIZE);
     488        memcpy(&_payload_buffer[idx], tspacket.data(), TSPacket::SIZE);
     489        return;
    485490    }
    486491
    487     for (uint i = 0; i < add.size(); i++)
    488         _eit_pids.push_back(add[i]);
    489 
    490     return true;
     492    // We are free to write the packet, but if we have buffered packet[s]
     493    // we have to write them first...
     494    if (!_payload_buffer.empty())
     495    {
     496        if (ringBuffer)
     497            ringBuffer->Write(&_payload_buffer[0], _payload_buffer.size());
     498        _payload_buffer.clear();
     499    }
     500    if (ringBuffer)
     501        ringBuffer->Write(tspacket.data(), TSPacket::SIZE);
    491502}
    492503
  • mythtv/libs/libmythtv/hdhrrecorder.h

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

    diff -r -u -N -X diff.exclude -x release.19703.0116b -x release.19703.0116c release.19703.0116b/mythtv/libs/libmythtv/hdhrstreamhandler.h release.19703.0116c/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(uint device_id, uint tuner, 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(uint, uint, 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.19703.0116b -x release.19703.0116c release.19703.0116b/mythtv/libs/libmythtv/libmythtv.pro release.19703.0116c/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/tv_rec.cpp

    diff -r -u -N -X diff.exclude -x release.19703.0116b -x release.19703.0116c release.19703.0116b/mythtv/libs/libmythtv/tv_rec.cpp release.19703.0116c/mythtv/libs/libmythtv/tv_rec.cpp
     
    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.19703.0116b -x release.19703.0116c release.19703.0116b/mythtv/libs/libmythtv/videosource.cpp release.19703.0116c/mythtv/libs/libmythtv/videosource.cpp
     
    131131class RecorderOptions : public ConfigurationWizard
    132132{
    133133  public:
    134     RecorderOptions(CaptureCard& parent);
     134    RecorderOptions(CaptureCard& parent, QString type);
    135135    uint GetInstanceCount(void) const { return (uint) count->intValue(); }
    136136
    137137  private:
     
    13551355        addChild(new SignalTimeout(parent, 1000, 250));
    13561356        addChild(new ChannelTimeout(parent, 3000, 1750));
    13571357        addChild(new SingleCardInput(parent));
     1358        //addChild(new InstanceCount(parent));
     1359
     1360        TransButtonSetting *buttonRecOpt = new TransButtonSetting();
     1361        buttonRecOpt->setLabel(tr("Recording Options"));   
     1362        addChild(buttonRecOpt);
     1363
     1364        connect(buttonRecOpt, SIGNAL(pressed()),
     1365            &parent,      SLOT(  recorderOptionsPanelHDHomerun()));
     1366
     1367
    13581368    };
    13591369
    13601370  private:
     
    15041514{
    15051515    MSqlQuery query(MSqlQuery::InitCon());
    15061516    QString qstr =
    1507         "SELECT cardid, videodevice, cardtype "
     1517        "SELECT cardid, videodevice, cardtype, dbox2_port "
    15081518        "FROM capturecard "
    15091519        "WHERE hostname = :HOSTNAME "
    15101520        "ORDER BY cardid";
     
    15241534        uint    cardid      = query.value(0).toUInt();
    15251535        QString videodevice = query.value(1).toString();
    15261536        QString cardtype    = query.value(2).toString();
     1537        QString hdhrTuner   = query.value(3).toString();
    15271538
    15281539        if ((cardtype.lower() == "dvb") && (1 != ++device_refs[videodevice]))
    15291540            continue;
    15301541
     1542        if (cardtype.lower() == "hdhomerun")
     1543        {
     1544            QString altvideodevice = videodevice + ":" + hdhrTuner;
     1545            if (1 != ++device_refs[altvideodevice])
     1546               continue;
     1547        }
     1548
    15311549        QString label = CardUtil::GetDeviceLabel(
    15321550            cardid, cardtype, videodevice);
    15331551
     
    15481566        if (CardUtil::IsTunerSharingCapable(type))
    15491567        {
    15501568            QString dev = CardUtil::GetVideoDevice(cardid);
    1551             vector<uint> cardids = CardUtil::GetCardIDs(dev, type);
    1552             new_cnt = cardids.size();
     1569            if (type == "HDHOMERUN")
     1570            {
     1571                uint hdhrTuner = CardUtil::GetHDHRTuner(cardid);
     1572                vector<uint> cardids = CardUtil::GetCardIDs(dev, hdhrTuner);
     1573                new_cnt = cardids.size();
     1574            }
     1575            else
     1576            {
     1577                vector<uint> cardids = CardUtil::GetCardIDs(dev, type);
     1578                new_cnt = cardids.size();
     1579            }
    15531580        }
    15541581    }
    15551582    instance_count = new_cnt;
     
    15761603
    15771604    if (!init_cardid)
    15781605    {
     1606        uint cid_size = 0;
    15791607        QString dev = CardUtil::GetVideoDevice(cardid);
    1580         vector<uint> cardids = CardUtil::GetCardIDs(dev, type);
    1581         if (cardids.size() > 1)
     1608        if (type == "HDHOMERUN")
     1609        {
     1610            uint hdhrTuner = CardUtil::GetHDHRTuner(cardid);
     1611            vector<uint> cardids = CardUtil::GetCardIDs(dev, hdhrTuner);
     1612            cid_size = cardids.size();
     1613        }
     1614        else
     1615        {
     1616            vector<uint> cardids = CardUtil::GetCardIDs(dev, type);
     1617            cid_size = cardids.size();
     1618        }
     1619        if (cid_size > 1)
    15821620        {
    15831621            VERBOSE(VB_IMPORTANT,
    15841622                    "A card using this video device already exists!");
     
    15871625        return;
    15881626    }
    15891627
    1590     vector<uint> cardids = CardUtil::GetCardIDs(init_dev, type);
     1628    vector<uint> cardids;
     1629    if (type == "HDHOMERUN")
     1630    {
     1631        uint hdhrTuner = CardUtil::GetHDHRTuner(cardid);
     1632        cardids = CardUtil::GetCardIDs(init_dev, hdhrTuner);
     1633    }
     1634    else
     1635    {
     1636        cardids = CardUtil::GetCardIDs(init_dev, type);
     1637    }
    15911638
    15921639    if (!instance_count)
    15931640        instance_count = max((size_t)0, cardids.size()) + 1;
     
    26442691
    26452692    MSqlQuery query(MSqlQuery::InitCon());
    26462693    query.prepare(
    2647         "SELECT cardid, videodevice, cardtype "
     2694        "SELECT cardid, videodevice, cardtype, dbox2_port "
    26482695        "FROM capturecard "
    26492696        "WHERE hostname = :HOSTNAME "
    26502697        "ORDER BY cardid");
     
    26632710        uint    cardid      = query.value(0).toUInt();
    26642711        QString videodevice = query.value(1).toString();
    26652712        QString cardtype    = query.value(2).toString();
     2713        QString hdhrTuner   = query.value(3).toString();
    26662714
    26672715        if ((cardtype.lower() == "dvb") && (1 != ++device_refs[videodevice]))
    26682716            continue;
    26692717
     2718        if (cardtype.lower() == "hdhomerun")
     2719        {
     2720            QString altvideodevice = videodevice + ":" + hdhrTuner;
     2721            if (1 != ++device_refs[altvideodevice])
     2722               continue;
     2723        }
     2724
     2725
    26702726        QStringList        inputLabels;
    26712727        vector<CardInput*> cardInputs;
    26722728
     
    29082964    connect(buttonDiSEqC, SIGNAL(pressed()),
    29092965            this,         SLOT(  DiSEqCPanel()));
    29102966    connect(buttonRecOpt, SIGNAL(pressed()),
    2911             &parent,      SLOT(  recorderOptionsPanel()));
     2967            &parent,      SLOT(  recorderOptionsPanelDVB()));
    29122968}
    29132969
    29142970DVBConfigurationGroup::~DVBConfigurationGroup()
     
    29533009    }
    29543010}
    29553011
    2956 void CaptureCard::recorderOptionsPanel()
     3012void CaptureCard::recorderOptionsPanelHDHomerun()
     3013{
     3014    reload();
     3015
     3016    RecorderOptions acw(*this, "HDHOMERUN");
     3017    acw.exec();
     3018    instance_count = acw.GetInstanceCount();
     3019}
     3020
     3021void CaptureCard::recorderOptionsPanelDVB()
    29573022{
    29583023    reload();
    29593024
    2960     RecorderOptions acw(*this);
     3025    RecorderOptions acw(*this, "DVB");
    29613026    acw.exec();
    29623027    instance_count = acw.GetInstanceCount();
    29633028}
    29643029
    2965 RecorderOptions::RecorderOptions(CaptureCard &parent)
     3030RecorderOptions::RecorderOptions(CaptureCard &parent, QString type)
    29663031    : count(new InstanceCount(parent))
    29673032{
    29683033    VerticalConfigurationGroup* rec = new VerticalConfigurationGroup(false);
     
    29703035    rec->setUseLabel(false);
    29713036
    29723037    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));
     3038    if (type == "DVB")
     3039    {
     3040        rec->addChild(new DVBNoSeqStart(parent));
     3041        rec->addChild(new DVBOnDemand(parent));
     3042        rec->addChild(new DVBEITScan(parent));
     3043        rec->addChild(new DVBTuningDelay(parent));
     3044    }
    29773045
    29783046    addChild(rec);
    29793047}
     3048
  • mythtv/libs/libmythtv/videosource.h

    diff -r -u -N -X diff.exclude -x release.19703.0116b -x release.19703.0116c release.19703.0116b/mythtv/libs/libmythtv/videosource.h release.19703.0116c/mythtv/libs/libmythtv/videosource.h
     
    477477    uint GetInstanceCount(void) const { return instance_count; }
    478478
    479479public slots:
    480     void recorderOptionsPanel();
     480    void recorderOptionsPanelDVB();
     481    void recorderOptionsPanelHDHomerun();
    481482
    482483private:
    483484