Merge branch 'development' into LTS_development
# Conflicts: # src/output/output_ebml.cpp
This commit is contained in:
commit
a0b011325c
5 changed files with 105 additions and 42 deletions
|
@ -516,6 +516,12 @@ namespace EBML{
|
|||
return std::string(strPtr, strLen);
|
||||
}
|
||||
|
||||
std::string Element::getValStringUntrimmed() const{
|
||||
uint64_t strLen = getPayloadLen();
|
||||
const char * strPtr = getPayload();
|
||||
return std::string(strPtr, strLen);
|
||||
}
|
||||
|
||||
uint64_t Block::getTrackNum() const{return UniInt::readInt(getPayload());}
|
||||
|
||||
int16_t Block::getTimecode() const{
|
||||
|
|
|
@ -97,6 +97,7 @@ namespace EBML{
|
|||
int64_t getValInt() const;
|
||||
double getValFloat() const;
|
||||
std::string getValString() const;
|
||||
std::string getValStringUntrimmed() const;
|
||||
const Element findChild(uint32_t id) const;
|
||||
|
||||
private:
|
||||
|
|
|
@ -36,11 +36,13 @@ namespace Mist{
|
|||
capa["codecs"].append("MP3");
|
||||
capa["codecs"].append("AC3");
|
||||
capa["codecs"].append("FLOAT");
|
||||
capa["codecs"].append("DTS");
|
||||
capa["codecs"].append("JSON");
|
||||
capa["codecs"].append("subtitle");
|
||||
lastClusterBPos = 0;
|
||||
lastClusterTime = 0;
|
||||
bufferedPacks = 0;
|
||||
wantBlocks = true;
|
||||
}
|
||||
|
||||
std::string ASStoSRT(const char * ptr, uint32_t len){
|
||||
|
@ -191,13 +193,13 @@ namespace Mist{
|
|||
trueCodec = "H264";
|
||||
trueType = "video";
|
||||
tmpElem = E.findChild(EBML::EID_CODECPRIVATE);
|
||||
if (tmpElem){init = tmpElem.getValString();}
|
||||
if (tmpElem){init = tmpElem.getValStringUntrimmed();}
|
||||
}
|
||||
if (codec == "V_MPEGH/ISO/HEVC"){
|
||||
trueCodec = "HEVC";
|
||||
trueType = "video";
|
||||
tmpElem = E.findChild(EBML::EID_CODECPRIVATE);
|
||||
if (tmpElem){init = tmpElem.getValString();}
|
||||
if (tmpElem){init = tmpElem.getValStringUntrimmed();}
|
||||
}
|
||||
if (codec == "V_AV1"){
|
||||
trueCodec = "AV1";
|
||||
|
@ -215,25 +217,29 @@ namespace Mist{
|
|||
trueCodec = "opus";
|
||||
trueType = "audio";
|
||||
tmpElem = E.findChild(EBML::EID_CODECPRIVATE);
|
||||
if (tmpElem){init = tmpElem.getValString();}
|
||||
if (tmpElem){init = tmpElem.getValStringUntrimmed();}
|
||||
}
|
||||
if (codec == "A_VORBIS"){
|
||||
trueCodec = "vorbis";
|
||||
trueType = "audio";
|
||||
tmpElem = E.findChild(EBML::EID_CODECPRIVATE);
|
||||
if (tmpElem){init = tmpElem.getValString();}
|
||||
if (tmpElem){init = tmpElem.getValStringUntrimmed();}
|
||||
}
|
||||
if (codec == "V_THEORA"){
|
||||
trueCodec = "theora";
|
||||
trueType = "video";
|
||||
tmpElem = E.findChild(EBML::EID_CODECPRIVATE);
|
||||
if (tmpElem){init = tmpElem.getValString();}
|
||||
if (tmpElem){init = tmpElem.getValStringUntrimmed();}
|
||||
}
|
||||
if (codec == "A_AAC"){
|
||||
trueCodec = "AAC";
|
||||
trueType = "audio";
|
||||
tmpElem = E.findChild(EBML::EID_CODECPRIVATE);
|
||||
if (tmpElem){init = tmpElem.getValString();}
|
||||
if (tmpElem){init = tmpElem.getValStringUntrimmed();}
|
||||
}
|
||||
if (codec == "A_DTS"){
|
||||
trueCodec = "DTS";
|
||||
trueType = "audio";
|
||||
}
|
||||
if (codec == "A_PCM/INT/BIG"){
|
||||
trueCodec = "PCM";
|
||||
|
@ -275,12 +281,12 @@ namespace Mist{
|
|||
trueCodec = "subtitle";
|
||||
trueType = "meta";
|
||||
tmpElem = E.findChild(EBML::EID_CODECPRIVATE);
|
||||
if (tmpElem){init = tmpElem.getValString();}
|
||||
if (tmpElem){init = tmpElem.getValStringUntrimmed();}
|
||||
}
|
||||
if (codec == "A_MS/ACM"){
|
||||
tmpElem = E.findChild(EBML::EID_CODECPRIVATE);
|
||||
if (tmpElem){
|
||||
std::string WAVEFORMATEX = tmpElem.getValString();
|
||||
std::string WAVEFORMATEX = tmpElem.getValStringUntrimmed();
|
||||
unsigned int formatTag = Bit::btohs_le(WAVEFORMATEX.data());
|
||||
switch (formatTag){
|
||||
case 3:
|
||||
|
@ -350,12 +356,27 @@ namespace Mist{
|
|||
bool isVideo = (Trk.type == "video");
|
||||
bool isAudio = (Trk.type == "audio");
|
||||
bool isASS = (Trk.codec == "subtitle" && Trk.init.size());
|
||||
//If this is a new video keyframe, flush the corresponding trackPredictor
|
||||
if (isVideo && B.isKeyframe()){
|
||||
while (TP.hasPackets(true)){
|
||||
packetData &C = TP.getPacketData(true);
|
||||
myMeta.update(C.time, C.offset, C.track, C.dsize, C.bpos, C.key);
|
||||
TP.remove();
|
||||
}
|
||||
TP.flush();
|
||||
}
|
||||
for (uint64_t frameNo = 0; frameNo < B.getFrameCount(); ++frameNo){
|
||||
if (frameNo){
|
||||
if (Trk.codec == "AAC"){
|
||||
newTime += (1000000 / Trk.rate)/timeScale;//assume ~1000 samples per frame
|
||||
} else if (Trk.codec == "MP3"){
|
||||
newTime += (1152000 / Trk.rate)/timeScale;//1152 samples per frame
|
||||
} else if (Trk.codec == "DTS"){
|
||||
//Assume 512 samples per frame (DVD default)
|
||||
//actual amount can be calculated from data, but data
|
||||
//is not available during header generation...
|
||||
//See: http://www.stnsoft.com/DVD/dtshdr.html
|
||||
newTime += (512000 / Trk.rate)/timeScale;
|
||||
}else{
|
||||
newTime += 1/timeScale;
|
||||
ERROR_MSG("Unknown frame duration for codec %s - timestamps WILL be wrong!", Trk.codec.c_str());
|
||||
|
@ -464,6 +485,7 @@ namespace Mist{
|
|||
}
|
||||
}
|
||||
EBML::Block B;
|
||||
if (wantBlocks){
|
||||
do{
|
||||
if (!readElement()){
|
||||
// Make sure we empty our buffer first
|
||||
|
@ -486,6 +508,9 @@ namespace Mist{
|
|||
}
|
||||
B = EBML::Block(ptr);
|
||||
}while (!B || B.getType() != EBML::ELEM_BLOCK || !selectedTracks.count(B.getTrackNum()));
|
||||
}else{
|
||||
B = EBML::Block(ptr);
|
||||
}
|
||||
|
||||
uint64_t tNum = B.getTrackNum();
|
||||
uint64_t newTime = lastClusterTime + B.getTimecode();
|
||||
|
@ -494,12 +519,36 @@ namespace Mist{
|
|||
bool isVideo = (Trk.type == "video");
|
||||
bool isAudio = (Trk.type == "audio");
|
||||
bool isASS = (Trk.codec == "subtitle" && Trk.init.size());
|
||||
|
||||
//If this is a new video keyframe, flush the corresponding trackPredictor
|
||||
if (isVideo && B.isKeyframe() && bufferedPacks){
|
||||
if (TP.hasPackets(true)){
|
||||
wantBlocks = false;
|
||||
packetData &C = TP.getPacketData(true);
|
||||
fillPacket(C);
|
||||
TP.remove();
|
||||
--bufferedPacks;
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (isVideo && B.isKeyframe()){
|
||||
TP.flush();
|
||||
}
|
||||
wantBlocks = true;
|
||||
|
||||
|
||||
for (uint64_t frameNo = 0; frameNo < B.getFrameCount(); ++frameNo){
|
||||
if (frameNo){
|
||||
if (Trk.codec == "AAC"){
|
||||
newTime += (1000000 / Trk.rate)/timeScale;//assume ~1000 samples per frame
|
||||
} else if (Trk.codec == "MP3"){
|
||||
newTime += (1152000 / Trk.rate)/timeScale;//1152 samples per frame
|
||||
} else if (Trk.codec == "DTS"){
|
||||
//Assume 512 samples per frame (DVD default)
|
||||
//actual amount can be calculated from data, but data
|
||||
//is not available during header generation...
|
||||
//See: http://www.stnsoft.com/DVD/dtshdr.html
|
||||
newTime += (512000 / Trk.rate)/timeScale;
|
||||
}else{
|
||||
ERROR_MSG("Unknown frame duration for codec %s - timestamps WILL be wrong!", Trk.codec.c_str());
|
||||
}
|
||||
|
@ -532,6 +581,7 @@ namespace Mist{
|
|||
}
|
||||
|
||||
void InputEBML::seek(int seekTime){
|
||||
wantBlocks = true;
|
||||
packBuf.clear();
|
||||
bufferedPacks = 0;
|
||||
uint64_t mainTrack = getMainSelectedTrack();
|
||||
|
@ -542,17 +592,6 @@ namespace Mist{
|
|||
uint64_t partCount = 0;
|
||||
for (unsigned int i = 0; i < Trk.keys.size(); i++){
|
||||
if (Trk.keys[i].getTime() > seekTime){
|
||||
if (i > 1){
|
||||
partCount -= Trk.keys[i-1].getParts() + Trk.keys[i-2].getParts();
|
||||
uint64_t partEnd = partCount + Trk.keys[i-2].getParts();
|
||||
uint64_t partTime = Trk.keys[i-2].getTime();
|
||||
for (uint64_t prt = partCount; prt < partEnd; ++prt){
|
||||
INSANE_MSG("Replay part %llu, timestamp: %llu+%llu", prt, partTime, Trk.parts[prt].getOffset());
|
||||
packBuf[mainTrack].add(partTime, Trk.parts[prt].getOffset(), mainTrack, 0, 0, false, isVideo, (void *)0);
|
||||
packBuf[mainTrack].remove();
|
||||
partTime += Trk.parts[prt].getDuration();
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
partCount += Trk.keys[i].getParts();
|
||||
|
|
|
@ -40,15 +40,13 @@ namespace Mist{
|
|||
class trackPredictor{
|
||||
public:
|
||||
packetData pkts[PKT_COUNT];
|
||||
uint64_t frameOffset;
|
||||
uint16_t smallestFrame;
|
||||
uint64_t lastTime;
|
||||
uint64_t ctr;
|
||||
uint64_t rem;
|
||||
trackPredictor(){
|
||||
smallestFrame = 0;
|
||||
lastTime = 0;
|
||||
ctr = 0;
|
||||
rem = 0;
|
||||
flush();
|
||||
}
|
||||
bool hasPackets(bool finished = false){
|
||||
if (finished){
|
||||
|
@ -57,6 +55,14 @@ namespace Mist{
|
|||
return (ctr - rem > 12);
|
||||
}
|
||||
}
|
||||
/// Clears all internal values, for reuse as-new.
|
||||
void flush(){
|
||||
frameOffset = 0;
|
||||
smallestFrame = 0;
|
||||
lastTime = 0;
|
||||
ctr = 0;
|
||||
rem = 0;
|
||||
}
|
||||
packetData & getPacketData(bool mustCalcOffsets){
|
||||
frameOffsetKnown = true;
|
||||
//grab the next packet to output
|
||||
|
@ -74,13 +80,20 @@ namespace Mist{
|
|||
//we assume it's just time stamp drift due to lack of precision.
|
||||
p.time = (lastTime + smallestFrame);
|
||||
}else{
|
||||
p.offset = maxEBMLFrameOffset;
|
||||
p.time -= frameOffset?frameOffset + smallestFrame:0;
|
||||
p.offset = maxEBMLFrameOffset + frameOffset + smallestFrame;
|
||||
}
|
||||
}
|
||||
lastTime = p.time;
|
||||
DONTEVEN_MSG("Outputting%s %llu + %llu, offset %llu (%llu -> %llu), display at %llu", (p.key?" (KEY)":""), p.time, frameOffset, p.offset, rem, rem % PKT_COUNT, p.time+p.offset);
|
||||
return p;
|
||||
}
|
||||
void add(uint64_t packTime, uint64_t packOffset, uint64_t packTrack, uint64_t packDataSize, uint64_t packBytePos, bool isKeyframe, bool isVideo, void * dataPtr = 0){
|
||||
//If no packets have been removed yet and there is more than one packet, calculate frameOffset
|
||||
if (!rem && ctr && packTime < pkts[0].time){
|
||||
frameOffset = pkts[0].time - packTime;
|
||||
INSANE_MSG("Setting frameOffset to %llu", frameOffset);
|
||||
}
|
||||
if (isVideo && ctr && ctr >= rem){
|
||||
int32_t currOffset = packTime - pkts[(ctr-1)%PKT_COUNT].time;
|
||||
if (currOffset < 0){currOffset *= -1;}
|
||||
|
@ -131,6 +144,7 @@ namespace Mist{
|
|||
bool openStreamSource(){return true;}
|
||||
bool needHeader(){return needsLock() && !readExistingHeader();}
|
||||
double timeScale;
|
||||
bool wantBlocks;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -70,6 +70,7 @@ namespace Mist{
|
|||
capa["codecs"][0u][1u].append("MP3");
|
||||
capa["codecs"][0u][1u].append("FLOAT");
|
||||
capa["codecs"][0u][1u].append("AC3");
|
||||
capa["codecs"][0u][1u].append("DTS");
|
||||
capa["codecs"][0u][2u].append("+JSON");
|
||||
capa["methods"][0u]["handler"] = "http";
|
||||
capa["methods"][0u]["type"] = "html5/video/webm";
|
||||
|
@ -89,6 +90,7 @@ namespace Mist{
|
|||
capa["exceptions"]["codec:MP3"] = blacklistNonChrome;
|
||||
capa["exceptions"]["codec:FLOAT"] = blacklistNonChrome;
|
||||
capa["exceptions"]["codec:AC3"] = blacklistNonChrome;
|
||||
capa["exceptions"]["codec:DTS"] = blacklistNonChrome;
|
||||
capa["push_urls"].append("/*.mkv");
|
||||
capa["push_urls"].append("/*.webm");
|
||||
|
||||
|
@ -176,6 +178,7 @@ namespace Mist{
|
|||
if (Trk.codec == "ALAW"){return "A_MS/ACM";}
|
||||
if (Trk.codec == "ULAW"){return "A_MS/ACM";}
|
||||
if (Trk.codec == "FLOAT"){return "A_PCM/FLOAT/IEEE";}
|
||||
if (Trk.codec == "DTS"){return "A_DTS";}
|
||||
if (Trk.codec == "JSON"){return "M_JSON";}
|
||||
return "E_UNKNOWN";
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue