Major DASH cleanup/bugfix spree: live DASH now works in bitmovin player.
This commit is contained in:
parent
bf1e2c8083
commit
e36b05500b
2 changed files with 71 additions and 116 deletions
|
@ -1180,7 +1180,7 @@ namespace DTSC {
|
||||||
unsigned int Track::timeToKeynum(unsigned int timestamp){
|
unsigned int Track::timeToKeynum(unsigned int timestamp){
|
||||||
unsigned int result = 0;
|
unsigned int result = 0;
|
||||||
for (std::deque<Key>::iterator it = keys.begin(); it != keys.end(); it++){
|
for (std::deque<Key>::iterator it = keys.begin(); it != keys.end(); it++){
|
||||||
if (it->getTime() >= timestamp){
|
if (it->getTime() > timestamp){
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
result = it->getNumber();
|
result = it->getNumber();
|
||||||
|
|
|
@ -28,10 +28,6 @@ namespace Mist {
|
||||||
H.Chunkify("mp42dash", 8, myConn);
|
H.Chunkify("mp42dash", 8, myConn);
|
||||||
}
|
}
|
||||||
|
|
||||||
void OutDashMP4::buildStyp(unsigned int tid){
|
|
||||||
H.Chunkify("\000\000\000\030stypmsdh\000\000\000\000msdhmsix", 24, myConn);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string OutDashMP4::buildMoov(unsigned int tid){
|
std::string OutDashMP4::buildMoov(unsigned int tid){
|
||||||
std::string trackType = myMeta.tracks[tid].type;
|
std::string trackType = myMeta.tracks[tid].type;
|
||||||
MP4::MOOV moovBox;
|
MP4::MOOV moovBox;
|
||||||
|
@ -199,86 +195,11 @@ namespace Mist {
|
||||||
return std::string(moovBox.asBox(),moovBox.boxedSize());
|
return std::string(moovBox.asBox(),moovBox.boxedSize());
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string OutDashMP4::buildSidx(unsigned int tid){
|
|
||||||
fragmentSizes[tid].clear();
|
|
||||||
MP4::AVCC avccBox;
|
|
||||||
MP4::HVCC hvccBox;
|
|
||||||
if (myMeta.tracks[tid].codec == "H264"){
|
|
||||||
avccBox.setPayload(myMeta.tracks[tid].init);
|
|
||||||
}
|
|
||||||
if (myMeta.tracks[tid].codec == "HEVC"){
|
|
||||||
hvccBox.setPayload(myMeta.tracks[tid].init);
|
|
||||||
}
|
|
||||||
int curPart = 0;
|
|
||||||
MP4::SIDX sidxBox;
|
|
||||||
sidxBox.setReferenceID(1);
|
|
||||||
sidxBox.setTimescale(1000);
|
|
||||||
sidxBox.setEarliestPresentationTime(myMeta.tracks[tid].firstms);
|
|
||||||
sidxBox.setFirstOffset(0);
|
|
||||||
int j = 0;
|
|
||||||
for (std::deque<DTSC::Key>::iterator it = myMeta.tracks[tid].keys.begin(); it != myMeta.tracks[tid].keys.end(); it++){
|
|
||||||
MP4::sidxReference refItem;
|
|
||||||
refItem.referenceType = false;
|
|
||||||
refItem.referencedSize = 0;
|
|
||||||
for (int i = 0; i < it->getParts(); i++){
|
|
||||||
refItem.referencedSize += myMeta.tracks[tid].parts[curPart++].getSize();
|
|
||||||
}
|
|
||||||
if (myMeta.tracks[tid].codec == "H264"){
|
|
||||||
refItem.referencedSize += 14 + avccBox.getSPSLen() + avccBox.getPPSLen();
|
|
||||||
}
|
|
||||||
if (myMeta.tracks[tid].codec == "HEVC"){
|
|
||||||
std::deque<MP4::HVCCArrayEntry> content = hvccBox.getArrays();
|
|
||||||
for (std::deque<MP4::HVCCArrayEntry>::iterator it = content.begin(); it != content.end(); it++){
|
|
||||||
for (std::deque<std::string>::iterator it2 = it->nalUnits.begin(); it2 != it->nalUnits.end(); it2++){
|
|
||||||
refItem.referencedSize += 4 + (*it2).size();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fragmentSizes[tid][j] = refItem.referencedSize;
|
|
||||||
if (it->getLength()){
|
|
||||||
refItem.subSegmentDuration = it->getLength();
|
|
||||||
}else{
|
|
||||||
refItem.subSegmentDuration = myMeta.tracks[tid].lastms - it->getTime();
|
|
||||||
}
|
|
||||||
refItem.sapStart = false;
|
|
||||||
refItem.sapType = 0;
|
|
||||||
refItem.sapDeltaTime = 0;
|
|
||||||
sidxBox.setReference(refItem, j++);
|
|
||||||
}
|
|
||||||
return std::string(sidxBox.asBox(),sidxBox.boxedSize());
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string OutDashMP4::buildSidx(unsigned int tid, unsigned int keyNum){
|
|
||||||
MP4::AVCC avccBox;
|
|
||||||
avccBox.setPayload(myMeta.tracks[tid].init);
|
|
||||||
int curPart = 0;
|
|
||||||
MP4::SIDX sidxBox;
|
|
||||||
sidxBox.setReferenceID(1);
|
|
||||||
sidxBox.setTimescale(1000);
|
|
||||||
sidxBox.setEarliestPresentationTime(myMeta.tracks[tid].keys[keyNum].getTime());
|
|
||||||
sidxBox.setFirstOffset(0);
|
|
||||||
for (int i = 0; i < keyNum; i++){
|
|
||||||
curPart += myMeta.tracks[tid].keys[i].getParts();
|
|
||||||
}
|
|
||||||
MP4::sidxReference refItem;
|
|
||||||
refItem.referenceType = false;
|
|
||||||
if (myMeta.tracks[tid].keys[keyNum].getLength()){
|
|
||||||
refItem.subSegmentDuration = myMeta.tracks[tid].keys[keyNum].getLength();
|
|
||||||
}else{
|
|
||||||
refItem.subSegmentDuration = myMeta.tracks[tid].lastms - myMeta.tracks[tid].keys[keyNum].getTime();
|
|
||||||
}
|
|
||||||
refItem.sapStart = false;
|
|
||||||
refItem.sapType = 0;
|
|
||||||
refItem.sapDeltaTime = 0;
|
|
||||||
sidxBox.setReference(refItem, 0);
|
|
||||||
return std::string(sidxBox.asBox(),sidxBox.boxedSize());
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string OutDashMP4::buildMoof(unsigned int tid, unsigned int keyNum){
|
std::string OutDashMP4::buildMoof(unsigned int tid, unsigned int keyNum){
|
||||||
MP4::MOOF moofBox;
|
MP4::MOOF moofBox;
|
||||||
|
|
||||||
MP4::MFHD mfhdBox;
|
MP4::MFHD mfhdBox;
|
||||||
mfhdBox.setSequenceNumber(keyNum + 1);
|
mfhdBox.setSequenceNumber(keyNum);
|
||||||
moofBox.setContent(mfhdBox, 0);
|
moofBox.setContent(mfhdBox, 0);
|
||||||
|
|
||||||
MP4::TRAF trafBox;
|
MP4::TRAF trafBox;
|
||||||
|
@ -295,12 +216,15 @@ namespace Mist {
|
||||||
|
|
||||||
MP4::TFDT tfdtBox;
|
MP4::TFDT tfdtBox;
|
||||||
///\todo Determine index for live
|
///\todo Determine index for live
|
||||||
tfdtBox.setBaseMediaDecodeTime(myMeta.tracks[tid].keys[keyNum].getTime());
|
tfdtBox.setBaseMediaDecodeTime(myMeta.tracks[tid].getKey(keyNum).getTime());
|
||||||
trafBox.setContent(tfdtBox, 1);
|
trafBox.setContent(tfdtBox, 1);
|
||||||
|
|
||||||
int i = 0;
|
int i = 0;
|
||||||
|
|
||||||
for (int j = 0; j < keyNum; j++){
|
for (int j = 0; j < myMeta.tracks[tid].keys.size(); j++){
|
||||||
|
if (myMeta.tracks[tid].keys[j].getNumber() >= keyNum){
|
||||||
|
break;
|
||||||
|
}
|
||||||
i += myMeta.tracks[tid].keys[j].getParts();
|
i += myMeta.tracks[tid].keys[j].getParts();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -308,11 +232,11 @@ namespace Mist {
|
||||||
if (myMeta.tracks[tid].codec == "H264"){
|
if (myMeta.tracks[tid].codec == "H264"){
|
||||||
trunBox.setFlags(MP4::trundataOffset | MP4::trunsampleSize | MP4::trunsampleDuration | MP4::trunfirstSampleFlags | MP4::trunsampleOffsets);
|
trunBox.setFlags(MP4::trundataOffset | MP4::trunsampleSize | MP4::trunsampleDuration | MP4::trunfirstSampleFlags | MP4::trunsampleOffsets);
|
||||||
trunBox.setFirstSampleFlags(MP4::isKeySample);
|
trunBox.setFirstSampleFlags(MP4::isKeySample);
|
||||||
trunBox.setDataOffset(88 + (12 * myMeta.tracks[tid].keys[keyNum].getParts()) + 8);
|
trunBox.setDataOffset(88 + (12 * myMeta.tracks[tid].getKey(keyNum).getParts()) + 8);
|
||||||
|
|
||||||
MP4::AVCC avccBox;
|
MP4::AVCC avccBox;
|
||||||
avccBox.setPayload(myMeta.tracks[tid].init);
|
avccBox.setPayload(myMeta.tracks[tid].init);
|
||||||
for (int j = 0; j < myMeta.tracks[tid].keys[keyNum].getParts(); j++){
|
for (int j = 0; j < myMeta.tracks[tid].getKey(keyNum).getParts(); j++){
|
||||||
MP4::trunSampleInformation trunEntry;
|
MP4::trunSampleInformation trunEntry;
|
||||||
if (!j){
|
if (!j){
|
||||||
trunEntry.sampleSize = myMeta.tracks[tid].parts[i].getSize() + 14 + avccBox.getSPSLen() + avccBox.getPPSLen();
|
trunEntry.sampleSize = myMeta.tracks[tid].parts[i].getSize() + 14 + avccBox.getSPSLen() + avccBox.getPPSLen();
|
||||||
|
@ -328,12 +252,12 @@ namespace Mist {
|
||||||
if (myMeta.tracks[tid].codec == "HEVC"){
|
if (myMeta.tracks[tid].codec == "HEVC"){
|
||||||
trunBox.setFlags(MP4::trundataOffset | MP4::trunsampleSize | MP4::trunsampleDuration | MP4::trunfirstSampleFlags | MP4::trunsampleOffsets);
|
trunBox.setFlags(MP4::trundataOffset | MP4::trunsampleSize | MP4::trunsampleDuration | MP4::trunfirstSampleFlags | MP4::trunsampleOffsets);
|
||||||
trunBox.setFirstSampleFlags(MP4::isKeySample);
|
trunBox.setFirstSampleFlags(MP4::isKeySample);
|
||||||
trunBox.setDataOffset(88 + (12 * myMeta.tracks[tid].keys[keyNum].getParts()) + 8);
|
trunBox.setDataOffset(88 + (12 * myMeta.tracks[tid].getKey(keyNum).getParts()) + 8);
|
||||||
|
|
||||||
MP4::HVCC hvccBox;
|
MP4::HVCC hvccBox;
|
||||||
hvccBox.setPayload(myMeta.tracks[tid].init);
|
hvccBox.setPayload(myMeta.tracks[tid].init);
|
||||||
std::deque<MP4::HVCCArrayEntry> content = hvccBox.getArrays();
|
std::deque<MP4::HVCCArrayEntry> content = hvccBox.getArrays();
|
||||||
for (int j = 0; j < myMeta.tracks[tid].keys[keyNum].getParts(); j++){
|
for (int j = 0; j < myMeta.tracks[tid].getKey(keyNum).getParts(); j++){
|
||||||
MP4::trunSampleInformation trunEntry;
|
MP4::trunSampleInformation trunEntry;
|
||||||
trunEntry.sampleSize = myMeta.tracks[tid].parts[i].getSize();
|
trunEntry.sampleSize = myMeta.tracks[tid].parts[i].getSize();
|
||||||
if (!j){
|
if (!j){
|
||||||
|
@ -351,8 +275,8 @@ namespace Mist {
|
||||||
}
|
}
|
||||||
if (myMeta.tracks[tid].codec == "AAC" || myMeta.tracks[tid].codec == "AC3" || myMeta.tracks[tid].codec == "MP3"){
|
if (myMeta.tracks[tid].codec == "AAC" || myMeta.tracks[tid].codec == "AC3" || myMeta.tracks[tid].codec == "MP3"){
|
||||||
trunBox.setFlags(MP4::trundataOffset | MP4::trunsampleSize | MP4::trunsampleDuration);
|
trunBox.setFlags(MP4::trundataOffset | MP4::trunsampleSize | MP4::trunsampleDuration);
|
||||||
trunBox.setDataOffset(88 + (8 * myMeta.tracks[tid].keys[keyNum].getParts()) + 8);
|
trunBox.setDataOffset(88 + (8 * myMeta.tracks[tid].getKey(keyNum).getParts()) + 8);
|
||||||
for (int j = 0; j < myMeta.tracks[tid].keys[keyNum].getParts(); j++){
|
for (int j = 0; j < myMeta.tracks[tid].getKey(keyNum).getParts(); j++){
|
||||||
MP4::trunSampleInformation trunEntry;
|
MP4::trunSampleInformation trunEntry;
|
||||||
trunEntry.sampleSize = myMeta.tracks[tid].parts[i].getSize();
|
trunEntry.sampleSize = myMeta.tracks[tid].parts[i].getSize();
|
||||||
trunEntry.sampleDuration = myMeta.tracks[tid].parts[i].getDuration();
|
trunEntry.sampleDuration = myMeta.tracks[tid].parts[i].getDuration();
|
||||||
|
@ -378,28 +302,45 @@ namespace Mist {
|
||||||
}
|
}
|
||||||
|
|
||||||
void OutDashMP4::buildMdat(unsigned int tid, unsigned int keyNum){
|
void OutDashMP4::buildMdat(unsigned int tid, unsigned int keyNum){
|
||||||
buildSidx(tid);//Nasty hack for updating fragment sizes...
|
unsigned int size = 8;
|
||||||
MP4::AVCC avccBox;
|
unsigned int curPart = 0;
|
||||||
avccBox.setPayload(myMeta.tracks[tid].init);
|
for (unsigned int i = 0; i < myMeta.tracks[tid].keys.size(); ++i){
|
||||||
std::stringstream r;
|
if (myMeta.tracks[tid].keys[i].getNumber() >= keyNum){break;}
|
||||||
int size = fragmentSizes[tid][keyNum] + 8;
|
curPart += myMeta.tracks[tid].keys[i].getParts();
|
||||||
r << (char)((size >> 24) & 0xFF);
|
}
|
||||||
r << (char)((size >> 16) & 0xFF);
|
for (int i = 0; i < myMeta.tracks[tid].getKey(keyNum).getParts(); i++){
|
||||||
r << (char)((size >> 8) & 0xFF);
|
size += myMeta.tracks[tid].parts[curPart++].getSize();
|
||||||
r << (char)((size) & 0xFF);
|
|
||||||
r << "mdat";
|
|
||||||
H.Chunkify(r.str().data(), r.str().size(), myConn);
|
|
||||||
selectedTracks.clear();
|
|
||||||
selectedTracks.insert(tid);
|
|
||||||
seek(myMeta.tracks[tid].keys[keyNum].getTime());
|
|
||||||
std::string init;
|
|
||||||
char * data;
|
|
||||||
unsigned int dataLen;
|
|
||||||
int partNum = 0;
|
|
||||||
for (int i = 0; i < keyNum; i++){
|
|
||||||
partNum += myMeta.tracks[tid].keys[i].getParts();
|
|
||||||
}
|
}
|
||||||
if (myMeta.tracks[tid].codec == "H264"){
|
if (myMeta.tracks[tid].codec == "H264"){
|
||||||
|
MP4::AVCC avccBox;
|
||||||
|
avccBox.setPayload(myMeta.tracks[tid].init);
|
||||||
|
size += 14 + avccBox.getSPSLen() + avccBox.getPPSLen();
|
||||||
|
}
|
||||||
|
if (myMeta.tracks[tid].codec == "HEVC"){
|
||||||
|
MP4::HVCC hvccBox;
|
||||||
|
hvccBox.setPayload(myMeta.tracks[tid].init);
|
||||||
|
std::deque<MP4::HVCCArrayEntry> content = hvccBox.getArrays();
|
||||||
|
for (std::deque<MP4::HVCCArrayEntry>::iterator it = content.begin(); it != content.end(); it++){
|
||||||
|
for (std::deque<std::string>::iterator it2 = it->nalUnits.begin(); it2 != it->nalUnits.end(); it2++){
|
||||||
|
size += 4 + (*it2).size();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
char mdatstr[8] = {0, 0, 0, 0, 'm', 'd', 'a', 't'};
|
||||||
|
mdatstr[0] = (char)((size >> 24) & 0xFF);
|
||||||
|
mdatstr[1] = (char)((size >> 16) & 0xFF);
|
||||||
|
mdatstr[2] = (char)((size >> 8) & 0xFF);
|
||||||
|
mdatstr[3] = (char)((size) & 0xFF);
|
||||||
|
H.Chunkify(mdatstr, 8, myConn);
|
||||||
|
selectedTracks.clear();
|
||||||
|
selectedTracks.insert(tid);
|
||||||
|
seek(myMeta.tracks[tid].getKey(keyNum).getTime());
|
||||||
|
std::string init;
|
||||||
|
char * data;
|
||||||
|
unsigned int dataLen;
|
||||||
|
if (myMeta.tracks[tid].codec == "H264"){
|
||||||
|
MP4::AVCC avccBox;
|
||||||
|
avccBox.setPayload(myMeta.tracks[tid].init);
|
||||||
init = buildNalUnit(2, "\011\340");
|
init = buildNalUnit(2, "\011\340");
|
||||||
H.Chunkify(init, myConn);//09E0
|
H.Chunkify(init, myConn);//09E0
|
||||||
init = buildNalUnit(avccBox.getSPSLen(), avccBox.getSPS());
|
init = buildNalUnit(avccBox.getSPSLen(), avccBox.getSPS());
|
||||||
|
@ -411,7 +352,7 @@ namespace Mist {
|
||||||
MP4::HVCC hvccBox;
|
MP4::HVCC hvccBox;
|
||||||
hvccBox.setPayload(myMeta.tracks[tid].init);
|
hvccBox.setPayload(myMeta.tracks[tid].init);
|
||||||
std::deque<MP4::HVCCArrayEntry> content = hvccBox.getArrays();
|
std::deque<MP4::HVCCArrayEntry> content = hvccBox.getArrays();
|
||||||
for (int j = 0; j < myMeta.tracks[tid].keys[keyNum].getParts(); j++){
|
for (int j = 0; j < myMeta.tracks[tid].getKey(keyNum).getParts(); j++){
|
||||||
for (std::deque<MP4::HVCCArrayEntry>::iterator it = content.begin(); it != content.end(); it++){
|
for (std::deque<MP4::HVCCArrayEntry>::iterator it = content.begin(); it != content.end(); it++){
|
||||||
for (std::deque<std::string>::iterator it2 = it->nalUnits.begin(); it2 != it->nalUnits.end(); it2++){
|
for (std::deque<std::string>::iterator it2 = it->nalUnits.begin(); it2 != it->nalUnits.end(); it2++){
|
||||||
init = buildNalUnit((*it2).size(), (*it2).c_str());
|
init = buildNalUnit((*it2).size(), (*it2).c_str());
|
||||||
|
@ -420,7 +361,7 @@ namespace Mist {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (int i = 0; i < myMeta.tracks[tid].keys[keyNum].getParts(); i++){
|
for (int i = 0; i < myMeta.tracks[tid].getKey(keyNum).getParts(); i++){
|
||||||
prepareNext();
|
prepareNext();
|
||||||
thisPacket.getString("data", data, dataLen);
|
thisPacket.getString("data", data, dataLen);
|
||||||
H.Chunkify(data, dataLen, myConn);
|
H.Chunkify(data, dataLen, myConn);
|
||||||
|
@ -614,7 +555,6 @@ namespace Mist {
|
||||||
for (std::map<unsigned int,DTSC::Track>::iterator it = myMeta.tracks.begin(); it != myMeta.tracks.end(); it++){
|
for (std::map<unsigned int,DTSC::Track>::iterator it = myMeta.tracks.begin(); it != myMeta.tracks.end(); it++){
|
||||||
if (!moovBoxes.count(it->first)){
|
if (!moovBoxes.count(it->first)){
|
||||||
moovBoxes[it->first] = buildMoov(it->first);
|
moovBoxes[it->first] = buildMoov(it->first);
|
||||||
buildSidx(it->first);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -665,10 +605,25 @@ namespace Mist {
|
||||||
DEBUG_MSG(DLVL_DEVEL, "Searching for time %d", keyId);
|
DEBUG_MSG(DLVL_DEVEL, "Searching for time %d", keyId);
|
||||||
unsigned int keyNum = myMeta.tracks[tid].timeToKeynum(keyId);
|
unsigned int keyNum = myMeta.tracks[tid].timeToKeynum(keyId);
|
||||||
INFO_MSG("Detected key %d:%d for time %d", tid, keyNum, keyId);
|
INFO_MSG("Detected key %d:%d for time %d", tid, keyNum, keyId);
|
||||||
buildStyp(tid);
|
H.Chunkify("\000\000\000\030stypmsdh\000\000\000\000msdhmsix", 24, myConn);
|
||||||
std::string tmp = buildSidx(tid, keyNum);
|
MP4::SIDX sidxBox;
|
||||||
H.Chunkify(tmp, myConn);
|
sidxBox.setReferenceID(1);
|
||||||
tmp = buildMoof(tid, keyNum);
|
sidxBox.setTimescale(1000);
|
||||||
|
sidxBox.setEarliestPresentationTime(myMeta.tracks[tid].getKey(keyNum).getTime());
|
||||||
|
sidxBox.setFirstOffset(0);
|
||||||
|
MP4::sidxReference refItem;
|
||||||
|
refItem.referenceType = false;
|
||||||
|
if (myMeta.tracks[tid].getKey(keyNum).getLength()){
|
||||||
|
refItem.subSegmentDuration = myMeta.tracks[tid].getKey(keyNum).getLength();
|
||||||
|
}else{
|
||||||
|
refItem.subSegmentDuration = myMeta.tracks[tid].lastms - myMeta.tracks[tid].getKey(keyNum).getTime();
|
||||||
|
}
|
||||||
|
refItem.sapStart = false;
|
||||||
|
refItem.sapType = 0;
|
||||||
|
refItem.sapDeltaTime = 0;
|
||||||
|
sidxBox.setReference(refItem, 0);
|
||||||
|
H.Chunkify(sidxBox.asBox(),sidxBox.boxedSize(), myConn);
|
||||||
|
std::string tmp = buildMoof(tid, keyNum);
|
||||||
H.Chunkify(tmp, myConn);
|
H.Chunkify(tmp, myConn);
|
||||||
buildMdat(tid, keyNum);
|
buildMdat(tid, keyNum);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue