From cde42ce36eb6729d700ea0c02cd46e9cfd441c3f Mon Sep 17 00:00:00 2001 From: Thulinma Date: Wed, 27 Nov 2013 15:30:34 +0100 Subject: [PATCH] Metadata upgrades as well as improvements to the buffer in terms of debugging and code maintainability. --- src/analysers/dtsc_analyser.cpp | 97 +------- src/buffer/buffer.cpp | 31 ++- src/buffer/buffer_stream.cpp | 5 +- src/buffer/buffer_user.cpp | 2 +- src/buffer/player.cpp | 18 +- src/connectors/conn_http_dynamic.cpp | 102 ++++---- src/connectors/conn_http_json.cpp | 14 +- src/connectors/conn_http_live.cpp | 113 ++++----- src/connectors/conn_http_progressive_flv.cpp | 26 +- src/connectors/conn_http_progressive_mp3.cpp | 8 +- src/connectors/conn_http_progressive_mp4.cpp | 16 +- src/connectors/conn_http_progressive_ogg.cpp | 16 +- src/connectors/conn_http_smooth.cpp | 228 +++++++++--------- src/connectors/conn_http_srt.cpp | 17 +- src/connectors/conn_raw.cpp | 4 +- src/connectors/conn_rtmp.cpp | 22 +- src/connectors/conn_ts.cpp | 39 ++- src/controller/controller_capabilities.cpp | 4 +- src/converters/dtsc2flv.cpp | 20 +- src/converters/dtsc2mp4.cpp | 5 +- src/converters/dtsc2ogg.cpp | 2 +- src/converters/dtsc2ts.cpp | 16 +- src/converters/dtscfix.cpp | 236 ++----------------- src/converters/dtscmerge.cpp | 8 +- src/info.cpp | 5 +- 25 files changed, 390 insertions(+), 664 deletions(-) diff --git a/src/analysers/dtsc_analyser.cpp b/src/analysers/dtsc_analyser.cpp index 7308495f..9e6e70cd 100644 --- a/src/analysers/dtsc_analyser.cpp +++ b/src/analysers/dtsc_analyser.cpp @@ -17,108 +17,13 @@ namespace Analysers { ///\return The return code of the analyser. int analyseDTSC(Util::Config conf){ DTSC::File F(conf.getString("filename")); - JSON::Value meta = F.getMeta(); - std::cout << meta.toPrettyString() << std::endl; - JSON::Value pack; - - long long unsigned int firstpack = 0; - long long unsigned int nowpack = 0; - long long unsigned int lastaudio = 0; - long long unsigned int lastvideo = 0; - long long unsigned int lastkey = 0; - long long unsigned int totalvideo = 0; - long long unsigned int totalaudio = 0; - long long unsigned int keyframes = 0; - long long unsigned int key_min = 0xffffffff; - long long unsigned int key_max = 0; - long long unsigned int vid_min = 0xffffffff; - long long unsigned int vid_max = 0; - long long unsigned int aud_min = 0xffffffff; - long long unsigned int aud_max = 0; - long long unsigned int bfrm_min = 0xffffffff; - long long unsigned int bfrm_max = 0; - long long unsigned int bps = 0; - - F.getMeta().null(); + std::cout << F.getMeta().toJSON().toPrettyString() << std::endl; F.parseNext(); while (F.getJSON()){ - nowpack = F.getJSON()["time"].asInt(); std::cout << F.getJSON().toPrettyString() << std::endl; - if (firstpack == 0){ - firstpack = nowpack; - } - if (F.getJSON()["datatype"].asString() == "audio"){ - if (lastaudio != 0 && (nowpack - lastaudio) != 0){ - bps = F.getJSON()["data"].asString().size() / (nowpack - lastaudio); - if (bps < aud_min){ - aud_min = bps; - } - if (bps > aud_max){ - aud_max = bps; - } - } - totalaudio += F.getJSON()["data"].asString().size(); - lastaudio = nowpack; - } - if (F.getJSON()["datatype"].asString() == "video"){ - if (lastvideo != 0 && (nowpack - lastvideo) != 0){ - bps = F.getJSON()["data"].asString().size() / (nowpack - lastvideo); - if (bps < vid_min){ - vid_min = bps; - } - if (bps > vid_max){ - vid_max = bps; - } - } - if (F.getJSON()["keyframe"].asInt() != 0){ - if (lastkey != 0){ - bps = nowpack - lastkey; - if (bps < key_min){ - key_min = bps; - } - if (bps > key_max){ - key_max = bps; - } - } - keyframes++; - lastkey = nowpack; - } - if (F.getJSON()["offset"].asInt() != 0){ - bps = F.getJSON()["offset"].asInt(); - if (bps < bfrm_min){ - bfrm_min = bps; - } - if (bps > bfrm_max){ - bfrm_max = bps; - } - } - totalvideo += F.getJSON()["data"].asString().size(); - lastvideo = nowpack; - } F.parseNext(); } - - std::cout << std::endl << "Summary:" << std::endl; - meta["length"] = (long long int)((nowpack - firstpack) / 1000); - if (meta.isMember("audio")){ - meta["audio"]["bps"] = (long long int)(totalaudio / ((lastaudio - firstpack) / 1000)); - std::cout << " Audio: " << meta["audio"]["codec"].asString() << std::endl; - std::cout << " Bitrate: " << meta["audio"]["bps"].asInt() << std::endl; - } - if (meta.isMember("video")){ - meta["video"]["bps"] = (long long int)(totalvideo / ((lastvideo - firstpack) / 1000)); - meta["video"]["keyms"] = (long long int)((lastvideo - firstpack) / keyframes); - if (meta["video"]["keyms"].asInt() - key_min > key_max - meta["video"]["keyms"].asInt()){ - meta["video"]["keyvar"] = (long long int)(meta["video"]["keyms"].asInt() - key_min); - }else{ - meta["video"]["keyvar"] = (long long int)(key_max - meta["video"]["keyms"].asInt()); - } - std::cout << " Video: " << meta["video"]["codec"].asString() << std::endl; - std::cout << " Bitrate: " << meta["video"]["bps"].asInt() << std::endl; - std::cout << " Keyframes: " << meta["video"]["keyms"].asInt() << "~" << meta["video"]["keyvar"].asInt() << std::endl; - std::cout << " B-frames: " << bfrm_min << " - " << bfrm_max << std::endl; - } return 0; } } diff --git a/src/buffer/buffer.cpp b/src/buffer/buffer.cpp index db0e6187..d13e6e40 100644 --- a/src/buffer/buffer.cpp +++ b/src/buffer/buffer.cpp @@ -27,6 +27,9 @@ namespace Buffer { ///\brief A function running in a thread to send all statistics. ///\param empty A null pointer. void handleStats(void * empty){ +#ifdef _TTHREAD_POSIX_ + pthread_setname_np(pthread_self(), "StatsHandler"); +#endif if (empty != 0){ return; } @@ -52,6 +55,9 @@ namespace Buffer { ///\brief A function to handle input data. ///\param conn A socket reference. void handlePushIn(Socket::Connection & conn){ + #ifdef _TTHREAD_POSIX_ + pthread_setname_np(pthread_self(), "Push Input"); + #endif conn.setBlocking(true); while (buffer_running && conn.connected()){ if (conn.spool()){ @@ -70,6 +76,9 @@ namespace Buffer { if (empty != 0){ return; } + #ifdef _TTHREAD_POSIX_ + pthread_setname_np(pthread_self(), "Standard Input"); + #endif long long int timeDiff = 0; //difference between local time and stream time unsigned int lastPacket = 0; //last parsed packet timestamp std::string inBuffer; @@ -105,7 +114,10 @@ namespace Buffer { user * usr = (user*)v_usr; thisStream->addUser(usr); #if DEBUG >= 5 - std::cerr << "Thread launched for user " << usr->MyStr << ", socket number " << usr->S.getSocket() << std::endl; + std::cerr << "Thread launched for user " << usr->sID << ", socket number " << usr->S.getSocket() << std::endl; +#endif +#ifdef _TTHREAD_POSIX_ + pthread_setname_np(pthread_self(), usr->sID.c_str()); #endif usr->myRing = thisStream->getRing(); thisStream->sendMeta(usr->S); @@ -122,10 +134,10 @@ namespace Buffer { if (usr->myRing->playCount < 1 || usr->playUntil <= Stream::get()->getPacket(usr->myRing->b)["time"].asInt()){ usr->myRing->playCount = 0; JSON::Value pausemark; - pausemark["datatype"] = "pause_marker"; + pausemark["trackid"] = 0ll; + pausemark["mark"] = "pause"; pausemark["time"] = Stream::get()->getPacket(usr->myRing->b)["time"].asInt(); - pausemark.toPacked(); - usr->S.SendNow(pausemark.toNetPacked()); + pausemark.sendTo(usr->S); } } } @@ -144,10 +156,10 @@ namespace Buffer { if (usr->myRing->playCount < 1 || usr->playUntil <= Stream::get()->getPacket(usr->myRing->b)["time"].asInt()){ usr->myRing->playCount = 0; JSON::Value pausemark; - pausemark["datatype"] = "pause_marker"; + pausemark["trackid"] = 0ll; + pausemark["mark"] = "pause"; pausemark["time"] = Stream::get()->getPacket(usr->myRing->b)["time"].asInt(); - pausemark.toPacked(); - usr->S.SendNow(pausemark.toNetPacked()); + pausemark.sendTo(usr->S); } } } @@ -275,6 +287,9 @@ namespace Buffer { } SS.setBlocking(false); conf.activate(); + #ifdef _TTHREAD_POSIX_ + pthread_setname_np(pthread_self(), "Main accepter"); + #endif thisStream = Stream::get(); thisStream->setName(name); thisStream->setBufferTime(conf.getInteger("time")); @@ -299,7 +314,7 @@ namespace Buffer { //starts a thread for every accepted connection incoming = SS.accept(true); if (incoming.connected()){ - tthread::thread thisUser(handleUser, (void *)new user(incoming, userId++)); + tthread::thread thisUser(handleUser, (void *)new user(incoming, ++userId)); thisUser.detach(); }else{ Util::sleep(50);//sleep 50ms diff --git a/src/buffer/buffer_stream.cpp b/src/buffer/buffer_stream.cpp index 944357ec..87e5d778 100644 --- a/src/buffer/buffer_stream.cpp +++ b/src/buffer/buffer_stream.cpp @@ -17,8 +17,7 @@ namespace Buffer { creator.lock(); if (ref == 0){ ref = new Stream(); - ref->metadata["tracks"] = 1ll; - ref->metadata["live"] = 1ll; + ref->metadata.live = true; } creator.unlock(); } @@ -194,7 +193,7 @@ namespace Buffer { void Stream::sendMeta(Socket::Connection & s){ if (metadata){ rw_mutex.lock(); - metadata.sendTo(s); + metadata.send(s); rw_mutex.unlock(); } } diff --git a/src/buffer/buffer_user.cpp b/src/buffer/buffer_user.cpp index f8dad153..cf98119a 100644 --- a/src/buffer/buffer_user.cpp +++ b/src/buffer/buffer_user.cpp @@ -11,7 +11,7 @@ namespace Buffer { ///Also prints "User connected" text to stdout. ///\param fd A connection to the user. user::user(Socket::Connection fd, long long ID){ - sID = JSON::Value(ID).asStringRef(); + sID = JSON::Value(ID).asString(); S = fd; curr_up = 0; curr_down = 0; diff --git a/src/buffer/player.cpp b/src/buffer/player.cpp index 9f7d50d7..48543cdf 100644 --- a/src/buffer/player.cpp +++ b/src/buffer/player.cpp @@ -81,15 +81,17 @@ int main(int argc, char** argv){ Socket::Connection in_out = Socket::Connection(fileno(stdout), fileno(stdin)); DTSC::File source = DTSC::File(conf.getString("filename")); - in_out.SendNow(source.getMeta().toNetPacked()); - if ( !DTSC::isFixed(source.getMeta())){ + if ( !source.getMeta().isFixed()){ std::cerr << "Encountered a non-fixed file." << std::endl; return 1; } - + + source.getMeta().send(in_out); + JSON::Value pausemark; - pausemark["datatype"] = "pause_marker"; + pausemark["trackid"] = 0ll; + pausemark["mark"] = "pause"; pausemark["time"] = (long long int)0; Socket::Connection StatsSocket = Socket::Connection(Util::getTmpFolder() + "statistics", true); @@ -140,11 +142,12 @@ int main(int argc, char** argv){ json_sts["vod"]["now"] = Util::epoch(); json_sts["vod"]["start"] = Util::epoch() - sts.conntime; if ( !meta_sent){ - json_sts["vod"]["meta"] = source.getMeta(); + json_sts["vod"]["meta"] = source.getMeta().toJSON(); json_sts["vod"]["meta"]["is_fixed"] = 1; for (JSON::ObjIter oIt = json_sts["vod"]["meta"]["tracks"].ObjBegin(); oIt != json_sts["vod"]["meta"]["tracks"].ObjEnd(); oIt++){ oIt->second.removeMember("keys"); - oIt->second.removeMember("frags"); + oIt->second.removeMember("fragments"); + oIt->second.removeMember("parts"); } meta_sent = true; } @@ -237,8 +240,7 @@ int main(int argc, char** argv){ std::cerr << "Completed VoD request in MistPlayer (" << (Util::getMS() - bench) << "ms)" << std::endl; #endif pausemark["time"] = source.getJSON()["time"]; - pausemark.netPrepare(); - in_out.SendNow(pausemark.toNetPacked()); + pausemark.sendTo(in_out); in_out.setBlocking(true); }else{ lasttime = Util::epoch(); diff --git a/src/connectors/conn_http_dynamic.cpp b/src/connectors/conn_http_dynamic.cpp index d8cf6726..3cc173e4 100644 --- a/src/connectors/conn_http_dynamic.cpp +++ b/src/connectors/conn_http_dynamic.cpp @@ -27,16 +27,16 @@ /// Holds everything unique to HTTP Connectors. namespace Connector_HTTP { - std::set videoTracks;///<< Holds valid video tracks for playback + std::set videoTracks;///<< Holds valid video tracks for playback long long int audioTrack = 0;///<< Holds audio track ID for playback - void getTracks(JSON::Value & metadata){ + void getTracks(DTSC::Meta & metadata){ videoTracks.clear(); - for (JSON::ObjIter it = metadata["tracks"].ObjBegin(); it != metadata["tracks"].ObjEnd(); it++){ - if (it->second["type"] == "video"){ + for (std::map::iterator it = metadata.tracks.begin(); it != metadata.tracks.end(); it++){ + if (it->second.type == "video"){ videoTracks.insert(it->first); } - if (it->second["type"] == "audio"){ - audioTrack = it->second["trackid"].asInt(); + if (it->second.type == "audio"){ + audioTrack = it->first; } } } @@ -47,7 +47,7 @@ namespace Connector_HTTP { ///\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, bool isLive = false, int fragnum = 0){ + std::string dynamicBootstrap(std::string & streamName, DTSC::Track & trackMeta, bool isLive = false, int fragnum = 0){ std::string empty; MP4::ASRT asrt; @@ -57,7 +57,7 @@ namespace Connector_HTTP { if (isLive){ asrt.setSegmentRun(1, 4294967295ul, 0); }else{ - asrt.setSegmentRun(1, metadata["keys"].size(), 0); + asrt.setSegmentRun(1, trackMeta.keys.size(), 0); } MP4::AFRT afrt; @@ -66,14 +66,14 @@ namespace Connector_HTTP { afrt.setTimeScale(1000); //afrt.setQualityEntry(empty, 0); MP4::afrt_runtable afrtrun; - long long int currTime = 0; - for (int i = 0; i < metadata["keys"].size(); i++){ - if (metadata["keys"][i]["len"].asInt() > 0){ - afrtrun.firstFragment = metadata["keys"][i]["num"].asInt(); - afrtrun.firstTimestamp = metadata["keys"][i]["time"].asInt(); - afrtrun.duration = metadata["keys"][i]["len"].asInt(); - currTime = afrtrun.firstTimestamp + afrtrun.duration; + int i = 0; + for (std::deque::iterator it = trackMeta.keys.begin(); it != trackMeta.keys.end(); it++){ + if (it->getLength()){ + afrtrun.firstFragment = it->getNumber(); + afrtrun.firstTimestamp = it->getTime(); + afrtrun.duration = it->getLength(); afrt.setFragmentRun(afrtrun, i); + i++; } } @@ -84,7 +84,7 @@ namespace Connector_HTTP { abst.setUpdate(false); abst.setTimeScale(1000); abst.setLive(isLive); - abst.setCurrentMediaTime(metadata["lastms"].asInt()); + abst.setCurrentMediaTime(trackMeta.lastms); abst.setSmpteTimeCodeOffset(0); abst.setMovieIdentifier(streamName); abst.setSegmentRunTable(asrt, 0); @@ -100,7 +100,7 @@ namespace Connector_HTTP { ///\param streamName The name of the stream. ///\param metadata The current metadata, used to generate the index. ///\return The index file for HTTP Dynamic Streaming. - std::string dynamicIndex(std::string & streamName, JSON::Value & metadata){ + std::string dynamicIndex(std::string & streamName, DTSC::Meta & metadata){ if ( !audioTrack){getTracks(metadata);} std::stringstream Result; Result << "" << std::endl; @@ -108,27 +108,27 @@ namespace Connector_HTTP { Result << " " << streamName << "" << std::endl; Result << " video/mp4" << std::endl; Result << " streaming" << std::endl; - if (metadata.isMember("vod")){ - Result << " " << metadata["length"].asInt() << ".000" << std::endl; + if (metadata.vod){ + Result << " " << metadata.tracks[*videoTracks.begin()].lastms / 1000 << ".000" << std::endl; Result << " recorded" << std::endl; }else{ Result << " 0.00" << std::endl; Result << " live" << std::endl; } - for (std::set::iterator it = videoTracks.begin(); it != videoTracks.end(); it++){ + for (std::set::iterator it = videoTracks.begin(); it != videoTracks.end(); it++){ Result << " " + "id=\"boot" << (*it) << "\" " + "url=\"" << (*it) << ".abst\">" "" << std::endl; } - for (std::set::iterator it = videoTracks.begin(); it != videoTracks.end(); it++){ + for (std::set::iterator it = videoTracks.begin(); it != videoTracks.end(); it++){ Result << " " << std::endl; + "url=\"" << (*it) << "-\" " + "bitrate=\"" << metadata.tracks[(*it)].bps * 8 << "\" " + "bootstrapInfoId=\"boot" << (*it) << "\" " + "width=\"" << metadata.tracks[(*it)].width << "\" " + "height=\"" << metadata.tracks[(*it)].height << "\">" << std::endl; Result << " AgAKb25NZXRhRGF0YQMAAAk=" << std::endl; Result << " " << std::endl; } @@ -183,7 +183,7 @@ namespace Connector_HTTP { std::string streamID = HTTP_R.url.substr(streamname.size() + 10); streamID = streamID.substr(0, streamID.find(".abst")); HTTP_S.Clean(); - HTTP_S.SetBody(dynamicBootstrap(streamname, Strm.getTrackById(atoll(streamID.c_str())),Strm.metadata.isMember("live"))); + HTTP_S.SetBody(dynamicBootstrap(streamname, Strm.metadata.tracks[atoll(streamID.c_str())], Strm.metadata.live)); HTTP_S.SetHeader("Content-Type", "binary/octet"); HTTP_S.SetHeader("Cache-Control", "no-cache"); HTTP_S.SendResponse("200", "OK", conn); @@ -202,32 +202,30 @@ namespace Connector_HTTP { printf("Video track %d, segment %d, fragment %d\n", Quality, Segment, ReqFragment); #endif if (!audioTrack){getTracks(Strm.metadata);} - JSON::Value & vidTrack = Strm.getTrackById(Quality); + DTSC::Track & vidTrack = Strm.metadata.tracks[Quality]; mstime = 0; mslen = 0; - if (vidTrack.isMember("keys")){ - for (JSON::ArrIter it = vidTrack["keys"].ArrBegin(); it != vidTrack["keys"].ArrEnd(); it++){ - if ((*it)["num"].asInt() >= ReqFragment){ - mstime = (*it)["time"].asInt(); - mslen = (*it)["len"].asInt(); - if (Strm.metadata.isMember("live")){ - if (it == vidTrack["keys"].ArrEnd() - 2){ - HTTP_S.Clean(); - HTTP_S.SetBody("Proxy, re-request this in a second or two.\n"); - HTTP_S.SendResponse("208", "Ask again later", conn); - HTTP_R.Clean(); //clean for any possible next requests - std::cout << "Fragment after fragment " << ReqFragment << " not available yet" << std::endl; - if (ss.spool()){ - while (Strm.parsePacket(ss.Received())){} - } + for (std::deque::iterator it = vidTrack.keys.begin(); it != vidTrack.keys.end(); it++){ + if (it->getNumber() >= ReqFragment){ + mstime = it->getTime(); + mslen = it->getLength(); + if (Strm.metadata.live){ + if (it == vidTrack.keys.end() - 2){ + HTTP_S.Clean(); + HTTP_S.SetBody("Proxy, re-request this in a second or two.\n"); + HTTP_S.SendResponse("208", "Ask again later", conn); + HTTP_R.Clean(); //clean for any possible next requests + std::cout << "Fragment after fragment " << ReqFragment << " not available yet" << std::endl; + if (ss.spool()){ + while (Strm.parsePacket(ss.Received())){} } } - break; } + break; } } if (HTTP_R.url == "/"){continue;}//Don't continue, but continue instead. - if (Strm.metadata.isMember("live")){ + if (Strm.metadata.live){ if (mstime == 0 && ReqFragment > 1){ HTTP_S.Clean(); HTTP_S.SetBody("The requested fragment is no longer kept in memory on the server and cannot be served.\n"); @@ -245,18 +243,18 @@ namespace Connector_HTTP { HTTP_S.SetHeader("Content-Type", "video/mp4"); HTTP_S.StartResponse(HTTP_R, conn); //send the bootstrap - std::string bootstrap = dynamicBootstrap(streamname, Strm.getTrackById(Quality), Strm.metadata.isMember("live"), ReqFragment); + std::string bootstrap = dynamicBootstrap(streamname, Strm.metadata.tracks[Quality], Strm.metadata.live, ReqFragment); HTTP_S.Chunkify(bootstrap, conn); //send a zero-size mdat, meaning it stretches until end of file. HTTP_S.Chunkify("\000\000\000\000mdat", 8, conn); //send init data, if needed. - if (audioTrack > 0 && Strm.getTrackById(audioTrack).isMember("init")){ - tmp.DTSCAudioInit(Strm.getTrackById(audioTrack)); + if (audioTrack > 0){ + tmp.DTSCAudioInit(Strm.metadata.tracks[audioTrack]); tmp.tagTime(mstime); HTTP_S.Chunkify(tmp.data, tmp.len, conn); } - if (Quality > 0 && Strm.getTrackById(Quality).isMember("init")){ - tmp.DTSCVideoInit(Strm.getTrackById(Quality)); + if (Quality > 0){ + tmp.DTSCVideoInit(Strm.metadata.tracks[Quality]); tmp.tagTime(mstime); HTTP_S.Chunkify(tmp.data, tmp.len, conn); } diff --git a/src/connectors/conn_http_json.cpp b/src/connectors/conn_http_json.cpp index 1342aef1..8dd7bf05 100644 --- a/src/connectors/conn_http_json.cpp +++ b/src/connectors/conn_http_json.cpp @@ -121,12 +121,14 @@ namespace Connector_HTTP { std::stringstream cmd; cmd << "t"; - if (Strm.metadata["tracks"].size()){ - for (JSON::ObjIter objIt = Strm.metadata["tracks"].ObjBegin(); objIt != Strm.metadata["tracks"].ObjEnd(); objIt++){ - if ( objIt->second["type"].asStringRef() == "meta" ){ - cmd << " " << objIt->second["trackid"].asInt(); + int tid = -1; + for (std::map::iterator it = Strm.metadata.tracks.begin(); it != Strm.metadata.tracks.end(); it++){ + if (it->second.type == "meta" ){ + if (tid == -1){ + tid = it->second.trackID; } - } + cmd << " " << it->second.trackID; + } } if( cmd.str() == "t" ){ @@ -134,7 +136,7 @@ namespace Connector_HTTP { cmd.clear(); } - int maxTime = Strm.metadata["lastms"].asInt(); + int maxTime = Strm.metadata.tracks[tid].lastms; cmd << "\ns " << seek_sec << "\np " << maxTime << "\n"; ss.SendNow(cmd.str().c_str(), cmd.str().size()); diff --git a/src/connectors/conn_http_live.cpp b/src/connectors/conn_http_live.cpp index 2949d716..9c826b9f 100644 --- a/src/connectors/conn_http_live.cpp +++ b/src/connectors/conn_http_live.cpp @@ -28,62 +28,65 @@ namespace Connector_HTTP { ///\brief Builds an index file for HTTP Live streaming. ///\param metadata The current metadata, used to generate the index. ///\return The index file for HTTP Live Streaming. - std::string liveIndex(JSON::Value & metadata, bool isLive){ + std::string liveIndex(DTSC::Meta & metadata, bool isLive){ std::stringstream result; - if (metadata.isMember("tracks")){ - result << "#EXTM3U\r\n"; - int audioId = -1; - std::string audioName; - bool defAudio = false;//set default audio track; - for (JSON::ObjIter trackIt = metadata["tracks"].ObjBegin(); trackIt != metadata["tracks"].ObjEnd(); trackIt++){ - if (trackIt->second["type"].asStringRef() == "audio"){ - audioId = trackIt->second["trackid"].asInt(); - audioName = trackIt->first; - break; - } + result << "#EXTM3U\r\n"; + int audioId = -1; + std::string audioName; + bool defAudio = false;//set default audio track; + for (std::map::iterator it = metadata.tracks.begin(); it != metadata.tracks.end(); it++){ + if (it->second.type == "audio"){ + audioId = it->first; + audioName = it->second.getIdentifier(); + break; } - for (JSON::ObjIter trackIt = metadata["tracks"].ObjBegin(); trackIt != metadata["tracks"].ObjEnd(); trackIt++){ - if (trackIt->second["type"].asStringRef() == "video"){ - int bWidth = trackIt->second["maxbps"].asInt(); - if (audioId != -1){ - bWidth += (metadata["tracks"][audioName]["maxbps"].asInt() * 2); - } - result << "#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=" << bWidth * 10 << "\r\n"; - result << trackIt->second["trackid"].asInt(); - if (audioId != -1){ - result << "_" << audioId; - } - result << "/index.m3u8\r\n"; + } + for (std::map::iterator it = metadata.tracks.begin(); it != metadata.tracks.end(); it++){ + if (it->second.type == "video"){ + int bWidth = it->second.bps * 2; + if (audioId != -1){ + bWidth += metadata.tracks[audioId].bps * 2; } - } - }else{ - //parse single track - int longestFragment = 0; - for (JSON::ArrIter ai = metadata["frags"].ArrBegin(); ai != metadata["frags"].ArrEnd(); ai++){ - if ((*ai)["dur"].asInt() > longestFragment){ - longestFragment = (*ai)["dur"].asInt(); + result << "#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=" << bWidth * 10 << "\r\n"; + result << it->first; + if (audioId != -1){ + result << "_" << audioId; } + result << "/index.m3u8\r\n"; } - result << "#EXTM3U\r\n" - "#EXT-X-TARGETDURATION:" << (longestFragment / 1000) + 1 << "\r\n" - "#EXT-X-MEDIA-SEQUENCE:" << metadata["missed_frags"].asInt() << "\r\n"; - for (JSON::ArrIter ai = metadata["frags"].ArrBegin(); ai != metadata["frags"].ArrEnd(); ai++){ - long long int starttime = 0; - JSON::ArrIter fi = metadata["keys"].ArrBegin(); - while (fi != metadata["keys"].ArrEnd() && (*fi)["num"].asInt() < (*ai)["num"].asInt()){ - fi++; - } - if (fi != metadata["keys"].ArrEnd()){ - starttime = (*fi)["time"].asInt(); - } - - result << "#EXTINF:" << (((*ai)["dur"].asInt() + 500) / 1000) << ", no desc\r\n" - << starttime << "_" << (*ai)["dur"].asInt() + starttime << ".ts\r\n"; - } - if ( !isLive){ - result << "#EXT-X-ENDLIST\r\n"; + } +#if DEBUG >= 8 + std::cerr << "Sending this index:" << std::endl << Result.str() << std::endl; +#endif + return result.str(); + } + + std::string liveIndex(DTSC::Track & metadata, bool isLive){ + std::stringstream result; + //parse single track + int longestFragment = 0; + for (std::deque::iterator it = metadata.fragments.begin(); (it + 1) != metadata.fragments.end(); it++){ + if (it->getDuration() > longestFragment){ + longestFragment = it->getDuration(); } } + result << "#EXTM3U\r\n" + "#EXT-X-TARGETDURATION:" << (longestFragment / 1000) + 1 << "\r\n" + "#EXT-X-MEDIA-SEQUENCE:" << metadata.missedFrags << "\r\n"; + for (std::deque::iterator it = metadata.fragments.begin(); it != metadata.fragments.end(); it++){ + long long int starttime = metadata.getKey(it->getNumber()).getTime(); + + if (it != (metadata.fragments.end() - 1)){ + result << "#EXTINF:" << ((it->getDuration() + 500) / 1000) << ", no desc\r\n" + << starttime << "_" << it->getDuration() + starttime << ".ts\r\n"; + }else{ + result << "#EXTINF:" << ((metadata.lastms - starttime + 500) / 1000) << ", no desc\r\n" + << starttime << "_" << metadata.lastms << ".ts\r\n"; + } + } + if ( !isLive){ + result << "#EXT-X-ENDLIST\r\n"; + } #if DEBUG >= 8 std::cerr << "Sending this index:" << std::endl << Result.str() << std::endl; #endif @@ -161,7 +164,7 @@ namespace Connector_HTTP { lastVid = Segment * 90; temp = HTTP_R.url.find("_", temp) + 1; int frameCount = atoi(HTTP_R.url.substr(temp, HTTP_R.url.find(".ts", temp) - temp).c_str()); - if (Strm.metadata.isMember("live")){ + if (Strm.metadata.live){ int seekable = Strm.canSeekms(Segment); if (seekable < 0){ HTTP_S.Clean(); @@ -207,10 +210,10 @@ namespace Connector_HTTP { HTTP_S.SetHeader("Cache-Control", "no-cache"); std::string manifest; if (request.find("/") == std::string::npos){ - manifest = liveIndex(Strm.metadata, Strm.metadata.isMember("live")); + manifest = liveIndex(Strm.metadata, Strm.metadata.live); }else{ int selectId = atoi(request.substr(0,request.find("/")).c_str()); - manifest = liveIndex(Strm.getTrackById(selectId), Strm.metadata.isMember("live")); + manifest = liveIndex(Strm.metadata.tracks[selectId], Strm.metadata.live); } HTTP_S.SetBody(manifest); conn.SendNow(HTTP_S.BuildResponse("200", "OK")); @@ -235,7 +238,7 @@ namespace Connector_HTTP { handlingRequest = false; } if ( !haveAvcc){ - avccbox.setPayload(Strm.getTrackById(trackID)["init"].asString()); + avccbox.setPayload(Strm.metadata.tracks[trackID].init); haveAvcc = true; } if (Strm.lastType() == DTSC::VIDEO || Strm.lastType() == DTSC::AUDIO){ @@ -269,10 +272,10 @@ namespace Connector_HTTP { } } ToPack.prepend(TS::Packet::getPESVideoLeadIn(0ul, Strm.getPacket()["time"].asInt() * 90)); - PIDno = 0x100 - 1 + Strm.getPacket()["trackid"].asInt(); + PIDno = 0x100 - 1 + Strm.getPacket()["trackid"].asInt(); ContCounter = &VideoCounter; }else if (Strm.lastType() == DTSC::AUDIO){ - ToPack.append(TS::GetAudioHeader(Strm.lastData().size(), Strm.getTrackById(audioTrackID)["init"].asString())); + ToPack.append(TS::GetAudioHeader(Strm.lastData().size(), Strm.metadata.tracks[audioTrackID].init)); ToPack.append(Strm.lastData()); if (AppleCompat){ ToPack.prepend(TS::Packet::getPESAudioLeadIn(ToPack.bytes(1073741824ul), lastVid)); diff --git a/src/connectors/conn_http_progressive_flv.cpp b/src/connectors/conn_http_progressive_flv.cpp index 2c20c4ff..a4a8f5a9 100644 --- a/src/connectors/conn_http_progressive_flv.cpp +++ b/src/connectors/conn_http_progressive_flv.cpp @@ -101,19 +101,19 @@ namespace Connector_HTTP { } Strm.waitForMeta(ss); int byterate = 0; - for (JSON::ObjIter objIt = Strm.metadata["tracks"].ObjBegin(); objIt != Strm.metadata["tracks"].ObjEnd(); objIt++){ - if (videoID == -1 && objIt->second["type"].asString() == "video"){ - videoID = objIt->second["trackid"].asInt(); + for (std::map::iterator it = Strm.metadata.tracks.begin(); it != Strm.metadata.tracks.end(); it++){ + if (videoID == -1 && it->second.type == "video"){ + videoID = it->second.trackID; } - if (audioID == -1 && objIt->second["type"].asString() == "audio"){ - audioID = objIt->second["trackid"].asInt(); + if (audioID == -1 && it->second.type == "audio"){ + audioID = it->second.trackID; } } if (videoID != -1){ - byterate += Strm.getTrackById(videoID)["bps"].asInt(); + byterate += Strm.metadata.tracks[videoID].bps; } if (audioID != -1){ - byterate += Strm.getTrackById(audioID)["bps"].asInt(); + byterate += Strm.metadata.tracks[audioID].bps; } if ( !byterate){byterate = 1;} if (seek_byte){ @@ -146,16 +146,16 @@ namespace Connector_HTTP { conn.SendNow(HTTP_S.BuildResponse("200", "OK")); //no SetBody = unknown length - this is intentional, we will stream the entire file conn.SendNow(FLV::Header, 13); //write FLV header //write metadata - tag.DTSCMetaInit(Strm, Strm.getTrackById(videoID), Strm.getTrackById(audioID)); + tag.DTSCMetaInit(Strm, Strm.metadata.tracks[videoID], Strm.metadata.tracks[audioID]); conn.SendNow(tag.data, tag.len); //write video init data, if needed - if (videoID != -1 && Strm.getTrackById(videoID).isMember("init")){ - tag.DTSCVideoInit(Strm.getTrackById(videoID)); + if (videoID != -1){ + tag.DTSCVideoInit(Strm.metadata.tracks[videoID]); conn.SendNow(tag.data, tag.len); } //write audio init data, if needed - if (audioID != -1 && Strm.getTrackById(audioID).isMember("init")){ - tag.DTSCAudioInit(Strm.getTrackById(audioID)); + if (audioID != -1){ + tag.DTSCAudioInit(Strm.metadata.tracks[audioID]); conn.SendNow(tag.data, tag.len); } progressive_has_sent_header = true; @@ -170,7 +170,7 @@ namespace Connector_HTTP { conn.close(); } if (Strm.lastType() == DTSC::AUDIO || Strm.lastType() == DTSC::VIDEO){ - std::string codec = Strm.getTrackById(Strm.getPacket()["trackid"].asInt())["codec"].asString(); + std::string codec = Strm.metadata.tracks[Strm.getPacket()["trackid"].asInt()].codec; if (codec == "AAC" || codec == "MP3" || codec == "H264" || codec == "H263" || codec == "VP6"){ tag.DTSCLoader(Strm); conn.SendNow(tag.data, tag.len); //write the tag contents diff --git a/src/connectors/conn_http_progressive_mp3.cpp b/src/connectors/conn_http_progressive_mp3.cpp index 7159dc75..2cbef1df 100644 --- a/src/connectors/conn_http_progressive_mp3.cpp +++ b/src/connectors/conn_http_progressive_mp3.cpp @@ -96,13 +96,13 @@ namespace Connector_HTTP { } Strm.waitForMeta(ss); int byterate = 0; - for (JSON::ObjIter objIt = Strm.metadata["tracks"].ObjBegin(); objIt != Strm.metadata["tracks"].ObjEnd(); objIt++){ - if (audioID == -1 && objIt->second["codec"].asString() == "MP3"){ - audioID = objIt->second["trackid"].asInt(); + for (std::map::iterator it = Strm.metadata.tracks.begin(); it != Strm.metadata.tracks.end(); it++){ + if (audioID == -1 && it->second.codec == "MP3"){ + audioID = it->second.trackID; } } if (audioID != -1){ - byterate += Strm.getTrackById(audioID)["bps"].asInt(); + byterate += Strm.metadata.tracks[audioID].bps; } if ( !byterate){byterate = 1;} if (seek_byte){ diff --git a/src/connectors/conn_http_progressive_mp4.cpp b/src/connectors/conn_http_progressive_mp4.cpp index 31056098..b0a7e534 100644 --- a/src/connectors/conn_http_progressive_mp4.cpp +++ b/src/connectors/conn_http_progressive_mp4.cpp @@ -98,7 +98,7 @@ namespace Connector_HTTP { HTTP_S.SetHeader("Content-Type", "video/MP4"); //Send the correct content-type for FLV files HTTP_S.protocol = "HTTP/1.0"; conn.SendNow(HTTP_S.BuildResponse("200", "OK")); //no SetBody = unknown length - this is intentional, we will stream the entire file - conn.SendNow(Conv.DTSCMeta2MP4Header(Strm.metadata));//SENDING MP4HEADER + conn.SendNow(Conv.DTSCMeta2MP4Header(Strm.metadata.toJSON()));//SENDING MP4HEADER keyPartIt = Conv.keyParts.begin(); {//using scope to have cmd not declared after action std::stringstream cmd; @@ -127,19 +127,19 @@ namespace Connector_HTTP { } } int byterate = 0; - for (JSON::ObjIter objIt = Strm.metadata["tracks"].ObjBegin(); objIt != Strm.metadata["tracks"].ObjEnd(); objIt++){ - if (videoID == -1 && objIt->second["type"].asString() == "video"){ - videoID = objIt->second["trackid"].asInt(); + for (std::map::iterator it = Strm.metadata.tracks.begin(); it != Strm.metadata.tracks.end(); it++){ + if (videoID == -1 && it->second.type == "video"){ + videoID = it->second.trackID; } - if (audioID == -1 && objIt->second["type"].asString() == "audio"){ - audioID = objIt->second["trackid"].asInt(); + if (audioID == -1 && it->second.type == "audio"){ + audioID = it->second.trackID; } } if (videoID != -1){ - byterate += Strm.getTrackById(videoID)["bps"].asInt(); + byterate += Strm.metadata.tracks[videoID].bps; } if (audioID != -1){ - byterate += Strm.getTrackById(audioID)["bps"].asInt(); + byterate += Strm.metadata.tracks[audioID].bps; } if ( !byterate){byterate = 1;} seek_sec = (seek_byte / byterate) * 1000; diff --git a/src/connectors/conn_http_progressive_ogg.cpp b/src/connectors/conn_http_progressive_ogg.cpp index 8bedfcd4..9fe639b4 100644 --- a/src/connectors/conn_http_progressive_ogg.cpp +++ b/src/connectors/conn_http_progressive_ogg.cpp @@ -112,19 +112,19 @@ namespace Connector_HTTP { } Strm.waitForMeta(ss); int byterate = 0; - for (JSON::ObjIter objIt = Strm.metadata["tracks"].ObjBegin(); objIt != Strm.metadata["tracks"].ObjEnd(); objIt++){ - if (videoID == -1 && objIt->second["codec"].asString() == "theora"){ - videoID = objIt->second["trackid"].asInt(); + for (std::map::iterator it = Strm.metadata.tracks.begin(); it != Strm.metadata.tracks.end(); it++){ + if (videoID == -1 && it->second.codec == "theora"){ + videoID = it->second.trackID; } - if (audioID == -1 && objIt->second["codec"].asString() == "vorbis"){ - audioID = objIt->second["trackid"].asInt(); + if (audioID == -1 && it->second.codec == "vorbis"){ + audioID = it->second.trackID; } } if (videoID != -1){ - byterate += Strm.getTrackById(videoID)["bps"].asInt(); + byterate += Strm.metadata.tracks[videoID].bps; } if (audioID != -1){ - byterate += Strm.getTrackById(audioID)["bps"].asInt(); + byterate += Strm.metadata.tracks[audioID].bps; } if ( !byterate){byterate = 1;} if (seek_byte){ @@ -163,7 +163,7 @@ namespace Connector_HTTP { HTTP_S.protocol = "HTTP/1.0"; conn.SendNow(HTTP_S.BuildResponse("200", "OK")); //no SetBody = unknown length - this is intentional, we will stream the entire file //Fill in ogg header here - oggMeta.readDTSCHeader(Strm.metadata); + oggMeta.readDTSCHeader(Strm.metadata.toJSON()); conn.SendNow((char*)oggMeta.parsedPages.c_str(), oggMeta.parsedPages.size()); progressive_has_sent_header = true; //setting sendReady to not ready diff --git a/src/connectors/conn_http_smooth.cpp b/src/connectors/conn_http_smooth.cpp index e19984e7..e1f190fb 100644 --- a/src/connectors/conn_http_smooth.cpp +++ b/src/connectors/conn_http_smooth.cpp @@ -30,42 +30,42 @@ namespace Connector_HTTP { ///\brief Builds an index file for HTTP Smooth streaming. ///\param metadata The current metadata, used to generate the index. ///\return The index file for HTTP Smooth Streaming. - std::string smoothIndex(JSON::Value & metadata){ + std::string smoothIndex(DTSC::Meta & metadata){ std::stringstream Result; Result << "\n"; Result << "\n"; - JSON::Value allAudio; - JSON::Value allVideo; + std::map allAudio; + std::map allVideo; long long int maxWidth = 0; long long int maxHeight = 0; long long int minWidth = 99999999; long long int minHeight = 99999999; - for (JSON::ObjIter oIt = metadata["tracks"].ObjBegin(); oIt != metadata["tracks"].ObjEnd(); oIt++){ - if (oIt->second["type"].asString() == "audio" && oIt->second["codec"].asString() == "AAC"){ - allAudio[oIt->first] = oIt->second; + for (std::map::iterator it = metadata.tracks.begin(); it != metadata.tracks.end(); it++){ + if (it->second.type == "audio" && it->second.codec == "AAC"){ + allAudio.insert(*it); } - if (oIt->second["type"].asString() == "video" && oIt->second["codec"].asString() == "H264"){ - allVideo[oIt->first] = oIt->second; - if (oIt->second["width"].asInt() > maxWidth){maxWidth = oIt->second["width"].asInt();} - if (oIt->second["width"].asInt() < minWidth){minWidth = oIt->second["width"].asInt();} - if (oIt->second["height"].asInt() > maxHeight){maxHeight = oIt->second["height"].asInt();} - if (oIt->second["height"].asInt() < minHeight){minHeight = oIt->second["height"].asInt();} + if (it->second.type == "video" && it->second.codec == "H264"){ + allVideo.insert(*it); + if (it->second.width > maxWidth){maxWidth = it->second.width;} + if (it->second.width < minWidth){minWidth = it->second.width;} + if (it->second.height > maxHeight){maxHeight = it->second.height;} + if (it->second.height < minHeight){minHeight = it->second.height;} } } + if (metadata.vod){ + Result << "Duration=\"" << metadata.tracks[allVideo.begin()->first].lastms << "0000\""; + }else{ + Result << "Duration=\"0\" " + "IsLive=\"TRUE\" " + "LookAheadFragmentCount=\"2\" " + "DVRWindowLength=\"" << metadata.bufferWindow << "0000\" " + "CanSeek=\"TRUE\" " + "CanPause=\"TRUE\" "; + } + Result << ">\n"; //Add audio entries if (allAudio.size()){ @@ -73,36 +73,36 @@ namespace Connector_HTTP { "Type=\"audio\" " "QualityLevels=\"" << allAudio.size() << "\" " "Name=\"audio\" " - "Chunks=\"" << allAudio.ObjBegin()->second["keys"].size() << "\" " + "Chunks=\"" << allAudio.begin()->second.keys.size() << "\" " "Url=\"Q({bitrate},{CustomAttributes})/A({start time})\">\n"; int index = 0; - for (JSON::ObjIter oIt = allAudio.ObjBegin(); oIt != allAudio.ObjEnd(); oIt++){ + for (std::map::iterator it = allAudio.begin(); it != allAudio.end(); it++){ Result << "second["bps"].asInt() * 8 << "\" " + "Bitrate=\"" << it->second.bps * 8 << "\" " "CodecPrivateData=\"" << std::hex; - for (int i = 0; i < oIt->second["init"].asString().size(); i++){ - Result << std::setfill('0') << std::setw(2) << std::right << (int)oIt->second["init"].asString()[i]; + for (int i = 0; i < it->second.init.size(); i++){ + Result << std::setfill('0') << std::setw(2) << std::right << (int)it->second.init[i]; } Result << std::dec << "\" " - "SamplingRate=\"" << oIt->second["rate"].asInt() << "\" " + "SamplingRate=\"" << it->second.rate << "\" " "Channels=\"2\" " "BitsPerSample=\"16\" " "PacketSize=\"4\" " "AudioTag=\"255\" " "FourCC=\"AACL\" >\n"; Result << "\n" - "second["trackid"].asString() << "\" />" + "first << "\" />" ""; Result << "\n"; index++; } - for (JSON::ArrIter keyIt = allAudio.ObjBegin()->second["keys"].ArrBegin(); keyIt != ((allAudio.ObjBegin()->second["keys"].ArrEnd()) - 1); keyIt++){ + for (std::deque::iterator it = allAudio.begin()->second.keys.begin(); it != ((allAudio.begin()->second.keys.end()) - 1); it++){ Result << "second["keys"].ArrBegin()){ - Result << "t=\"" << allAudio.ObjBegin()->second["firstms"].asInt() * 10000 << "\" "; + if (it == allAudio.begin()->second.keys.begin()){ + Result << "t=\"" << it->getTime() * 10000 << "\" "; } - Result << "d=\"" << (*keyIt)["len"].asInt() * 10000 << "\" />\n"; + Result << "d=\"" << it->getLength() * 10000 << "\" />\n"; } Result << "\n"; } @@ -112,41 +112,41 @@ namespace Connector_HTTP { "Type=\"video\" " "QualityLevels=\"" << allVideo.size() << "\" " "Name=\"video\" " - "Chunks=\"" << allVideo.ObjBegin()->second["keys"].size() << "\" " + "Chunks=\"" << allVideo.begin()->second.keys.size() << "\" " "Url=\"Q({bitrate},{CustomAttributes})/V({start time})\" " "MaxWidth=\"" << maxWidth << "\" " "MaxHeight=\"" << maxHeight << "\" " "DisplayWidth=\"" << maxWidth << "\" " "DisplayHeight=\"" << maxHeight << "\">\n"; int index = 0; - for (JSON::ObjIter oIt = allVideo.ObjBegin(); oIt != allVideo.ObjEnd(); oIt++){ - //Add video qualities + for (std::map::iterator it = allVideo.begin(); it != allVideo.end(); it++){ + //Add video qualities Result << "second["bps"].asInt() * 8 << "\" " + "Bitrate=\"" << it->second.bps * 8 << "\" " "CodecPrivateData=\"" << std::hex; MP4::AVCC avccbox; - avccbox.setPayload(oIt->second["init"].asString()); + avccbox.setPayload(it->second.init); std::string tmpString = avccbox.asAnnexB(); for (int i = 0; i < tmpString.size(); i++){ Result << std::setfill('0') << std::setw(2) << std::right << (int)tmpString[i]; } Result << std::dec << "\" " - "MaxWidth=\"" << oIt->second["width"].asInt() << "\" " - "MaxHeight=\"" << oIt->second["height"].asInt() << "\" " + "MaxWidth=\"" << it->second.width << "\" " + "MaxHeight=\"" << it->second.height << "\" " "FourCC=\"AVC1\" >\n"; Result << "\n" - "second["trackid"].asString() << "\" />" + "first << "\" />" ""; Result << "\n"; index++; } - for (JSON::ArrIter keyIt = allVideo.ObjBegin()->second["keys"].ArrBegin(); keyIt != ((allVideo.ObjBegin()->second["keys"].ArrEnd()) - 1); keyIt++){ + for (std::deque::iterator it = allVideo.begin()->second.keys.begin(); it != ((allVideo.begin()->second.keys.end()) - 1); it++){ Result << "second["keys"].ArrBegin()){ - Result << "t=\"" << (*keyIt)["time"].asInt() * 10000 << "\" "; + if (it == allVideo.begin()->second.keys.begin()){ + Result << "t=\"" << it->getTime() * 10000 << "\" "; } - Result << "d=\"" << (*keyIt)["len"].asInt() * 10000 << "\" />\n"; + Result << "d=\"" << it->getLength() * 10000 << "\" />\n"; } Result << "\n"; } @@ -183,8 +183,8 @@ namespace Connector_HTTP { unsigned int lastStats = 0;//Indicates the last time that we have sent stats to the server socket. conn.setBlocking(false);//Set the client socket to non-blocking - JSON::Value allAudio; - JSON::Value allVideo; + std::map allAudio; + std::map allVideo; while (conn.connected()){ if ( !handlingRequest){ @@ -211,12 +211,12 @@ namespace Connector_HTTP { } ss.setBlocking(false); Strm.waitForMeta(ss); - for (JSON::ObjIter oIt = Strm.metadata["tracks"].ObjBegin(); oIt != Strm.metadata["tracks"].ObjEnd(); oIt++){ - if (oIt->second["type"].asString() == "audio" && oIt->second["codec"].asString() == "AAC"){ - allAudio[oIt->first] = oIt->second; + for (std::map::iterator it = Strm.metadata.tracks.begin(); it != Strm.metadata.tracks.end(); it++){ + if (it->second.type == "audio" && it->second.codec == "AAC"){ + allAudio[it->first] = it->second; } - if (oIt->second["type"].asString() == "video" && oIt->second["codec"].asString() == "H264"){ - allVideo[oIt->first] = oIt->second; + if (it->second.type == "video" && it->second.codec == "H264"){ + allVideo[it->first] = it->second; } } }; @@ -250,14 +250,14 @@ namespace Connector_HTTP { parseString = parseString.substr(parseString.find("(") + 1); requestedTime = atoll(parseString.substr(0, parseString.find(")")).c_str()); long long int selectedQuality = atoll(Quality.c_str()); - JSON::Value & myRef = Strm.getTrackById(selectedQuality); - if (Strm.metadata.isMember("live")){ + DTSC::Track & myRef = Strm.metadata.tracks[selectedQuality]; + if (Strm.metadata.live){ int seekable = Strm.canSeekms(requestedTime / 10000); if (seekable == 0){ // iff the fragment in question is available, check if the next is available too - for (JSON::ArrIter aIt = myRef["keys"].ArrBegin(); aIt != myRef["keys"].ArrEnd(); aIt++){ - if ((*aIt)["time"].asInt() >= (requestedTime / 10000)){ - if ((aIt + 1) == myRef["keys"].ArrEnd()){ + for (std::deque::iterator it = myRef.keys.begin(); it != myRef.keys.end(); it++){ + if (it->getTime() >= (requestedTime / 10000)){ + if ((it + 1) == myRef.keys.end()){ seekable = 1; } break; @@ -269,7 +269,7 @@ namespace Connector_HTTP { HTTP_S.SetBody("The requested fragment is no longer kept in memory on the server and cannot be served.\n"); conn.SendNow(HTTP_S.BuildResponse("412", "Fragment out of range")); HTTP_R.Clean(); //clean for any possible next requests - std::cout << "Fragment @ " << requestedTime / 10000 << "ms too old (" << myRef["keys"][0u]["time"].asInt() << " - " << myRef["keys"][myRef["keys"].size() - 1]["time"].asInt() << " ms)" << std::endl; + std::cout << "Fragment @ " << requestedTime / 10000 << "ms too old (" << myRef.keys.begin()->getTime() << " - " << myRef.keys.rbegin()->getTime() << " ms)" << std::endl; continue; } if (seekable > 0){ @@ -277,7 +277,7 @@ namespace Connector_HTTP { HTTP_S.SetBody("Proxy, re-request this in a second or two.\n"); conn.SendNow(HTTP_S.BuildResponse("208", "Ask again later")); HTTP_R.Clean(); //clean for any possible next requests - std::cout << "Fragment @ " << requestedTime / 10000 << "ms not available yet (" << myRef["keys"][0u]["time"].asInt() << " - " << myRef["keys"][myRef["keys"].size() - 1]["time"].asInt() << " ms)" << std::endl; + std::cout << "Fragment @ " << requestedTime / 10000 << "ms not available yet (" << myRef.keys.begin()->getTime() << " - " << myRef.keys.rbegin()->getTime() << " ms)" << std::endl; continue; } } @@ -286,26 +286,24 @@ namespace Connector_HTTP { long long mstime = 0; long long mslen = 0; - if (myRef.isMember("keys")){ - for (JSON::ArrIter it = myRef["keys"].ArrBegin(); it != myRef["keys"].ArrEnd(); it++){ - if ((*it)["time"].asInt() >= (requestedTime / 10000)){ - mstime = (*it)["time"].asInt(); - mslen = (*it)["len"].asInt(); - if (Strm.metadata.isMember("live")){ - if (it == myRef["keys"].ArrEnd() - 2){ - HTTP_S.Clean(); - HTTP_S.SetBody("Proxy, re-request this in a second or two.\n"); - conn.SendNow(HTTP_S.BuildResponse("208", "Ask again later")); - HTTP_R.Clean(); //clean for any possible next requests - std::cout << "Fragment after fragment @ " << (requestedTime / 10000) << " not available yet" << std::endl; - } + for (std::deque::iterator it = myRef.keys.end(); it != myRef.keys.end(); it++){ + if (it->getTime() >= (requestedTime / 10000)){ + mstime = it->getTime(); + mslen = it->getLength(); + if (Strm.metadata.live){ + if (it == myRef.keys.end() - 2){ + HTTP_S.Clean(); + HTTP_S.SetBody("Proxy, re-request this in a second or two.\n"); + conn.SendNow(HTTP_S.BuildResponse("208", "Ask again later")); + HTTP_R.Clean(); //clean for any possible next requests + std::cout << "Fragment after fragment @ " << (requestedTime / 10000) << " not available yet" << std::endl; } - break; } + break; } } if (HTTP_R.url == "/"){continue;}//Don't continue, but continue instead. - if (Strm.metadata.isMember("live")){ + if (Strm.metadata.live){ if (mstime == 0 && (requestedTime / 10000) > 1){ HTTP_S.Clean(); HTTP_S.SetBody("The requested fragment is no longer kept in memory on the server and cannot be served.\n"); @@ -317,73 +315,83 @@ namespace Connector_HTTP { } //Obtain the corresponding track; - JSON::Value trackRef; + DTSC::Track trackRef; if (wantsVideo){ - trackRef = allVideo.ObjBegin()->second; + trackRef = allVideo.begin()->second; } if (wantsAudio){ - trackRef = allAudio.ObjBegin()->second; + trackRef = allAudio.begin()->second; } //Also obtain the associated keyframe; - JSON::Value keyObj; - for (JSON::ArrIter keyIt = trackRef["keys"].ArrBegin(); keyIt != trackRef["keys"].ArrEnd(); keyIt++){ - if ((*keyIt)["time"].asInt() >= (requestedTime / 10000)){ + DTSC::Key keyObj; + int partOffset = 0; + int keyDur = 0; + for (std::deque::iterator keyIt = trackRef.keys.begin(); keyIt != trackRef.keys.end(); keyIt++){ + if (keyIt->getTime() >= (requestedTime / 10000)){ keyObj = (*keyIt); + std::deque::iterator nextIt = keyIt; + nextIt++; + if (nextIt != trackRef.keys.end()){ + keyDur = nextIt->getTime() - keyIt->getTime(); + }else{ + keyDur = -1; + } break; } + partOffset += keyIt->getParts(); } - sstream << "t " << myRef["trackid"].asInt() << "\n"; - sstream << "s " << keyObj["time"].asInt() << "\n"; - sstream << "p " << keyObj["time"].asInt() + keyObj["len"].asInt() << "\n"; -// sstream << "o\n"; + sstream << "t " << myRef.trackID << "\n"; + sstream << "s " << keyObj.getTime() << "\n"; + if (keyDur != -1){ + sstream << "p " << keyObj.getTime() + keyDur << "\n"; + }else{ + sstream << "p\n"; + } ss.SendNow(sstream.str().c_str()); + std::cerr << "[[]]Requested " << sstream.str() << std::endl; + unsigned int myDuration; //Wrap everything in mp4 boxes MP4::MFHD mfhd_box; - mfhd_box.setSequenceNumber(keyObj["num"].asInt()); - myDuration = keyObj["len"].asInt() * 10000; + mfhd_box.setSequenceNumber(keyObj.getNumber()); + myDuration = keyObj.getLength() * 10000; MP4::TFHD tfhd_box; tfhd_box.setFlags(MP4::tfhdSampleFlag); tfhd_box.setTrackID(1); - //if (trackRef["type"].asString() == "video"){ - tfhd_box.setDefaultSampleFlags(0x000000C0 | MP4::noIPicture | MP4::noDisposable | MP4::noKeySample); - //}else{ - // tfhd_box.setDefaultSampleFlags(0x000000C0 | MP4::noKeySample); - //} + tfhd_box.setDefaultSampleFlags(0x000000C0 | MP4::noIPicture | MP4::noDisposable | MP4::noKeySample); MP4::TRUN trun_box; trun_box.setDataOffset(42); - if (trackRef["type"].asString() == "video"){ + int keySize = 0; + if (trackRef.type == "video"){ trun_box.setFlags(MP4::trundataOffset | MP4::trunfirstSampleFlags | MP4::trunsampleDuration | MP4::trunsampleSize); }else{ trun_box.setFlags(MP4::trundataOffset | MP4::trunsampleDuration | MP4::trunsampleSize); - // trun_box.setFirstSampleFlags(0x00000040 | MP4::noKeySample); } trun_box.setFirstSampleFlags(0x00000040 | MP4::isIPicture | MP4::noDisposable | MP4::isKeySample); - std::deque tmpParts; - JSON::decodeVector(keyObj["parts"].asString(), tmpParts); - for (int i = 0; i < tmpParts.size(); i++){ + for (int i = 0; i < keyObj.getParts(); i++){ MP4::trunSampleInformation trunSample; - trunSample.sampleSize = tmpParts[i]; + trunSample.sampleSize = Strm.metadata.tracks[myRef.trackID].parts[i + partOffset].getSize(); + keySize += Strm.metadata.tracks[myRef.trackID].parts[i + partOffset].getSize(); //Guesstimate sample duration. - trunSample.sampleDuration = ((double)(keyObj["len"].asInt() * 10000) / tmpParts.size()); + trunSample.sampleDuration = Strm.metadata.tracks[myRef.trackID].parts[i + partOffset].getDuration() * 10000; trun_box.setSampleInformation(trunSample, i); } MP4::SDTP sdtp_box; sdtp_box.setVersion(0); - if (trackRef["type"].asString() == "video"){ + if (trackRef.type == "video"){ sdtp_box.setValue(36, 4); - for (int i = 1; i < keyObj["partsize"].asInt(); i++){ + for (int i = 1; i < keyObj.getParts(); i++){ sdtp_box.setValue(20, 4 + i); } }else{ sdtp_box.setValue(40, 4); - for (int i = 1; i < keyObj["partsize"].asInt(); i++){ + for (int i = 1; i < keyObj.getParts(); i++){ sdtp_box.setValue(40, 4 + i); } } @@ -394,22 +402,24 @@ namespace Connector_HTTP { traf_box.setContent(sdtp_box, 2); //If the stream is live, we want to have a fragref box if possible - if (Strm.metadata.isMember("live")){ + if (Strm.metadata.live){ ///\todo Fix this for live MP4::UUID_TrackFragmentReference fragref_box; fragref_box.setVersion(1); fragref_box.setFragmentCount(0); int fragCount = 0; - for (int i = 0; i < 2 && i < trackRef["keys"].size() - 1; i++){//< trackRef["keys"].size() - 1; i++){ - if (trackRef["keys"][i]["time"].asInt() > (requestedTime / 10000)){ - fragref_box.setTime(fragCount, trackRef["keys"][i]["time"].asInt() * 10000); - fragref_box.setDuration(fragCount, trackRef["keys"][i]["len"].asInt() * 10000); + for (int i = 0; i < 2 && i < trackRef.keys.size() - 1; i++){//< trackRef["keys"].size() - 1; i++){ + if (trackRef.keys[i].getTime() > (requestedTime / 10000)){ + fragref_box.setTime(fragCount, trackRef.keys[i].getTime() * 10000); + fragref_box.setDuration(fragCount, trackRef.keys[i].getLength() * 10000); fragref_box.setFragmentCount(++fragCount); } } traf_box.setContent(fragref_box, 3); } + + MP4::MOOF moof_box; moof_box.setContent(mfhd_box, 0); moof_box.setContent(traf_box, 1); @@ -423,7 +433,7 @@ namespace Connector_HTTP { HTTP_S.SetHeader("Content-Type", "video/mp4"); HTTP_S.StartResponse(HTTP_R, conn); HTTP_S.Chunkify(moof_box.asBox(), moof_box.boxedSize(), conn); - int size = htonl(keyObj["size"].asInt() + 8); + int size = htonl(keySize + 8); HTTP_S.Chunkify((char*)&size, 4, conn); HTTP_S.Chunkify("mdat", 4, conn); handlingRequest = true; @@ -465,6 +475,8 @@ namespace Connector_HTTP { handlingRequest = false; } } + }else{ + Util::sleep(10); } if ( !ss.connected()){ break; diff --git a/src/connectors/conn_http_srt.cpp b/src/connectors/conn_http_srt.cpp index ab127f5b..f1854dcb 100644 --- a/src/connectors/conn_http_srt.cpp +++ b/src/connectors/conn_http_srt.cpp @@ -107,23 +107,16 @@ namespace Connector_HTTP { if(trackID == -1){ // no track was given. Fetch the first track that has SRT data - for (JSON::ObjIter objIt = Strm.metadata["tracks"].ObjBegin(); objIt != Strm.metadata["tracks"].ObjEnd(); objIt++){ - if (objIt->second["codec"].asStringRef() == "srt"){ - trackID = objIt->second["trackid"].asInt(); + for (std::map::iterator it = Strm.metadata.tracks.begin(); it != Strm.metadata.tracks.end(); it++){ + if (it->second.codec == "srt"){ + trackID = it->second.trackID; subtitleTrack = true; break; } } }else{ // track *was* given, but we have to check whether it's an actual srt track - for (JSON::ObjIter objIt = Strm.metadata["tracks"].ObjBegin(); objIt != Strm.metadata["tracks"].ObjEnd(); objIt++){ - if (objIt->second["trackid"].asInt() == trackID){ - subtitleTrack = (objIt->second["codec"].asStringRef() == "srt"); - break; - }else{ - subtitleTrack = false; - } - } + subtitleTrack = Strm.metadata.tracks[trackID].codec == "srt"; } if(!subtitleTrack){ @@ -139,7 +132,7 @@ namespace Connector_HTTP { cmd << "t " << trackID; - int maxTime = Strm.metadata["lastms"].asInt(); + int maxTime = Strm.metadata.tracks[trackID].lastms; cmd << "\ns " << seek_time << "\np " << maxTime << "\n"; ss.SendNow(cmd.str().c_str(), cmd.str().size()); diff --git a/src/connectors/conn_raw.cpp b/src/connectors/conn_raw.cpp index f0926c2e..646e9f51 100644 --- a/src/connectors/conn_raw.cpp +++ b/src/connectors/conn_raw.cpp @@ -33,14 +33,14 @@ int main(int argc, char ** argv){ } long long int lastStats = 0; long long int started = Util::epoch(); - while (std::cout.good()){ + while (std::cout.good() && S.connected()){ if (S.spool()){ while (S.Received().size()){ std::cout.write(S.Received().get().c_str(), S.Received().get().size()); S.Received().get().clear(); } }else{ - Util::sleep(10); //sleep 10ms if no data + Util::sleep(500); //sleep 500ms if no data } unsigned int now = Util::epoch(); if (now != lastStats){ diff --git a/src/connectors/conn_rtmp.cpp b/src/connectors/conn_rtmp.cpp index 798bb4b5..f37e150a 100644 --- a/src/connectors/conn_rtmp.cpp +++ b/src/connectors/conn_rtmp.cpp @@ -568,12 +568,12 @@ namespace Connector_RTMP { ss.setBlocking(false); Strm.waitForMeta(ss); //find first audio and video tracks - for (JSON::ObjIter objIt = Strm.metadata["tracks"].ObjBegin(); objIt != Strm.metadata["tracks"].ObjEnd(); objIt++){ - if (videoID == -1 && objIt->second["type"].asStringRef() == "video"){ - videoID = objIt->second["trackid"].asInt(); + for (std::map::iterator it = Strm.metadata.tracks.begin(); it != Strm.metadata.tracks.end(); it++){ + if (videoID == -1 && it->second.type == "video"){ + videoID = it->second.trackID; } - if (audioID == -1 && objIt->second["type"].asStringRef() == "audio"){ - audioID = objIt->second["trackid"].asInt(); + if (audioID == -1 && it->second.type == "audio"){ + audioID = it->second.trackID; } } //select the tracks and play @@ -612,7 +612,7 @@ namespace Connector_RTMP { amfreply.getContentP(3)->addContent(AMF::Object("clientid", (double)1337)); sendCommand(amfreply, playMessageType, playStreamId); //send streamisrecorded if stream, well, is recorded. - if (Strm.metadata.isMember("length") && Strm.metadata["length"].asInt() > 0){ + if (Strm.metadata.vod){//isMember("length") && Strm.metadata["length"].asInt() > 0){ Socket.Send(RTMPStream::SendUSR(4, 1)); //send UCM StreamIsRecorded (4), stream 1 } //send streambegin @@ -638,14 +638,14 @@ namespace Connector_RTMP { //sent init data if needed if ( !streamInited){ - init_tag.DTSCMetaInit(Strm, Strm.getTrackById(videoID), Strm.getTrackById(audioID)); + init_tag.DTSCMetaInit(Strm, Strm.metadata.tracks[videoID], Strm.metadata.tracks[audioID]); Socket.SendNow(RTMPStream::SendMedia(init_tag)); - if (audioID != -1 && Strm.getTrackById(audioID).isMember("init")){ - init_tag.DTSCAudioInit(Strm.getTrackById(audioID)); + if (audioID != -1){ + init_tag.DTSCAudioInit(Strm.metadata.tracks[audioID]); Socket.SendNow(RTMPStream::SendMedia(init_tag)); } - if (videoID != -1 && Strm.getTrackById(videoID).isMember("init")){ - init_tag.DTSCVideoInit(Strm.getTrackById(videoID)); + if (videoID != -1){ + init_tag.DTSCVideoInit(Strm.metadata.tracks[videoID]); Socket.SendNow(RTMPStream::SendMedia(init_tag)); } streamInited = true; diff --git a/src/connectors/conn_ts.cpp b/src/connectors/conn_ts.cpp index 1733bc73..48507925 100644 --- a/src/connectors/conn_ts.cpp +++ b/src/connectors/conn_ts.cpp @@ -61,36 +61,25 @@ namespace Connector_TS { } if(trackIDs == ""){ + std::stringstream tmpTracks; // no track ids given? Find the first video and first audio track (if available) and use those! int videoID = -1; int audioID = -1; Strm.waitForMeta(ss); - - if (Strm.metadata.isMember("tracks")){ + for (std::map::iterator it = Strm.metadata.tracks.begin(); it != Strm.metadata.tracks.end(); it){ + if (audioID == -1 && it->second.type == "audio"){ + audioID = it->first; + tmpTracks << " " << it->first; + } - for (JSON::ObjIter trackIt = Strm.metadata["tracks"].ObjBegin(); trackIt != Strm.metadata["tracks"].ObjEnd(); trackIt++){ + if (videoID == -1 && it->second.type == "video"){ + videoID = it->first; + tmpTracks << " " << it->first; + } - if (audioID == -1 && trackIt->second["type"].asString() == "audio"){ - audioID = trackIt->second["trackid"].asInt(); - if( trackIDs != ""){ - trackIDs += " " + trackIt->second["trackid"].asString(); - }else{ - trackIDs = trackIt->second["trackid"].asString(); - } - } - - if (videoID == -1 && trackIt->second["type"].asString() == "video"){ - videoID = trackIt->second["trackid"].asInt(); - if( trackIDs != ""){ - trackIDs += " " + trackIt->second["trackid"].asString(); - }else{ - trackIDs = trackIt->second["trackid"].asString(); - } - } - - } // for iterator - } // if isMember("tracks") + } // for iterator + trackIDs += tmpTracks.str(); } // if trackIDs == "" std::string cmd = "t " + trackIDs + "\ns 0\np\n"; @@ -115,7 +104,7 @@ namespace Connector_TS { char * ContCounter = 0; if (Strm.lastType() == DTSC::VIDEO){ if ( !haveAvcc){ - avccbox.setPayload(Strm.getTrackById(Strm.getPacket()["trackid"].asInt())["init"].asString()); + avccbox.setPayload(Strm.metadata.tracks[Strm.getPacket()["trackid"].asInt()].init); haveAvcc = true; } @@ -139,7 +128,7 @@ namespace Connector_TS { PIDno = 0x100 - 1 + Strm.getPacket()["trackid"].asInt(); ContCounter = &VideoCounter; }else if (Strm.lastType() == DTSC::AUDIO){ - ToPack.append(TS::GetAudioHeader(Strm.lastData().size(), Strm.getTrackById(Strm.getPacket()["trackid"].asInt())["init"].asString())); + ToPack.append(TS::GetAudioHeader(Strm.lastData().size(), Strm.metadata.tracks[Strm.getPacket()["trackid"].asInt()].init)); ToPack.append(Strm.lastData()); ToPack.prepend(TS::Packet::getPESAudioLeadIn(ToPack.bytes(1073741824ul), Strm.getPacket()["time"].asInt() * 90)); PIDno = 0x100 - 1 + Strm.getPacket()["trackid"].asInt(); diff --git a/src/controller/controller_capabilities.cpp b/src/controller/controller_capabilities.cpp index 496fa69e..c2b5b2ab 100644 --- a/src/controller/controller_capabilities.cpp +++ b/src/controller/controller_capabilities.cpp @@ -153,8 +153,8 @@ namespace Controller { float onemin, fivemin, fifteenmin; if (sscanf(line, "%f %f %f", &onemin, &fivemin, &fifteenmin) == 3){ capa["load"]["one"] = (long long int)(onemin * 100); - capa["load"]["five"] = (long long int)(onemin * 100); - capa["load"]["fifteen"] = (long long int)(onemin * 100); + capa["load"]["five"] = (long long int)(fivemin * 100); + capa["load"]["fifteen"] = (long long int)(fifteenmin * 100); } } diff --git a/src/converters/dtsc2flv.cpp b/src/converters/dtsc2flv.cpp index 4fcd87f9..343c9c63 100644 --- a/src/converters/dtsc2flv.cpp +++ b/src/converters/dtsc2flv.cpp @@ -33,25 +33,25 @@ namespace Converters { if (Strm.parsePacket(inBuffer)){ if ( !doneheader){ //find first audio and video tracks - for (JSON::ObjIter objIt = Strm.metadata["tracks"].ObjBegin(); objIt != Strm.metadata["tracks"].ObjEnd(); objIt++){ - if (videoID == -1 && objIt->second["type"].asString() == "video"){ - videoID = objIt->second["trackid"].asInt(); + for (std::map::iterator it = Strm.metadata.tracks.begin(); it != Strm.metadata.tracks.end(); it++){ + if (videoID == -1 && it->second.type == "video"){ + videoID = it->first; } - if (audioID == -1 && objIt->second["type"].asString() == "audio"){ - audioID = objIt->second["trackid"].asInt(); + if (audioID == -1 && it->second.type == "audio"){ + audioID = it->first; } } doneheader = true; std::cout.write(FLV::Header, 13); - FLV_out.DTSCMetaInit(Strm, Strm.getTrackById(videoID), Strm.getTrackById(audioID)); + FLV_out.DTSCMetaInit(Strm, Strm.metadata.tracks[videoID], Strm.metadata.tracks[audioID]); std::cout.write(FLV_out.data, FLV_out.len); - if (videoID && Strm.getTrackById(videoID).isMember("init")){ - FLV_out.DTSCVideoInit(Strm.getTrackById(videoID)); + if (videoID != -1){ + FLV_out.DTSCVideoInit(Strm.metadata.tracks[videoID]); std::cout.write(FLV_out.data, FLV_out.len); } - if (audioID && Strm.getTrackById(audioID).isMember("init")){ - FLV_out.DTSCAudioInit(Strm.getTrackById(audioID)); + if (audioID != -1){ + FLV_out.DTSCAudioInit(Strm.metadata.tracks[audioID]); std::cout.write(FLV_out.data, FLV_out.len); } } diff --git a/src/converters/dtsc2mp4.cpp b/src/converters/dtsc2mp4.cpp index 27e3c42e..4c9d88a6 100644 --- a/src/converters/dtsc2mp4.cpp +++ b/src/converters/dtsc2mp4.cpp @@ -24,11 +24,12 @@ namespace Converters { int DTSC2MP4(Util::Config & conf){ DTSC::File input(conf.getString("filename"));//DTSC input MP4::DTSC2MP4Converter Conv;//DTSC to MP4 converter class will handle header creation and media parsing - std::cout << Conv.DTSCMeta2MP4Header(input.getMeta());//Creating and outputting MP4 header from DTSC file + std::cout << Conv.DTSCMeta2MP4Header(input.getMeta().toJSON());//Creating and outputting MP4 header from DTSC file //initialising JSON input std::set selector; - for (JSON::ObjIter trackIt = input.getMeta()["tracks"].ObjBegin(); trackIt != input.getMeta()["tracks"].ObjEnd(); trackIt++){ + JSON::Value tmp = input.getMeta().toJSON(); + for (JSON::ObjIter trackIt = tmp["tracks"].ObjBegin(); trackIt != tmp["tracks"].ObjEnd(); trackIt++){ selector.insert(trackIt->second["trackid"].asInt()); } input.selectTracks(selector); diff --git a/src/converters/dtsc2ogg.cpp b/src/converters/dtsc2ogg.cpp index 31afa2ed..cfea2f13 100644 --- a/src/converters/dtsc2ogg.cpp +++ b/src/converters/dtsc2ogg.cpp @@ -20,7 +20,7 @@ namespace Converters{ char* curNewPayload; OGG::headerPages oggMeta; //Creating ID headers for theora and vorbis - oggMeta.readDTSCHeader(DTSCFile.getMeta()); + oggMeta.readDTSCHeader(DTSCFile.getMeta().toJSON()); std::cout << oggMeta.parsedPages;//outputting header pages //create DTSC in OGG pages diff --git a/src/converters/dtsc2ts.cpp b/src/converters/dtsc2ts.cpp index d3fbad1b..c8ed5441 100644 --- a/src/converters/dtsc2ts.cpp +++ b/src/converters/dtsc2ts.cpp @@ -32,10 +32,22 @@ namespace Converters { MP4::AVCC avccbox; bool haveAvcc = false; std::stringstream TSBuf; + int videoID = -1; + int audioID = -1; while (std::cin.good()){ if (Strm.parsePacket(StrData)){ + if ((videoID == -1 || audioID == -1) && Strm.metadata){ + for (std::map::iterator it = Strm.metadata.tracks.begin(); it != Strm.metadata.tracks.end(); it++){ + if (videoID == -1 && it->second.type == "video"){ + videoID = it->first; + } + if (audioID == -1 && it->second.type == "audio"){ + audioID = it->first; + } + } + } if (Strm.lastType() == DTSC::PAUSEMARK){ TSBuf.flush(); if (TSBuf.str().size()){ @@ -46,7 +58,7 @@ namespace Converters { TSBuf.str(""); } if ( !haveAvcc){ - avccbox.setPayload(Strm.metadata["video"]["init"].asString()); + avccbox.setPayload(Strm.metadata.tracks[videoID].init); haveAvcc = true; } if (Strm.lastType() == DTSC::VIDEO || Strm.lastType() == DTSC::AUDIO){ @@ -83,7 +95,7 @@ namespace Converters { PIDno = 0x100; ContCounter = &VideoCounter; }else if (Strm.lastType() == DTSC::AUDIO){ - ToPack.append(TS::GetAudioHeader(Strm.lastData().size(), Strm.metadata["audio"]["init"].asString())); + ToPack.append(TS::GetAudioHeader(Strm.lastData().size(), Strm.metadata.tracks[audioID].init)); ToPack.append(Strm.lastData()); ToPack.prepend(TS::Packet::getPESAudioLeadIn(ToPack.bytes(1073741824ul), Strm.getPacket()["time"].asInt() * 90)); PIDno = 0x101; diff --git a/src/converters/dtscfix.cpp b/src/converters/dtscfix.cpp index 50555664..9a8cacd8 100644 --- a/src/converters/dtscfix.cpp +++ b/src/converters/dtscfix.cpp @@ -8,19 +8,6 @@ ///\brief Holds everything unique to converters. namespace Converters { - class HeaderEntryDTSC { - public: - HeaderEntryDTSC() : totalSize(0), lastKeyTime(-5001), trackID(0), firstms(0x7FFFFFFF), lastms(0), keynum(0) {} - long long int totalSize; - std::vector parts; - long long int lastKeyTime; - long long int trackID; - long long int firstms; - long long int lastms; - long long int keynum; - std::string type; - }; - ///\brief Reads a DTSC file and attempts to fix the metadata in it. ///\param conf The current configuration of the program. ///\return The return code for the fixed program. @@ -29,232 +16,39 @@ namespace Converters { F.seek_bpos(0); F.parseNext(); JSON::Value oriheader = F.getJSON(); - JSON::Value meta = F.getMeta(); - JSON::Value pack; + DTSC::Meta meta(F.getMeta()); - if ( !oriheader.isMember("moreheader")){ - std::cerr << "This file is too old to fix - please reconvert." << std::endl; - return 1; - } - if (DTSC::isFixed(meta) && !conf.getBool("force")){ + if (meta.isFixed() && !conf.getBool("force")){ std::cerr << "This file was already fixed or doesn't need fixing - cancelling." << std::endl; return 0; } - meta.removeMember("isFixed"); - meta.removeMember("keytime"); - meta.removeMember("keybpos"); - meta.removeMember("moreheader"); - - std::map trackIDs; - std::map trackData; - - - long long int nowpack = 0; - - std::string currentID; - int nextFreeID = 0; - - for (JSON::ObjIter it = meta["tracks"].ObjBegin(); it != meta["tracks"].ObjEnd(); it++){ - trackIDs.insert(std::pair(it->first,it->second["trackid"].asInt())); - trackData[it->first].type = it->second["type"].asString(); - trackData[it->first].trackID = it->second["trackid"].asInt(); - trackData[it->first].type = it->second["type"].asString(); - if (it->second["trackid"].asInt() >= nextFreeID){ - nextFreeID = it->second["trackid"].asInt() + 1; - } - it->second.removeMember("keylen"); - it->second.removeMember("keybpos"); - it->second.removeMember("frags"); - it->second.removeMember("keytime"); - it->second.removeMember("keynum"); - it->second.removeMember("keydata"); - it->second.removeMember("keyparts"); - it->second.removeMember("keys"); - } + meta.reset(); + int bPos = F.getBytePos(); F.parseNext(); while ( !F.getJSON().isNull()){ - currentID = ""; - if (F.getJSON()["trackid"].asInt() == 0){ - if (F.getJSON()["datatype"].asString() == "video"){ - currentID = "video0"; - if (trackData[currentID].trackID == 0){ - trackData[currentID].trackID = nextFreeID++; - } - if (meta.isMember("video")){ - meta["tracks"][currentID] = meta["video"]; - meta.removeMember("video"); - } - trackData[currentID].type = F.getJSON()["datatype"].asString(); - }else{ - if (F.getJSON()["datatype"].asString() == "audio"){ - currentID = "audio0"; - if (trackData[currentID].trackID == 0){ - trackData[currentID].trackID = nextFreeID++; - } - if (meta.isMember("audio")){ - meta["tracks"][currentID] = meta["audio"]; - meta.removeMember("audio"); - } - trackData[currentID].type = F.getJSON()["datatype"].asString(); - }else{ - //fprintf(stderr, "Found an unknown package with packetid 0 and datatype %s\n",F.getJSON()["datatype"].asString().c_str()); - F.parseNext(); - continue; - } - } - }else{ - for( std::map::iterator it = trackIDs.begin(); it != trackIDs.end(); it++ ) { - if( it->second == F.getJSON()["trackid"].asInt() ) { - currentID = it->first; - break; - } - } - if( currentID == "" ) { - //fprintf(stderr, "Found an unknown v2 packet with id %d\n", F.getJSON()["trackid"].asInt()); - F.parseNext(); - continue; - //should create new track but this shouldnt be needed... - } - } - if (F.getJSON()["time"].asInt() < trackData[currentID].firstms){ - trackData[currentID].firstms = F.getJSON()["time"].asInt(); - } - if (F.getJSON()["time"].asInt() >= nowpack){ - nowpack = F.getJSON()["time"].asInt(); - } - if (trackData[currentID].type == "video"){ - if (F.getJSON().isMember("keyframe")){ - int newNum = meta["tracks"][currentID]["keys"].size(); - meta["tracks"][currentID]["keys"][newNum]["num"] = ++trackData[currentID].keynum; - meta["tracks"][currentID]["keys"][newNum]["time"] = F.getJSON()["time"]; - meta["tracks"][currentID]["keys"][newNum]["bpos"] = F.getLastReadPos(); - if (meta["tracks"][currentID]["keys"].size() > 1){ - meta["tracks"][currentID]["keys"][newNum - 1]["len"] = F.getJSON()["time"].asInt() - meta["tracks"][currentID]["keys"][newNum - 1]["time"].asInt(); - meta["tracks"][currentID]["keys"][newNum - 1]["size"] = trackData[currentID].totalSize; - trackData[currentID].totalSize = 0; - std::string encodeVec = JSON::encodeVector( trackData[currentID].parts.begin(), trackData[currentID].parts.end() ); - meta["tracks"][currentID]["keys"][newNum - 1]["parts"] = encodeVec; - meta["tracks"][currentID]["keys"][newNum - 1]["partsize"] = (long long int)trackData[currentID].parts.size(); - trackData[currentID].parts.clear(); - } - } - }else{ - if ((F.getJSON()["time"].asInt() - trackData[currentID].lastKeyTime) > 1000){ - trackData[currentID].lastKeyTime = F.getJSON()["time"].asInt(); - int newNum = meta["tracks"][currentID]["keys"].size(); - meta["tracks"][currentID]["keys"][newNum]["num"] = ++trackData[currentID].keynum; - meta["tracks"][currentID]["keys"][newNum]["time"] = F.getJSON()["time"]; - meta["tracks"][currentID]["keys"][newNum]["bpos"] = F.getLastReadPos(); - if (meta["tracks"][currentID]["keys"].size() > 1){ - meta["tracks"][currentID]["keys"][newNum - 1]["len"] = F.getJSON()["time"].asInt() - meta["tracks"][currentID]["keys"][newNum - 1]["time"].asInt(); - meta["tracks"][currentID]["keys"][newNum - 1]["size"] = trackData[currentID].totalSize; - trackData[currentID].totalSize = 0; - std::string encodeVec = JSON::encodeVector( trackData[currentID].parts.begin(), trackData[currentID].parts.end() ); - meta["tracks"][currentID]["keys"][newNum - 1]["parts"] = encodeVec; - meta["tracks"][currentID]["keys"][newNum - 1]["partsize"] = (long long int)trackData[currentID].parts.size(); - trackData[currentID].parts.clear(); - } - } - } - trackData[currentID].totalSize += F.getJSON()["data"].asString().size(); - trackData[currentID].lastms = nowpack; - trackData[currentID].parts.push_back(F.getJSON()["data"].asString().size()); + F.getJSON()["bpos"] = bPos; + meta.update(F.getJSON()); + bPos = F.getBytePos(); F.parseNext(); } - - long long int firstms = 0x7fffffff; - long long int lastms = -1; - - for (std::map::iterator it = trackData.begin(); it != trackData.end(); it++){ - if (it->second.firstms < firstms){ - firstms = it->second.firstms; + for (std::map::iterator it = meta.tracks.begin(); it != meta.tracks.end(); it++){ + if (it->second.fragments.size()){ + it->second.fragments.rbegin()->setDuration(it->second.fragments.rbegin()->getDuration() - it->second.lastms); } - if (it->second.lastms > lastms){ - lastms = it->second.lastms; + if (it->second.lastms / 1000){ + it->second.bps /= (it->second.lastms / 1000); } - meta["tracks"][it->first]["firstms"] = it->second.firstms; - meta["tracks"][it->first]["lastms"] = it->second.lastms; - meta["tracks"][it->first]["length"] = (it->second.lastms - it->second.firstms) / 1000; - if ( !meta["tracks"][it->first].isMember("bps")){ - meta["tracks"][it->first]["bps"] = (long long int)(it->second.lastms / ((it->second.lastms - it->second.firstms) / 1000)); - } - if (it->second.trackID != 0){ - meta["tracks"][it->first]["trackid"] = trackIDs[it->first]; - }else{ - meta["tracks"][it->first]["trackid"] = nextFreeID ++; - } - meta["tracks"][it->first]["type"] = it->second.type; - int tmp = meta["tracks"][it->first]["keys"].size(); - if (tmp > 0){ - if (tmp > 1){ - meta["tracks"][it->first]["keys"][tmp - 1]["len"] = it->second.lastms - meta["tracks"][it->first]["keys"][tmp - 2]["time"].asInt(); - }else{ - meta["tracks"][it->first]["keys"][tmp - 1]["len"] = it->second.lastms; - } - meta["tracks"][it->first]["keys"][tmp - 1]["size"] = it->second.totalSize; - std::string encodeVec = JSON::encodeVector( trackData[it->first].parts.begin(), trackData[it->first].parts.end() ); - meta["tracks"][it->first]["keys"][tmp - 1]["parts"] = encodeVec; - meta["tracks"][it->first]["keys"][tmp - 1]["partsize"] = (long long int)trackData[it->first].parts.size(); - }else{ - meta["tracks"][it->first]["keys"][tmp]["len"] = it->second.lastms; - meta["tracks"][it->first]["keys"][tmp]["size"] = it->second.totalSize; - std::string encodeVec = JSON::encodeVector( trackData[it->first].parts.begin(), trackData[it->first].parts.end() ); - meta["tracks"][it->first]["keys"][tmp]["parts"] = encodeVec; - meta["tracks"][it->first]["keys"][tmp]["partsize"] = (long long int)trackData[it->first].parts.size(); - meta["tracks"][it->first]["keys"][tmp]["time"] = it->second.firstms; - } - //calculate fragments - meta["tracks"][it->first]["frags"].null(); - long long int currFrag = -1; - long long int maxBps = 0; - for (JSON::ArrIter arrIt = meta["tracks"][it->first]["keys"].ArrBegin(); arrIt != meta["tracks"][it->first]["keys"].ArrEnd(); arrIt++) { - if ((*arrIt)["time"].asInt() / 10000 > currFrag){ - currFrag = (*arrIt)["time"].asInt() / 10000; - long long int fragLen = 1; - long long int fragDur = (*arrIt)["len"].asInt(); - long long int fragSize = (*arrIt)["size"].asInt(); - for (JSON::ArrIter it2 = arrIt + 1; it2 != meta["tracks"][it->first]["keys"].ArrEnd(); it2++){ - if ((*it2)["time"].asInt() / 10000 > currFrag || (it2 + 1) == meta["tracks"][it->first]["keys"].ArrEnd()){ - JSON::Value thisFrag; - thisFrag["num"] = (*arrIt)["num"].asInt(); - thisFrag["time"] = (*arrIt)["time"].asInt(); - thisFrag["len"] = fragLen; - thisFrag["dur"] = fragDur; - thisFrag["size"] = fragSize; - if (fragDur / 1000){ - thisFrag["bps"] = fragSize / (fragDur / 1000); - if (maxBps < (fragSize / (fragDur / 1000))){ - maxBps = (fragSize / (fragDur / 999)); - } - } else { - thisFrag["bps"] = 1; - } - meta["tracks"][it->first]["frags"].append(thisFrag); - break; - } - fragLen ++; - fragDur += (*it2)["len"].asInt(); - fragSize += (*it2)["size"].asInt(); - } - } - } - meta["tracks"][it->first]["maxbps"] = maxBps; } - meta["firstms"] = firstms; - meta["lastms"] = lastms; - meta["length"] = (lastms - firstms) / 1000; - //append the revised header - std::string loader = meta.toPacked(); - long long int newHPos = F.addHeader(loader); - if ( !newHPos){ + std::string loader = meta.toJSON().toPacked(); + oriheader["moreheader"] = F.addHeader(loader); + if ( !oriheader["moreheader"].asInt()){ std::cerr << "Failure appending new header." << std::endl; return -1; } //re-write the original header with information about the location of the new one - oriheader["moreheader"] = newHPos; loader = oriheader.toPacked(); if (F.writeHeader(loader)){ return 0; diff --git a/src/converters/dtscmerge.cpp b/src/converters/dtscmerge.cpp index 4f63311c..218b1c51 100644 --- a/src/converters/dtscmerge.cpp +++ b/src/converters/dtscmerge.cpp @@ -57,7 +57,7 @@ namespace Converters { fullSort = false; }else{ DTSC::File F(tmpFileName); - if (!DTSC::isFixed(F.getMeta())){ + if (!F.getMeta().isFixed()){ std::cerr << tmpFileName << " has not been run through DTSCFix yet." << std::endl; return 1; } @@ -69,11 +69,11 @@ namespace Converters { outFile = DTSC::File(outFileName, true); }else{ outFile = DTSC::File(outFileName); - if (!DTSC::isFixed(outFile.getMeta())){ + if ( !outFile.getMeta().isFixed()){ std::cerr << outFileName << " has not been run through DTSCFix yet." << std::endl; return 1; } - meta = outFile.getMeta(); + meta = outFile.getMeta().toJSON(); newMeta = meta; if (meta.isMember("tracks") && meta["tracks"].size() > 0){ for (JSON::ObjIter trackIt = meta["tracks"].ObjBegin(); trackIt != meta["tracks"].ObjEnd(); trackIt++){ @@ -86,7 +86,7 @@ namespace Converters { std::multimap allSorted; for (std::map::iterator it = inFiles.begin(); it != inFiles.end(); it++){ - JSON::Value tmpMeta = it->second.getMeta(); + JSON::Value tmpMeta = it->second.getMeta().toJSON(); if (tmpMeta.isMember("tracks") && tmpMeta["tracks"].size() > 0){ for (JSON::ObjIter trackIt = tmpMeta["tracks"].ObjBegin(); trackIt != tmpMeta["tracks"].ObjEnd(); trackIt++){ long long int oldID = trackIt->second["trackid"].asInt(); diff --git a/src/info.cpp b/src/info.cpp index 1cdf0b71..65eccc5b 100644 --- a/src/info.cpp +++ b/src/info.cpp @@ -15,7 +15,7 @@ namespace Info { return 1; } DTSC::File F(argv[1]); - JSON::Value fileSpecs = F.getMeta(); + JSON::Value fileSpecs = F.getMeta().toJSON(); if( !fileSpecs ) { char ** cmd = (char**)malloc(3*sizeof(char*)); cmd[0] = (char*)"ffprobe"; @@ -95,8 +95,9 @@ namespace Info { } JSON::Value tracks = fileSpecs["tracks"]; for(JSON::ObjIter trackIt = tracks.ObjBegin(); trackIt != tracks.ObjEnd(); trackIt++){ - fileSpecs["tracks"][trackIt->first].removeMember("frags"); + fileSpecs["tracks"][trackIt->first].removeMember("fragments"); fileSpecs["tracks"][trackIt->first].removeMember("keys"); + fileSpecs["tracks"][trackIt->first].removeMember("parts"); } } printf( "%s", fileSpecs.toString().c_str() );