Ticket #7205: 0003-Generate-PSI-packets-for-broken-firmware-cable-boxes.patch

File 0003-Generate-PSI-packets-for-broken-firmware-cable-boxes.patch, 13.1 KB (added by Chase Douglas <chasedouglas@…>, 8 years ago)
  • mythtv/libs/libmythtv/darwinfirewiredevice.cpp

    From ca5f31b9e4fb1368cf23a7144fd55c445c0bd107 Mon Sep 17 00:00:00 2001
    From: Chase Douglas <chase.douglas@canonical.com>
    Date: Sun, 31 Jul 2011 10:46:29 -0700
    Subject: [PATCH 3/4] Generate PSI packets for broken firmware cable boxes
    
    If the firewire_gen_psip option is set for the capture device, generate
    MPEG2-TS PAT and PMT packets (aka Program Specific Information (PSI)
    packets).
    ---
     mythtv/libs/libmythtv/darwinfirewiredevice.cpp |    4 +-
     mythtv/libs/libmythtv/darwinfirewiredevice.h   |    3 +-
     mythtv/libs/libmythtv/firewirechannel.cpp      |    6 +-
     mythtv/libs/libmythtv/firewiredevice.cpp       |  183 +++++++++++++++++++++++-
     mythtv/libs/libmythtv/firewiredevice.h         |   25 +++-
     mythtv/libs/libmythtv/linuxfirewiredevice.cpp  |    4 +-
     mythtv/libs/libmythtv/linuxfirewiredevice.h    |    2 +-
     7 files changed, 215 insertions(+), 12 deletions(-)
    
    diff --git a/mythtv/libs/libmythtv/darwinfirewiredevice.cpp b/mythtv/libs/libmythtv/darwinfirewiredevice.cpp
    index 58224c9..8fa57d7 100644
    a b class DFDPriv 
    114114};
    115115
    116116DarwinFirewireDevice::DarwinFirewireDevice(
    117     uint64_t guid, uint subunitid, uint speed) :
    118     FirewireDevice(guid, subunitid, speed),
     117    uint64_t guid, uint subunitid, uint speed, bool gen_psip) :
     118    FirewireDevice(guid, subunitid, speed, gen_psip),
    119119    m_local_node(-1), m_remote_node(-1), m_priv(new DFDPriv())
    120120{
    121121
  • mythtv/libs/libmythtv/darwinfirewiredevice.h

    diff --git a/mythtv/libs/libmythtv/darwinfirewiredevice.h b/mythtv/libs/libmythtv/darwinfirewiredevice.h
    index 4ed70df..68c1f35 100644
    a b class DarwinFirewireDevice : public FirewireDevice 
    2020
    2121
    2222  public:
    23     DarwinFirewireDevice(uint64_t guid, uint subunitid, uint speed);
     23    DarwinFirewireDevice(uint64_t guid, uint subunitid, uint speed,
     24                         bool gen_psip = false);
    2425    ~DarwinFirewireDevice();
    2526
    2627    virtual bool OpenPort(void);
  • mythtv/libs/libmythtv/firewirechannel.cpp

    diff --git a/mythtv/libs/libmythtv/firewirechannel.cpp b/mythtv/libs/libmythtv/firewirechannel.cpp
    index adf6e09..a397614 100644
    a b FirewireChannel::FirewireChannel(TVRec *parent, const QString &_videodevice, 
    2828#ifdef USING_LINUX_FIREWIRE
    2929    device = new LinuxFirewireDevice(
    3030        guid, subunitid, fw_opts.speed,
    31         LinuxFirewireDevice::kConnectionP2P == (uint) fw_opts.connection);
     31        LinuxFirewireDevice::kConnectionP2P == (uint) fw_opts.connection,
     32        fw_opts.gen_psip);
    3233#endif // USING_LINUX_FIREWIRE
    3334
    3435#ifdef USING_OSX_FIREWIRE
    35     device = new DarwinFirewireDevice(guid, subunitid, fw_opts.speed);
     36    device = new DarwinFirewireDevice(guid, subunitid, fw_opts.speed,
     37        fw_opts.gen_psip);
    3638#endif // USING_OSX_FIREWIRE
    3739}
    3840
  • mythtv/libs/libmythtv/firewiredevice.cpp

    diff --git a/mythtv/libs/libmythtv/firewiredevice.cpp b/mythtv/libs/libmythtv/firewiredevice.cpp
    index 2015e57..a074026 100644
    a b  
    11/**
    22 *  FirewireDevice
    33 *  Copyright (c) 2005 by Jim Westfall
     4 *  Copyright (c) 2011 by Chase Douglas
    45 *  Distributed as part of MythTV under GPL v2 and later.
    56 */
    67
     
    1516#include "darwinfirewiredevice.h"
    1617#include "mythlogging.h"
    1718#include "pespacket.h"
     19#include "mpegtables.h"
    1820
    1921#define LOC      QString("FireDev(%1): ").arg(guid_to_string(m_guid))
    2022
     23extern "C" {
     24extern const uint8_t *ff_find_start_code(const uint8_t *p, const uint8_t *end, uint32_t *state);
     25}
     26
    2127static void fw_init(QMap<uint64_t,QString> &id_to_model);
    2228
    2329QMap<uint64_t,QString> FirewireDevice::s_id_to_model;
    2430QMutex                 FirewireDevice::s_static_lock;
    2531
    26 FirewireDevice::FirewireDevice(uint64_t guid, uint subunitid, uint speed) :
     32FirewireDevice::FirewireDevice(uint64_t guid, uint subunitid, uint speed,
     33                               bool gen_psip) :
    2734    m_guid(guid),           m_subunitid(subunitid),
    2835    m_speed(speed),
    2936    m_last_channel(0),      m_last_crc(0),
    3037    m_buffer_cleared(true), m_open_port_cnt(0),
    31     m_lock()
     38    m_lock(), m_gen_psip(gen_psip),
     39    m_vpid(0), m_apid(0), m_pat(NULL), m_pat_cc(0), m_pmt(NULL), m_pmt_cc(0)
     40{
     41}
     42
     43FirewireDevice::~FirewireDevice()
    3244{
     45    delete m_pat;
     46    delete m_pmt;
    3347}
    3448
    3549void FirewireDevice::AddListener(TSDataListener *listener)
    bool FirewireDevice::SetChannel(const QString &panel_model, 
    303317        return true;
    304318    }
    305319
     320    m_apid = 0;
     321    m_vpid = 0;
     322    m_pat_timer.stop();
     323    delete m_pat;
     324    m_pat = NULL;
     325    m_pmt_timer.stop();
     326    delete m_pmt;
     327    m_pmt = NULL;
     328
     329    return false;
     330}
     331
     332void FirewireDevice::SendPAT()
     333{
     334    vector<TSPacket> m_pat_pkts;
     335    m_pat->GetAsTSPackets(m_pat_pkts, m_pat_cc);
     336    for (vector<TSPacket>::const_iterator it = m_pat_pkts.begin(); it != m_pat_pkts.end(); ++it)
     337        SendDataToListeners(it->data(), TSPacket::kSize);
     338    m_pat_cc = (m_pat_pkts.back().ContinuityCounter() + 1) & 0xf;
     339}
     340
     341void FirewireDevice::SendPMT()
     342{
     343    vector<TSPacket> m_pmt_pkts;
     344    m_pmt->GetAsTSPackets(m_pmt_pkts, m_pmt_cc);
     345    for (vector<TSPacket>::const_iterator it = m_pmt_pkts.begin(); it != m_pmt_pkts.end(); ++it)
     346        SendDataToListeners(it->data(), TSPacket::kSize);
     347    m_pmt_cc = (m_pmt_pkts.back().ContinuityCounter() + 1) & 0xf;
     348}
     349
     350void FirewireDevice::GetTSPackets(const unsigned char *data, uint len, vector<const TSPacket*> *packets)
     351{
     352    uint bufsz = m_buffer.size();
     353    if ((SYNC_BYTE == data[0]) && (TSPacket::kSize == len) &&
     354        (TSPacket::kSize > bufsz))
     355    {
     356        m_buffer.clear();
     357
     358        packets->push_back(reinterpret_cast<const TSPacket*>(data));
     359        return;
     360    }
     361
     362    m_buffer.insert(m_buffer.end(), data, data + len);
     363    bufsz += len;
     364
     365    uint sync_at;
     366    for (sync_at = 0; sync_at < bufsz; sync_at++)
     367        if (m_buffer[sync_at] == SYNC_BYTE)
     368            break;
     369
     370    if (sync_at == bufsz)
     371        return;
     372
     373    while (sync_at + TSPacket::kSize < bufsz)
     374    { 
     375        packets->push_back(reinterpret_cast<const TSPacket*>(
     376                                &m_buffer[0] + sync_at));
     377
     378        sync_at += TSPacket::kSize;
     379    }
     380
     381    m_buffer.erase(m_buffer.begin(), m_buffer.begin() + sync_at);
     382
     383    return;
     384}
     385
     386/* Check for MPEG2 video PES packet header */
     387static bool IsMPEG2Frame(const TSPacket &tspacket)
     388{
     389    const uint8_t *bufptr = tspacket.data() + tspacket.AFCOffset();
     390    const uint8_t *bufend = tspacket.data() + TSPacket::kSize;
     391    uint32_t start_code;
     392
     393    while (bufptr < bufend)
     394    {
     395        bufptr = ff_find_start_code(bufptr, bufend, &start_code);
     396        if ((start_code & 0xffffff00) == 0x00000100)
     397        {
     398            const int stream_id = start_code & 0x000000ff;
     399
     400            if (stream_id == PESStreamID::PictureStartCode ||
     401                stream_id == PESStreamID::GOPStartCode)
     402                return true;
     403        }
     404    }
     405
    306406    return false;
    307407}
    308408
     409/* Firewire devices emit one video and one audio elementary stream. We must
     410 * figure out which PID is the video stream and which is the audio stream. It's
     411 * easy to determine the video stream, so find it first. Then assume the other
     412 * is audio.
     413 */
     414void FirewireDevice::GeneratePSIP(const unsigned char *data, uint dataSize)
     415{
     416    vector<const TSPacket*> packets;
     417
     418    /* If PAT packet hasn't been generated, chunk data into packets for analyzing */
     419    if (!m_pat)
     420        GetTSPackets(data, dataSize, &packets);
     421
     422    for (vector<const TSPacket*>::const_iterator it = packets.begin(); it != packets.end(); ++it)
     423    {
     424        const TSPacket *tspacket = *it;
     425
     426        if (!m_vpid)
     427        {
     428            if (IsMPEG2Frame(*tspacket))
     429                m_vpid = tspacket->PID();
     430            continue;
     431        }
     432
     433        if (m_vpid && !m_apid && tspacket->PID() != m_vpid &&
     434            tspacket->PID() != TSPacket::kNullPacket->PID())
     435        {
     436            m_apid = tspacket->PID();
     437
     438            /* Generate PAT */
     439            vector<uint> programs;
     440            programs.push_back(1);
     441            vector<uint> pids;
     442            pids.push_back(10);
     443
     444            m_pat = ProgramAssociationTable::Create(0, 0, programs, pids);
     445            SendPAT();
     446            m_pat_timer.start();
     447
     448            /* Generate PMT */
     449            vector<uint> ppids;
     450            ppids.push_back(m_vpid);
     451            ppids.push_back(m_apid);
     452            vector<uint> types;
     453            types.push_back(StreamID::MPEG2Video);
     454            types.push_back(StreamID::AC3Audio);
     455
     456            m_pmt = ProgramMapTable::Create(1, 10, 0x1fff, 0, ppids, types);
     457            SendPMT();
     458            m_pmt_timer.start();
     459        }
     460    }
     461
     462    /* The ATSC standard is a reasonable choice to mimic. It says a PAT must
     463     * occur at least once every 100 ms. A PMT must occur at least once every
     464     * 400 ms. We'll set the frequencies at 75% of the limits. */
     465
     466    if (m_pat_timer.isRunning() && m_pat_timer.elapsed() >= 75)
     467    {
     468        SendPAT();
     469        m_pat_timer.start();
     470    }
     471
     472    if (m_pmt_timer.isRunning() && m_pmt_timer.elapsed() >= 300)
     473    {
     474        SendPMT();
     475        m_pmt_timer.start();
     476    }
     477}
     478
    309479void FirewireDevice::BroadcastToListeners(
    310480    const unsigned char *data, uint dataSize)
    311481{
     482    if (m_gen_psip)
     483        GeneratePSIP(data, dataSize);
     484
     485    SendDataToListeners(data, dataSize);
     486}
     487
     488void FirewireDevice::SendDataToListeners(const unsigned char *data,
     489                                         uint dataSize)
     490{
    312491    if ((dataSize >= TSPacket::kSize) && (data[0] == SYNC_BYTE) &&
    313492        ((data[1] & 0x1f) == 0) && (data[2] == 0))
    314493    {
  • mythtv/libs/libmythtv/firewiredevice.h

    diff --git a/mythtv/libs/libmythtv/firewiredevice.h b/mythtv/libs/libmythtv/firewiredevice.h
    index 4151220..381020b 100644
    a b using namespace std; 
    1818// MythTV headers
    1919#include "streamlisteners.h"
    2020#include "avcinfo.h"
     21#include "mythtimer.h"
    2122
    2223class TSPacket;
    2324
    class FirewireDevice 
    190191
    191192    } IEEE1394PanelPassThroughParam0;
    192193
    193     virtual ~FirewireDevice() { }
     194    virtual ~FirewireDevice();
    194195
    195196    // Commands
    196197    virtual bool OpenPort(void) = 0;
    class FirewireDevice 
    218219    static vector<AVCInfo> GetSTBList(void);
    219220
    220221  protected:
    221     FirewireDevice(uint64_t guid, uint subunitid, uint speed);
     222    FirewireDevice(uint64_t guid, uint subunitid, uint speed, bool gen_psip);
    222223
    223224    virtual bool SendAVCCommand(const vector<uint8_t> &cmd,
    224225                                vector<uint8_t> &result,
    class FirewireDevice 
    229230    void ProcessPATPacket(const TSPacket&);
    230231    virtual void BroadcastToListeners(
    231232        const unsigned char *data, uint dataSize);
     233    void SendDataToListeners(const unsigned char *data, uint dataSize);
     234    void GeneratePSIP(const unsigned char *data, uint dataSize);
     235    void GetTSPackets(const unsigned char *data, uint len,
     236                      vector<const TSPacket*> *packets);
     237    void SendPAT();
     238    void SendPMT();
    232239
    233240    uint64_t                 m_guid;
    234241    uint                     m_subunitid;
    class FirewireDevice 
    241248    vector<TSDataListener*>  m_listeners;
    242249    mutable QMutex           m_lock;
    243250
     251    bool                     m_gen_psip;
     252    vector<unsigned char>    m_buffer;
     253
     254    uint                     m_vpid;
     255    uint                     m_apid;
     256
     257    ProgramAssociationTable *m_pat;
     258    uint                     m_pat_cc;
     259    MythTimer                m_pat_timer;
     260
     261    ProgramMapTable         *m_pmt;
     262    uint                     m_pmt_cc;
     263    MythTimer                m_pmt_timer;
     264
    244265    /// Vendor ID + Model ID to FirewireDevice STB model string
    245266    static QMap<uint64_t,QString> s_id_to_model;
    246267    static QMutex                 s_static_lock;
  • mythtv/libs/libmythtv/linuxfirewiredevice.cpp

    diff --git a/mythtv/libs/libmythtv/linuxfirewiredevice.cpp b/mythtv/libs/libmythtv/linuxfirewiredevice.cpp
    index 7ef8dd1..1eee67e 100644
    a b static int linux_firewire_device_bus_reset_handler( 
    136136
    137137LinuxFirewireDevice::LinuxFirewireDevice(
    138138    uint64_t guid, uint subunitid,
    139     uint speed, bool use_p2p, uint av_buffer_size_in_bytes) :
    140     FirewireDevice(guid, subunitid, speed),
     139    uint speed, bool use_p2p, bool gen_psip, uint av_buffer_size_in_bytes) :
     140    FirewireDevice(guid, subunitid, speed, gen_psip),
    141141    m_bufsz(av_buffer_size_in_bytes),
    142142    m_db_reset_disabled(false),
    143143    m_use_p2p(use_p2p), m_priv(new LFDPriv())
  • mythtv/libs/libmythtv/linuxfirewiredevice.h

    diff --git a/mythtv/libs/libmythtv/linuxfirewiredevice.h b/mythtv/libs/libmythtv/linuxfirewiredevice.h
    index adb71aa..9187486 100644
    a b class LinuxFirewireDevice : public FirewireDevice 
    3333
    3434  public:
    3535    LinuxFirewireDevice(uint64_t guid, uint subunitid,
    36                         uint speed, bool use_p2p,
     36                        uint speed, bool use_p2p, bool gen_psip = false,
    3737                        uint av_buffer_size_in_bytes = 0);
    3838    ~LinuxFirewireDevice();
    3939