CMAF debug session 2021-02-04
This commit is contained in:
parent
4a3204cb1e
commit
5a40225046
5 changed files with 36 additions and 32 deletions
|
@ -170,6 +170,7 @@ static inline void show_stackframe(){}
|
||||||
|
|
||||||
#define DEFAULT_FRAGMENT_DURATION 1900
|
#define DEFAULT_FRAGMENT_DURATION 1900
|
||||||
|
|
||||||
|
/// \TODO These values are hardcoded and that is dangerous and probably a very bad idea. I don't even know if they are currently correct...?! I doubt they are.
|
||||||
#define META_META_OFFSET 104
|
#define META_META_OFFSET 104
|
||||||
#define META_META_RECORDSIZE 576
|
#define META_META_RECORDSIZE 576
|
||||||
|
|
||||||
|
|
|
@ -1723,12 +1723,12 @@ namespace DTSC{
|
||||||
t.track.addField("channels", RAX_16UINT);
|
t.track.addField("channels", RAX_16UINT);
|
||||||
t.track.addField("width", RAX_32UINT);
|
t.track.addField("width", RAX_32UINT);
|
||||||
t.track.addField("height", RAX_32UINT);
|
t.track.addField("height", RAX_32UINT);
|
||||||
|
t.track.addField("fpks", RAX_16UINT);
|
||||||
|
t.track.addField("missedFrags", RAX_32UINT);
|
||||||
t.track.addField("parts", RAX_NESTED, TRACK_PART_OFFSET + (TRACK_PART_RECORDSIZE * partCount));
|
t.track.addField("parts", RAX_NESTED, TRACK_PART_OFFSET + (TRACK_PART_RECORDSIZE * partCount));
|
||||||
t.track.addField("keys", RAX_NESTED, TRACK_KEY_OFFSET + (TRACK_KEY_RECORDSIZE * keyCount));
|
t.track.addField("keys", RAX_NESTED, TRACK_KEY_OFFSET + (TRACK_KEY_RECORDSIZE * keyCount));
|
||||||
t.track.addField("fragments", RAX_NESTED, TRACK_FRAGMENT_OFFSET + (TRACK_FRAGMENT_RECORDSIZE * fragCount));
|
t.track.addField("fragments", RAX_NESTED, TRACK_FRAGMENT_OFFSET + (TRACK_FRAGMENT_RECORDSIZE * fragCount));
|
||||||
t.track.addField("pages", RAX_NESTED, TRACK_PAGE_OFFSET + (TRACK_PAGE_RECORDSIZE * pageCount));
|
t.track.addField("pages", RAX_NESTED, TRACK_PAGE_OFFSET + (TRACK_PAGE_RECORDSIZE * pageCount));
|
||||||
t.track.addField("fpks", RAX_16UINT);
|
|
||||||
t.track.addField("missedFrags", RAX_32UINT);
|
|
||||||
|
|
||||||
t.track.setRCount(1);
|
t.track.setRCount(1);
|
||||||
t.track.addRecords(1);
|
t.track.addRecords(1);
|
||||||
|
|
|
@ -737,8 +737,6 @@ namespace Mist{
|
||||||
HIGH_MSG("Seeking to track %zu key %zu => time %" PRIu64, tid, keyNum, pos);
|
HIGH_MSG("Seeking to track %zu key %zu => time %" PRIu64, tid, keyNum, pos);
|
||||||
if (actualKeyTime > pos){
|
if (actualKeyTime > pos){
|
||||||
if (M.getLive()){
|
if (M.getLive()){
|
||||||
WARN_MSG("Actually seeking to %" PRIu64 ", for %" PRIu64 " is not available any more",
|
|
||||||
actualKeyTime, pos);
|
|
||||||
pos = actualKeyTime;
|
pos = actualKeyTime;
|
||||||
userSelect[tid].setKeyNum(keyNum);
|
userSelect[tid].setKeyNum(keyNum);
|
||||||
}
|
}
|
||||||
|
@ -784,7 +782,7 @@ namespace Mist{
|
||||||
stats();
|
stats();
|
||||||
}
|
}
|
||||||
if (curPage[tid].mapped[tmp.offset]){return seek(tid, pos, getNextKey);}
|
if (curPage[tid].mapped[tmp.offset]){return seek(tid, pos, getNextKey);}
|
||||||
FAIL_MSG("Track %zu no data (key %zu@%" PRIu64 ") - timeout", tid, keyNum + (getNextKey ? 1 : 0), tmp.offset);
|
FAIL_MSG("Track %zu no data (key %zu@%" PRIu64 ", page %s, time %" PRIu64 " -> %" PRIu64 ", next=%" PRIu64 ") - timeout", tid, keyNum + (getNextKey ? 1 : 0), tmp.offset, curPage[tid].name.c_str(), pos, actualKeyTime, keys.getTime(keyNum+1));
|
||||||
userSelect.erase(tid);
|
userSelect.erase(tid);
|
||||||
firstTime = Util::bootMS() - (buffer.begin()->time * realTime / 1000);
|
firstTime = Util::bootMS() - (buffer.begin()->time * realTime / 1000);
|
||||||
return false;
|
return false;
|
||||||
|
@ -1249,7 +1247,7 @@ namespace Mist{
|
||||||
uint32_t sleepTime = std::min(20ul, needsLookAhead);
|
uint32_t sleepTime = std::min(20ul, needsLookAhead);
|
||||||
// wait at most double the look ahead time, plus ten seconds
|
// wait at most double the look ahead time, plus ten seconds
|
||||||
uint64_t timeoutTries = (needsLookAhead / sleepTime) * 2 + (10000 / sleepTime);
|
uint64_t timeoutTries = (needsLookAhead / sleepTime) * 2 + (10000 / sleepTime);
|
||||||
uint64_t needsTime = thisPacket.getTime() + needsLookAhead;
|
uint64_t needsTime = thisTime + needsLookAhead;
|
||||||
bool firstTime = true;
|
bool firstTime = true;
|
||||||
while (--timeoutTries && keepGoing()){
|
while (--timeoutTries && keepGoing()){
|
||||||
bool lookReady = true;
|
bool lookReady = true;
|
||||||
|
@ -1273,9 +1271,10 @@ namespace Mist{
|
||||||
//Make sure we stay responsive to requests and stats while waiting
|
//Make sure we stay responsive to requests and stats while waiting
|
||||||
if (wantRequest){requestHandler();}
|
if (wantRequest){requestHandler();}
|
||||||
stats();
|
stats();
|
||||||
|
meta.reloadReplacedPagesIfNeeded();
|
||||||
}
|
}
|
||||||
if (!timeoutTries){
|
if (!timeoutTries){
|
||||||
WARN_MSG("Waiting for lookahead timed out - resetting lookahead!");
|
WARN_MSG("Waiting for lookahead (%zums in %zu tracks) timed out - resetting lookahead!", needsLookAhead, userSelect.size());
|
||||||
needsLookAhead = 0;
|
needsLookAhead = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -65,6 +65,7 @@ namespace Mist{
|
||||||
|
|
||||||
OutCMAF::OutCMAF(Socket::Connection &conn) : HTTPOutput(conn){
|
OutCMAF::OutCMAF(Socket::Connection &conn) : HTTPOutput(conn){
|
||||||
uaDelay = 0;
|
uaDelay = 0;
|
||||||
|
realTime = 0;
|
||||||
if (config->getString("target").size()){
|
if (config->getString("target").size()){
|
||||||
needsLookAhead = 5000;
|
needsLookAhead = 5000;
|
||||||
|
|
||||||
|
@ -78,10 +79,7 @@ namespace Mist{
|
||||||
initialize();
|
initialize();
|
||||||
initialSeek();
|
initialSeek();
|
||||||
startPushOut();
|
startPushOut();
|
||||||
} else {
|
|
||||||
realTime = 0;
|
|
||||||
}
|
}
|
||||||
INFO_MSG("Out of constructor now");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//Properly end all tracks on shutdown.
|
//Properly end all tracks on shutdown.
|
||||||
|
@ -802,18 +800,19 @@ namespace Mist{
|
||||||
/// Function that waits at most `maxWait` ms (in steps of 100ms) for the next keyframe to become available.
|
/// Function that waits at most `maxWait` ms (in steps of 100ms) for the next keyframe to become available.
|
||||||
/// Uses thisIdx and thisPacket to determine track and current timestamp respectively.
|
/// Uses thisIdx and thisPacket to determine track and current timestamp respectively.
|
||||||
bool OutCMAF::waitForNextKey(uint64_t maxWait){
|
bool OutCMAF::waitForNextKey(uint64_t maxWait){
|
||||||
size_t currentKey = M.getKeyIndexForTime(getMainSelectedTrack(), thisPacket.getTime());
|
uint64_t mTrk = getMainSelectedTrack();
|
||||||
DTSC::Keys keys(M.keys(getMainSelectedTrack()));
|
size_t currentKey = M.getKeyIndexForTime(mTrk, thisTime);
|
||||||
size_t waitTimes = maxWait / 100;
|
uint64_t startTime = Util::bootMS();
|
||||||
for (size_t i = 0; i < waitTimes; ++i){
|
DTSC::Keys keys(M.keys(mTrk));
|
||||||
if (keys.getEndValid() > currentKey + 1 && M.getLastms(thisIdx) > M.getTimeForKeyIndex(getMainSelectedTrack(), currentKey+1)){
|
while (startTime + maxWait > Util::bootMS() && keepGoing()){
|
||||||
|
if (keys.getEndValid() > currentKey + 1 && M.getLastms(thisIdx) >= M.getTimeForKeyIndex(mTrk, currentKey+1)){
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
Util::wait(100);
|
Util::sleep(20);
|
||||||
//Make sure we don't accidentally timeout while waiting - runs approximately every second.
|
meta.reloadReplacedPagesIfNeeded();
|
||||||
if (i % 10 == 0){stats();}
|
|
||||||
}
|
}
|
||||||
return (keys.getEndValid() > currentKey + 1 && M.getLastms(thisIdx) > M.getTimeForKeyIndex(getMainSelectedTrack(), currentKey+1));
|
INFO_MSG("Timed out waiting for next key (track %" PRIu64 ", %zu+1, last is %zu, time is %" PRIu64 ")", mTrk, currentKey, keys.getEndValid()-1, M.getTimeForKeyIndex(getMainSelectedTrack(), currentKey+1));
|
||||||
|
return (keys.getEndValid() > currentKey + 1 && M.getLastms(thisIdx) >= M.getTimeForKeyIndex(mTrk, currentKey+1));
|
||||||
}
|
}
|
||||||
|
|
||||||
//Set up an empty connection to the target to make sure we can push data towards it.
|
//Set up an empty connection to the target to make sure we can push data towards it.
|
||||||
|
@ -827,14 +826,15 @@ namespace Mist{
|
||||||
|
|
||||||
//CMAF Push output uses keyframe boundaries instead of fragment boundaries, to allow for lower latency
|
//CMAF Push output uses keyframe boundaries instead of fragment boundaries, to allow for lower latency
|
||||||
void OutCMAF::pushNext() {
|
void OutCMAF::pushNext() {
|
||||||
|
size_t mTrk = getMainSelectedTrack();
|
||||||
//Set up a new connection if this is a new track, or if we have been disconnected.
|
//Set up a new connection if this is a new track, or if we have been disconnected.
|
||||||
if (!pushTracks.count(thisIdx) || !pushTracks.at(thisIdx).D.getSocket()){
|
if (!pushTracks.count(thisIdx) || !pushTracks.at(thisIdx).D.getSocket()){
|
||||||
if (pushTracks.count(thisIdx)){INFO_MSG("Reconnecting existing track: socket was disconnected");}
|
if (pushTracks.count(thisIdx)){INFO_MSG("Reconnecting existing track: socket was disconnected");}
|
||||||
CMAFPushTrack & track = pushTracks[thisIdx];
|
CMAFPushTrack & track = pushTracks[thisIdx];
|
||||||
size_t keyIndex = M.getKeyIndexForTime(getMainSelectedTrack(), thisPacket.getTime());
|
size_t keyIndex = M.getKeyIndexForTime(mTrk, thisPacket.getTime());
|
||||||
track.headerFrom = M.getTimeForKeyIndex(getMainSelectedTrack(), keyIndex);
|
track.headerFrom = M.getTimeForKeyIndex(mTrk, keyIndex);
|
||||||
if (track.headerFrom < thisPacket.getTime()){
|
if (track.headerFrom < thisPacket.getTime()){
|
||||||
track.headerFrom = M.getTimeForKeyIndex(getMainSelectedTrack(), keyIndex + 1);
|
track.headerFrom = M.getTimeForKeyIndex(mTrk, keyIndex + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
INFO_MSG("Starting track %zu at %" PRIu64 "ms into the stream, current packet at %" PRIu64 "ms", thisIdx, track.headerFrom, thisPacket.getTime());
|
INFO_MSG("Starting track %zu at %" PRIu64 "ms into the stream, current packet at %" PRIu64 "ms", thisIdx, track.headerFrom, thisPacket.getTime());
|
||||||
|
@ -846,14 +846,18 @@ namespace Mist{
|
||||||
CMAFPushTrack & track = pushTracks[thisIdx];
|
CMAFPushTrack & track = pushTracks[thisIdx];
|
||||||
if (thisPacket.getTime() < track.headerFrom){return;}
|
if (thisPacket.getTime() < track.headerFrom){return;}
|
||||||
if (thisPacket.getTime() >= track.headerUntil){
|
if (thisPacket.getTime() >= track.headerUntil){
|
||||||
size_t keyIndex = M.getKeyIndexForTime(getMainSelectedTrack(), thisPacket.getTime());
|
size_t keyIndex = M.getKeyIndexForTime(mTrk, thisTime);
|
||||||
uint64_t keyTime = M.getTimeForKeyIndex(getMainSelectedTrack(), keyIndex);
|
uint64_t keyTime = M.getTimeForKeyIndex(mTrk, keyIndex);
|
||||||
if (keyTime > thisPacket.getTime()){
|
if (keyTime > thisTime){
|
||||||
WARN_MSG("Corruption probably occurred, initiating reconnect %" PRIu64 " != %" PRIu64, keyTime, thisPacket.getTime());
|
realTime = 1000;
|
||||||
onTrackEnd(thisIdx);
|
if (!liveSeek()){
|
||||||
track.headerFrom = M.getTimeForKeyIndex(getMainSelectedTrack(), keyIndex + 1);
|
WARN_MSG("Corruption probably occurred, initiating reconnect. Key %zu is time %" PRIu64 ", but packet is time %" PRIu64, keyIndex, keyTime, thisTime);
|
||||||
track.headerUntil = 0;
|
onTrackEnd(thisIdx);
|
||||||
pushNext();
|
track.headerFrom = M.getTimeForKeyIndex(mTrk, keyIndex + 1);
|
||||||
|
track.headerUntil = 0;
|
||||||
|
pushNext();
|
||||||
|
}
|
||||||
|
realTime = 0;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
track.headerFrom = keyTime;
|
track.headerFrom = keyTime;
|
||||||
|
@ -862,7 +866,7 @@ namespace Mist{
|
||||||
dropTrack(thisIdx, "No next keyframe available");
|
dropTrack(thisIdx, "No next keyframe available");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
track.headerUntil = M.getTimeForKeyIndex(getMainSelectedTrack(), keyIndex + 1);
|
track.headerUntil = M.getTimeForKeyIndex(mTrk, keyIndex + 1);
|
||||||
std::string keyHeader = CMAF::keyHeader(M, thisIdx, track.headerFrom, track.headerUntil, keyIndex+1, true, true);
|
std::string keyHeader = CMAF::keyHeader(M, thisIdx, track.headerFrom, track.headerUntil, keyIndex+1, true, true);
|
||||||
uint64_t mdatSize = 8 + CMAF::payloadSize(M, thisIdx, track.headerFrom, track.headerUntil);
|
uint64_t mdatSize = 8 + CMAF::payloadSize(M, thisIdx, track.headerFrom, track.headerUntil);
|
||||||
char mdatHeader[] ={0x00, 0x00, 0x00, 0x00, 'm', 'd', 'a', 't'};
|
char mdatHeader[] ={0x00, 0x00, 0x00, 0x00, 'm', 'd', 'a', 't'};
|
||||||
|
|
|
@ -69,7 +69,7 @@ namespace Mist{
|
||||||
HTTP::URL pushUrl;
|
HTTP::URL pushUrl;
|
||||||
std::map<size_t, CMAFPushTrack> pushTracks;
|
std::map<size_t, CMAFPushTrack> pushTracks;
|
||||||
void setupTrackObject(size_t idx);
|
void setupTrackObject(size_t idx);
|
||||||
bool waitForNextKey(uint64_t maxWait = 5000);
|
bool waitForNextKey(uint64_t maxWait = 15000);
|
||||||
// End CMAF push out
|
// End CMAF push out
|
||||||
};
|
};
|
||||||
}// namespace Mist
|
}// namespace Mist
|
||||||
|
|
Loading…
Add table
Reference in a new issue