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

File 133-hdhr.multirec.3.patch, 82.4 KB (added by anonymous, 12 years ago)

Updated multirec patch. Includes skip tuning patch and fix for crash during recorder teardown.

  • mythtv/libs/libmythtv/cardutil.cpp

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

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

    diff -r -u -N -X diff.exclude -x release.19740.0119a -x release.19740.0119b release.19740.0119a/mythtv/libs/libmythtv/hdhrstreamhandler.h release.19740.0119b/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.19740.0119a -x release.19740.0119b release.19740.0119a/mythtv/libs/libmythtv/libmythtv.pro release.19740.0119b/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.19740.0119a -x release.19740.0119b release.19740.0119a/mythtv/libs/libmythtv/tv_rec.cpp release.19740.0119b/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.19740.0119a -x release.19740.0119b release.19740.0119a/mythtv/libs/libmythtv/videosource.cpp release.19740.0119b/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.19740.0119a -x release.19740.0119b release.19740.0119a/mythtv/libs/libmythtv/videosource.h release.19740.0119b/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