Fixed what hopefully were the last few problems with live Smooth/Dynamic streaming.
This commit is contained in:
parent
f18dc5d85e
commit
b1e0894fd7
3 changed files with 39 additions and 38 deletions
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 {
|
|||
"<mimeType>video/mp4</mimeType>\n"
|
||||
"<streamType>recorded</streamType>\n"
|
||||
"<deliveryType>streaming</deliveryType>\n"
|
||||
"<bootstrapInfo profile=\"named\" id=\"bootstrap1\">" + Base64::encode(GenerateBootstrap(MovieId, metadata, 1, 0, 0)) + "</bootstrapInfo>\n"
|
||||
"<bootstrapInfo profile=\"named\" id=\"bootstrap1\">" + Base64::encode(GenerateBootstrap(MovieId, metadata)) + "</bootstrapInfo>\n"
|
||||
"<media streamId=\"1\" bootstrapInfoId=\"bootstrap1\" url=\"" + MovieId + "/\">\n"
|
||||
"<metadata>AgAKb25NZXRhRGF0YQMAAAk=</metadata>\n"
|
||||
"</media>\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);
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
#include <mist/stream.h>
|
||||
#include <mist/timing.h>
|
||||
|
||||
/// 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 << "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n";
|
||||
Result << "<SmoothStreamingMedia MajorVersion=\"2\" MinorVersion=\"0\" TimeScale=\"10000000\" ";
|
||||
if (metadata.isMember("vod")){
|
||||
Result << "Duration=\"" << metadata["lastms"].asInt() << "\"";
|
||||
Result << "Duration=\"" << metadata["lastms"].asInt() << "0000\"";
|
||||
}else{
|
||||
Result << "Duration=\"0\" IsLive=\"TRUE\" LookAheadFragmentCount=\"2\" DVRWindowLength=\"" + metadata["buffer_window"].asString() + "0000\" CanSeek=\"TRUE\" CanPause=\"TRUE\" ";
|
||||
}
|
||||
|
@ -47,14 +47,13 @@ namespace Connector_HTTP {
|
|||
Result << std::dec;
|
||||
Result << "\" SamplingRate=\"" << metadata["audio"]["rate"].asInt()
|
||||
<< "\" Channels=\"2\" BitsPerSample=\"16\" PacketSize=\"4\" AudioTag=\"255\" FourCC=\"AACL\" />\n";
|
||||
for (int i = 0; i < metadata["keytime"].size() - 1; i++){
|
||||
for (unsigned int i = 0; i < metadata["keylen"].size(); i++){
|
||||
Result << " <c ";
|
||||
if (i == 0){
|
||||
Result << "t=\"" << metadata["keytime"][0u].asInt() * 10000 << "\" ";
|
||||
Result << "t=\"" << metadata["keytime"][i].asInt() * 10000 << "\" ";
|
||||
}
|
||||
Result << "d=\"" << 10000 * (metadata["keytime"][i + 1].asInt() - metadata["keytime"][i].asInt()) << "\" />\n";
|
||||
Result << "d=\"" << metadata["keylen"][i].asInt() * 10000 << "\" />\n";
|
||||
}
|
||||
Result << " <c d=\"" << 10000 * (metadata["lastms"].asInt() - metadata["keytime"][metadata["keytime"].size() - 1].asInt()) << "\" />\n";
|
||||
Result << " </StreamIndex>\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 << " <c ";
|
||||
if (i == 0){
|
||||
Result << "t=\"" << metadata["keytime"][0u].asInt() * 10000 << "\" ";
|
||||
Result << "t=\"" << metadata["keytime"][i].asInt() * 10000 << "\" ";
|
||||
}
|
||||
Result << "d=\"" << 10000 * (metadata["keytime"][i + 1].asInt() - metadata["keytime"][i].asInt()) << "\" />\n";
|
||||
Result << "d=\"" << metadata["keylen"][i].asInt() * 10000 << "\" />\n";
|
||||
}
|
||||
Result << " <c d=\"" << 10000 * (metadata["lastms"].asInt() - metadata["keytime"][metadata["keytime"].size() - 1].asInt()) << "\" />\n";
|
||||
Result << " </StreamIndex>\n";
|
||||
}
|
||||
Result << "</SmoothStreamingMedia>\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);
|
||||
|
|
Loading…
Add table
Reference in a new issue