From c6aabfa4bf9311fae5d17efa9528f91e2cc587b7 Mon Sep 17 00:00:00 2001 From: Erik Zandvliet Date: Thu, 6 Jun 2013 14:52:55 +0200 Subject: [PATCH] Updated MistConnHTTPLive for DTSC2, fixed a bug in fragmentizing. --- src/buffer/player.cpp | 12 ++++- src/connectors/conn_http_live.cpp | 84 ++++++++++++++++++++++--------- src/converters/dtscfix.cpp | 11 +++- 3 files changed, 81 insertions(+), 26 deletions(-) diff --git a/src/buffer/player.cpp b/src/buffer/player.cpp index 66b9bf3c..fd8960f6 100644 --- a/src/buffer/player.cpp +++ b/src/buffer/player.cpp @@ -111,8 +111,10 @@ int main(int argc, char** argv){ JSON::Value last_pack; bool meta_sent = false; + int playUntil = -1; long long now, lastTime = 0; //for timing of sending packets long long bench = 0; //for benchmarking + std::set newSelect; Stats sts; CYG_DEFI @@ -182,6 +184,11 @@ int main(int argc, char** argv){ playing = -1; lastTime = 0; in_out.setBlocking(false); + if (in_out.Received().get().size() >= 2){ + playUntil = atoi(in_out.Received().get().substr(2).c_str()); + }else{ + playUntil = 0; + } break; } case 'o': { //once-play @@ -199,7 +206,7 @@ int main(int argc, char** argv){ break; } case 't': { - std::set newSelect; + newSelect.clear(); std::string tmp = in_out.Received().get().substr(2); while (tmp != ""){ newSelect.insert(atoi(tmp.substr(0,tmp.find(' ')).c_str())); @@ -239,6 +246,9 @@ int main(int argc, char** argv){ --playing; } } + if ( playUntil && playUntil < source.getJSON()["time"].asInt()){ + playing = 0; + } if (playing == 0){ #if DEBUG >= 4 std::cerr << "Completed VoD request in MistPlayer (" << (Util::getMS() - bench) << "ms)" << std::endl; diff --git a/src/connectors/conn_http_live.cpp b/src/connectors/conn_http_live.cpp index dc97a907..d9fe2db3 100644 --- a/src/connectors/conn_http_live.cpp +++ b/src/connectors/conn_http_live.cpp @@ -29,36 +29,54 @@ namespace Connector_HTTP { ///\param metadata The current metadata, used to generate the index. ///\return The index file for HTTP Live Streaming. std::string liveIndex(JSON::Value & metadata){ - std::stringstream Result; - if ( !metadata.isMember("live")){ + 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"].asString() == "audio"){ + audioId = trackIt->second["trackid"].asInt(); + audioName = trackIt->first; + break; + } + } + for (JSON::ObjIter trackIt = metadata["tracks"].ObjBegin(); trackIt != metadata["tracks"].ObjEnd(); trackIt++){ + if (trackIt->second["type"].asString() == "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 * 8 << "\r\n"; + result << trackIt->second["trackid"].asInt(); + if (audioId != -1){ + result << "_" << audioId; + } + result << "/index.m3u8\r\n"; + } + } + }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 << "#EXTM3U\r\n" + result << "#EXTM3U\r\n" "#EXT-X-TARGETDURATION:" << (longestFragment / 1000) + 1 << "\r\n" - "#EXT-X-MEDIA-SEQUENCE:0\r\n"; + "#EXT-X-MEDIA-SEQUENCE:" << metadata["trackid"].asInt() << "\r\n"; for (JSON::ArrIter ai = metadata["frags"].ArrBegin(); ai != metadata["frags"].ArrEnd(); ai++){ - Result << "#EXTINF:" << (*ai)["dur"].asInt() / 1000 << ", no desc\r\n" << (*ai)["num"].asInt() << "_" << (*ai)["len"].asInt() << ".ts\r\n"; - } - Result << "#EXT-X-ENDLIST"; - }else{ - if (metadata["missed_frags"].asInt() < 0){ - metadata["missed_frags"] = 0ll; - } - Result << "#EXTM3U\r\n" - "#EXT-X-MEDIA-SEQUENCE:" << metadata["missed_frags"].asInt() <<"\r\n" - "#EXT-X-TARGETDURATION:30\r\n"; - for (JSON::ArrIter ai = metadata["frags"].ArrBegin(); ai != metadata["frags"].ArrEnd(); ai++){ - Result << "#EXTINF:" << (*ai)["dur"].asInt() / 1000 << ", no desc\r\n" << (*ai)["num"].asInt() << "_" << (*ai)["len"].asInt() << ".ts\r\n"; + result << "#EXTINF:" << (*ai)["dur"].asInt() / 1000 << ", no desc\r\n" + << metadata["keys"][(*ai)["num"].asInt() - 1]["time"].asInt() << "_" << (*ai)["dur"].asInt() + metadata["keys"][(*ai)["num"].asInt() - 1]["time"].asInt() << ".ts\r\n"; } + result << "#EXT-X-ENDLIST"; } #if DEBUG >= 8 std::cerr << "Sending this index:" << std::endl << Result.str() << std::endl; #endif - return Result.str(); + return result.str(); } //liveIndex ///\brief Main function for the HTTP Live Connector @@ -92,6 +110,8 @@ namespace Connector_HTTP { int Segment = -1; int temp; + int trackID = 0; + int audioTrackID = 0; unsigned int lastStats = 0; conn.setBlocking(false); //do not block on conn.spool() when no data is available @@ -137,6 +157,10 @@ namespace Connector_HTTP { } if (HTTP_R.url.find(".m3u") == std::string::npos){ temp = HTTP_R.url.find("/", 5) + 1; + std::string allTracks = HTTP_R.url.substr(temp, HTTP_R.url.find("/", temp) - temp); + trackID = atoi(allTracks.c_str()); + audioTrackID = atoi(allTracks.substr(allTracks.find("_")+1).c_str()); + temp = HTTP_R.url.find("/", temp) + 1; Segment = atoi(HTTP_R.url.substr(temp, HTTP_R.url.find("_", temp) - temp).c_str()); temp = HTTP_R.url.find("_", temp) + 1; int frameCount = atoi(HTTP_R.url.substr(temp, HTTP_R.url.find(".ts", temp) - temp).c_str()); @@ -159,13 +183,19 @@ namespace Connector_HTTP { continue; } } - std::stringstream sstream; - sstream << "f " << Segment << "\n"; - for (int i = 0; i < frameCount; i++){ - sstream << "o \n"; + for (int i = 0; i < allTracks.size(); i++){ + if (allTracks[i] == '_'){ + allTracks[i] = ' '; + } } + std::stringstream sstream; + sstream << "t " << allTracks << "\n"; + sstream << "s " << Segment << "\n"; + sstream << "p " << frameCount << "\n"; ss.SendNow(sstream.str().c_str()); + fprintf(stderr,"Sending %s to player\n", sstream.str().c_str()); }else{ + std::string request = HTTP_R.url.substr(HTTP_R.url.find("/", 5) + 1); if (HTTP_R.url.find(".m3u8") != std::string::npos){ manifestType = "audio/x-mpegurl"; }else{ @@ -174,7 +204,13 @@ namespace Connector_HTTP { HTTP_S.Clean(); HTTP_S.SetHeader("Content-Type", manifestType); HTTP_S.SetHeader("Cache-Control", "no-cache"); - std::string manifest = liveIndex(Strm.metadata); + std::string manifest; + if (request.find("/") == std::string::npos){ + manifest = liveIndex(Strm.metadata); + }else{ + int selectId = atoi(request.substr(0,request.find("/")).c_str()); + manifest = liveIndex(Strm.getTrackById(selectId)); + } HTTP_S.SetBody(manifest); conn.SendNow(HTTP_S.BuildResponse("200", "OK")); } @@ -209,7 +245,7 @@ namespace Connector_HTTP { TSBuf.str(""); } if ( !haveAvcc){ - avccbox.setPayload(Strm.metadata["video"]["init"].asString()); + avccbox.setPayload(Strm.getTrackById(trackID)["init"].asString()); haveAvcc = true; } if (Strm.lastType() == DTSC::VIDEO || Strm.lastType() == DTSC::AUDIO){ @@ -246,7 +282,7 @@ namespace Connector_HTTP { 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.getTrackById(audioTrackID)["init"].asString())); ToPack.append(Strm.lastData()); ToPack.prepend(TS::Packet::getPESAudioLeadIn(ToPack.bytes(1073741824ul), Strm.getPacket(0)["time"].asInt() * 90)); PIDno = 0x101; diff --git a/src/converters/dtscfix.cpp b/src/converters/dtscfix.cpp index f941a3b6..5b1942ad 100644 --- a/src/converters/dtscfix.cpp +++ b/src/converters/dtscfix.cpp @@ -216,25 +216,34 @@ namespace Converters { //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(); - for (JSON::ArrIter it2 = arrIt; it2 != meta["tracks"][it->first]["keys"].ArrEnd(); it2++){ + 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["len"] = fragLen; thisFrag["dur"] = fragDur; + thisFrag["size"] = fragSize; + thisFrag["bps"] = fragSize / (fragDur / 1000); + if (maxBps < (fragSize / (fragDur / 1000))){ + maxBps = (fragSize / (fragDur / 1000)); + } 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;