From b1e0894fd7d866bf24e284418aa409975c43718d Mon Sep 17 00:00:00 2001 From: Thulinma Date: Fri, 22 Mar 2013 22:57:14 +0100 Subject: [PATCH] Fixed what hopefully were the last few problems with live Smooth/Dynamic streaming. --- src/connectors/conn_http.cpp | 2 +- src/connectors/conn_http_dynamic.cpp | 43 ++++++++++++---------------- src/connectors/conn_http_smooth.cpp | 32 +++++++++++++-------- 3 files changed, 39 insertions(+), 38 deletions(-) diff --git a/src/connectors/conn_http.cpp b/src/connectors/conn_http.cpp index 71897f86..5be144c9 100644 --- a/src/connectors/conn_http.cpp +++ b/src/connectors/conn_http.cpp @@ -296,7 +296,7 @@ namespace Connector_HTTP { } connconn[uid]->lastuse = 0; timeout = 0; - Util::sleep(2000); + Util::sleep(5000); connconn[uid]->conn->SendNow(request); continue; } diff --git a/src/connectors/conn_http_dynamic.cpp b/src/connectors/conn_http_dynamic.cpp index e8a1570b..759f4d8c 100644 --- a/src/connectors/conn_http_dynamic.cpp +++ b/src/connectors/conn_http_dynamic.cpp @@ -26,15 +26,11 @@ /// Holds everything unique to HTTP Dynamic Connector. namespace Connector_HTTP { - std::string GenerateBootstrap(std::string & MovieId, JSON::Value & metadata, int fragnum, int starttime, int endtime){ + std::string GenerateBootstrap(std::string & MovieId, JSON::Value & metadata, int fragnum = 0){ std::string empty; MP4::ASRT asrt; - if (starttime == 0 && metadata.isMember("vod")){ - asrt.setUpdate(false); - }else{ - asrt.setUpdate(true); - } + asrt.setUpdate(false); asrt.setVersion(1); //asrt.setQualityEntry(empty, 0); if (metadata.isMember("live")){ @@ -44,18 +40,19 @@ namespace Connector_HTTP { } MP4::AFRT afrt; - if (starttime == 0 && metadata.isMember("vod")){ - afrt.setUpdate(false); - }else{ - afrt.setUpdate(true); - } + 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; - for (int i = std::max(0u, metadata["keynum"].size() - 3); i < metadata["keynum"].size(); i++){ + 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(); @@ -72,17 +69,9 @@ namespace Connector_HTTP { MP4::ABST abst; abst.setVersion(1); - if (metadata.isMember("live")){ - abst.setBootstrapinfoVersion(metadata["keynum"][metadata["keynum"].size() - 2].asInt()); - }else{ - abst.setBootstrapinfoVersion(1); - } + abst.setBootstrapinfoVersion(1); abst.setProfile(0); - if (starttime == 0){ - abst.setUpdate(false); - }else{ - abst.setUpdate(true); - } + abst.setUpdate(false); abst.setTimeScale(1000); abst.setLive(false); abst.setCurrentMediaTime(metadata["lastms"].asInt()); @@ -111,7 +100,7 @@ namespace Connector_HTTP { "video/mp4\n" "recorded\n" "streaming\n" - "" + Base64::encode(GenerateBootstrap(MovieId, metadata, 1, 0, 0)) + "\n" + "" + Base64::encode(GenerateBootstrap(MovieId, metadata)) + "\n" "\n" "AgAKb25NZXRhRGF0YQMAAAk=\n" "\n" @@ -195,7 +184,7 @@ namespace Connector_HTTP { } if (HTTP_R.url.find(".abst") != std::string::npos){ HTTP_S.Clean(); - HTTP_S.SetBody(GenerateBootstrap(streamname, Strm.metadata, 1, 0, 0)); + HTTP_S.SetBody(GenerateBootstrap(streamname, Strm.metadata)); HTTP_S.SetHeader("Content-Type", "binary/octet"); HTTP_S.SetHeader("Cache-Control", "no-cache"); conn.SendNow(HTTP_S.BuildResponse("200", "OK")); @@ -215,6 +204,10 @@ namespace Connector_HTTP { #endif if (Strm.metadata.isMember("live")){ int seekable = Strm.canSeekFrame(ReqFragment); + if (seekable == 0){ + // iff the fragment in question is available, check if the next is available too + seekable = Strm.canSeekFrame(ReqFragment + 1); + } if (seekable < 0){ HTTP_S.Clean(); HTTP_S.SetBody("The requested fragment is no longer kept in memory on the server and cannot be served.\n"); @@ -261,7 +254,7 @@ namespace Connector_HTTP { HTTP_S.Clean(); HTTP_S.SetHeader("Content-Type", "video/mp4"); HTTP_S.SetBody(""); - std::string new_strap = GenerateBootstrap(streamname, Strm.metadata, 1, 0, 0); + std::string new_strap = GenerateBootstrap(streamname, Strm.metadata, ReqFragment); HTTP_S.SetHeader("Content-Length", FlashBufSize + 8 + new_strap.size()); //32+33+btstrp.size()); conn.SendNow(HTTP_S.BuildResponse("200", "OK")); conn.SendNow(new_strap); diff --git a/src/connectors/conn_http_smooth.cpp b/src/connectors/conn_http_smooth.cpp index e7b7e6f3..e7b5a5ab 100644 --- a/src/connectors/conn_http_smooth.cpp +++ b/src/connectors/conn_http_smooth.cpp @@ -23,7 +23,7 @@ #include #include -/// Holds everything unique to HTTP Dynamic Connector. +/// Holds everything unique to HTTP Connectors. namespace Connector_HTTP { /// Returns a Smooth-format manifest file std::string BuildManifest(std::string & MovieId, JSON::Value & metadata){ @@ -31,7 +31,7 @@ namespace Connector_HTTP { Result << "\n"; Result << "\n"; - for (int i = 0; i < metadata["keytime"].size() - 1; i++){ + for (unsigned int i = 0; i < metadata["keylen"].size(); i++){ Result << " \n"; + Result << "d=\"" << metadata["keylen"][i].asInt() * 10000 << "\" />\n"; } - Result << " \n"; Result << " \n"; } if (metadata.isMember("video")){ @@ -73,14 +72,13 @@ namespace Connector_HTTP { Result << std::dec; Result << "\" MaxWidth=\"" << metadata["video"]["width"].asInt() << "\" MaxHeight=\"" << metadata["video"]["height"].asInt() << "\" FourCC=\"AVC1\" />\n"; - for (int i = 0; i < metadata["keytime"].size() - 1; i++){ + for (unsigned int i = 0; i < metadata["keylen"].size(); i++){ Result << " \n"; + Result << "d=\"" << metadata["keylen"][i].asInt() * 10000 << "\" />\n"; } - Result << " \n"; Result << " \n"; } Result << "\n"; @@ -168,6 +166,17 @@ namespace Connector_HTTP { ReqFragment = atoll(tempStr.substr(0, tempStr.find(")")).c_str()); if (Strm.metadata.isMember("live")){ int seekable = Strm.canSeekms(ReqFragment / 10000); + if (seekable == 0){ + // iff the fragment in question is available, check if the next is available too + for (int i = 0; i < Strm.metadata["keytime"].size(); i++){ + if (Strm.metadata["keytime"][i].asInt() >= (ReqFragment / 10000)){ + if (i + 1 == Strm.metadata["keytime"].size()){ + seekable = 1; + } + break; + } + } + } if (seekable < 0){ HTTP_S.Clean(); HTTP_S.SetBody("The requested fragment is no longer kept in memory on the server and cannot be served.\n"); @@ -266,8 +275,7 @@ namespace Connector_HTTP { if (Strm.metadata["keytime"][i].asInt() > (ReqFragment / 10000)){ fragref_box.setTime(fragCount, Strm.metadata["keytime"][i].asInt() * 10000); fragref_box.setDuration(fragCount, Strm.metadata["keylen"][i].asInt() * 10000); - fragCount++; - fragref_box.setFragmentCount(fragCount); + fragref_box.setFragmentCount(++fragCount); } } traf_box.setContent(fragref_box, 3);