///\brief Builds a bootstrap for use in HTTP Dynamic streaming. ///\param streamName The name of the stream. ///\param metadata The current metadata, used to generate the index. ///\param fragnum The index of the current fragment ///\return The generated bootstrap. std::string dynamicBootstrap(std::string & streamName, JSON::Value & metadata, int fragnum = 0){ std::string empty; MP4::ASRT asrt; asrt.setUpdate(false); asrt.setVersion(1); //asrt.setQualityEntry(empty, 0); if (metadata.isMember("live")){ asrt.setSegmentRun(1, 4294967295ul, 0); }else{ asrt.setSegmentRun(1, metadata["keytime"].size(), 0); } MP4::AFRT afrt; afrt.setUpdate(false); afrt.setVersion(1); afrt.setTimeScale(1000); //afrt.setQualityEntry(empty, 0); MP4::afrt_runtable afrtrun; if (metadata.isMember("live")){ // restrict data to last 2 fragments, unless an earlier fragment was expressly requested. int count = 0; unsigned int begin = std::max(0u, metadata["keynum"].size() - 3); while (begin > 0 && fragnum && metadata["keynum"][begin].asInt() > fragnum){ begin--; } for (int i = begin; i < metadata["keynum"].size(); i++){ afrtrun.firstFragment = metadata["keynum"][i].asInt(); afrtrun.firstTimestamp = metadata["keytime"][i].asInt(); afrtrun.duration = metadata["keylen"][i].asInt(); afrt.setFragmentRun(afrtrun, count++); } }else{ for (int i = 0; i < metadata["keynum"].size(); i++){ afrtrun.firstFragment = metadata["keynum"][i].asInt(); afrtrun.firstTimestamp = metadata["keytime"][i].asInt(); afrtrun.duration = metadata["keylen"][i].asInt(); afrt.setFragmentRun(afrtrun, i); } } MP4::ABST abst; abst.setVersion(1); abst.setBootstrapinfoVersion(1); abst.setProfile(0); abst.setUpdate(false); abst.setTimeScale(1000); abst.setLive(false); abst.setCurrentMediaTime(metadata["lastms"].asInt()); abst.setSmpteTimeCodeOffset(0); abst.setMovieIdentifier(streamName); abst.setSegmentRunTable(asrt, 0); abst.setFragmentRunTable(afrt, 0); #if DEBUG >= 8 std::cout << "Sending bootstrap:" << std::endl << abst.toPrettyString(0) << std::endl; #endif return std::string((char*)abst.asBox(), (int)abst.boxedSize()); }
///\brief Builds a bootstrap for use in HTTP Dynamic streaming. ///\param tid The track this bootstrap is generated for. ///\return The generated bootstrap. std::string OutHDS::dynamicBootstrap(int tid){ updateMeta(); std::string empty; MP4::ASRT asrt; asrt.setUpdate(false); asrt.setVersion(1); //asrt.setQualityEntry(empty, 0); if (myMeta.live){ asrt.setSegmentRun(1, 4294967295ul, 0); }else{ asrt.setSegmentRun(1, myMeta.tracks[tid].fragments.size(), 0); } MP4::AFRT afrt; afrt.setUpdate(false); afrt.setVersion(1); afrt.setTimeScale(1000); //afrt.setQualityEntry(empty, 0); MP4::afrt_runtable afrtrun; int i = 0; int j = 0; if (myMeta.tracks[tid].fragments.size()){ std::deque<DTSC::Fragment>::iterator fragIt = myMeta.tracks[tid].fragments.begin(); unsigned int firstTime = myMeta.tracks[tid].getKey(fragIt->getNumber()).getTime(); while (fragIt != myMeta.tracks[tid].fragments.end()){ if (myMeta.vod || fragIt->getDuration() > 0){ afrtrun.firstFragment = myMeta.tracks[tid].missedFrags + j + 1; afrtrun.firstTimestamp = myMeta.tracks[tid].getKey(fragIt->getNumber()).getTime() - firstTime; if (fragIt->getDuration() > 0){ afrtrun.duration = fragIt->getDuration(); }else{ afrtrun.duration = myMeta.tracks[tid].lastms - afrtrun.firstTimestamp; } afrt.setFragmentRun(afrtrun, i); ++i; } ++j; ++fragIt; } } MP4::ABST abst; abst.setVersion(1); abst.setBootstrapinfoVersion(1); abst.setProfile(0); abst.setUpdate(false); abst.setTimeScale(1000); abst.setLive(myMeta.live); abst.setCurrentMediaTime(myMeta.tracks[tid].lastms); abst.setSmpteTimeCodeOffset(0); abst.setMovieIdentifier(streamName); abst.setSegmentRunTable(asrt, 0); abst.setFragmentRunTable(afrt, 0); DEBUG_MSG(DLVL_VERYHIGH, "Sending bootstrap: %s", abst.toPrettyString(0).c_str()); return std::string((char*)abst.asBox(), (int)abst.boxedSize()); }
/// Generates a bootstrap equal to the above file, then compares. /// \returns Zero if they are equal (test success), other values otherwise. int main(int argc, char ** argv) { std::string temp; MP4::ASRT asrt; asrt.setVersion(1); asrt.setQualityEntry(temp, 0); asrt.setSegmentRun(1, 199, 0); MP4::AFRT afrt; afrt.setVersion(1); afrt.setTimeScale(1000); afrt.setQualityEntry(temp, 0); MP4::afrt_runtable afrtrun; for (int i = 0; i < 198; i++){ afrtrun.firstFragment = i+1; afrtrun.firstTimestamp = 3000*i; afrtrun.duration = 3000; afrt.setFragmentRun(afrtrun, i); } afrtrun.firstFragment = 199; afrtrun.firstTimestamp = 594000; afrtrun.duration = 2458; afrt.setFragmentRun(afrtrun, 198); MP4::ABST abst; abst.setVersion(1); abst.setBootstrapinfoVersion(1); abst.setProfile(0); abst.setLive(false); abst.setUpdate(false); abst.setTimeScale(1000); abst.setCurrentMediaTime(596458); abst.setSmpteTimeCodeOffset(0); abst.setMovieIdentifier(temp); abst.setServerEntry(temp, 0); abst.setQualityEntry(temp, 0); abst.setDrmData(temp); abst.setMetaData(temp); abst.setSegmentRunTable(asrt, 0); abst.setFragmentRunTable(afrt, 0); if (abst.boxedSize() != __data_len){return 42;} return memcmp(abst.asBox(), __data, __data_len); }