Fix refreshing from DTSH in HLS input
Co-authored-by: Thulinma <jaron@vietors.com>
This commit is contained in:
parent
55589e4aa9
commit
7792845238
2 changed files with 104 additions and 56 deletions
|
@ -701,63 +701,61 @@ namespace Mist{
|
||||||
}
|
}
|
||||||
|
|
||||||
bool inputHLS::readExistingHeader(){
|
bool inputHLS::readExistingHeader(){
|
||||||
if (!Input::readExistingHeader()){return false;}
|
if (!Input::readExistingHeader()){
|
||||||
if (!M.inputLocalVars.isMember("version") || M.inputLocalVars["version"].asInt() < 2){
|
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");
|
INFO_MSG("Header needs update, regenerating");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// Vars for parsing TS packets
|
// Check if the DTSH file contains all expected data
|
||||||
TS::Packet packet;
|
if (!M.inputLocalVars.isMember("streamoffset")){
|
||||||
bool hasPacket;
|
INFO_MSG("Header needs update as it contains no streamoffset, regenerating");
|
||||||
|
return false;
|
||||||
// Set internal variables based on existing header file
|
}
|
||||||
|
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);
|
tthread::lock_guard<tthread::mutex> guard(entryMutex);
|
||||||
for (std::map<uint32_t, std::deque<playListEntries> >::iterator pListIt = listEntries.begin();
|
jsonForEachConst(M.inputLocalVars["playlistEntries"], i){
|
||||||
pListIt != listEntries.end(); pListIt++){
|
std::deque<playListEntries> newList;
|
||||||
tsStream.clear();
|
jsonForEachConst(*i, j){
|
||||||
uint32_t entId = 0;
|
const JSON::Value & thisEntry = *j;
|
||||||
// For each entry in the playlist, we need to parse the earliest packet in order to set the segment offset
|
playListEntries newEntry;
|
||||||
for (std::deque<playListEntries>::iterator entryIt = pListIt->second.begin();
|
newEntry.filename = thisEntry[0u].asString();
|
||||||
entryIt != pListIt->second.end(); entryIt++){
|
newEntry.bytePos = thisEntry[1u].asInt();
|
||||||
tsStream.partialClear();
|
newEntry.mUTC = thisEntry[2u].asInt();
|
||||||
|
newEntry.duration = thisEntry[3u].asDouble();
|
||||||
if (!segDowner.loadSegment(*entryIt)){
|
newEntry.timestamp = thisEntry[4u].asInt();
|
||||||
FAIL_MSG("Failed to load segment - skipping to next");
|
newEntry.timeOffset = thisEntry[5u].asInt();
|
||||||
continue;
|
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);
|
||||||
}
|
}
|
||||||
// Flag to allow getPacketTime to set the offset
|
newList.push_back(newEntry);
|
||||||
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
|
listEntries[JSON::Value(i.key()).asInt()] = newList;
|
||||||
}else if (segDowner.readNext()){
|
|
||||||
packet.FromPointer(segDowner.packetPtr);
|
|
||||||
tsStream.parse(packet, entId);
|
|
||||||
}
|
}
|
||||||
|
// 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;
|
||||||
}
|
}
|
||||||
// Finally save the offset as part of the TS segment. This is required for bufferframe
|
// Set bootMsOffset in order to display the program time correctly in the player
|
||||||
// to work correctly, since not every segment might have an UTC timestamp tag
|
streamOffset = M.inputLocalVars["streamoffset"].asInt();
|
||||||
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];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
tsStream.clear();
|
|
||||||
// set bootMsOffset in order to display the program time correctly in the player
|
|
||||||
if (meta.getLive()){meta.setUTCOffset(streamOffset + (Util::unixMS() - Util::bootMS()));}
|
if (meta.getLive()){meta.setUTCOffset(streamOffset + (Util::unixMS() - Util::bootMS()));}
|
||||||
meta.setBootMsOffset(streamOffset);
|
meta.setBootMsOffset(streamOffset);
|
||||||
return true;
|
return true;
|
||||||
|
@ -765,6 +763,7 @@ namespace Mist{
|
||||||
|
|
||||||
bool inputHLS::readHeader(){
|
bool inputHLS::readHeader(){
|
||||||
if (streamIsLive && !isLiveDVR){return true;}
|
if (streamIsLive && !isLiveDVR){return true;}
|
||||||
|
if (readExistingHeader()){return true;}
|
||||||
// to analyse and extract data
|
// to analyse and extract data
|
||||||
TS::Packet packet;
|
TS::Packet packet;
|
||||||
char *data;
|
char *data;
|
||||||
|
@ -843,8 +842,13 @@ namespace Mist{
|
||||||
}
|
}
|
||||||
// Finally save the offset as part of the TS segment. This is required for bufferframe
|
// 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
|
// to work correctly, since not every segment might have an UTC timestamp tag
|
||||||
|
if (plsTimeOffset.count(pListIt->first)){
|
||||||
std::deque<playListEntries> &curList = listEntries[pListIt->first];
|
std::deque<playListEntries> &curList = listEntries[pListIt->first];
|
||||||
curList.at(entId-1).timeOffset = plsTimeOffset[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;}
|
if (streamIsLive || isLiveDVR){return true;}
|
||||||
|
|
||||||
// Set local vars used for parsing existing headers
|
// 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...");
|
INFO_MSG("write header file...");
|
||||||
M.toFile((config->getString("input") + ".dtsh").c_str());
|
M.toFile((config->getString("input") + ".dtsh").c_str());
|
||||||
|
|
|
@ -32,6 +32,18 @@ namespace Mist{
|
||||||
uint64_t wait;
|
uint64_t wait;
|
||||||
char ivec[16];
|
char ivec[16];
|
||||||
char keyAES[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
|
/// Keeps the segment entry list by playlist ID
|
||||||
|
|
Loading…
Add table
Reference in a new issue