Index: libs/libmythtv/avformatdecoder.cpp =================================================================== --- libs/libmythtv/avformatdecoder.cpp (revision 11558) +++ libs/libmythtv/avformatdecoder.cpp (working copy) @@ -1251,6 +1251,64 @@ } } +/** \fn AvFormatDecoder::ScanDSMCCStreams(void) + * \brief Check to see whether there is a Network Boot Ifo sub-descriptor in the PMT which + * requires the MHEG application to reboot. + */ +void AvFormatDecoder::ScanDSMCCStreams(void) +{ + if (!ic->cur_pmt_sect) + return; + + if (!itv && ! (itv = GetNVP()->GetInteractiveTV())) + return; + + const PESPacket pes = PESPacket::ViewData(ic->cur_pmt_sect); + const PSIPTable psip(pes); + const ProgramMapTable pmt(psip); + + for (uint i = 0; i < pmt.StreamCount(); i++) + { + if (! StreamID::IsObjectCarousel(pmt.StreamType(i))) + continue; + + const desc_list_t desc_list = MPEGDescriptor::ParseOnlyInclude( + pmt.StreamInfo(i), pmt.StreamInfoLength(i), + DescriptorID::data_broadcast_id); + + for (uint j = 0; j < desc_list.size(); j++) + { + const unsigned char *desc = desc_list[j]; + desc++; // Skip tag + uint length = *desc++; + const unsigned char *endDesc = desc+length; + uint dataBroadcastId = desc[0]<<8 | desc[1]; + if (dataBroadcastId != 0x0106) // ETSI/UK Profile + continue; + desc += 2; // Skip data ID + while (desc != endDesc) + { + uint appTypeCode = desc[0]<<8 | desc[1]; + desc += 3; // Skip app type code and boot priority hint + uint appSpecDataLen = *desc++; + if (appTypeCode == 0x101) // UK MHEG profile + { + const unsigned char *subDescEnd = desc + appSpecDataLen; + while (desc < subDescEnd) + { + uint sub_desc_tag = *desc++; + uint sub_desc_len = *desc++; + if (sub_desc_tag == 1) // Network boot info sub-descriptor. + itv->SetNetBootInfo(desc, sub_desc_len); + desc += sub_desc_len; + } + } + else desc += appSpecDataLen; + } + } + } +} + int AvFormatDecoder::ScanStreams(bool novideo) { int scanerror = 0; @@ -1562,6 +1620,8 @@ if (GetNVP()->IsErrored()) scanerror = -1; + ScanDSMCCStreams(); + return scanerror; } Index: libs/libmythtv/dsmccobjcarousel.cpp =================================================================== --- libs/libmythtv/dsmccobjcarousel.cpp (revision 11558) +++ libs/libmythtv/dsmccobjcarousel.cpp (working copy) @@ -150,20 +150,26 @@ VERBOSE(VB_DSMCC, QString("[dsmcc] Already Know " "Module %1") .arg(info->module_id)); - - return; + if (cachep->ModuleSize() == info->module_size) + return; + // It seems that when ITV4 starts broadcasting it + // updates the contents of a file but doesn't + // update the version. This is a work-around. + VERBOSE(VB_DSMCC, QString("[dsmcc] Module %1 size " + "has changed (%2 to %3) " + "but version has not!!") + .arg(info->module_id) + .arg(info->module_size) + .arg(cachep->DataSize())); } - else - { - // Version has change - Drop old data. - VERBOSE(VB_DSMCC, QString("[dsmcc] Updated " - "Module %1") - .arg(info->module_id)); + // Version has changed - Drop old data. + VERBOSE(VB_DSMCC, QString("[dsmcc] Updated " + "Module %1") + .arg(info->module_id)); - // Remove and delete the cache object. - m_Cache.remove(); - break; - } + // Remove and delete the cache object. + m_Cache.remove(); + break; } } Index: libs/libmythtv/interactivetv.cpp =================================================================== --- libs/libmythtv/interactivetv.cpp (revision 11558) +++ libs/libmythtv/interactivetv.cpp (working copy) @@ -75,3 +75,8 @@ { m_context->GetInitialStreams(audioTag, videoTag); } + +void InteractiveTV::SetNetBootInfo(const unsigned char *data, uint length) +{ + m_context->SetNetBootInfo(data, length); +} Index: libs/libmythtv/dsmccobjcarousel.h =================================================================== --- libs/libmythtv/dsmccobjcarousel.h (revision 11558) +++ libs/libmythtv/dsmccobjcarousel.h (working copy) @@ -35,6 +35,7 @@ unsigned short ModuleId(void) const { return m_module_id; } unsigned short StreamId(void) const { return m_stream_id; } unsigned char Version(void) const { return m_version; } + unsigned long ModuleSize(void) const { return m_moduleSize; } /// Return the, possibly uncompressed, module size unsigned long DataSize(void) const Index: libs/libmythtv/mhi.h =================================================================== --- libs/libmythtv/mhi.h (revision 11558) +++ libs/libmythtv/mhi.h (working copy) @@ -44,6 +44,8 @@ void QueueDSMCCPacket(unsigned char *data, int length, int componentTag, unsigned carouselId, int dataBroadcastId); + // A NetworkBootInfo sub-descriptor is present in the PMT. + void SetNetBootInfo(const unsigned char *data, uint length); /// Restart the MHEG engine. void Restart(uint chanid, uint cardid, bool isLive); // Offer a key press. Returns true if it accepts it. @@ -133,6 +135,7 @@ static void *StartMHEGEngine(void *param); void RunMHEGEngine(void); void ProcessDSMCCQueue(void); + void NetworkBootRequested(void); InteractiveTV *m_parent; @@ -169,6 +172,9 @@ int m_audioTag; int m_videoTag; int m_tuningTo; + + uint m_lastNbiVersion; + QMemArray m_nbiData; }; // Object for drawing text. Index: libs/libmythtv/interactivetv.h =================================================================== --- libs/libmythtv/interactivetv.h (revision 11558) +++ libs/libmythtv/interactivetv.h (working copy) @@ -21,6 +21,9 @@ int componentTag, unsigned carouselId, int dataBroadcastId); + // A NetworkBootInfo sub-descriptor is present in the PMT + void SetNetBootInfo(const unsigned char *data, uint length); + // See if the image has changed. bool ImageHasChanged(void); // Draw the (updated) image. Index: libs/libmythtv/avformatdecoder.h =================================================================== --- libs/libmythtv/avformatdecoder.h (revision 11558) +++ libs/libmythtv/avformatdecoder.h (working copy) @@ -147,6 +147,7 @@ void ScanATSCCaptionStreams(int av_stream_index); void ScanTeletextCaptions(int av_stream_index); + void ScanDSMCCStreams(void); int AutoSelectAudioTrack(void); private: Index: libs/libmythtv/mhi.cpp =================================================================== --- libs/libmythtv/mhi.cpp (revision 11558) +++ libs/libmythtv/mhi.cpp (working copy) @@ -21,6 +21,10 @@ int m_y; }; +// Special values for the NetworkBootInfo version. Real values are a byte. +#define NBI_VERSION_UNSET 257 +#define NBI_VERSION_ABSENT 256 + MHIContext::MHIContext(InteractiveTV *parent) : m_parent(parent), m_dsmcc(NULL), m_engine(NULL), m_stop(false), @@ -29,7 +33,7 @@ m_face_loaded(false), m_currentChannel(-1), m_isLive(false), m_currentCard(0), m_audioTag(-1), m_videoTag(-1), - m_tuningTo(-1) + m_tuningTo(-1), m_lastNbiVersion(NBI_VERSION_UNSET) { m_display.setAutoDelete(true); m_dsmccQueue.setAutoDelete(true); @@ -146,6 +150,8 @@ m_updated = true; m_stop = false; m_isLive = isLive; + // Don't set the NBI version here. Restart is called + // after the PMT is processed. m_stopped = pthread_create(&m_engineThread, NULL, StartMHEGEngine, this) != 0; m_audioTag = -1; @@ -173,6 +179,7 @@ int key = 0; do { + (void)NetworkBootRequested(); ProcessDSMCCQueue(); { QMutexLocker locker(&m_keyLock); @@ -242,6 +249,40 @@ m_engine_wait.wakeAll(); } +// A NetworkBootInfo sub-descriptor is present in the PMT. +void MHIContext::SetNetBootInfo(const unsigned char *data, uint length) +{ + if (length < 2) return; + QMutexLocker locker(&m_dsmccLock); + // Save the data from the descriptor. + m_nbiData.duplicate(data, length); + // If there is no Network Boot Info or we're setting it + // for the first time just update the "last version". + if (length < 2) + m_lastNbiVersion = NBI_VERSION_ABSENT; + else if (m_lastNbiVersion == NBI_VERSION_UNSET) + m_lastNbiVersion = data[0]; + else + m_engine_wait.wakeAll(); +} + +void MHIContext::NetworkBootRequested(void) +{ + QMutexLocker locker(&m_dsmccLock); + if (m_nbiData.size() >= 2 && m_nbiData[0] != m_lastNbiVersion) + { + m_lastNbiVersion = m_nbiData[0]; // Update the saved version + if (m_nbiData[1] == 1) + { + m_dsmcc->Reset(); + m_engine->SetBooting(); + m_display.clear(); + m_updated = true; + } + // TODO: else if it is 2 generate an EngineEvent. + } +} + // Called by the engine to check for the presence of an object in the carousel. bool MHIContext::CheckCarouselObject(QString objectPath) { @@ -549,7 +590,10 @@ // Post an event requesting a channel change. MythEvent me(QString("NETWORK_CONTROL CHANID %1").arg(channel)); gContext->dispatch(me); - + // Reset the NBI version here to prevent a reboot. + QMutexLocker locker(&m_dsmccLock); + m_lastNbiVersion = NBI_VERSION_UNSET; + m_nbiData.resize(0); return true; }