diff --git a/lib/dtscmeta.cpp b/lib/dtscmeta.cpp index 9a69ddd8..e1f62386 100644 --- a/lib/dtscmeta.cpp +++ b/lib/dtscmeta.cpp @@ -1422,10 +1422,10 @@ namespace DTSC { std::string tmp; tmp.reserve(keySizes.size() * 4); for (unsigned int i = 0; i < keySizes.size(); i++){ - tmp += ((char)keySizes[i] >> 24); - tmp += ((char)keySizes[i] >> 16); - tmp += ((char)keySizes[i] >> 8); - tmp += ((char)keySizes[i]); + tmp += (char)(keySizes[i] >> 24); + tmp += (char)(keySizes[i] >> 16); + tmp += (char)(keySizes[i] >> 8); + tmp += (char)(keySizes[i]); } writePointer(p, tmp.data(), tmp.size()); writePointer(p, "\000\005parts\002", 8); @@ -1492,10 +1492,10 @@ namespace DTSC { std::string tmp; tmp.reserve(keySizes.size() * 4); for (unsigned int i = 0; i < keySizes.size(); i++){ - tmp += ((char)keySizes[i] >> 24); - tmp += ((char)keySizes[i] >> 16); - tmp += ((char)keySizes[i] >> 8); - tmp += ((char)keySizes[i]); + tmp += (char)(keySizes[i] >> 24); + tmp += (char)(keySizes[i] >> 16); + tmp += (char)(keySizes[i] >> 8); + tmp += (char)(keySizes[i]); } conn.SendNow(tmp.data(), tmp.size()); conn.SendNow("\000\005parts\002", 8); @@ -1631,10 +1631,10 @@ namespace DTSC { tmp = ""; tmp.reserve(keySizes.size() * 4); for (unsigned int i = 0; i < keySizes.size(); i++){ - tmp += ((char)(keySizes[i] >> 24)); - tmp += ((char)(keySizes[i] >> 16)); - tmp += ((char)(keySizes[i] >> 8)); - tmp += ((char)keySizes[i]); + tmp += (char)((keySizes[i] >> 24)); + tmp += (char)((keySizes[i] >> 16)); + tmp += (char)((keySizes[i] >> 8)); + tmp += (char)(keySizes[i]); } result["keysizes"] = tmp; tmp = ""; diff --git a/lib/http_parser.cpp b/lib/http_parser.cpp index 4ca23b5b..fe61d168 100644 --- a/lib/http_parser.cpp +++ b/lib/http_parser.cpp @@ -309,10 +309,10 @@ void HTTP::Parser::SetHeader(std::string i, std::string 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); char val[23]; //ints are never bigger than 22 chars as decimal - sprintf(val, "%i", v); + sprintf(val, "%lld", v); headers[i] = val; } diff --git a/lib/http_parser.h b/lib/http_parser.h index 0204a045..f3f89e62 100644 --- a/lib/http_parser.h +++ b/lib/http_parser.h @@ -20,7 +20,7 @@ namespace HTTP { std::string GetVar(std::string i); std::string getUrl(); 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 SetBody(std::string s); void SetBody(char * buffer, int len); diff --git a/lib/mp4_generic.cpp b/lib/mp4_generic.cpp index 5dce8443..bf9d4bc3 100644 --- a/lib/mp4_generic.cpp +++ b/lib/mp4_generic.cpp @@ -817,6 +817,20 @@ namespace MP4 { 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::stringstream r; r << std::string(indent, ' ') << "[" << (int)data[0] << "] DecoderConfig Descriptor (" << getDataSize() << ")" << std::endl; @@ -893,10 +907,10 @@ namespace MP4 { ESDS::ESDS(std::string init) { ///\todo Do this better, in a non-hardcoded way. 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; 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++] = 2;//es_id data[i++] = 0;//priority @@ -907,7 +921,7 @@ namespace MP4 { }else{ 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 @@ -923,13 +937,21 @@ namespace MP4 { data[i++] = 0x5;//DecSpecificInfoTag data[i++] = 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(){ return getESDescriptor().getDecoderConfig().isAAC(); } + std::string ESDS::getCodec(){ + return getESDescriptor().getDecoderConfig().getCodec(); + } + std::string ESDS::getInitData(){ return getESDescriptor().getDecoderConfig().getSpecific().toString(); } @@ -2195,6 +2217,7 @@ namespace MP4 { for (unsigned int i = getEntryCount(); i < no; i++) { setInt64(0, 8 + (i * 8));//filling up undefined entries of 64 bits } + setEntryCount(no + 1); } setInt32(newCTTSEntry.sampleCount, 8 + no * 8); setInt32(newCTTSEntry.sampleOffset, 8 + (no * 8) + 4); @@ -2213,7 +2236,7 @@ namespace MP4 { std::string CTTS::toPrettyString(uint32_t indent) { 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 << std::string(indent + 1, ' ') << "EntryCount: " << getEntryCount() << std::endl; for (unsigned int i = 0; i < getEntryCount(); i++) { diff --git a/lib/mp4_generic.h b/lib/mp4_generic.h index 381a12dc..b11cb7e7 100644 --- a/lib/mp4_generic.h +++ b/lib/mp4_generic.h @@ -152,6 +152,7 @@ namespace MP4 { public: DCDescriptor (const char* pointer, const unsigned long length, const bool master = false); bool isAAC(); ///< Returns true if this track is AAC. + std::string getCodec(); DSDescriptor getSpecific(); std::string toPrettyString(uint32_t indent = 0);///< put it into a pretty string }; @@ -176,6 +177,7 @@ namespace MP4 { ESDS(std::string init); ESDescriptor getESDescriptor(); bool isAAC(); + std::string getCodec(); std::string getInitData(); std::string toPrettyString(uint32_t indent = 0); }; diff --git a/src/output/output_progressive_mp4.cpp b/src/output/output_progressive_mp4.cpp index 3a5c6e68..ac2964f2 100644 --- a/src/output/output_progressive_mp4.cpp +++ b/src/output/output_progressive_mp4.cpp @@ -23,12 +23,22 @@ namespace Mist { capa["methods"][0u]["nolive"] = 1; } + long long unsigned OutProgressiveMP4::estimateFileSize(){ + long long unsigned retVal = 0; + for (std::set::iterator it = selectedTracks.begin(); it != selectedTracks.end(); it++){ + for (std::deque::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::stringstream header; //ftyp box MP4::FTYP ftypBox; header.write(ftypBox.asBox(),ftypBox.boxedSize()); - + bool biggerThan4G = (estimateFileSize() > 0xFFFFFFFFull); uint64_t mdatSize = 0; //moov box MP4::MOOV moovBox; @@ -161,27 +171,63 @@ namespace Mist { stblBox.setContent(stscBox,offset++); }//stsc box { + bool makeCTTS = false; MP4::STSZ stszBox; stszBox.setVersion(0); if (thisTrack.parts.size()){ std::deque::reverse_iterator tmpIt = thisTrack.parts.rbegin(); for (unsigned int part = thisTrack.parts.size(); part > 0; --part){ unsigned int partSize = tmpIt->getSize(); - tmpIt++; stszBox.setEntrySize(partSize, part-1);//in bytes in file size += partSize; + makeCTTS |= tmpIt->getOffset(); + tmpIt++; } } + if (makeCTTS){ + MP4::CTTS cttsBox; + cttsBox.setVersion(0); + if (thisTrack.parts.size()){ + std::deque::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++); }//stsz box { - MP4::STCO stcoBox; - stcoBox.setVersion(1); - //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 + if (biggerThan4G){ + MP4::CO64 CO64Box; + //Inserting empty values on purpose here, will be fixed later. + if (thisTrack.parts.size() != 0){ + 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 minfBox.setContent(stblBox,minfOffset++); }//stbl box @@ -194,8 +240,9 @@ namespace Mist { }//for each selected track //initial offset length ftyp, length moov + 8 unsigned long long int byteOffset = ftypBox.boxedSize() + moovBox.boxedSize() + 8; - //update all STCO from the following map; - std::map checkStcoBoxes; + //update all STCO or CO64 from the following maps; + std::map checkStcoBoxes; + std::map checkCO64Boxes; //for all tracks for (unsigned int i = 1; i < moovBox.getContentCount(); i++){ //10 lines to get the STCO box. @@ -229,7 +276,11 @@ namespace Mist { } for (unsigned int j = 0; j < checkStblBox.getContentCount(); j++){ if (checkStblBox.getContent(j).isType("stco")){ - checkStcoBoxes.insert( std::pair(((MP4::TKHD&)checkTkhdBox).getTrackID(), ((MP4::STCO&)checkStblBox.getContent(j)) )); + checkStcoBoxes.insert( std::pair(((MP4::TKHD&)checkTkhdBox).getTrackID(), ((MP4::STCO&)checkStblBox.getContent(j)) )); + break; + } + if (checkStblBox.getContent(j).isType("co64")){ + checkCO64Boxes.insert( std::pair(((MP4::TKHD&)checkTkhdBox).getTrackID(), ((MP4::CO64&)checkStblBox.getContent(j)) )); break; } } @@ -251,7 +302,11 @@ namespace Mist { while (!sortSet.empty()){ std::set::iterator keyBegin = sortSet.begin(); //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; //add keyPart to sortSet keyPart temp; @@ -375,7 +430,7 @@ namespace Mist { } break; } - if (byteEnd > size-1){byteEnd = size;} + if (byteEnd > size - 1){byteEnd = size - 1;} }else{ byteEnd = size; } diff --git a/src/output/output_progressive_mp4.h b/src/output/output_progressive_mp4.h index e40956ac..367dbe15 100644 --- a/src/output/output_progressive_mp4.h +++ b/src/output/output_progressive_mp4.h @@ -41,6 +41,8 @@ namespace Mist { long long currPos; long long seekPoint; std::set sortSet;//filling sortset for interleaving parts + + long long unsigned estimateFileSize(); }; }