diff --git a/lib/mp4_conv.cpp b/lib/mp4_conv.cpp index 0be96112..20b725d3 100644 --- a/lib/mp4_conv.cpp +++ b/lib/mp4_conv.cpp @@ -2,10 +2,6 @@ #include namespace MP4{ - /*bool keyPartSort(keyPart i, keyPart j){ - return (i.time < j.time); - }*/ - std::string DTSC2MP4Converter::DTSCMeta2MP4Header(DTSC::Meta & metaData){ std::stringstream header; //ftyp box @@ -52,257 +48,228 @@ namespace MP4{ //calculate interleaving //putting all metadata in a huge, auto-sorting vector 'keyParts' + //sort by time on keyframes for interleaving keyParts.clear(); for ( std::map::iterator trackIt = metaData.tracks.begin(); trackIt != metaData.tracks.end(); trackIt ++) { if (trackIt->first>0){ - std::cerr << "preparing track: " << trackIt->first << std::endl; int partItNumber = 0; for ( std::deque< DTSC::Key>::iterator keyIt = trackIt->second.keys.begin(); keyIt != trackIt->second.keys.end(); keyIt ++) { - //if ((*keyIt)->size > 0){ - keyPart temp; - temp.trackID = trackIt->second.trackID; - /* - temp.size = (*keyIt)["size"].asInt(); - temp.time = (*keyIt)["time"].asInt(); - temp.len = (*keyIt)["len"].asInt(); - temp.parts = (*keyIt)["parts"].asString(); - temp.partsize = (*keyIt)["partsize"].asInt(); - */ - temp.time = keyIt->getTime();//timeplaats van keyframe - std::cerr << "time: " << temp.time << std::endl; - temp.len = keyIt->getLength();//duration van keyframe - //std::cerr << "totalparts, partItNumber, getparts:"<< trackIt->second.parts.size() << ", " << partItNumber << ", " << keyIt->getParts() << std::endl; - temp.parts = std::deque (trackIt->second.parts.begin() + partItNumber,trackIt->second.parts.begin() + partItNumber + keyIt->getParts() );//array met bytegrootte van elke aparte part - //calculate total size of parts - int tempSize = 0; - //std::cerr << "keyframe parts: "; - for (unsigned int di = 0; di < temp.parts.size(); di++){ - tempSize += temp.parts[di].getSize(); - //std::cerr << temp.parts[di].getSize() << " "; - } - //std::cerr << std::endl; - temp.size = tempSize;//bytegrootte van keyframe (alle parts bij elkaar) - temp.partsize = keyIt->getParts();//amount of parts in this keyframe - - keyParts.insert(temp); - //} + keyPart temp; + temp.trackID = trackIt->second.trackID; + temp.time = keyIt->getTime();//timeplaats van keyframe + temp.len = keyIt->getLength();//duration van keyframe + temp.parts = std::deque (trackIt->second.parts.begin() + partItNumber,trackIt->second.parts.begin() + partItNumber + keyIt->getParts() );//array met bytegrootte van elke aparte part + //calculate total size of parts + int tempSize = 0; + for (unsigned int di = 0; di < temp.parts.size(); di++){ + tempSize += temp.parts[di].getSize(); + } + temp.size = tempSize;//bytegrootte van keyframe (alle parts bij elkaar) + temp.partsize = keyIt->getParts();//amount of parts in this keyframe + + keyParts.insert(temp); partItNumber += keyIt->getParts(); } } } - //sort by time on keyframes for interleaving - //std::sort(keyParts.begin(), keyParts.end(), keyPartSort); //start arbitrary track addition for header int boxOffset = 1; for ( std::map::iterator it = metaData.tracks.begin(); it != metaData.tracks.end(); it ++) { if (it->first > 0){ - std::cerr << "track " << it->second.trackID << std::endl; - //for (JSON::ObjIter it = metaData["tracks"].ObjBegin(); it != metaData["tracks"].ObjEnd(); it++){ - int timescale = 0; - MP4::TRAK trakBox; - MP4::TKHD tkhdBox; - tkhdBox.setVersion(0); - tkhdBox.setFlags(15); - tkhdBox.setTrackID(it->second.trackID); - ///\TODO duration firstms and lastms fix - tkhdBox.setDuration(it->second.lastms + it->second.firstms); - - if (it->second.type == "video"){ - tkhdBox.setWidth(it->second.width << 16); - tkhdBox.setHeight(it->second.height << 16); - tkhdBox.setVolume(0); - }else{ - tkhdBox.setVolume(256); - tkhdBox.setAlternateGroup(1); - } - tkhdBox.setMatrix(0x00010000,0); - tkhdBox.setMatrix(0,1); - tkhdBox.setMatrix(0,2); - tkhdBox.setMatrix(0,3); - tkhdBox.setMatrix(0x00010000,4); - tkhdBox.setMatrix(0,5); - tkhdBox.setMatrix(0,6); - tkhdBox.setMatrix(0,7); - tkhdBox.setMatrix(0x40000000,8); - trakBox.setContent(tkhdBox, 0); - - MP4::MDIA mdiaBox; - MP4::MDHD mdhdBox(0);/// \todo fix constructor mdhd in lib - mdhdBox.setCreationTime(0); - mdhdBox.setModificationTime(0); - //Calculating media time based on sampledelta. Probably cheating, but it works... - int tmpParts = 0; - for (std::deque< DTSC::Key>::iterator tmpIt = it->second.keys.begin(); tmpIt != it->second.keys.end(); tmpIt ++) { - //for (JSON::ArrIter tmpIt = it->second["keys"].ArrBegin(); tmpIt != it->second["keys"].ArrEnd(); tmpIt++){ - tmpParts += tmpIt->getParts(); - } - timescale = ((double)(42 * tmpParts) / (it->second.lastms + it->second.firstms)) * 1000; - mdhdBox.setTimeScale(timescale); - ///\TODO fix lastms, firstms - mdhdBox.setDuration((it->second.lastms + it->second.firstms) * ((double)timescale / 1000)); - mdiaBox.setContent(mdhdBox, 0); + int timescale = 0; + MP4::TRAK trakBox; + MP4::TKHD tkhdBox; + tkhdBox.setVersion(0); + tkhdBox.setFlags(15); + tkhdBox.setTrackID(it->second.trackID); + ///\TODO duration firstms and lastms fix + tkhdBox.setDuration(it->second.lastms + it->second.firstms); - std::string tmpStr = it->second.type; - MP4::HDLR hdlrBox;/// \todo fix constructor hdlr in lib - if (tmpStr == "video"){ - hdlrBox.setHandlerType(0x76696465);//vide - }else if (tmpStr == "audio"){ - hdlrBox.setHandlerType(0x736F756E);//soun + if (it->second.type == "video"){ + tkhdBox.setWidth(it->second.width << 16); + tkhdBox.setHeight(it->second.height << 16); + tkhdBox.setVolume(0); + }else{ + tkhdBox.setVolume(256); + tkhdBox.setAlternateGroup(1); } - hdlrBox.setName(it->second.getIdentifier()); - mdiaBox.setContent(hdlrBox, 1); + tkhdBox.setMatrix(0x00010000,0); + tkhdBox.setMatrix(0,1); + tkhdBox.setMatrix(0,2); + tkhdBox.setMatrix(0,3); + tkhdBox.setMatrix(0x00010000,4); + tkhdBox.setMatrix(0,5); + tkhdBox.setMatrix(0,6); + tkhdBox.setMatrix(0,7); + tkhdBox.setMatrix(0x40000000,8); + trakBox.setContent(tkhdBox, 0); - MP4::MINF minfBox; - if (tmpStr == "video"){ - MP4::VMHD vmhdBox; - vmhdBox.setFlags(1); - minfBox.setContent(vmhdBox,0); - }else if (tmpStr == "audio"){ - MP4::SMHD smhdBox; - minfBox.setContent(smhdBox,0); + MP4::MDIA mdiaBox; + MP4::MDHD mdhdBox(0);/// \todo fix constructor mdhd in lib + mdhdBox.setCreationTime(0); + mdhdBox.setModificationTime(0); + //Calculating media time based on sampledelta. Probably cheating, but it works... + int tmpParts = 0; + for (std::deque< DTSC::Key>::iterator tmpIt = it->second.keys.begin(); tmpIt != it->second.keys.end(); tmpIt ++) { + tmpParts += tmpIt->getParts(); } - MP4::DINF dinfBox; - MP4::DREF drefBox;/// \todo fix constructor dref in lib - drefBox.setVersion(0); - MP4::URL urlBox; - urlBox.setFlags(1); - drefBox.setDataEntry(urlBox,0); - dinfBox.setContent(drefBox,0); - minfBox.setContent(dinfBox,1); + timescale = ((double)(42 * tmpParts) / (it->second.lastms + it->second.firstms)) * 1000; + mdhdBox.setTimeScale(timescale); + ///\TODO fix lastms, firstms + mdhdBox.setDuration((it->second.lastms + it->second.firstms) * ((double)timescale / 1000)); + mdiaBox.setContent(mdhdBox, 0); - MP4::STBL stblBox; - MP4::STSD stsdBox; - stsdBox.setVersion(0); - if (tmpStr == "video"){//boxname = codec - MP4::VisualSampleEntry vse; - std::string tmpStr2 = it->second.codec; - if (tmpStr2 == "H264"){ - vse.setCodec("avc1"); - } - vse.setDataReferenceIndex(1); - vse.setWidth(it->second.width); - vse.setHeight(it->second.height); - MP4::AVCC avccBox; - avccBox.setPayload(it->second.init); - vse.setCLAP(avccBox); - stsdBox.setEntry(vse,0); - }else if(tmpStr == "audio"){//boxname = codec - MP4::AudioSampleEntry ase; - std::string tmpStr2 = it->second.codec; - if (tmpStr2 == "AAC"){ - ase.setCodec("mp4a"); - ase.setDataReferenceIndex(1); - } - ase.setSampleRate(it->second.rate); - ase.setChannelCount(it->second.channels); - ase.setSampleSize(it->second.size); - MP4::ESDS esdsBox; - esdsBox.setESDescriptorTypeLength(32+it->second.init.size()); - esdsBox.setESID(2); - esdsBox.setStreamPriority(0); - esdsBox.setDecoderConfigDescriptorTypeLength(18+it->second.init.size()); - esdsBox.setByteObjectTypeID(0x40); - esdsBox.setStreamType(5); - esdsBox.setReservedFlag(1); - esdsBox.setBufferSize(1250000); - esdsBox.setMaximumBitRate(10000000); - esdsBox.setAverageBitRate(it->second.bps * 8); - esdsBox.setConfigDescriptorTypeLength(5); - esdsBox.setESHeaderStartCodes(it->second.init); - esdsBox.setSLConfigDescriptorTypeTag(0x6); - esdsBox.setSLConfigExtendedDescriptorTypeTag(0x808080); - esdsBox.setSLDescriptorTypeLength(1); - esdsBox.setSLValue(2); - ase.setCodecBox(esdsBox); - stsdBox.setEntry(ase,0); - } - stblBox.setContent(stsdBox,0); - - /// \todo update following stts lines - MP4::STTS sttsBox;//current version probably causes problems - sttsBox.setVersion(0); - MP4::STTSEntry newEntry; - newEntry.sampleCount = tmpParts; - //42, Used as magic number for timescale calculation - newEntry.sampleDelta = 42; - sttsBox.setSTTSEntry(newEntry, 0); - stblBox.setContent(sttsBox,1); - - if (it->second.type == "video"){ - //STSS Box here - MP4::STSS stssBox; - stssBox.setVersion(0); - int tmpCount = 1; - int tmpItCount = 0; - for ( std::deque< DTSC::Key>::iterator tmpIt = it->second.keys.begin(); tmpIt != it->second.keys.end(); tmpIt ++) { - stssBox.setSampleNumber(tmpCount,tmpItCount); - tmpCount += tmpIt->getParts(); - tmpItCount ++; - } - stblBox.setContent(stssBox,2); + std::string tmpStr = it->second.type; + MP4::HDLR hdlrBox;/// \todo fix constructor hdlr in lib + if (tmpStr == "video"){ + hdlrBox.setHandlerType(0x76696465);//vide + }else if (tmpStr == "audio"){ + hdlrBox.setHandlerType(0x736F756E);//soun + } + hdlrBox.setName(it->second.getIdentifier()); + mdiaBox.setContent(hdlrBox, 1); + + MP4::MINF minfBox; + if (tmpStr == "video"){ + MP4::VMHD vmhdBox; + vmhdBox.setFlags(1); + minfBox.setContent(vmhdBox,0); + }else if (tmpStr == "audio"){ + MP4::SMHD smhdBox; + minfBox.setContent(smhdBox,0); } - - int offset = (it->second.type == "video"); - + MP4::DINF dinfBox; + MP4::DREF drefBox;/// \todo fix constructor dref in lib + drefBox.setVersion(0); + MP4::URL urlBox; + urlBox.setFlags(1); + drefBox.setDataEntry(urlBox,0); + dinfBox.setContent(drefBox,0); + minfBox.setContent(dinfBox,1); - MP4::STSC stscBox; - stscBox.setVersion(0); - uint32_t total = 0; - MP4::STSCEntry stscEntry; - stscEntry.firstChunk = 1; - stscEntry.samplesPerChunk = 1; - stscEntry.sampleDescriptionIndex = 1; - stscBox.setSTSCEntry(stscEntry, 0); - stblBox.setContent(stscBox,2 + offset); - - MP4::STSZ stszBox; - stszBox.setVersion(0); - total = 0; - for (std::deque< DTSC::Part>::iterator partIt = it->second.parts.begin(); partIt != it->second.parts.end(); partIt ++) { - //for (int i = 0; i < it->second["keys"].size(); i++){ - //std::deque parsedParts; - //JSON::decodeVector(it->second["keys"][i]["parts"].asString(), parsedParts); - //for (unsigned int o = 0; o < tmpIt->parts.size(); o++){ - stszBox.setEntrySize(partIt->getSize(), total);//in bytes in file - total++; - } - stblBox.setContent(stszBox,3 + offset); + MP4::STBL stblBox; + MP4::STSD stsdBox; + stsdBox.setVersion(0); + if (tmpStr == "video"){//boxname = codec + MP4::VisualSampleEntry vse; + std::string tmpStr2 = it->second.codec; + if (tmpStr2 == "H264"){ + vse.setCodec("avc1"); + } + vse.setDataReferenceIndex(1); + vse.setWidth(it->second.width); + vse.setHeight(it->second.height); + MP4::AVCC avccBox; + avccBox.setPayload(it->second.init); + vse.setCLAP(avccBox); + stsdBox.setEntry(vse,0); + }else if(tmpStr == "audio"){//boxname = codec + MP4::AudioSampleEntry ase; + std::string tmpStr2 = it->second.codec; + if (tmpStr2 == "AAC"){ + ase.setCodec("mp4a"); + ase.setDataReferenceIndex(1); + } + ase.setSampleRate(it->second.rate); + ase.setChannelCount(it->second.channels); + ase.setSampleSize(it->second.size); + MP4::ESDS esdsBox; + esdsBox.setESDescriptorTypeLength(32+it->second.init.size()); + esdsBox.setESID(2); + esdsBox.setStreamPriority(0); + esdsBox.setDecoderConfigDescriptorTypeLength(18+it->second.init.size()); + esdsBox.setByteObjectTypeID(0x40); + esdsBox.setStreamType(5); + esdsBox.setReservedFlag(1); + esdsBox.setBufferSize(1250000); + esdsBox.setMaximumBitRate(10000000); + esdsBox.setAverageBitRate(it->second.bps * 8); + esdsBox.setConfigDescriptorTypeLength(5); + esdsBox.setESHeaderStartCodes(it->second.init); + esdsBox.setSLConfigDescriptorTypeTag(0x6); + esdsBox.setSLConfigExtendedDescriptorTypeTag(0x808080); + esdsBox.setSLDescriptorTypeLength(1); + esdsBox.setSLValue(2); + ase.setCodecBox(esdsBox); + stsdBox.setEntry(ase,0); + } + stblBox.setContent(stsdBox,0); - MP4::STCO stcoBox; - stcoBox.setVersion(1); - total = 0; - long long unsigned int totalByteOffset = 0; - //Inserting wrong values on purpose here, will be fixed later. - //Current values are actual byte offset without header-sized offset - std::cerr << "pre-totalByteOffset: " << totalByteOffset << std::endl; - for (std::set::iterator i = keyParts.begin(); i != keyParts.end(); i++){//for all keypart size - if(i->trackID == it->second.trackID){//if keypart is of current trackID - //std::deque parsedParts; - //JSON::decodeVector(i->parts, parsedParts); - std::deque onowai = i->parts; - for (unsigned int o = 0; o < onowai.size(); o++){//add all parts to STCO - //for (std::deque::iterator partIt = (*i).parts.begin(); partIt != (*i).parts.end(); partIt++){ - stcoBox.setChunkOffset(totalByteOffset, total); - total++; - totalByteOffset += onowai[o].getSize(); - std::cerr << "small totalByteOffset: " << totalByteOffset << std::endl; - } - }else{ - totalByteOffset += i->size; - std::cerr << "large totalByteOffset: " << totalByteOffset << std::endl; + /// \TODO update following stts lines + MP4::STTS sttsBox;//current version probably causes problems + sttsBox.setVersion(0); + MP4::STTSEntry newEntry; + newEntry.sampleCount = tmpParts; + //42, Used as magic number for timescale calculation + newEntry.sampleDelta = 42; + sttsBox.setSTTSEntry(newEntry, 0); + stblBox.setContent(sttsBox,1); + + if (it->second.type == "video"){ + //STSS Box here + MP4::STSS stssBox; + stssBox.setVersion(0); + int tmpCount = 1; + int tmpItCount = 0; + for ( std::deque< DTSC::Key>::iterator tmpIt = it->second.keys.begin(); tmpIt != it->second.keys.end(); tmpIt ++) { + stssBox.setSampleNumber(tmpCount,tmpItCount); + tmpCount += tmpIt->getParts(); + tmpItCount ++; + } + stblBox.setContent(stssBox,2); } - } - //calculating the offset where the STCO box will be in the main MOOV box - //needed for probable optimise - mdatSize = totalByteOffset; - - stblBox.setContent(stcoBox,4 + offset); - minfBox.setContent(stblBox,2); - mdiaBox.setContent(minfBox, 2); - trakBox.setContent(mdiaBox, 1); - moovBox.setContent(trakBox, boxOffset); - boxOffset++; + + int offset = (it->second.type == "video"); + + + MP4::STSC stscBox; + stscBox.setVersion(0); + uint32_t total = 0; + MP4::STSCEntry stscEntry; + stscEntry.firstChunk = 1; + stscEntry.samplesPerChunk = 1; + stscEntry.sampleDescriptionIndex = 1; + stscBox.setSTSCEntry(stscEntry, 0); + stblBox.setContent(stscBox,2 + offset); + + MP4::STSZ stszBox; + stszBox.setVersion(0); + total = 0; + for (std::deque< DTSC::Part>::iterator partIt = it->second.parts.begin(); partIt != it->second.parts.end(); partIt ++) { + stszBox.setEntrySize(partIt->getSize(), total);//in bytes in file + total++; + } + stblBox.setContent(stszBox,3 + offset); + + MP4::STCO stcoBox; + stcoBox.setVersion(1); + total = 0; + long long unsigned int totalByteOffset = 0; + //Inserting wrong values on purpose here, will be fixed later. + //Current values are actual byte offset without header-sized offset + for (std::set::iterator i = keyParts.begin(); i != keyParts.end(); i++){//for all keypart size + if(i->trackID == it->second.trackID){//if keypart is of current trackID + std::deque tempArr = i->parts; + for (unsigned int o = 0; o < tempArr.size(); o++){//add all parts to STCO + stcoBox.setChunkOffset(totalByteOffset, total); + total++; + totalByteOffset += tempArr[o].getSize(); + } + }else{ + totalByteOffset += i->size; + } + } + //calculating the offset where the STCO box will be in the main MOOV box + //needed for probable optimise + mdatSize = totalByteOffset; + + stblBox.setContent(stcoBox,4 + offset); + minfBox.setContent(stblBox,2); + mdiaBox.setContent(minfBox, 2); + trakBox.setContent(mdiaBox, 1); + moovBox.setContent(trakBox, boxOffset); + boxOffset++; } } //end arbitrary @@ -363,9 +330,7 @@ namespace MP4{ //while there are requested packets in the trackBuffer:... while (!trackBuffer[curKey->trackID].empty()){ //output requested packages - //std::deque onowai = curKey->parts; stringBuffer += trackBuffer[curKey->trackID].front()["data"].asString(); - //std::cerr << "bufDataSize, antDataSize" << trackBuffer[curKey->trackID].front()["data"].asString().size() << ", " << onowai[curPart].getSize() << std::endl; trackBuffer[curKey->trackID].pop_front(); curPart++; if(curPart >= curKey->parts.size()){ @@ -377,8 +342,6 @@ namespace MP4{ if(curKey->trackID == mediaPart["trackid"].asInt()){ //output JSON packet stringBuffer += mediaPart["data"].asStringRef(); - //std::deque onowai = curKey->parts; - //std::cerr << "dataSize, antDataSize" << mediaPart["data"].asStringRef().size() << ", " << onowai[curPart].getSize() << std::endl; curPart++; if(curPart >= curKey->parts.size()){ curPart = 0;