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<unsigned char> 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;
 }
 
