Fixes to HTTP parser lib, DTSCMeta keysizes, MP4 headers and 4+GiB MP4 file output by Oswald de Bruin
This commit is contained in:
parent
3f6e465d6e
commit
f9201cbf9a
7 changed files with 114 additions and 32 deletions
|
@ -1422,10 +1422,10 @@ namespace DTSC {
|
||||||
std::string tmp;
|
std::string tmp;
|
||||||
tmp.reserve(keySizes.size() * 4);
|
tmp.reserve(keySizes.size() * 4);
|
||||||
for (unsigned int i = 0; i < keySizes.size(); i++){
|
for (unsigned int i = 0; i < keySizes.size(); i++){
|
||||||
tmp += ((char)keySizes[i] >> 24);
|
tmp += (char)(keySizes[i] >> 24);
|
||||||
tmp += ((char)keySizes[i] >> 16);
|
tmp += (char)(keySizes[i] >> 16);
|
||||||
tmp += ((char)keySizes[i] >> 8);
|
tmp += (char)(keySizes[i] >> 8);
|
||||||
tmp += ((char)keySizes[i]);
|
tmp += (char)(keySizes[i]);
|
||||||
}
|
}
|
||||||
writePointer(p, tmp.data(), tmp.size());
|
writePointer(p, tmp.data(), tmp.size());
|
||||||
writePointer(p, "\000\005parts\002", 8);
|
writePointer(p, "\000\005parts\002", 8);
|
||||||
|
@ -1492,10 +1492,10 @@ namespace DTSC {
|
||||||
std::string tmp;
|
std::string tmp;
|
||||||
tmp.reserve(keySizes.size() * 4);
|
tmp.reserve(keySizes.size() * 4);
|
||||||
for (unsigned int i = 0; i < keySizes.size(); i++){
|
for (unsigned int i = 0; i < keySizes.size(); i++){
|
||||||
tmp += ((char)keySizes[i] >> 24);
|
tmp += (char)(keySizes[i] >> 24);
|
||||||
tmp += ((char)keySizes[i] >> 16);
|
tmp += (char)(keySizes[i] >> 16);
|
||||||
tmp += ((char)keySizes[i] >> 8);
|
tmp += (char)(keySizes[i] >> 8);
|
||||||
tmp += ((char)keySizes[i]);
|
tmp += (char)(keySizes[i]);
|
||||||
}
|
}
|
||||||
conn.SendNow(tmp.data(), tmp.size());
|
conn.SendNow(tmp.data(), tmp.size());
|
||||||
conn.SendNow("\000\005parts\002", 8);
|
conn.SendNow("\000\005parts\002", 8);
|
||||||
|
@ -1631,10 +1631,10 @@ namespace DTSC {
|
||||||
tmp = "";
|
tmp = "";
|
||||||
tmp.reserve(keySizes.size() * 4);
|
tmp.reserve(keySizes.size() * 4);
|
||||||
for (unsigned int i = 0; i < keySizes.size(); i++){
|
for (unsigned int i = 0; i < keySizes.size(); i++){
|
||||||
tmp += ((char)(keySizes[i] >> 24));
|
tmp += (char)((keySizes[i] >> 24));
|
||||||
tmp += ((char)(keySizes[i] >> 16));
|
tmp += (char)((keySizes[i] >> 16));
|
||||||
tmp += ((char)(keySizes[i] >> 8));
|
tmp += (char)((keySizes[i] >> 8));
|
||||||
tmp += ((char)keySizes[i]);
|
tmp += (char)(keySizes[i]);
|
||||||
}
|
}
|
||||||
result["keysizes"] = tmp;
|
result["keysizes"] = tmp;
|
||||||
tmp = "";
|
tmp = "";
|
||||||
|
|
|
@ -309,10 +309,10 @@ void HTTP::Parser::SetHeader(std::string i, std::string v) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets header i to integer value v.
|
/// Sets header i to integer value v.
|
||||||
void HTTP::Parser::SetHeader(std::string i, int v) {
|
void HTTP::Parser::SetHeader(std::string i, long long v) {
|
||||||
Trim(i);
|
Trim(i);
|
||||||
char val[23]; //ints are never bigger than 22 chars as decimal
|
char val[23]; //ints are never bigger than 22 chars as decimal
|
||||||
sprintf(val, "%i", v);
|
sprintf(val, "%lld", v);
|
||||||
headers[i] = val;
|
headers[i] = val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,7 @@ namespace HTTP {
|
||||||
std::string GetVar(std::string i);
|
std::string GetVar(std::string i);
|
||||||
std::string getUrl();
|
std::string getUrl();
|
||||||
void SetHeader(std::string i, std::string v);
|
void SetHeader(std::string i, std::string v);
|
||||||
void SetHeader(std::string i, int v);
|
void SetHeader(std::string i, long long v);
|
||||||
void SetVar(std::string i, std::string v);
|
void SetVar(std::string i, std::string v);
|
||||||
void SetBody(std::string s);
|
void SetBody(std::string s);
|
||||||
void SetBody(char * buffer, int len);
|
void SetBody(char * buffer, int len);
|
||||||
|
|
|
@ -817,6 +817,20 @@ namespace MP4 {
|
||||||
return (getData()[0] == 0x40);
|
return (getData()[0] == 0x40);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string DCDescriptor::getCodec(){
|
||||||
|
switch(getData()[0]){
|
||||||
|
case 0x40:
|
||||||
|
return "AAC";
|
||||||
|
break;
|
||||||
|
case 0x69:
|
||||||
|
case 0x6B:
|
||||||
|
return "MP3";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return "UNKNOWN";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
std::string DCDescriptor::toPrettyString(uint32_t indent){
|
std::string DCDescriptor::toPrettyString(uint32_t indent){
|
||||||
std::stringstream r;
|
std::stringstream r;
|
||||||
r << std::string(indent, ' ') << "[" << (int)data[0] << "] DecoderConfig Descriptor (" << getDataSize() << ")" << std::endl;
|
r << std::string(indent, ' ') << "[" << (int)data[0] << "] DecoderConfig Descriptor (" << getDataSize() << ")" << std::endl;
|
||||||
|
@ -893,10 +907,10 @@ namespace MP4 {
|
||||||
ESDS::ESDS(std::string init) {
|
ESDS::ESDS(std::string init) {
|
||||||
///\todo Do this better, in a non-hardcoded way.
|
///\todo Do this better, in a non-hardcoded way.
|
||||||
memcpy(data + 4, "esds", 4);
|
memcpy(data + 4, "esds", 4);
|
||||||
reserve(payloadOffset, 0, init.size() ? init.size()+26 : 24);
|
reserve(payloadOffset, 0, init.size() ? init.size()+29 : 26);
|
||||||
unsigned int i = 12;
|
unsigned int i = 12;
|
||||||
data[i++] = 3;//ES_DescrTag
|
data[i++] = 3;//ES_DescrTag
|
||||||
data[i++] = init.size() ? init.size()+20 : 18;//size
|
data[i++] = init.size() ? init.size()+23 : 21;//size
|
||||||
data[i++] = 0;//es_id
|
data[i++] = 0;//es_id
|
||||||
data[i++] = 2;//es_id
|
data[i++] = 2;//es_id
|
||||||
data[i++] = 0;//priority
|
data[i++] = 0;//priority
|
||||||
|
@ -907,7 +921,7 @@ namespace MP4 {
|
||||||
}else{
|
}else{
|
||||||
data[i++] = 0x69;//objType MP3
|
data[i++] = 0x69;//objType MP3
|
||||||
}
|
}
|
||||||
data[i++] = 0x14;//streamType audio (5<<2)
|
data[i++] = 0x15;//streamType audio (5<<2 + 1)
|
||||||
data[i++] = 0;//buffer size
|
data[i++] = 0;//buffer size
|
||||||
data[i++] = 0;//buffer size
|
data[i++] = 0;//buffer size
|
||||||
data[i++] = 0;//buffer size
|
data[i++] = 0;//buffer size
|
||||||
|
@ -923,13 +937,21 @@ namespace MP4 {
|
||||||
data[i++] = 0x5;//DecSpecificInfoTag
|
data[i++] = 0x5;//DecSpecificInfoTag
|
||||||
data[i++] = init.size();
|
data[i++] = init.size();
|
||||||
memcpy(data+i, init.data(), init.size());
|
memcpy(data+i, init.data(), init.size());
|
||||||
|
i += init.size();
|
||||||
}
|
}
|
||||||
|
data[i++] = 6;//SLConfigDescriptor
|
||||||
|
data[i++] = 1;//size
|
||||||
|
data[i++] = 2;//predefined, reserverd for use in MP4 files
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ESDS::isAAC(){
|
bool ESDS::isAAC(){
|
||||||
return getESDescriptor().getDecoderConfig().isAAC();
|
return getESDescriptor().getDecoderConfig().isAAC();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string ESDS::getCodec(){
|
||||||
|
return getESDescriptor().getDecoderConfig().getCodec();
|
||||||
|
}
|
||||||
|
|
||||||
std::string ESDS::getInitData(){
|
std::string ESDS::getInitData(){
|
||||||
return getESDescriptor().getDecoderConfig().getSpecific().toString();
|
return getESDescriptor().getDecoderConfig().getSpecific().toString();
|
||||||
}
|
}
|
||||||
|
@ -2195,6 +2217,7 @@ namespace MP4 {
|
||||||
for (unsigned int i = getEntryCount(); i < no; i++) {
|
for (unsigned int i = getEntryCount(); i < no; i++) {
|
||||||
setInt64(0, 8 + (i * 8));//filling up undefined entries of 64 bits
|
setInt64(0, 8 + (i * 8));//filling up undefined entries of 64 bits
|
||||||
}
|
}
|
||||||
|
setEntryCount(no + 1);
|
||||||
}
|
}
|
||||||
setInt32(newCTTSEntry.sampleCount, 8 + no * 8);
|
setInt32(newCTTSEntry.sampleCount, 8 + no * 8);
|
||||||
setInt32(newCTTSEntry.sampleOffset, 8 + (no * 8) + 4);
|
setInt32(newCTTSEntry.sampleOffset, 8 + (no * 8) + 4);
|
||||||
|
@ -2213,7 +2236,7 @@ namespace MP4 {
|
||||||
|
|
||||||
std::string CTTS::toPrettyString(uint32_t indent) {
|
std::string CTTS::toPrettyString(uint32_t indent) {
|
||||||
std::stringstream r;
|
std::stringstream r;
|
||||||
r << std::string(indent, ' ') << "[stts] Sample Table Box (" << boxedSize() << ")" << std::endl;
|
r << std::string(indent, ' ') << "[ctts] Composition Time To Sample Box (" << boxedSize() << ")" << std::endl;
|
||||||
r << fullBox::toPrettyString(indent);
|
r << fullBox::toPrettyString(indent);
|
||||||
r << std::string(indent + 1, ' ') << "EntryCount: " << getEntryCount() << std::endl;
|
r << std::string(indent + 1, ' ') << "EntryCount: " << getEntryCount() << std::endl;
|
||||||
for (unsigned int i = 0; i < getEntryCount(); i++) {
|
for (unsigned int i = 0; i < getEntryCount(); i++) {
|
||||||
|
|
|
@ -152,6 +152,7 @@ namespace MP4 {
|
||||||
public:
|
public:
|
||||||
DCDescriptor (const char* pointer, const unsigned long length, const bool master = false);
|
DCDescriptor (const char* pointer, const unsigned long length, const bool master = false);
|
||||||
bool isAAC(); ///< Returns true if this track is AAC.
|
bool isAAC(); ///< Returns true if this track is AAC.
|
||||||
|
std::string getCodec();
|
||||||
DSDescriptor getSpecific();
|
DSDescriptor getSpecific();
|
||||||
std::string toPrettyString(uint32_t indent = 0);///< put it into a pretty string
|
std::string toPrettyString(uint32_t indent = 0);///< put it into a pretty string
|
||||||
};
|
};
|
||||||
|
@ -176,6 +177,7 @@ namespace MP4 {
|
||||||
ESDS(std::string init);
|
ESDS(std::string init);
|
||||||
ESDescriptor getESDescriptor();
|
ESDescriptor getESDescriptor();
|
||||||
bool isAAC();
|
bool isAAC();
|
||||||
|
std::string getCodec();
|
||||||
std::string getInitData();
|
std::string getInitData();
|
||||||
std::string toPrettyString(uint32_t indent = 0);
|
std::string toPrettyString(uint32_t indent = 0);
|
||||||
};
|
};
|
||||||
|
|
|
@ -23,12 +23,22 @@ namespace Mist {
|
||||||
capa["methods"][0u]["nolive"] = 1;
|
capa["methods"][0u]["nolive"] = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
long long unsigned OutProgressiveMP4::estimateFileSize(){
|
||||||
|
long long unsigned retVal = 0;
|
||||||
|
for (std::set<unsigned long>::iterator it = selectedTracks.begin(); it != selectedTracks.end(); it++){
|
||||||
|
for (std::deque<unsigned long>::iterator keyIt = myMeta.tracks[*it].keySizes.begin(); keyIt != myMeta.tracks[*it].keySizes.end(); keyIt++){
|
||||||
|
retVal += *keyIt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return retVal * (1 + (double)selectedTracks.size() * 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
std::string OutProgressiveMP4::DTSCMeta2MP4Header(long long & size){
|
std::string OutProgressiveMP4::DTSCMeta2MP4Header(long long & size){
|
||||||
std::stringstream header;
|
std::stringstream header;
|
||||||
//ftyp box
|
//ftyp box
|
||||||
MP4::FTYP ftypBox;
|
MP4::FTYP ftypBox;
|
||||||
header.write(ftypBox.asBox(),ftypBox.boxedSize());
|
header.write(ftypBox.asBox(),ftypBox.boxedSize());
|
||||||
|
bool biggerThan4G = (estimateFileSize() > 0xFFFFFFFFull);
|
||||||
uint64_t mdatSize = 0;
|
uint64_t mdatSize = 0;
|
||||||
//moov box
|
//moov box
|
||||||
MP4::MOOV moovBox;
|
MP4::MOOV moovBox;
|
||||||
|
@ -161,27 +171,63 @@ namespace Mist {
|
||||||
stblBox.setContent(stscBox,offset++);
|
stblBox.setContent(stscBox,offset++);
|
||||||
}//stsc box
|
}//stsc box
|
||||||
{
|
{
|
||||||
|
bool makeCTTS = false;
|
||||||
MP4::STSZ stszBox;
|
MP4::STSZ stszBox;
|
||||||
stszBox.setVersion(0);
|
stszBox.setVersion(0);
|
||||||
if (thisTrack.parts.size()){
|
if (thisTrack.parts.size()){
|
||||||
std::deque<DTSC::Part>::reverse_iterator tmpIt = thisTrack.parts.rbegin();
|
std::deque<DTSC::Part>::reverse_iterator tmpIt = thisTrack.parts.rbegin();
|
||||||
for (unsigned int part = thisTrack.parts.size(); part > 0; --part){
|
for (unsigned int part = thisTrack.parts.size(); part > 0; --part){
|
||||||
unsigned int partSize = tmpIt->getSize();
|
unsigned int partSize = tmpIt->getSize();
|
||||||
tmpIt++;
|
|
||||||
stszBox.setEntrySize(partSize, part-1);//in bytes in file
|
stszBox.setEntrySize(partSize, part-1);//in bytes in file
|
||||||
size += partSize;
|
size += partSize;
|
||||||
|
makeCTTS |= tmpIt->getOffset();
|
||||||
|
tmpIt++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (makeCTTS){
|
||||||
|
MP4::CTTS cttsBox;
|
||||||
|
cttsBox.setVersion(0);
|
||||||
|
if (thisTrack.parts.size()){
|
||||||
|
std::deque<DTSC::Part>::iterator tmpIt = thisTrack.parts.begin();
|
||||||
|
MP4::CTTSEntry tmpEntry;
|
||||||
|
tmpEntry.sampleCount = 1;
|
||||||
|
tmpEntry.sampleOffset = tmpIt->getOffset();
|
||||||
|
unsigned int totalEntries = 0;
|
||||||
|
tmpIt++;
|
||||||
|
while (tmpIt != thisTrack.parts.end()){
|
||||||
|
unsigned int timeOffset = tmpIt->getOffset();
|
||||||
|
if (timeOffset == tmpEntry.sampleOffset){
|
||||||
|
tmpEntry.sampleCount++;
|
||||||
|
}else{
|
||||||
|
cttsBox.setCTTSEntry(tmpEntry, totalEntries++);
|
||||||
|
tmpEntry.sampleCount = 1;
|
||||||
|
tmpEntry.sampleOffset = timeOffset;
|
||||||
|
}
|
||||||
|
tmpIt++;
|
||||||
|
}
|
||||||
|
cttsBox.setCTTSEntry(tmpEntry, totalEntries++);
|
||||||
|
//cttsBox.setEntryCount(totalEntries);
|
||||||
|
}
|
||||||
|
stblBox.setContent(cttsBox,offset++);
|
||||||
|
}//ctts
|
||||||
stblBox.setContent(stszBox,offset++);
|
stblBox.setContent(stszBox,offset++);
|
||||||
}//stsz box
|
}//stsz box
|
||||||
{
|
{
|
||||||
MP4::STCO stcoBox;
|
if (biggerThan4G){
|
||||||
stcoBox.setVersion(1);
|
MP4::CO64 CO64Box;
|
||||||
//Inserting empty values on purpose here, will be fixed later.
|
//Inserting empty values on purpose here, will be fixed later.
|
||||||
if (thisTrack.parts.size() != 0){
|
if (thisTrack.parts.size() != 0){
|
||||||
stcoBox.setChunkOffset(0, thisTrack.parts.size() - 1);//this inserts all empty entries at once
|
CO64Box.setChunkOffset(0, thisTrack.parts.size() - 1);//this inserts all empty entries at once
|
||||||
|
}
|
||||||
|
stblBox.setContent(CO64Box,offset++);
|
||||||
|
}else{
|
||||||
|
MP4::STCO stcoBox;
|
||||||
|
//Inserting empty values on purpose here, will be fixed later.
|
||||||
|
if (thisTrack.parts.size() != 0){
|
||||||
|
stcoBox.setChunkOffset(0, thisTrack.parts.size() - 1);//this inserts all empty entries at once
|
||||||
|
}
|
||||||
|
stblBox.setContent(stcoBox,offset++);
|
||||||
}
|
}
|
||||||
stblBox.setContent(stcoBox,offset++);
|
|
||||||
}//stco box
|
}//stco box
|
||||||
minfBox.setContent(stblBox,minfOffset++);
|
minfBox.setContent(stblBox,minfOffset++);
|
||||||
}//stbl box
|
}//stbl box
|
||||||
|
@ -194,8 +240,9 @@ namespace Mist {
|
||||||
}//for each selected track
|
}//for each selected track
|
||||||
//initial offset length ftyp, length moov + 8
|
//initial offset length ftyp, length moov + 8
|
||||||
unsigned long long int byteOffset = ftypBox.boxedSize() + moovBox.boxedSize() + 8;
|
unsigned long long int byteOffset = ftypBox.boxedSize() + moovBox.boxedSize() + 8;
|
||||||
//update all STCO from the following map;
|
//update all STCO or CO64 from the following maps;
|
||||||
std::map <int, MP4::STCO> checkStcoBoxes;
|
std::map <long unsigned, MP4::STCO> checkStcoBoxes;
|
||||||
|
std::map <long unsigned, MP4::CO64> checkCO64Boxes;
|
||||||
//for all tracks
|
//for all tracks
|
||||||
for (unsigned int i = 1; i < moovBox.getContentCount(); i++){
|
for (unsigned int i = 1; i < moovBox.getContentCount(); i++){
|
||||||
//10 lines to get the STCO box.
|
//10 lines to get the STCO box.
|
||||||
|
@ -229,7 +276,11 @@ namespace Mist {
|
||||||
}
|
}
|
||||||
for (unsigned int j = 0; j < checkStblBox.getContentCount(); j++){
|
for (unsigned int j = 0; j < checkStblBox.getContentCount(); j++){
|
||||||
if (checkStblBox.getContent(j).isType("stco")){
|
if (checkStblBox.getContent(j).isType("stco")){
|
||||||
checkStcoBoxes.insert( std::pair<int, MP4::STCO>(((MP4::TKHD&)checkTkhdBox).getTrackID(), ((MP4::STCO&)checkStblBox.getContent(j)) ));
|
checkStcoBoxes.insert( std::pair<long unsigned, MP4::STCO>(((MP4::TKHD&)checkTkhdBox).getTrackID(), ((MP4::STCO&)checkStblBox.getContent(j)) ));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (checkStblBox.getContent(j).isType("co64")){
|
||||||
|
checkCO64Boxes.insert( std::pair<long unsigned, MP4::CO64>(((MP4::TKHD&)checkTkhdBox).getTrackID(), ((MP4::CO64&)checkStblBox.getContent(j)) ));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -251,7 +302,11 @@ namespace Mist {
|
||||||
while (!sortSet.empty()){
|
while (!sortSet.empty()){
|
||||||
std::set<keyPart>::iterator keyBegin = sortSet.begin();
|
std::set<keyPart>::iterator keyBegin = sortSet.begin();
|
||||||
//setting the right STCO size in the STCO box
|
//setting the right STCO size in the STCO box
|
||||||
checkStcoBoxes[keyBegin->trackID].setChunkOffset(totalByteOffset + byteOffset, keyBegin->index);
|
if (checkCO64Boxes.count(keyBegin->trackID)){
|
||||||
|
checkCO64Boxes[keyBegin->trackID].setChunkOffset(totalByteOffset + byteOffset, keyBegin->index);
|
||||||
|
}else{
|
||||||
|
checkStcoBoxes[keyBegin->trackID].setChunkOffset(totalByteOffset + byteOffset, keyBegin->index);
|
||||||
|
}
|
||||||
totalByteOffset += keyBegin->size;
|
totalByteOffset += keyBegin->size;
|
||||||
//add keyPart to sortSet
|
//add keyPart to sortSet
|
||||||
keyPart temp;
|
keyPart temp;
|
||||||
|
@ -375,7 +430,7 @@ namespace Mist {
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (byteEnd > size-1){byteEnd = size;}
|
if (byteEnd > size - 1){byteEnd = size - 1;}
|
||||||
}else{
|
}else{
|
||||||
byteEnd = size;
|
byteEnd = size;
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,6 +41,8 @@ namespace Mist {
|
||||||
long long currPos;
|
long long currPos;
|
||||||
long long seekPoint;
|
long long seekPoint;
|
||||||
std::set <keyPart> sortSet;//filling sortset for interleaving parts
|
std::set <keyPart> sortSet;//filling sortset for interleaving parts
|
||||||
|
|
||||||
|
long long unsigned estimateFileSize();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue