Fix bug in Output::seek() when seeking to a timestamp that is between the last part of a key and the first part of the next key
This commit is contained in:
parent
dd5ae98002
commit
4080d141f8
7 changed files with 44 additions and 26 deletions
41
lib/dtsc.cpp
41
lib/dtsc.cpp
|
@ -6,6 +6,7 @@
|
||||||
#include "dtsc.h"
|
#include "dtsc.h"
|
||||||
#include "encode.h"
|
#include "encode.h"
|
||||||
#include "lib/shared_memory.h"
|
#include "lib/shared_memory.h"
|
||||||
|
#include "lib/util.h"
|
||||||
#include <arpa/inet.h> //for htonl/ntohl
|
#include <arpa/inet.h> //for htonl/ntohl
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
@ -3159,6 +3160,35 @@ namespace DTSC{
|
||||||
return pages.getInt("firstkey", res);
|
return pages.getInt("firstkey", res);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the key number containing a given time.
|
||||||
|
/// Or, closest key if given time is not available.
|
||||||
|
/// Or, zero if no keys are available at all.
|
||||||
|
/// If the time is in the gap before a key, returns that next key instead.
|
||||||
|
size_t Meta::getKeyNumForTime(uint32_t idx, uint64_t time) const{
|
||||||
|
const Track &trk = tracks.at(idx);
|
||||||
|
const Util::RelAccX &keys = trk.keys;
|
||||||
|
const Util::RelAccX &parts = trk.parts;
|
||||||
|
if (!keys.getEndPos()){return 0;}
|
||||||
|
size_t res = keys.getStartPos();
|
||||||
|
for (size_t i = res; i < keys.getEndPos(); i++){
|
||||||
|
if (keys.getInt(trk.keyTimeField, i) > time){
|
||||||
|
//It's possible we overshot our timestamp, but the previous key does not contain it.
|
||||||
|
//This happens when seeking to a timestamp past the last part of the previous key, but
|
||||||
|
//before the first part of the next key.
|
||||||
|
//In this case, we should _not_ return the previous key, but the current key.
|
||||||
|
//That prevents getting stuck at the end of the page, waiting for a part to show up that never will.
|
||||||
|
if (keys.getInt(trk.keyFirstPartField, i) > parts.getStartPos()){
|
||||||
|
uint64_t dur = parts.getInt(trk.partDurationField, keys.getInt(trk.keyFirstPartField, i)-1);
|
||||||
|
if (keys.getInt(trk.keyTimeField, i) - dur < time){res = i;}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
res = i;
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
Parts::Parts(const Util::RelAccX &_parts) : parts(_parts){
|
Parts::Parts(const Util::RelAccX &_parts) : parts(_parts){
|
||||||
sizeField = parts.getFieldData("size");
|
sizeField = parts.getFieldData("size");
|
||||||
durationField = parts.getFieldData("duration");
|
durationField = parts.getFieldData("duration");
|
||||||
|
@ -3208,17 +3238,6 @@ namespace DTSC{
|
||||||
}
|
}
|
||||||
size_t Keys::getSize(size_t idx) const{return cKeys.getInt(sizeField, idx);}
|
size_t Keys::getSize(size_t idx) const{return cKeys.getInt(sizeField, idx);}
|
||||||
|
|
||||||
/// Returns the key number containing a given timestamp.
|
|
||||||
/// Returns the closest key number if the timestamp is not available.
|
|
||||||
size_t Keys::getNumForTime(uint64_t time) const{
|
|
||||||
size_t res = getFirstValid();
|
|
||||||
for (size_t i = getFirstValid(); i < getEndValid(); i++){
|
|
||||||
if (getTime(i) > time){break;}
|
|
||||||
res = i;
|
|
||||||
}
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
Fragments::Fragments(const Util::RelAccX &_fragments) : fragments(_fragments){}
|
Fragments::Fragments(const Util::RelAccX &_fragments) : fragments(_fragments){}
|
||||||
size_t Fragments::getFirstValid() const{return fragments.getDeleted();}
|
size_t Fragments::getFirstValid() const{return fragments.getDeleted();}
|
||||||
size_t Fragments::getEndValid() const{return fragments.getEndPos();}
|
size_t Fragments::getEndValid() const{return fragments.getEndPos();}
|
||||||
|
|
|
@ -189,7 +189,6 @@ namespace DTSC{
|
||||||
uint64_t getTime(size_t idx) const;
|
uint64_t getTime(size_t idx) const;
|
||||||
void setSize(size_t idx, size_t _size);
|
void setSize(size_t idx, size_t _size);
|
||||||
size_t getSize(size_t idx) const;
|
size_t getSize(size_t idx) const;
|
||||||
size_t getNumForTime(uint64_t time) const;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool isConst;
|
bool isConst;
|
||||||
|
@ -442,6 +441,7 @@ namespace DTSC{
|
||||||
bool nextPageAvailable(uint32_t idx, size_t currentPage) const;
|
bool nextPageAvailable(uint32_t idx, size_t currentPage) const;
|
||||||
size_t getPageNumberForTime(uint32_t idx, uint64_t time) const;
|
size_t getPageNumberForTime(uint32_t idx, uint64_t time) const;
|
||||||
size_t getPageNumberForKey(uint32_t idx, uint64_t keynumber) const;
|
size_t getPageNumberForKey(uint32_t idx, uint64_t keynumber) const;
|
||||||
|
size_t getKeyNumForTime(uint32_t idx, uint64_t time) const;
|
||||||
|
|
||||||
const Util::RelAccX &parts(size_t idx) const;
|
const Util::RelAccX &parts(size_t idx) const;
|
||||||
Util::RelAccX &keys(size_t idx);
|
Util::RelAccX &keys(size_t idx);
|
||||||
|
|
|
@ -394,7 +394,7 @@ namespace Mist{
|
||||||
tmpPos.seekTime = 0;
|
tmpPos.seekTime = 0;
|
||||||
}
|
}
|
||||||
DTSC::Keys keys(M.keys(trackIdx));
|
DTSC::Keys keys(M.keys(trackIdx));
|
||||||
uint32_t keyNum = keys.getNumForTime(ms);
|
uint32_t keyNum = M.getKeyNumForTime(trackIdx, ms);
|
||||||
if (keys.getTime(keyNum) > tmpPos.seekTime){
|
if (keys.getTime(keyNum) > tmpPos.seekTime){
|
||||||
tmpPos.seekTime = keys.getTime(keyNum);
|
tmpPos.seekTime = keys.getTime(keyNum);
|
||||||
tmpPos.bytePos = keys.getBpos(keyNum);
|
tmpPos.bytePos = keys.getBpos(keyNum);
|
||||||
|
|
|
@ -163,7 +163,7 @@ namespace Mist{
|
||||||
// keyframe. Flv files are never multi-track, so track 1 is video, track 2 is audio.
|
// keyframe. Flv files are never multi-track, so track 1 is video, track 2 is audio.
|
||||||
size_t seekTrack = (idx == INVALID_TRACK_ID ? M.mainTrack() : idx);
|
size_t seekTrack = (idx == INVALID_TRACK_ID ? M.mainTrack() : idx);
|
||||||
DTSC::Keys keys(M.keys(seekTrack));
|
DTSC::Keys keys(M.keys(seekTrack));
|
||||||
uint32_t keyNum = keys.getNumForTime(seekTime);
|
uint32_t keyNum = M.getKeyNumForTime(seekTrack, seekTime);
|
||||||
Util::fseek(inFile, keys.getBpos(keyNum), SEEK_SET);
|
Util::fseek(inFile, keys.getBpos(keyNum), SEEK_SET);
|
||||||
}
|
}
|
||||||
}// namespace Mist
|
}// namespace Mist
|
||||||
|
|
|
@ -150,7 +150,7 @@ namespace Mist{
|
||||||
|
|
||||||
void inputMP3::seek(uint64_t seekTime, size_t idx){
|
void inputMP3::seek(uint64_t seekTime, size_t idx){
|
||||||
DTSC::Keys keys(M.keys(idx));
|
DTSC::Keys keys(M.keys(idx));
|
||||||
uint32_t keyNum = keys.getNumForTime(seekTime);
|
uint32_t keyNum = M.getKeyNumForTime(idx, seekTime);
|
||||||
fseek(inFile, keys.getBpos(keyNum), SEEK_SET);
|
fseek(inFile, keys.getBpos(keyNum), SEEK_SET);
|
||||||
timestamp = keys.getTime(keyNum);
|
timestamp = keys.getTime(keyNum);
|
||||||
}
|
}
|
||||||
|
|
|
@ -457,14 +457,14 @@ namespace Mist{
|
||||||
readPMT();
|
readPMT();
|
||||||
uint64_t seekPos = 0xFFFFFFFFull;
|
uint64_t seekPos = 0xFFFFFFFFull;
|
||||||
if (idx != INVALID_TRACK_ID){
|
if (idx != INVALID_TRACK_ID){
|
||||||
|
uint32_t keyNum = M.getKeyNumForTime(idx, seekTime);
|
||||||
DTSC::Keys keys(M.keys(idx));
|
DTSC::Keys keys(M.keys(idx));
|
||||||
uint32_t keyNum = keys.getNumForTime(seekTime);
|
|
||||||
seekPos = keys.getBpos(keyNum);
|
seekPos = keys.getBpos(keyNum);
|
||||||
}else{
|
}else{
|
||||||
std::set<size_t> tracks = M.getValidTracks();
|
std::set<size_t> tracks = M.getValidTracks();
|
||||||
for (std::set<size_t>::iterator it = tracks.begin(); it != tracks.end(); it++){
|
for (std::set<size_t>::iterator it = tracks.begin(); it != tracks.end(); it++){
|
||||||
|
uint32_t keyNum = M.getKeyNumForTime(*it, seekTime);
|
||||||
DTSC::Keys keys(M.keys(*it));
|
DTSC::Keys keys(M.keys(*it));
|
||||||
uint32_t keyNum = keys.getNumForTime(seekTime);
|
|
||||||
uint64_t thisBPos = keys.getBpos(keyNum);
|
uint64_t thisBPos = keys.getBpos(keyNum);
|
||||||
if (thisBPos < seekPos){seekPos = thisBPos;}
|
if (thisBPos < seekPos){seekPos = thisBPos;}
|
||||||
}
|
}
|
||||||
|
|
|
@ -491,11 +491,11 @@ namespace Mist{
|
||||||
}
|
}
|
||||||
//Abort if the track is not loaded
|
//Abort if the track is not loaded
|
||||||
if (!M.trackLoaded(trk)){return 0;}
|
if (!M.trackLoaded(trk)){return 0;}
|
||||||
DTSC::Keys keys(M.keys(trk));
|
const DTSC::Keys &keys = M.keys(trk);
|
||||||
//Abort if there are no keys
|
//Abort if there are no keys
|
||||||
if (!keys.getValidCount()){return 0;}
|
if (!keys.getValidCount()){return 0;}
|
||||||
//Get the key for the current time
|
//Get the key for the current time
|
||||||
size_t keyNum = keys.getNumForTime(lastPacketTime);
|
size_t keyNum = M.getKeyNumForTime(trk, lastPacketTime);
|
||||||
if (keys.getEndValid() <= keyNum+1){return 0;}
|
if (keys.getEndValid() <= keyNum+1){return 0;}
|
||||||
//Return the next key
|
//Return the next key
|
||||||
return keys.getTime(keyNum+1);
|
return keys.getTime(keyNum+1);
|
||||||
|
@ -687,7 +687,7 @@ namespace Mist{
|
||||||
}
|
}
|
||||||
if (M.getType(mainTrack) == "video"){
|
if (M.getType(mainTrack) == "video"){
|
||||||
DTSC::Keys keys(M.keys(mainTrack));
|
DTSC::Keys keys(M.keys(mainTrack));
|
||||||
size_t keyNum = keys.getNumForTime(pos);
|
size_t keyNum = M.getKeyNumForTime(mainTrack, pos);
|
||||||
pos = keys.getTime(keyNum);
|
pos = keys.getTime(keyNum);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -732,7 +732,7 @@ namespace Mist{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
DTSC::Keys keys(M.keys(tid));
|
DTSC::Keys keys(M.keys(tid));
|
||||||
size_t keyNum = keys.getNumForTime(pos);
|
size_t keyNum = M.getKeyNumForTime(tid, pos);
|
||||||
uint64_t actualKeyTime = keys.getTime(keyNum);
|
uint64_t actualKeyTime = keys.getTime(keyNum);
|
||||||
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){
|
||||||
|
@ -1419,7 +1419,7 @@ namespace Mist{
|
||||||
userSelect[mainTrack].reload(streamName, mainTrack);
|
userSelect[mainTrack].reload(streamName, mainTrack);
|
||||||
// now, seek to the exact timestamp of the keyframe
|
// now, seek to the exact timestamp of the keyframe
|
||||||
DTSC::Keys keys(M.keys(mainTrack));
|
DTSC::Keys keys(M.keys(mainTrack));
|
||||||
unsigned int targetKey = keys.getNumForTime(currTime);
|
size_t targetKey = M.getKeyNumForTime(mainTrack, currTime);
|
||||||
seek(keys.getTime(targetKey));
|
seek(keys.getTime(targetKey));
|
||||||
// attempt to load the key into thisPacket
|
// attempt to load the key into thisPacket
|
||||||
bool ret = prepareNext();
|
bool ret = prepareNext();
|
||||||
|
@ -1547,11 +1547,11 @@ namespace Mist{
|
||||||
dropTrack(nxt.tid, "end of VoD track reached", false);
|
dropTrack(nxt.tid, "end of VoD track reached", false);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
DTSC::Keys keys(M.keys(nxt.tid));
|
size_t thisKey = M.getKeyNumForTime(nxt.tid, nxt.time);
|
||||||
size_t thisKey = keys.getNumForTime(nxt.time);
|
|
||||||
//Check if there exists a different page for the next key
|
//Check if there exists a different page for the next key
|
||||||
size_t nextKeyPage = M.getPageNumberForKey(nxt.tid, thisKey + 1);
|
size_t nextKeyPage = M.getPageNumberForKey(nxt.tid, thisKey + 1);
|
||||||
if (nextKeyPage != INVALID_KEY_NUM && nextKeyPage != currentPage[nxt.tid]){
|
if (nextKeyPage != INVALID_KEY_NUM && nextKeyPage != currentPage[nxt.tid]){
|
||||||
|
DTSC::Keys keys(M.keys(nxt.tid));
|
||||||
// If so, the next key is our next packet
|
// If so, the next key is our next packet
|
||||||
nextTime = keys.getTime(thisKey + 1);
|
nextTime = keys.getTime(thisKey + 1);
|
||||||
}else{
|
}else{
|
||||||
|
@ -1617,8 +1617,7 @@ namespace Mist{
|
||||||
//Update keynum only when the second flips over in the timestamp
|
//Update keynum only when the second flips over in the timestamp
|
||||||
//We do this because DTSC::Keys is pretty CPU-heavy
|
//We do this because DTSC::Keys is pretty CPU-heavy
|
||||||
if (nxt.time / 1000 < nextTime/1000){
|
if (nxt.time / 1000 < nextTime/1000){
|
||||||
DTSC::Keys keys(M.keys(nxt.tid));
|
size_t thisKey = M.getKeyNumForTime(nxt.tid, nxt.time);
|
||||||
size_t thisKey = keys.getNumForTime(nxt.time);
|
|
||||||
userSelect[nxt.tid].setKeyNum(thisKey);
|
userSelect[nxt.tid].setKeyNum(thisKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue