Ticket #438: multiplePMT.patch

File multiplePMT.patch, 11.7 KB (added by redmundt@…, 20 years ago)
  • mpegstreamdata.cpp

     
    8989/** \fn MPEGStreamData::AssemblePSIP(const TSPacket* tspacket)
    9090 *  \brief PES packet assembler.
    9191 *
    92  *   This only assembles PES packets when new PES packets
    93  *   start in their own TSPacket. This is always true of
    94  *   ATSC & DVB tables, but not true of Audio and Video
    95  *   PES packets.
     92 *   This only starts assembling PES packets when new PES
     93 *   packets start in their own TSPacket.
     94 *
     95 *   DVB TSPackets may contain multiple segments of the PSI
     96 *   stream.  (see ISO 13818-1 section 2.4.3.3, particularly
     97 *   the definition of payload_unit_start_indicator, which
     98 *   indicates there is at least one segment start, but not
     99 *   limited to only one segment start.)
     100 *
     101 *   PSI stuffing bytes are 0xFF and will complete the
     102 *   remaining portion of the TSPacket.  (Section 2.4.4)
     103 *
     104 *   \note This method makes the assumption that AddTSPacket
     105 *   correctly handles duplicate packets.
    96106 */
    97 PSIPTable* MPEGStreamData::AssemblePSIP(const TSPacket* tspacket)
     107PSIPTable* MPEGStreamData::AssemblePSIP(const TSPacket* tspacket, bool &moreTablePackets)
    98108{
     109    moreTablePackets = true;
     110
     111    PESPacket* partial = GetPartialPES(tspacket->PID());
     112    if (partial)
     113    {
     114                if (partial->AddTSPacket(tspacket))
     115        {
     116            PSIPTable* psip = new PSIPTable(*partial);
     117
     118            // Advance to the next packet
     119            unsigned int packetStart = partial->PSIOffset() + psip->SectionLength();
     120            if (packetStart < partial->TSSizeInBuffer()) {
     121                if (partial->pesdata()[psip->SectionLength() + 1] != 0xff) {
     122                    // If the next section starts in the new tspacket
     123                    // create a new partial packet to prevent overflow
     124                    if ((partial->TSSizeInBuffer() > TSPacket::HEADER_SIZE + TSPacket::PAYLOAD_SIZE)
     125                            && (packetStart > partial->TSSizeInBuffer() - TSPacket::PAYLOAD_SIZE)) {
     126                        // Saving will handle deleting the old one
     127                        SavePartialPES(tspacket->PID(), new PESPacket(*tspacket));
     128                    } else {
     129                        partial->SetPSIOffset(partial->PSIOffset() + psip->SectionLength());
     130                    }
     131                    return psip;
     132                }
     133            }
     134
     135            moreTablePackets = false;
     136            DeletePartialPES(tspacket->PID());
     137            return psip;
     138        }
     139        moreTablePackets = false;
     140        return 0; // partial packet is not yet complete.
     141    }
     142
    99143    if (tspacket->PayloadStart())
    100144    {
    101145        const int offset = tspacket->AFCOffset() +
    102146            tspacket->StartOfFieldPointer();
     147
    103148        if (offset>181)
    104149        {
    105150            VERBOSE(VB_IMPORTANT, "Error: offset>181, pes length & "
     
    111156        const PESPacket pes = PESPacket::View(*tspacket);
    112157        if ((pes_length + offset)>188)
    113158        {
    114             if (!bool(pes.pesdata()[6]&1)/*current*/)
    115                 return 0; // we only care about current psip packets for now
    116159            SavePartialPES(tspacket->PID(), new PESPacket(*tspacket));
     160            moreTablePackets = false;
    117161            return 0;
    118162        }
    119         return new PSIPTable(*tspacket); // must be complete packet
    120     }
    121163
    122     PESPacket* partial = GetPartialPES(tspacket->PID());
    123     if (partial)
    124     {
    125         if (partial->AddTSPacket(tspacket))
    126         {
    127             PSIPTable* psip = new PSIPTable(*partial);
    128             DeletePartialPES(tspacket->PID());
    129             return psip;
     164        PSIPTable *psip = new PSIPTable(*tspacket); // must be complete packet
     165
     166        /* There might be another section after this one in the current packet.
     167         * We need room before the end of the packet, and it must not be packet stuffing.
     168         */
     169        if (offset + psip->SectionLength() < 188) {
     170            if (pesdata[psip->SectionLength() + 1] != 0xff) {
     171                // This isn't sutffing, so we need to put this on as a partial packet
     172                PESPacket *pesp = new PESPacket(*tspacket);
     173                pesp->SetPSIOffset(offset + psip->SectionLength());
     174                SavePartialPES(tspacket->PID(), pesp);
     175                return psip;
     176            }
    130177        }
    131         return 0; // partial packet is not yet complete.
     178
     179        moreTablePackets = false;
     180        return psip;
    132181    }
     182
    133183    // We didn't see this PES packet's start, so this must be the
    134184    // tail end of something we missed. Ignore it.
     185    moreTablePackets = false;
    135186    return 0;
    136187}
    137188
     
    359410 */
    360411bool MPEGStreamData::HandleTSTables(const TSPacket* tspacket)
    361412{
    362 #define HT_RETURN(HANDLED) { delete psip; return HANDLED; }
    363413    // Assemble PSIP
    364     PSIPTable *psip = AssemblePSIP(tspacket);
    365     if (!psip)
    366         return true;
     414    bool morePSIPPackets = true;
     415    while (morePSIPPackets) {
     416        PSIPTable *psip = AssemblePSIP(tspacket, morePSIPPackets);
     417        if (!psip)
     418            return true;
    367419
    368     // Validate PSIP
    369     // but don't validate PMT if our driver has the PMT CRC bug.
    370     bool validate = !_have_pmt_CRC_bug || (TableID::PMT != psip->TableID());
    371     if (validate && !psip->IsGood())
    372     {
    373         VERBOSE(VB_RECORD, QString("PSIP packet failed CRC check. "
    374                                    "pid(0x%1) type(0x%2)")
    375                 .arg(tspacket->PID(),0,16).arg(psip->TableID(),0,16));
    376         HT_RETURN(true);
    377     }
     420        // Validate PSIP
     421        // but don't validate PMT if our driver has the PMT CRC bug.
     422        bool validate = !_have_pmt_CRC_bug || (TableID::PMT != psip->TableID());
     423        if (validate && !psip->IsGood())
     424        {
     425            VERBOSE(VB_RECORD, QString("PSIP packet failed CRC check. "
     426                        "pid(0x%1) type(0x%2)")
     427                    .arg(tspacket->PID(),0,16).arg(psip->TableID(),0,16));
     428            delete psip;
     429            continue;
     430        }
    378431
    379     if (!psip->IsCurrent()) // we don't cache the next table, for now
    380         HT_RETURN(true);
     432        if (!psip->IsCurrent()) { // we don't cache the next table, for now
     433            delete psip;
     434            continue;
     435        }
    381436
    382     if (1!=tspacket->AdaptationFieldControl())
    383     { // payload only, ATSC req.
    384         VERBOSE(VB_RECORD,
    385                 "PSIP packet has Adaptation Field Control, not ATSC compiant");
    386         HT_RETURN(true);
    387     }
     437        if (1!=tspacket->AdaptationFieldControl())
     438        { // payload only, ATSC req.
     439            VERBOSE(VB_RECORD,
     440                    "PSIP packet has Adaptation Field Control, not ATSC compiant");
     441            delete psip;
     442            continue;
     443        }
    388444
    389     if (tspacket->ScramplingControl())
    390     { // scrambled! ATSC, DVB require tables not to be scrambled
    391         VERBOSE(VB_RECORD,
    392                 "PSIP packet is scrambled, not ATSC/DVB compiant");
    393         HT_RETURN(true);
    394     }
     445        if (tspacket->ScramplingControl())
     446        { // scrambled! ATSC, DVB require tables not to be scrambled
     447            VERBOSE(VB_RECORD,
     448                    "PSIP packet is scrambled, not ATSC/DVB compiant");
     449            delete psip;
     450            continue;
     451        }
    395452
    396     // Don't decode redundant packets,
    397     // but if it is a desired PAT or PMT emit a "heartbeat" signal.
    398     if (IsRedundant(*psip))
    399     {
    400         if (TableID::PAT == psip->TableID())
    401             emit UpdatePATSingleProgram(PATSingleProgram());
    402         if (TableID::PMT == psip->TableID() &&
    403             tspacket->PID() == _pid_pmt_single_program)
    404             emit UpdatePMTSingleProgram(PMTSingleProgram());
    405         HT_RETURN(true); // already parsed this table, toss it.
    406     }
     453        // Don't decode redundant packets,
     454        // but if it is a desired PAT or PMT emit a "heartbeat" signal.
     455        if (IsRedundant(*psip))
     456        {
     457            if (TableID::PAT == psip->TableID())
     458                emit UpdatePATSingleProgram(PATSingleProgram());
     459            if (TableID::PMT == psip->TableID() &&
     460                    tspacket->PID() == _pid_pmt_single_program)
     461                emit UpdatePMTSingleProgram(PMTSingleProgram());
     462            delete psip; // already parsed this table, toss it.
     463            continue;
     464        }
    407465
    408     bool handled = HandleTables(tspacket->PID(), *psip);
    409     HT_RETURN(handled);
    410 #undef HT_RETURN
     466        HandleTables(tspacket->PID(), *psip);
     467        delete psip;
     468    };
     469    return true;
    411470}
    412471
    413472int MPEGStreamData::ProcessData(unsigned char *buffer, int len)
  • mpegstreamdata.h

     
    128128
    129129  protected:
    130130    // Table processing -- for internal use
    131     PSIPTable* AssemblePSIP(const TSPacket* tspacket);
     131    PSIPTable* AssemblePSIP(const TSPacket* tspacket, bool& moreTablePackets);
    132132    bool AssemblePSIP(PSIPTable& psip, TSPacket* tspacket);
    133133    void SavePartialPES(uint pid, PESPacket* packet);
    134134    PESPacket* GetPartialPES(uint pid)
  • pespacket.h

     
    3232        {
    3333            _pesdata = tspacket.data() + tspacket.AFCOffset() +
    3434                tspacket.StartOfFieldPointer();
     35            _PSIOffset = tspacket.AFCOffset() + tspacket.StartOfFieldPointer();
    3536        }
    3637        else
    3738        {
    3839            cerr<<"Started PESPacket, but !payloadStart()"<<endl;
    3940            _pesdata = tspacket.data() + tspacket.AFCOffset();
     41            _PSIOffset = tspacket.AFCOffset();
    4042        }
    4143
    4244        _badPacket = true;
     
    4951  protected:
    5052    // does not create it's own data
    5153    PESPacket(const TSPacket* tspacket, bool)
    52         : _pesdata(0), _fullbuffer(0), _allocSize(0)
     54        : _pesdata(0), _fullbuffer(0), _allocSize(0), _PSIOffset(0)
    5355    {
    5456        InitPESPacket(const_cast<TSPacket&>(*tspacket));
    5557        _fullbuffer = const_cast<unsigned char*>(tspacket->data());
     
    6466        _allocSize = pkt._allocSize;
    6567        _fullbuffer = new unsigned char[_allocSize+188];
    6668        memcpy(_fullbuffer, pkt._fullbuffer, _allocSize+188);
    67         _pesdata = _fullbuffer + (pkt._pesdata - pkt._fullbuffer);
     69        _PSIOffset = pkt._PSIOffset;
     70        _pesdata = _fullbuffer + _PSIOffset;
    6871        _ccLast = pkt._ccLast;
    6972        _cnt = pkt._cnt;
    7073        _badPacket = pkt._badPacket;
     
    7679        InitPESPacket(const_cast<TSPacket&>(tspacket));
    7780
    7881        int len = (4*1024) - 188;
    79         int offset = _pesdata - tspacket.data();
    80         _allocSize=((len+offset)/188)*188+188;
     82        _allocSize=((len+_PSIOffset)/188)*188+188;
    8183        _fullbuffer = new unsigned char[_allocSize+188];
    82         _pesdata = _fullbuffer + offset;
     84        _pesdata = _fullbuffer + _PSIOffset;
    8385        memcpy(_fullbuffer, tspacket.data(), 188);
    8486        _ccLast = tspacket.ContinuityCounter();
    8587        _cnt = 1;
     
    116118    unsigned int Length() const
    117119        { return (pesdata()[2] & 0x0f) << 8 | pesdata()[3]; }
    118120
     121    unsigned int TSSizeInBuffer() { return (_cnt*TSPacket::PAYLOAD_SIZE)+TSPacket::HEADER_SIZE; }
     122    unsigned int PSIOffset() const { return _PSIOffset; }
     123
    119124    const unsigned char* pesdata() const { return _pesdata; }
    120125    unsigned char* pesdata() { return _pesdata; }
    121126
     
    153158        _pesdata[Length()+3] = (crc & 0x000000ff);
    154159    }
    155160
     161    void SetPSIOffset(unsigned int offset) {
     162        _PSIOffset = offset;
     163        _pesdata = _fullbuffer + _PSIOffset;
     164    }
     165
    156166    bool VerifyCRC() const { return CalcCRC() == CRC(); }
    157167
    158168    /*
     
    177187    unsigned int _ccLast;
    178188    unsigned int _cnt;
    179189    unsigned int _allocSize;
     190    unsigned int _PSIOffset;
    180191    bool _badPacket;
    181192};
    182193