Ticket #6138: 133-hdhr.multirec.fixes.12.patch

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

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

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

    diff -p -r -u -N -X /tmp/diff.exclude -x release.21606.0831a -x release.21606.0831b release.21606.0831a/mythtv/libs/libmythtv/hdhrchannel.cpp release.21606.0831b/mythtv/libs/libmythtv/hdhrchannel.cpp
    using namespace std; 
    2525#include "videosource.h"
    2626#include "channelutil.h"
    2727
     28#include "hdhrstreamhandler.h"
     29
    2830#define DEBUG_PID_FILTERS
    2931
    3032#define LOC QString("HDHRChan(%1): ").arg(GetDevice())
    3133#define LOC_ERR QString("HDHRChan(%1), Error: ").arg(GetDevice())
    3234
    33 HDHRChannel::HDHRChannel(TVRec *parent, const QString &device, uint tuner)
    34     : DTVChannel(parent),       _hdhomerun_device(NULL),
    35       _device_id(0),            _device_ip(0),
    36       _tuner(tuner),            _lock(true)
    37 {
    38     bool valid;
    39     _device_id = device.toUInt(&valid, 16);
    40 
    41     if (valid && hdhomerun_discover_validate_device_id(_device_id))
    42         return;
    43 
    44     _device_id = HDHOMERUN_DEVICE_ID_WILDCARD;
    45 
    46     /* Otherwise, is it a valid IP address? */
    47     struct in_addr address;
    48     if (inet_aton(device, &address))
    49     {
    50         _device_ip = ntohl(address.s_addr);
    51         return;
    52     }
    53 
    54     /* Invalid, use wildcard device ID. */
    55     VERBOSE(VB_IMPORTANT, LOC_ERR + QString("Invalid DeviceID '%1'")
    56             .arg(device));
    57 
     35HDHRChannel::HDHRChannel(TVRec *parent, const QString &device)
     36    : DTVChannel(parent),       _stream_handler(NULL),
     37      _device_id(device),            _lock(true),
     38      tune_lock(true),          hw_lock(true)
     39{
    5840}
    5941
    6042HDHRChannel::~HDHRChannel(void)
    HDHRChannel::~HDHRChannel(void) 
    6446
    6547bool HDHRChannel::Open(void)
    6648{
    67     if (IsOpen())
    68         return true;
     49    VERBOSE(VB_CHANNEL, LOC + "Opening HDHR channel");
    6950
    70     if (!InitializeInputs())
    71         return false;
    72 
    73     return Connect();
    74 }
    75 
    76 void HDHRChannel::Close(void)
    77 {
    78     if (_hdhomerun_device)
    79     {
    80         hdhomerun_device_destroy(_hdhomerun_device);
    81         _hdhomerun_device = NULL;
    82     }
    83 }
     51    QMutexLocker locker(&hw_lock);
    8452
    85 bool HDHRChannel::EnterPowerSavingMode(void)
    86 {
    87     return hdhomerun_device_set_tuner_channel(_hdhomerun_device, "none") > 0;
    88 }
     53    if (IsOpen())
     54        return true;
    8955
    90 bool HDHRChannel::Connect(void)
    91 {
    92     _hdhomerun_device = hdhomerun_device_create(
    93         _device_id, _device_ip, _tuner, NULL);
     56    _stream_handler = HDHRStreamHandler::Get(_device_id);
    9457
    95     if (!_hdhomerun_device)
     58    if (!InitializeInputs())
    9659    {
    97         VERBOSE(VB_IMPORTANT,
    98                 LOC_ERR + "Unable to create hdhomerun device object");
     60        Close();
    9961        return false;
    10062    }
    10163
    102     return true;
    103 }
    104 
    105 QString HDHRChannel::DeviceGet(const QString &name, bool report_error_return)
    106 {
    107     QMutexLocker locker(&_lock);
     64//  nextInputID = currentInputID;
    10865
    109     if (!_hdhomerun_device)
    110     {
    111         VERBOSE(VB_IMPORTANT, LOC_ERR + "Get request failed (not connected)");
    112         return QString::null;
    113     }
     66    return _stream_handler->Connected();
    11467
    115     char *value = NULL;
    116     char *error = NULL;
    117     if (hdhomerun_device_get_var(_hdhomerun_device, name, &value, &error) < 0)
    118     {
    119         VERBOSE(VB_IMPORTANT, LOC_ERR + "Get request failed" + ENO);
    120         return QString::null;
    121     }
    122 
    123     if (report_error_return && error)
    124     {
    125         VERBOSE(VB_IMPORTANT, LOC_ERR +
    126                 QString("DeviceGet(%1): %2").arg(name).arg(error));
    127 
    128         return QString::null;
    129     }
    130 
    131     return QString(value);
    13268}
    13369
    134 QString HDHRChannel::DeviceSet(const QString &name, const QString &val,
    135                                bool report_error_return)
     70void HDHRChannel::Close()
    13671{
    137     QMutexLocker locker(&_lock);
    138 
    139     if (!_hdhomerun_device)
    140     {
    141         VERBOSE(VB_IMPORTANT, LOC_ERR + "Set request failed (not connected)");
    142         return QString::null;
    143     }
     72    VERBOSE(VB_CHANNEL, LOC + "Closing HDHR channel");
    14473
    145     char *value = NULL;
    146     char *error = NULL;
    147     if (hdhomerun_device_set_var(
    148             _hdhomerun_device, name, val, &value, &error) < 0)
    149     {
    150         VERBOSE(VB_IMPORTANT, LOC_ERR + "Set request failed" + ENO);
    151 
    152         return QString::null;
    153     }
    154 
    155     if (report_error_return && error)
    156     {
    157         VERBOSE(VB_IMPORTANT, LOC_ERR +
    158                 QString("DeviceSet(%1 %2): %3").arg(name).arg(val).arg(error));
    159 
    160         return QString::null;
    161     }
     74    if (! IsOpen())
     75        return; // this caller didn't have it open in the first place..
    16276
    163     return QString(value);
     77    HDHRStreamHandler::Return(_stream_handler);
    16478}
    16579
    166 struct hdhomerun_device_t *HDHRChannel::GetHDHRDevice(void)
     80bool HDHRChannel::EnterPowerSavingMode(void)
    16781{
    168         return _hdhomerun_device;
     82    if ( IsOpen())
     83        return _stream_handler->EnterPowerSavingMode();
     84    else
     85        return true;
    16986}
    17087
    171 QString HDHRChannel::TunerGet(const QString &name, bool report_error_return)
    172 {
    173     return DeviceGet(QString("/tuner%1/%2").arg(_tuner).arg(name),
    174                      report_error_return);
    175 }
    17688
    177 QString HDHRChannel::TunerSet(const QString &name, const QString &value,
    178                               bool report_error_return)
     89bool HDHRChannel::IsOpen(void) const
    17990{
    180     return DeviceSet(QString("/tuner%1/%2").arg(_tuner).arg(name), value,
    181                      report_error_return);
     91      return (_stream_handler != NULL);
    18292}
    18393
    184 bool HDHRChannel::DeviceSetTarget(unsigned short localPort)
     94bool HDHRChannel::Init(QString &inputname, QString &startchannel, bool setchan)
    18595{
    186     if (localPort == 0)
    187     {
    188         return false;
    189     }
     96    if (setchan && !IsOpen())
     97        Open();
    19098
    191     unsigned long localIP = hdhomerun_device_get_local_machine_addr(
    192         _hdhomerun_device);
    193     if (localIP == 0)
    194     {
    195         return false;
    196     }
    197 
    198     QString configValue = QString("%1.%2.%3.%4:%5")
    199         .arg((localIP >> 24) & 0xFF).arg((localIP >> 16) & 0xFF)
    200         .arg((localIP >>  8) & 0xFF).arg((localIP >>  0) & 0xFF)
    201         .arg(localPort);
    202 
    203     if (hdhomerun_device_set_tuner_target(_hdhomerun_device, configValue) <= 0)
    204     {
    205         return false;
    206     }
    207 
    208     return true;
    209 }
    210 
    211 bool HDHRChannel::DeviceClearTarget(void)
    212 {
    213     return hdhomerun_device_set_tuner_target(_hdhomerun_device, "none") > 0;
     99    return ChannelBase::Init(inputname, startchannel, setchan);
    214100}
    215101
    216102bool HDHRChannel::SetChannelByString(const QString &channum)
    bool HDHRChannel::SetChannelByString(con 
    244130        return SwitchToInput(inputName, channum);
    245131
    246132    ClearDTVInfo();
    247     _ignore_filters = false;
    248133
    249134    InputMap::const_iterator it = inputs.find(currentInputID);
    250135    if (it == inputs.end())
    bool HDHRChannel::SetChannelByString(con 
    316201    if (mpeg_prog_num && (GetTuningMode() == "mpeg"))
    317202    {
    318203        QString pnum = QString::number(mpeg_prog_num);
    319         _ignore_filters = (hdhomerun_device_set_tuner_program(
    320                                _hdhomerun_device, pnum) > 0);
     204        //_ignore_filters = _stream_handler->TuneProgram(pnum);
     205        _stream_handler->TuneProgram(pnum);
    321206    }
    322207
    323208    return true;
    bool HDHRChannel::Tune(uint frequency, Q 
    364249
    365250    VERBOSE(VB_CHANNEL, LOC + "Tune()ing to " + chan);
    366251
    367     if (hdhomerun_device_set_tuner_channel(_hdhomerun_device, chan) > 0)
     252    if (_stream_handler->TuneChannel(chan))
    368253    {
    369254        SetSIStandard(si_std);
    370255        return true;
    371256    }
    372257
     258    // dtv_multiplex.modulation is from the DB. Could contain almost anything.
     259    // As a fallback, use the HDHR device's automatic scanning:
     260    chan = "auto:" + QString::number(frequency);
    373261
    374     // dtv_multiplex.modulation is from the DB. Could contain almost anything.
    375     // As a fallback, use the HDHR device's automatic scanning:
    376     chan = "auto:" + QString::number(frequency);
    377  
    378     VERBOSE(VB_CHANNEL, LOC + "Failed. Now trying " + chan);
    379  
    380     if (hdhomerun_device_set_tuner_channel(_hdhomerun_device, chan) > 0)
    381     {
    382         SetSIStandard(si_std);
    383         return true;
    384     }
    385  
    386  
    387     return false;
    388 }
    389 
    390 bool HDHRChannel::AddPID(uint pid, bool do_update)
    391 {
    392     QMutexLocker locker(&_lock);
     262    VERBOSE(VB_CHANNEL, LOC + "Failed. Now trying " + chan);
    393263
    394     vector<uint>::iterator it;
    395     it = lower_bound(_pids.begin(), _pids.end(), pid);
    396     if (it != _pids.end() && *it == pid)
     264    if (_stream_handler->TuneChannel(chan))
    397265    {
    398 #ifdef DEBUG_PID_FILTERS
    399         VERBOSE(VB_CHANNEL, "AddPID(0x"<<hex<<pid<<dec<<") NOOP");
    400 #endif // DEBUG_PID_FILTERS
    401         return true;
    402     }
    403 
    404     _pids.insert(it, pid);
    405 
    406 #ifdef DEBUG_PID_FILTERS
    407     VERBOSE(VB_CHANNEL, "AddPID(0x"<<hex<<pid<<dec<<")");
    408 #endif // DEBUG_PID_FILTERS
    409 
    410     if (do_update)
    411         return UpdateFilters();
    412     return true;
    413 }
    414 
    415 bool HDHRChannel::DelPID(uint pid, bool do_update)
    416 {
    417     QMutexLocker locker(&_lock);
    418 
    419     vector<uint>::iterator it;
    420     it = lower_bound(_pids.begin(), _pids.end(), pid);
    421     if (it == _pids.end())
    422     {
    423 #ifdef DEBUG_PID_FILTERS
    424         VERBOSE(VB_CHANNEL, "DelPID(0x"<<hex<<pid<<dec<<") NOOP");
    425 #endif // DEBUG_PID_FILTERS
    426 
    427        return true;
    428     }
    429 
    430     if (*it == pid)
    431     {
    432 #ifdef DEBUG_PID_FILTERS
    433         VERBOSE(VB_CHANNEL, "DelPID(0x"<<hex<<pid<<dec<<") -- found");
    434 #endif // DEBUG_PID_FILTERS
    435         _pids.erase(it);
    436     }
    437     else
    438     {
    439 #ifdef DEBUG_PID_FILTERS
    440         VERBOSE(VB_CHANNEL, "DelPID(0x"<<hex<<pid<<dec<<") -- failed");
    441 #endif // DEBUG_PID_FILTERS
    442     }
    443 
    444     if (do_update)
    445         return UpdateFilters();
    446     return true;
    447 }
    448 
    449 bool HDHRChannel::DelAllPIDs(void)
    450 {
    451     QMutexLocker locker(&_lock);
    452 
    453 #ifdef DEBUG_PID_FILTERS
    454     VERBOSE(VB_CHANNEL, "DelAllPID()");
    455 #endif // DEBUG_PID_FILTERS
    456 
    457     _pids.clear();
    458 
    459     return UpdateFilters();
    460 }
    461 
    462 QString filt_str(uint pid)
    463 {
    464     uint pid0 = (pid / (16*16*16)) % 16;
    465     uint pid1 = (pid / (16*16))    % 16;
    466     uint pid2 = (pid / (16))        % 16;
    467     uint pid3 = pid % 16;
    468     return QString("0x%1%2%3%4")
    469         .arg(pid0,0,16).arg(pid1,0,16)
    470         .arg(pid2,0,16).arg(pid3,0,16);
    471 }
    472 
    473 bool HDHRChannel::UpdateFilters(void)
    474 {
    475     QMutexLocker locker(&_lock);
    476 
    477     QString filter = "";
    478 
    479     vector<uint> range_min;
    480     vector<uint> range_max;
    481 
    482     if (_ignore_filters)
     266        SetSIStandard(si_std);
    483267        return true;
    484 
    485     for (uint i = 0; i < _pids.size(); i++)
    486     {
    487         uint pid_min = _pids[i];
    488         uint pid_max  = pid_min;
    489         for (uint j = i + 1; j < _pids.size(); j++)
    490         {
    491             if (pid_max + 1 != _pids[j])
    492                 break;
    493             pid_max++;
    494             i++;
    495         }
    496         range_min.push_back(pid_min);
    497         range_max.push_back(pid_max);
    498     }
    499 
    500     if (range_min.size() > 16)
    501     {
    502         range_min.resize(16);
    503         uint pid_max = range_max.back();
    504         range_max.resize(15);
    505         range_max.push_back(pid_max);
    506268    }
    507 
    508     for (uint i = 0; i < range_min.size(); i++)
    509     {
    510         filter += filt_str(range_min[i]);
    511         if (range_min[i] != range_max[i])
    512             filter += QString("-%1").arg(filt_str(range_max[i]));
    513         filter += " ";
    514     }
    515 
    516     filter = filter.stripWhiteSpace();
    517 
    518     QString new_filter = TunerSet("filter", filter);
    519 
    520 #ifdef DEBUG_PID_FILTERS
    521     QString msg = QString("Filter: '%1'").arg(filter);
    522     if (filter != new_filter)
    523         msg += QString("\n\t\t\t\t'%2'").arg(new_filter);
    524 
    525     VERBOSE(VB_CHANNEL, msg);
    526 #endif // DEBUG_PID_FILTERS
    527 
    528     return filter == new_filter;
     269    return false;
    529270}
  • mythtv/libs/libmythtv/hdhrchannel.h

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

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

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

    diff -p -r -u -N -X /tmp/diff.exclude -x release.21606.0831a -x release.21606.0831b release.21606.0831a/mythtv/libs/libmythtv/hdhrsignalmonitor.cpp release.21606.0831b/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())
    HDHRSignalMonitor::HDHRSignalMonitor(int 
    4142                                     HDHRChannel* _channel,
    4243                                     uint64_t _flags, const char *_name)
    4344    : DTVSignalMonitor(db_cardnum, _channel, _flags, _name),
    44       dtvMonitorRunning(false)
     45      streamHandlerStarted(false),
     46      streamHandler(NULL)
     47
    4548{
    4649    VERBOSE(VB_CHANNEL, LOC + "ctor");
    4750
    48     _channel->DelAllPIDs();
    49 
    5051    signalStrength.SetThreshold(45);
    5152
    5253    AddFlags(kDTVSigMon_WaitForSig);
     54
     55    streamHandler = HDHRStreamHandler::Get(_channel->GetDevice());
    5356}
    5457
    5558/** \fn HDHRSignalMonitor::~HDHRSignalMonitor()
    HDHRSignalMonitor::~HDHRSignalMonitor() 
    5962{
    6063    VERBOSE(VB_CHANNEL, LOC + "dtor");
    6164    Stop();
     65    HDHRStreamHandler::Return(streamHandler);
    6266}
    6367
    6468void HDHRSignalMonitor::deleteLater(void)
    void HDHRSignalMonitor::Stop(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 }
    85 
    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     }
     82    if (GetStreamData())
     83        streamHandler->RemoveListener(GetStreamData());
     84    streamHandlerStarted = false;
     85    streamHandler->SetRetuneAllowed(false, NULL, NULL);
    12686
    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     HDHRChannel *hdrc = dynamic_cast<HDHRChannel*>(channel);
    143     struct hdhomerun_device_t *_hdhomerun_device = hdrc->GetHDHRDevice();
    144 
    145     if (!_hdhomerun_device)
    146     {
    147         VERBOSE(VB_IMPORTANT, "Failed to get HDHomeRun device handle");
    148         return;
    149     }
    150 
    151     if (!hdhomerun_device_stream_start(_hdhomerun_device))
    152     {
    153         VERBOSE(VB_IMPORTANT, LOC_ERR + "Failed to set target");
    154         return;
    155     }
    156 
    157     VERBOSE(VB_CHANNEL, LOC + "RunTableMonitor(): " +
    158             QString("begin (# of pids %1)")
    159             .arg(GetStreamData()->ListeningPIDs().size()));
    160 
    161     while (dtvMonitorRunning && GetStreamData())
    162     {
    163         UpdateFiltersFromStreamData();
    164 
    165         size_t data_length;
    166         unsigned char *data_buffer =
    167             hdhomerun_device_stream_recv(_hdhomerun_device,
    168                                          VIDEO_DATA_BUFFER_SIZE_1S / 5,
    169                                          &data_length);
    170 
    171         if (data_buffer)
    172         {
    173             GetStreamData()->ProcessData(data_buffer, data_length);
    174             continue;
    175         }
    176 
    177         usleep(2500);
    178     }
    179 
    180     hdhomerun_device_stream_stop(_hdhomerun_device);
    181 
    182     VERBOSE(VB_CHANNEL, LOC + "RunTableMonitor(): -- shutdown");
    183 
    184     // TODO teardown PID filters here
    185 
    186     VERBOSE(VB_CHANNEL, LOC + "RunTableMonitor(): -- end");
     92    return dynamic_cast<HDHRChannel*>(channel);
    18793}
    18894
    18995/** \fn HDHRSignalMonitor::UpdateValues()
    void HDHRSignalMonitor::UpdateValues(voi 
    201107    if (!running || exit)
    202108        return;
    203109
    204     if (dtvMonitorRunning)
     110    if (streamHandlerStarted)
    205111    {
    206112        EmitHDHRSignals();
    207113        if (IsAllGood())
    void HDHRSignalMonitor::UpdateValues(voi 
    212118        return;
    213119    }
    214120
    215     HDHRChannel *hdrc = dynamic_cast<HDHRChannel*>(channel);
    216     struct hdhomerun_device_t *_hdhomerun_device = hdrc->GetHDHRDevice();
    217     struct hdhomerun_tuner_status_t status;
    218     hdhomerun_device_get_tuner_status(_hdhomerun_device, NULL, &status);
    219 
    220     uint sig = status.signal_strength;
    221     uint snq = status.signal_to_noise_quality;
    222     uint seq = status.symbol_error_quality;
    223 
     121    QString msg = streamHandler->GetTunerStatus();
     122    //ss  = signal strength,        [0,100]
     123    //snq = signal to noise quality [0,100]
     124    //seq = signal error quality    [0,100]
     125    int loc_sig = msg.find("ss="),  loc_snq = msg.find("snq=");
     126    int loc_seq = msg.find("seq="), loc_end = msg.length();
     127    bool ok0, ok1, ok2;
     128    uint sig = msg.mid(loc_sig + 3, loc_snq - loc_sig - 4).toUInt(&ok0);
     129    uint snq = msg.mid(loc_snq + 4, loc_seq - loc_snq - 5).toUInt(&ok1);
     130    uint seq = msg.mid(loc_seq + 4, loc_end - loc_seq - 4).toUInt(&ok2);
    224131    (void) snq; // TODO should convert to S/N
    225132    (void) seq; // TODO should report this...
    226133
    void HDHRSignalMonitor::UpdateValues(voi 
    232139    bool isLocked = false;
    233140    {
    234141        QMutexLocker locker(&statusLock);
    235         signalStrength.SetValue(sig);
    236         signalLock.SetValue(status.lock_supported);
     142        if (loc_sig > 0 && loc_snq > 0 && ok0)
     143            signalStrength.SetValue(sig);
     144        signalLock.SetValue(signalStrength.IsGood() ? 1 : 0);
    237145        isLocked = signalLock.IsGood();
    238146    }
    239147
    void HDHRSignalMonitor::UpdateValues(voi 
    248156                   kDTVSigMon_WaitForMGT | kDTVSigMon_WaitForVCT |
    249157                   kDTVSigMon_WaitForNIT | kDTVSigMon_WaitForSDT))
    250158    {
    251         pthread_create(&table_monitor_thread, NULL,
    252                        TableMonitorThread, this);
    253 
    254         VERBOSE(VB_CHANNEL, LOC + "UpdateValues() -- "
    255                 "Waiting for table monitor to start");
    256 
    257         while (!dtvMonitorRunning)
    258             usleep(50);
    259 
    260         VERBOSE(VB_CHANNEL, LOC + "UpdateValues() -- "
    261                 "Table monitor started");
     159        streamHandler->AddListener(GetStreamData());
     160        streamHandlerStarted = true;
    262161    }
    263162
    264163    update_done = true;
  • mythtv/libs/libmythtv/hdhrsignalmonitor.h

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

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

    diff -p -r -u -N -X /tmp/diff.exclude -x release.21606.0831a -x release.21606.0831b release.21606.0831a/mythtv/libs/libmythtv/libmythtv.pro release.21606.0831b/mythtv/libs/libmythtv/libmythtv.pro
    using_backend { 
    451451    using_hdhomerun {
    452452        # MythTV HDHomeRun glue
    453453        HEADERS += hdhrsignalmonitor.h   hdhrchannel.h
    454         HEADERS += hdhrrecorder.h
     454        HEADERS += hdhrrecorder.h        hdhrstreamhandler.h
    455455
    456456        SOURCES += hdhrsignalmonitor.cpp hdhrchannel.cpp
    457         SOURCES += hdhrrecorder.cpp
     457        SOURCES += hdhrrecorder.cpp      hdhrstreamhandler.cpp
    458458
    459459        DEFINES += USING_HDHOMERUN
    460460
  • mythtv/libs/libmythtv/scanwizardscanner.cpp

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

    diff -p -r -u -N -X /tmp/diff.exclude -x release.21606.0831a -x release.21606.0831b release.21606.0831a/mythtv/libs/libmythtv/tv_rec.cpp release.21606.0831b/mythtv/libs/libmythtv/tv_rec.cpp
    bool TVRec::CreateChannel(const QString  
    174174    else if (genOpt.cardtype == "HDHOMERUN")
    175175    {
    176176#ifdef USING_HDHOMERUN
    177         channel = new HDHRChannel(this, genOpt.videodev, dboxOpt.port);
     177        channel = new HDHRChannel(this, genOpt.videodev);
    178178        if (!channel->Open())
    179179            return false;
    180180        InitChannel(genOpt.defaultinput, startchannel);
    void TVRec::HandleTuning(void) 
    34303430            return;
    34313431
    34323432        ClearFlags(kFlagWaitingForRecPause);
    3433 #ifdef USING_HDHOMERUN
    3434         if (GetHDHRRecorder())
    3435         {
    3436             // We currently need to close the file descriptor for
    3437             // HDHomeRun signal monitoring to work.
    3438             GetHDHRRecorder()->Close();
    3439             GetHDHRRecorder()->SetRingBuffer(NULL);
    3440         }
    3441 #endif // USING_HDHOMERUN
    34423433        VERBOSE(VB_RECORD, LOC + "Recorder paused, calling TuningFrequency");
    34433434        TuningFrequency(lastTuningRequest);
    34443435    }
    void TVRec::TuningRestartRecorder(void) 
    40774068    }
    40784069    recorder->Reset();
    40794070
    4080 #ifdef USING_HDHOMERUN
    4081     if (GetHDHRRecorder())
    4082     {
    4083         pauseNotify = false;
    4084         GetHDHRRecorder()->Close();
    4085         pauseNotify = true;
    4086         GetHDHRRecorder()->Open();
    4087         GetHDHRRecorder()->StartData();
    4088     }
    4089 #endif // USING_HDHOMERUN
    4090 
    40914071    // Set file descriptor of channel from recorder for V4L
    40924072    channel->SetFd(recorder->GetVideoFd());
    40934073
  • mythtv/libs/libmythtv/videosource.cpp

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

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