diff --git a/src/input/input_hls.cpp b/src/input/input_hls.cpp
index 1529d653..9f079e81 100644
--- a/src/input/input_hls.cpp
+++ b/src/input/input_hls.cpp
@@ -701,63 +701,61 @@ namespace Mist{
   }
 
   bool inputHLS::readExistingHeader(){
-    if (!Input::readExistingHeader()){return false;}
-    if (!M.inputLocalVars.isMember("version") || M.inputLocalVars["version"].asInt() < 2){
+    if (!Input::readExistingHeader()){
+      INFO_MSG("Could not read existing header, regenerating");
+      return false;
+    }
+    if (!M.inputLocalVars.isMember("version") || M.inputLocalVars["version"].asInt() < 3){
       INFO_MSG("Header needs update, regenerating");
       return false;
     }
-    // Vars for parsing TS packets
-    TS::Packet packet;
-    bool hasPacket;
-
-    // Set internal variables based on existing header file
-    tthread::lock_guard<tthread::mutex> guard(entryMutex);
-    for (std::map<uint32_t, std::deque<playListEntries> >::iterator pListIt = listEntries.begin();
-         pListIt != listEntries.end(); pListIt++){
-      tsStream.clear();
-      uint32_t entId = 0;
-      // For each entry in the playlist, we need to parse the earliest packet in order to set the segment offset
-      for (std::deque<playListEntries>::iterator entryIt = pListIt->second.begin();
-           entryIt != pListIt->second.end(); entryIt++){
-        tsStream.partialClear();
-
-        if (!segDowner.loadSegment(*entryIt)){
-          FAIL_MSG("Failed to load segment - skipping to next");
-          continue;
-        }
-        // Flag to allow getPacketTime to set the offset
-        entId++;
-        allowRemap = true;
-        while (!segDowner.atEnd()){
-          hasPacket = tsStream.hasPacketOnEachTrack() || (segDowner.atEnd() && tsStream.hasPacket());
-          if (hasPacket){
-            DTSC::Packet headerPack;
-            tsStream.getEarliestPacket(headerPack);
-            while (headerPack){
-              size_t tmpTrackId = headerPack.getTrackId();
-              // Call getPacketID in order to set pidmapping
-              uint64_t packetId = getPacketID(pListIt->first, tmpTrackId);
-              // Call getPacketTime in order to set segment offset
-              uint64_t packetTime = getPacketTime(headerPack.getTime(), tmpTrackId, pListIt->first, entryIt->mUTC);
-              VERYHIGH_MSG("Parsed earliest TS packet with id '%lu' @ '%lu ms' for TS segment with index '%u'", packetId, packetTime, entId - 1);
-              // Keep parsing until we have called getPacketID for each track
-              tsStream.getEarliestPacket(headerPack);
-            }
-          // If we do not have a packet on each track, read the next TS packet
-          }else if (segDowner.readNext()){
-            packet.FromPointer(segDowner.packetPtr);
-            tsStream.parse(packet, entId);
-          }
-        }
-        // Finally save the offset as part of the TS segment. This is required for bufferframe
-        // to work correctly, since not every segment might have an UTC timestamp tag
-        std::deque<playListEntries> &curList = listEntries[pListIt->first];
-        VERYHIGH_MSG("Saving offset of '%" PRId64 "' to current TS segment", plsTimeOffset[pListIt->first]);
-        curList.at(entId-1).timeOffset = plsTimeOffset[pListIt->first];
-      }
+    // Check if the DTSH file contains all expected data
+    if (!M.inputLocalVars.isMember("streamoffset")){
+      INFO_MSG("Header needs update as it contains no streamoffset, regenerating");
+      return false;
     }
-    tsStream.clear();
-    // set bootMsOffset in order to display the program time correctly in the player
+    if (!M.inputLocalVars.isMember("playlistEntries")){
+      INFO_MSG("Header needs update as it contains no playlist entries, regenerating");
+      return false;
+    }
+    if (!M.inputLocalVars.isMember("pidMappingR")){
+      INFO_MSG("Header needs update as it contains no packet id mappings, regenerating");
+      return false;
+    }
+    // Recover playlist entries
+    tthread::lock_guard<tthread::mutex> guard(entryMutex);
+    jsonForEachConst(M.inputLocalVars["playlistEntries"], i){
+      std::deque<playListEntries> newList;
+      jsonForEachConst(*i, j){
+        const JSON::Value & thisEntry = *j;
+        playListEntries newEntry;
+        newEntry.filename = thisEntry[0u].asString();
+        newEntry.bytePos = thisEntry[1u].asInt();
+        newEntry.mUTC = thisEntry[2u].asInt();
+        newEntry.duration = thisEntry[3u].asDouble();
+        newEntry.timestamp = thisEntry[4u].asInt();
+        newEntry.timeOffset = thisEntry[5u].asInt();
+        newEntry.wait = thisEntry[6u].asInt();
+        if (thisEntry[7u].asString().size() && thisEntry[8u].asString().size()){
+          memcpy(newEntry.ivec, thisEntry[7u].asString().data(), 16);
+          memcpy(newEntry.keyAES, thisEntry[8u].asString().data(), 16);
+        }else{
+          memset(newEntry.ivec, 0, 16);
+          memset(newEntry.keyAES, 0, 16);
+        }
+        newList.push_back(newEntry);
+      }
+      listEntries[JSON::Value(i.key()).asInt()] = newList;
+    }
+    // Recover pidMappings
+    jsonForEachConst(M.inputLocalVars["pidMappingR"], i){
+      uint64_t key = JSON::Value(i.key()).asInt();
+      uint64_t val = i->asInt();
+      pidMappingR[key] = val;
+      pidMapping[val] = key;
+    }
+    // Set bootMsOffset in order to display the program time correctly in the player
+    streamOffset = M.inputLocalVars["streamoffset"].asInt();
     if (meta.getLive()){meta.setUTCOffset(streamOffset + (Util::unixMS() - Util::bootMS()));}
     meta.setBootMsOffset(streamOffset);
     return true;
@@ -765,6 +763,7 @@ namespace Mist{
 
   bool inputHLS::readHeader(){
     if (streamIsLive && !isLiveDVR){return true;}
+    if (readExistingHeader()){return true;}
     // to analyse and extract data
     TS::Packet packet; 
     char *data;
@@ -843,8 +842,13 @@ namespace Mist{
         }
         // Finally save the offset as part of the TS segment. This is required for bufferframe
         // to work correctly, since not every segment might have an UTC timestamp tag
-        std::deque<playListEntries> &curList = listEntries[pListIt->first];
-        curList.at(entId-1).timeOffset = plsTimeOffset[pListIt->first];
+        if (plsTimeOffset.count(pListIt->first)){
+          std::deque<playListEntries> &curList = listEntries[pListIt->first];
+          curList.at(entId-1).timeOffset = plsTimeOffset[pListIt->first];
+        }else{
+          std::deque<playListEntries> &curList = listEntries[pListIt->first];
+          curList.at(entId-1).timeOffset = 0;
+        }
       }
     }
 
@@ -854,7 +858,39 @@ namespace Mist{
     if (streamIsLive || isLiveDVR){return true;}
 
     // Set local vars used for parsing existing headers
-    meta.inputLocalVars["version"] = 2;
+    meta.inputLocalVars["version"] = 3;
+
+    // Write playlist entry info
+    JSON::Value allEntries;
+    for (std::map<uint32_t, std::deque<playListEntries> >::iterator pListIt = listEntries.begin();
+         pListIt != listEntries.end(); pListIt++){
+      JSON::Value thisPlaylist;
+      for (std::deque<playListEntries>::iterator entryIt = pListIt->second.begin();
+         entryIt != pListIt->second.end(); entryIt++){
+        JSON::Value thisEntries;
+        thisEntries.append(entryIt->filename);
+        thisEntries.append(entryIt->bytePos);
+        thisEntries.append(entryIt->mUTC);
+        thisEntries.append(entryIt->duration);
+        thisEntries.append(entryIt->timestamp);
+        thisEntries.append(entryIt->timeOffset);
+        thisEntries.append(entryIt->wait);
+        thisEntries.append(entryIt->ivec);
+        thisEntries.append(entryIt->keyAES);
+        thisPlaylist.append(thisEntries);
+      }
+      allEntries[JSON::Value(pListIt->first).asString()] = thisPlaylist;
+    }
+    meta.inputLocalVars["playlistEntries"] = allEntries;
+    meta.inputLocalVars["streamoffset"] = streamOffset;
+
+    // Write packet ID mappings
+    JSON::Value thisMappingsR;
+    for (std::map<size_t, uint64_t>::iterator pidIt = pidMappingR.begin();
+         pidIt != pidMappingR.end(); pidIt++){
+      thisMappingsR[JSON::Value(pidIt->first).asString()] = pidIt->second;
+    }
+    meta.inputLocalVars["pidMappingR"] = thisMappingsR;
 
     INFO_MSG("write header file...");
     M.toFile((config->getString("input") + ".dtsh").c_str());
diff --git a/src/input/input_hls.h b/src/input/input_hls.h
index 5dc89080..59f4d817 100644
--- a/src/input/input_hls.h
+++ b/src/input/input_hls.h
@@ -32,6 +32,18 @@ namespace Mist{
     uint64_t wait;
     char ivec[16];
     char keyAES[16];
+    playListEntries(){
+      bytePos = 0;
+      mUTC = 0;
+      duration = 0;
+      timestamp = 0;
+      timeOffset = 0;
+      wait = 0;
+      for (size_t i = 0; i < 16; ++i){
+        ivec[i] = 0;
+        keyAES[i] = 0;
+      }
+    }
   };
 
   /// Keeps the segment entry list by playlist ID