Updates to all connectors for live support

This commit is contained in:
Erik Zandvliet 2013-02-27 09:47:09 +01:00 committed by Thulinma
parent ddf4983836
commit dcd66ce4ff
5 changed files with 118 additions and 71 deletions

View file

@ -114,7 +114,14 @@ namespace Buffer {
break; break;
} }
case 'f': { //frame-seek case 'f': { //frame-seek
//ignored for now fprintf( stderr, "Received a frame-seek\n" );
unsigned int frameno = JSON::Value(usr->S.Received().get().substr(2)).asInt();
usr->myRing->waiting = false;
usr->myRing->starved = false;
usr->myRing->b = thisStream->getStream()->frameSeek(frameno);
if (usr->myRing->playCount > 0 ) {
usr->myRing->playCount = 0;
}
break; break;
} }
case 'p': { //play case 'p': { //play
@ -122,6 +129,7 @@ namespace Buffer {
break; break;
} }
case 'o': { //once-play case 'o': { //once-play
fprintf( stderr, "Received a play-once\n" );
if (usr->myRing->playCount >= 0 ) { if (usr->myRing->playCount >= 0 ) {
usr->myRing->playCount++; usr->myRing->playCount++;
} }
@ -156,7 +164,7 @@ namespace Buffer {
while (std::cin.good() && buffer_running){ while (std::cin.good() && buffer_running){
//slow down packet receiving to real-time //slow down packet receiving to real-time
now = getNowMS(); now = getNowMS();
if ((now - timeDiff >= lastPacket) || (lastPacket - (now - timeDiff) > 15000)){ if (((now - timeDiff) >= lastPacket) || (lastPacket - (now - timeDiff) > 15000)){
thisStream->getWriteLock(); thisStream->getWriteLock();
if (thisStream->getStream()->parsePacket(inBuffer)){ if (thisStream->getStream()->parsePacket(inBuffer)){
thisStream->getStream()->outPacket(0); thisStream->getStream()->outPacket(0);

View file

@ -203,6 +203,7 @@ namespace Connector_HTTP {
void Handle_Through_Connector(HTTP::Parser & H, Socket::Connection * conn, std::string & connector){ void Handle_Through_Connector(HTTP::Parser & H, Socket::Connection * conn, std::string & connector){
//create a unique ID based on a hash of the user agent and host, followed by the stream name and connector //create a unique ID based on a hash of the user agent and host, followed by the stream name and connector
std::string uid = Secure::md5(H.GetHeader("User-Agent") + conn->getHost()) + "_" + H.GetVar("stream") + "_" + connector; std::string uid = Secure::md5(H.GetHeader("User-Agent") + conn->getHost()) + "_" + H.GetVar("stream") + "_" + connector;
H.SetHeader("X-Stream", H.GetVar("stream"));
H.SetHeader("X-UID", uid); //add the UID to the headers before copying H.SetHeader("X-UID", uid); //add the UID to the headers before copying
H.SetHeader("X-Origin", conn->getHost()); //add the UID to the headers before copying H.SetHeader("X-Origin", conn->getHost()); //add the UID to the headers before copying
std::string request = H.BuildRequest(); //copy the request for later forwarding to the connector std::string request = H.BuildRequest(); //copy the request for later forwarding to the connector
@ -321,8 +322,8 @@ namespace Connector_HTTP {
/// - progressive (request fed from http_progressive connector) /// - progressive (request fed from http_progressive connector)
std::string getHTTPType(HTTP::Parser & H){ std::string getHTTPType(HTTP::Parser & H){
std::string url = H.getUrl(); std::string url = H.getUrl();
if ((url.find("f4m") != std::string::npos) || ((url.find("Seg") != std::string::npos) && (url.find("Frag") != std::string::npos))){ if (url.find("/dynamic/") != std::string::npos){
std::string streamname = url.substr(1, url.find("/", 1) - 1); std::string streamname = url.substr(9, url.find("/", 9) - 9);
Util::Stream::sanitizeName(streamname); Util::Stream::sanitizeName(streamname);
H.SetVar("stream", streamname); H.SetVar("stream", streamname);
return "dynamic"; return "dynamic";

View file

@ -35,10 +35,10 @@ namespace Connector_HTTP {
}else{ }else{
asrt.setUpdate(true); asrt.setUpdate(true);
} }
asrt.setVersion(1); asrt.setVersion(0);//1
asrt.setQualityEntry(empty, 0); //asrt.setQualityEntry(empty, 0);
if ( !metadata.isMember("keytime") || metadata["keytime"].size() == 0){ if (metadata.isMember("keynum")){
asrt.setSegmentRun(1, 20000, 0); asrt.setSegmentRun(1, -1, 0);
}else{ }else{
asrt.setSegmentRun(1, metadata["keytime"].size(), 0); asrt.setSegmentRun(1, metadata["keytime"].size(), 0);
} }
@ -49,19 +49,18 @@ namespace Connector_HTTP {
}else{ }else{
afrt.setUpdate(true); afrt.setUpdate(true);
} }
afrt.setVersion(1); afrt.setVersion(0);//1
afrt.setTimeScale(1000); afrt.setTimeScale(1000);
afrt.setQualityEntry(empty, 0); //afrt.setQualityEntry(empty, 0);
MP4::afrt_runtable afrtrun; MP4::afrt_runtable afrtrun;
if ( !metadata.isMember("keytime") || metadata["keytime"].size() == 0){ if (metadata.isMember("keynum")){
afrtrun.firstFragment = 1; unsigned long long int firstAvail = metadata["keynum"].size() / 2;
afrtrun.firstTimestamp = 0; for (int i = firstAvail; i < metadata["keynum"].size() -2; i++ ) {
if ( !metadata.isMember("video") || !metadata["video"].isMember("keyms") || metadata["video"]["keyms"].asInt() == 0){ afrtrun.firstFragment = metadata["keynum"][i].asInt();
afrtrun.duration = 2000; afrtrun.firstTimestamp = metadata["keytime"][i].asInt();
}else{ afrtrun.duration = metadata["keytime"][i+1].asInt() - metadata["keytime"][i].asInt();
afrtrun.duration = metadata["video"]["keyms"].asInt(); afrt.setFragmentRun(afrtrun, i - firstAvail);
} }
afrt.setFragmentRun(afrtrun, 0);
}else{ }else{
for (int i = 0; i < metadata["keytime"].size(); i++){ for (int i = 0; i < metadata["keytime"].size(); i++){
afrtrun.firstFragment = i + 1; afrtrun.firstFragment = i + 1;
@ -80,8 +79,12 @@ namespace Connector_HTTP {
} }
MP4::ABST abst; MP4::ABST abst;
abst.setVersion(1); abst.setVersion(0);
abst.setBootstrapinfoVersion(1); if( metadata.isMember("keynum") ) {
abst.setBootstrapinfoVersion(metadata["keynum"][0u].asInt());
}else{
abst.setBootstrapinfoVersion(1);
}
abst.setProfile(0); abst.setProfile(0);
if (starttime == 0){ if (starttime == 0){
abst.setUpdate(false); abst.setUpdate(false);
@ -98,14 +101,14 @@ namespace Connector_HTTP {
} }
}else{ }else{
abst.setLive(true); abst.setLive(true);
abst.setCurrentMediaTime(0xFFFFFFFF); abst.setCurrentMediaTime(metadata["lastms"].asInt());
} }
abst.setSmpteTimeCodeOffset(0); abst.setSmpteTimeCodeOffset(0);
abst.setMovieIdentifier(MovieId); abst.setMovieIdentifier(MovieId);
abst.setServerEntry(empty, 0); //abst.setServerEntry(empty, 0);
abst.setQualityEntry(empty, 0); //abst.setQualityEntry(empty, 0);
abst.setDrmData(empty); //abst.setDrmData(empty);
abst.setMetaData(empty); //abst.setMetaData(empty);
abst.setSegmentRunTable(asrt, 0); abst.setSegmentRunTable(asrt, 0);
abst.setFragmentRunTable(afrt, 0); abst.setFragmentRunTable(afrt, 0);
@ -118,7 +121,7 @@ namespace Connector_HTTP {
/// Returns a F4M-format manifest file /// Returns a F4M-format manifest file
std::string BuildManifest(std::string & MovieId, JSON::Value & metadata){ std::string BuildManifest(std::string & MovieId, JSON::Value & metadata){
std::string Result; std::string Result;
if (metadata.isMember("length") && metadata["length"].asInt() > 0){ if ( !metadata.isMember("keynum")){
Result = Result =
"<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
"<manifest xmlns=\"http://ns.adobe.com/f4m/1.0\">\n" "<manifest xmlns=\"http://ns.adobe.com/f4m/1.0\">\n"
@ -139,11 +142,14 @@ namespace Connector_HTTP {
Result = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" Result = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
"<manifest xmlns=\"http://ns.adobe.com/f4m/1.0\">\n" "<manifest xmlns=\"http://ns.adobe.com/f4m/1.0\">\n"
"<id>" + MovieId + "</id>\n" "<id>" + MovieId + "</id>\n"
"<duration>0.00</duration>\n"
"<mimeType>video/mp4</mimeType>\n" "<mimeType>video/mp4</mimeType>\n"
"<streamType>live</streamType>\n" "<streamType>live</streamType>\n"
"<deliveryType>streaming</deliveryType>\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\" url=\"" + MovieId + ".bootstrap\"></bootstrapInfo>\n"
"<media streamId=\"1\" bootstrapInfoId=\"bootstrap1\" url=\"" + MovieId + "/\"></media>\n" "<media bootstrapInfoId=\"bootstrap1\" url=\"" + MovieId + "/\">"
"<metadata>AgAKb25NZXRhRGF0YQgAAAAAAA9tZXRhZGF0YWNyZWF0b3ICABBBbmV2aWEgVmlhTW90aW9uAAhoYXNBdWRpbwEBAAhoYXNWaWRlbwEBAAhkdXJhdGlvbgBBIWWYAAAAAAAPYXVkaW9zYW1wbGVyYXRlAEBIAAAAAAAAAA1hdWRpb2RhdGFyYXRlAEBgAAAAAAAAAAxhdWRpb2NvZGVjaWQCAARtcDRhAAZhYWNhb3QAQAAAAAAAAAAABXdpZHRoAECQAAAAAAAAAAZoZWlnaHQAQIIAAAAAAAAADXZpZGVvZGF0YXJhdGUAQJ9AAAAAAAAADHZpZGVvY29kZWNpZAIABEFWQzEACmF2Y3Byb2ZpbGUAQFNAAAAAAAAACGF2Y2xldmVsAEA/AAAAAAAAAAAJ</metadata>\n"
"</media>\n"
"</manifest>\n"; "</manifest>\n";
} }
#if DEBUG >= 8 #if DEBUG >= 8
@ -193,27 +199,38 @@ namespace Connector_HTTP {
if (HTTP_R.Read(conn.Received().get())){ if (HTTP_R.Read(conn.Received().get())){
#if DEBUG >= 4 #if DEBUG >= 4
std::cout << "Received request: " << HTTP_R.getUrl() << std::endl; std::cout << "Received request: " << HTTP_R.getUrl() << std::endl;
std::cout << "Received request: " << HTTP_R.BuildRequest() << std::endl;
#endif #endif
conn.setHost(HTTP_R.GetHeader("X-Origin")); conn.setHost(HTTP_R.GetHeader("X-Origin"));
if (HTTP_R.url.find("f4m") == std::string::npos){ streamname = HTTP_R.GetHeader("X-Stream");
streamname = HTTP_R.url.substr(1, HTTP_R.url.find("/", 1) - 1); if ( !ss){
if ( !ss){ ss = Util::Stream::getStream(streamname);
ss = Util::Stream::getStream(streamname); if ( !ss.connected()){
if ( !ss.connected()){
#if DEBUG >= 1 #if DEBUG >= 1
fprintf(stderr, "Could not connect to server!\n"); fprintf(stderr, "Could not connect to server!\n");
#endif #endif
ss.close(); ss.close();
HTTP_S.Clean(); HTTP_S.Clean();
HTTP_S.SetBody("No such stream is available on the system. Please try again.\n"); HTTP_S.SetBody("No such stream is available on the system. Please try again.\n");
conn.SendNow(HTTP_S.BuildResponse("404", "Not found")); conn.SendNow(HTTP_S.BuildResponse("404", "Not found"));
ready4data = false; ready4data = false;
continue; HTTP_R.Clean(); //clean for any possible next requests
} continue;
ss.setBlocking(false);
inited = true;
} }
Quality = HTTP_R.url.substr(HTTP_R.url.find("/", 1) + 1); ss.setBlocking(false);
inited = true;
while ( !ss.spool()){}
Strm.parsePacket(ss.Received());
}
if (HTTP_R.url.find(".bootstrap") != std::string::npos){
HTTP_S.Clean();
HTTP_S.SetBody(GenerateBootstrap(streamname, Strm.metadata, 1, 0, 0));
conn.SendNow(HTTP_S.BuildResponse("200", "OK"));
HTTP_R.Clean(); //clean for any possible next requests
continue;
}
if (HTTP_R.url.find("f4m") == std::string::npos){
Quality = HTTP_R.url.substr(HTTP_R.url.find("/", 10) + 1);
Quality = Quality.substr(0, Quality.find("Seg")); Quality = Quality.substr(0, Quality.find("Seg"));
temp = HTTP_R.url.find("Seg") + 3; temp = HTTP_R.url.find("Seg") + 3;
Segment = atoi(HTTP_R.url.substr(temp, HTTP_R.url.find("-", temp) - temp).c_str()); Segment = atoi(HTTP_R.url.substr(temp, HTTP_R.url.find("-", temp) - temp).c_str());
@ -227,7 +244,6 @@ namespace Connector_HTTP {
ss.SendNow(sstream.str().c_str()); ss.SendNow(sstream.str().c_str());
Flash_RequestPending++; Flash_RequestPending++;
}else{ }else{
streamname = HTTP_R.url.substr(1, HTTP_R.url.find("/", 1) - 1);
if ( !Strm.metadata.isNull()){ if ( !Strm.metadata.isNull()){
HTTP_S.Clean(); HTTP_S.Clean();
HTTP_S.SetHeader("Content-Type", "text/xml"); HTTP_S.SetHeader("Content-Type", "text/xml");
@ -284,6 +300,7 @@ namespace Connector_HTTP {
} }
if (ss.spool()){ if (ss.spool()){
while (Strm.parsePacket(ss.Received())){ while (Strm.parsePacket(ss.Received())){
/*
if (Strm.getPacket(0).isMember("time")){ if (Strm.getPacket(0).isMember("time")){
if ( !Strm.metadata.isMember("firsttime")){ if ( !Strm.metadata.isMember("firsttime")){
Strm.metadata["firsttime"] = Strm.getPacket(0)["time"]; Strm.metadata["firsttime"] = Strm.getPacket(0)["time"];
@ -294,6 +311,7 @@ namespace Connector_HTTP {
} }
Strm.metadata["lasttime"] = Strm.getPacket(0)["time"]; Strm.metadata["lasttime"] = Strm.getPacket(0)["time"];
} }
*/
if (pending_manifest){ if (pending_manifest){
HTTP_S.Clean(); HTTP_S.Clean();
HTTP_S.SetHeader("Content-Type", "text/xml"); HTTP_S.SetHeader("Content-Type", "text/xml");

View file

@ -31,12 +31,18 @@ namespace Connector_HTTP {
if (metadata.isNull()){ if (metadata.isNull()){
return result; return result;
} }
result.push_back(0); if( metadata.isMember( "keynum" ) ) {
int currentBase = metadata["keytime"][0u].asInt(); for (int i = 0; i < metadata["keynum"].size(); i++){
for (int i = 0; i < metadata["keytime"].size(); i++){ result.push_back(metadata["keynum"][i].asInt());
if ((metadata["keytime"][i].asInt() - currentBase) > 10000){ }
currentBase = metadata["keytime"][i].asInt(); }else{
result.push_back(i); result.push_back(0);
int currentBase = metadata["keytime"][0u].asInt();
for (int i = 0; i < metadata["keytime"].size(); i++){
if ((metadata["keytime"][i].asInt() - currentBase) > 10000){
currentBase = metadata["keytime"][i].asInt();
result.push_back(i);
}
} }
} }
return result; return result;
@ -61,7 +67,6 @@ namespace Connector_HTTP {
"#EXT-X-MEDIA-SEQUENCE:0\r\n"; "#EXT-X-MEDIA-SEQUENCE:0\r\n";
//"#EXT-X-PLAYLIST-TYPE:VOD\r\n"; //"#EXT-X-PLAYLIST-TYPE:VOD\r\n";
int lastDuration = 0; int lastDuration = 0;
bool writeOffset = true;
for (int i = 0; i < fragIndices.size() - 1; i++){ for (int i = 0; i < fragIndices.size() - 1; i++){
Result << "#EXTINF:" << (metadata["keytime"][fragIndices[i + 1]].asInt() - lastDuration) / 1000 << ", no desc\r\n" << fragIndices[i] + 1 Result << "#EXTINF:" << (metadata["keytime"][fragIndices[i + 1]].asInt() - lastDuration) / 1000 << ", no desc\r\n" << fragIndices[i] + 1
<< "_" << fragIndices[i + 1] - fragIndices[i] << ".ts\r\n"; << "_" << fragIndices[i + 1] - fragIndices[i] << ".ts\r\n";
@ -72,6 +77,12 @@ namespace Connector_HTTP {
Result << "#EXTM3U\r\n" Result << "#EXTM3U\r\n"
"#EXT-X-MEDIA-SEQUENCE:0\r\n" "#EXT-X-MEDIA-SEQUENCE:0\r\n"
"#EXT-X-TARGETDURATION:" << (longestFragment / 1000) + 1 << "\r\n"; "#EXT-X-TARGETDURATION:" << (longestFragment / 1000) + 1 << "\r\n";
int lastDuration = 0;
for (int i = 0; i < fragIndices.size() - 1; i++){
Result << "#EXTINF:" << (metadata["keytime"][fragIndices[i + 1]].asInt() - lastDuration) / 1000 << ", no desc\r\n" << fragIndices[i] + 1
<< "_" << fragIndices[i + 1] - fragIndices[i] << ".ts\r\n";
lastDuration = metadata["keytime"][fragIndices[i + 1]].asInt();
}
} }
#if DEBUG >= 8 #if DEBUG >= 8
std::cerr << "Sending this index:" << std::endl << Result.str() << std::endl; std::cerr << "Sending this index:" << std::endl << Result.str() << std::endl;
@ -133,23 +144,25 @@ namespace Connector_HTTP {
std::cout << "Received request: " << HTTP_R.getUrl() << std::endl; std::cout << "Received request: " << HTTP_R.getUrl() << std::endl;
#endif #endif
conn.setHost(HTTP_R.GetHeader("X-Origin")); conn.setHost(HTTP_R.GetHeader("X-Origin"));
if (HTTP_R.url.find(".m3u") == std::string::npos){ streamname = HTTP_R.GetHeader("X-Stream");
streamname = HTTP_R.url.substr(5, HTTP_R.url.find("/", 5) - 5); if ( !ss){
if ( !ss){ ss = Util::Stream::getStream(streamname);
ss = Util::Stream::getStream(streamname); if ( !ss.connected()){
if ( !ss.connected()){
#if DEBUG >= 1 #if DEBUG >= 1
fprintf(stderr, "Could not connect to server!\n"); fprintf(stderr, "Could not connect to server!\n");
#endif #endif
HTTP_S.Clean(); HTTP_S.Clean();
HTTP_S.SetBody("No such stream is available on the system. Please try again.\n"); HTTP_S.SetBody("No such stream is available on the system. Please try again.\n");
conn.SendNow(HTTP_S.BuildResponse("404", "Not found")); conn.SendNow(HTTP_S.BuildResponse("404", "Not found"));
ready4data = false; ready4data = false;
continue; continue;
}
ss.setBlocking(false);
inited = true;
} }
ss.setBlocking(false);
inited = true;
while ( !ss.spool()){}
Strm.parsePacket(ss.Received());
}
if (HTTP_R.url.find(".m3u") == std::string::npos){
temp = HTTP_R.url.find("/", 5) + 1; temp = HTTP_R.url.find("/", 5) + 1;
Segment = atoi(HTTP_R.url.substr(temp, HTTP_R.url.find("_", temp) - temp).c_str()); Segment = atoi(HTTP_R.url.substr(temp, HTTP_R.url.find("_", temp) - temp).c_str());
temp = HTTP_R.url.find("_", temp) + 1; temp = HTTP_R.url.find("_", temp) + 1;
@ -163,7 +176,9 @@ namespace Connector_HTTP {
ss.SendNow(sstream.str().c_str()); ss.SendNow(sstream.str().c_str());
Flash_RequestPending++; Flash_RequestPending++;
}else{ }else{
streamname = HTTP_R.url.substr(5, HTTP_R.url.find("/", 5) - 5); if ( ss.spool()){
Strm.parsePacket(ss.Received());
}
if (HTTP_R.url.find(".m3u8") != std::string::npos){ if (HTTP_R.url.find(".m3u8") != std::string::npos){
manifestType = "audio/x-mpegurl"; manifestType = "audio/x-mpegurl";
}else{ }else{

View file

@ -29,8 +29,13 @@ namespace Connector_HTTP {
std::string BuildManifest(std::string & MovieId, JSON::Value & metadata){ std::string BuildManifest(std::string & MovieId, JSON::Value & metadata){
std::stringstream Result; std::stringstream Result;
Result << "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"; Result << "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n";
Result << "<SmoothStreamingMedia MajorVersion=\"2\" MinorVersion=\"0\" TimeScale=\"10000000\" Duration=\"" << metadata["lastms"].asInt() Result << "<SmoothStreamingMedia MajorVersion=\"2\" MinorVersion=\"0\" TimeScale=\"10000000\" ";
<< "\">\n"; if (metadata.isMember("length") && metadata["length"].asInt() > 0){
Result << "Duration=\"" << metadata["lastms"].asInt() << "\"";
} else {
Result << "Duration=\"0\" IsLive=\"TRUE\" LookAheadFragmentCount=\"2\" ";
}
Result << ">\n";
if (metadata.isMember("audio")){ if (metadata.isMember("audio")){
Result << " <StreamIndex Type=\"audio\" QualityLevels=\"1\" Name=\"audio\" Chunks=\"" << metadata["keytime"].size() Result << " <StreamIndex Type=\"audio\" QualityLevels=\"1\" Name=\"audio\" Chunks=\"" << metadata["keytime"].size()
<< "\" Url=\"Q({bitrate})/A({start time})\">\n"; << "\" Url=\"Q({bitrate})/A({start time})\">\n";
@ -45,7 +50,7 @@ namespace Connector_HTTP {
for (int i = 0; i < metadata["keytime"].size() - 1; i++){ for (int i = 0; i < metadata["keytime"].size() - 1; i++){
Result << " <c "; Result << " <c ";
if (i == 0){ if (i == 0){
Result << "t=\"0\" "; Result << "t=\"" << metadata["keytime"][0u].asInt() * 10000 << "\" ";
} }
Result << "d=\"" << 10000 * (metadata["keytime"][i + 1].asInt() - metadata["keytime"][i].asInt()) << "\" />\n"; Result << "d=\"" << 10000 * (metadata["keytime"][i + 1].asInt() - metadata["keytime"][i].asInt()) << "\" />\n";
} }
@ -71,7 +76,7 @@ namespace Connector_HTTP {
for (int i = 0; i < metadata["keytime"].size() - 1; i++){ for (int i = 0; i < metadata["keytime"].size() - 1; i++){
Result << " <c "; Result << " <c ";
if (i == 0){ if (i == 0){
Result << "t=\"0\" "; Result << "t=\"" << metadata["keytime"][0u].asInt() * 10000 << "\" ";
} }
Result << "d=\"" << 10000 * (metadata["keytime"][i + 1].asInt() - metadata["keytime"][i].asInt()) << "\" />\n"; Result << "d=\"" << 10000 * (metadata["keytime"][i + 1].asInt() - metadata["keytime"][i].asInt()) << "\" />\n";
} }