Updates to all connectors for live support
This commit is contained in:
parent
ddf4983836
commit
dcd66ce4ff
5 changed files with 118 additions and 71 deletions
|
@ -114,7 +114,14 @@ namespace Buffer {
|
|||
break;
|
||||
}
|
||||
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;
|
||||
}
|
||||
case 'p': { //play
|
||||
|
@ -122,6 +129,7 @@ namespace Buffer {
|
|||
break;
|
||||
}
|
||||
case 'o': { //once-play
|
||||
fprintf( stderr, "Received a play-once\n" );
|
||||
if (usr->myRing->playCount >= 0 ) {
|
||||
usr->myRing->playCount++;
|
||||
}
|
||||
|
@ -156,7 +164,7 @@ namespace Buffer {
|
|||
while (std::cin.good() && buffer_running){
|
||||
//slow down packet receiving to real-time
|
||||
now = getNowMS();
|
||||
if ((now - timeDiff >= lastPacket) || (lastPacket - (now - timeDiff) > 15000)){
|
||||
if (((now - timeDiff) >= lastPacket) || (lastPacket - (now - timeDiff) > 15000)){
|
||||
thisStream->getWriteLock();
|
||||
if (thisStream->getStream()->parsePacket(inBuffer)){
|
||||
thisStream->getStream()->outPacket(0);
|
||||
|
|
|
@ -203,6 +203,7 @@ namespace Connector_HTTP {
|
|||
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
|
||||
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-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
|
||||
|
@ -321,8 +322,8 @@ namespace Connector_HTTP {
|
|||
/// - progressive (request fed from http_progressive connector)
|
||||
std::string getHTTPType(HTTP::Parser & H){
|
||||
std::string url = H.getUrl();
|
||||
if ((url.find("f4m") != std::string::npos) || ((url.find("Seg") != std::string::npos) && (url.find("Frag") != std::string::npos))){
|
||||
std::string streamname = url.substr(1, url.find("/", 1) - 1);
|
||||
if (url.find("/dynamic/") != std::string::npos){
|
||||
std::string streamname = url.substr(9, url.find("/", 9) - 9);
|
||||
Util::Stream::sanitizeName(streamname);
|
||||
H.SetVar("stream", streamname);
|
||||
return "dynamic";
|
||||
|
|
|
@ -35,10 +35,10 @@ namespace Connector_HTTP {
|
|||
}else{
|
||||
asrt.setUpdate(true);
|
||||
}
|
||||
asrt.setVersion(1);
|
||||
asrt.setQualityEntry(empty, 0);
|
||||
if ( !metadata.isMember("keytime") || metadata["keytime"].size() == 0){
|
||||
asrt.setSegmentRun(1, 20000, 0);
|
||||
asrt.setVersion(0);//1
|
||||
//asrt.setQualityEntry(empty, 0);
|
||||
if (metadata.isMember("keynum")){
|
||||
asrt.setSegmentRun(1, -1, 0);
|
||||
}else{
|
||||
asrt.setSegmentRun(1, metadata["keytime"].size(), 0);
|
||||
}
|
||||
|
@ -49,19 +49,18 @@ namespace Connector_HTTP {
|
|||
}else{
|
||||
afrt.setUpdate(true);
|
||||
}
|
||||
afrt.setVersion(1);
|
||||
afrt.setVersion(0);//1
|
||||
afrt.setTimeScale(1000);
|
||||
afrt.setQualityEntry(empty, 0);
|
||||
//afrt.setQualityEntry(empty, 0);
|
||||
MP4::afrt_runtable afrtrun;
|
||||
if ( !metadata.isMember("keytime") || metadata["keytime"].size() == 0){
|
||||
afrtrun.firstFragment = 1;
|
||||
afrtrun.firstTimestamp = 0;
|
||||
if ( !metadata.isMember("video") || !metadata["video"].isMember("keyms") || metadata["video"]["keyms"].asInt() == 0){
|
||||
afrtrun.duration = 2000;
|
||||
}else{
|
||||
afrtrun.duration = metadata["video"]["keyms"].asInt();
|
||||
if (metadata.isMember("keynum")){
|
||||
unsigned long long int firstAvail = metadata["keynum"].size() / 2;
|
||||
for (int i = firstAvail; i < metadata["keynum"].size() -2; i++ ) {
|
||||
afrtrun.firstFragment = metadata["keynum"][i].asInt();
|
||||
afrtrun.firstTimestamp = metadata["keytime"][i].asInt();
|
||||
afrtrun.duration = metadata["keytime"][i+1].asInt() - metadata["keytime"][i].asInt();
|
||||
afrt.setFragmentRun(afrtrun, i - firstAvail);
|
||||
}
|
||||
afrt.setFragmentRun(afrtrun, 0);
|
||||
}else{
|
||||
for (int i = 0; i < metadata["keytime"].size(); i++){
|
||||
afrtrun.firstFragment = i + 1;
|
||||
|
@ -80,8 +79,12 @@ namespace Connector_HTTP {
|
|||
}
|
||||
|
||||
MP4::ABST abst;
|
||||
abst.setVersion(1);
|
||||
abst.setBootstrapinfoVersion(1);
|
||||
abst.setVersion(0);
|
||||
if( metadata.isMember("keynum") ) {
|
||||
abst.setBootstrapinfoVersion(metadata["keynum"][0u].asInt());
|
||||
}else{
|
||||
abst.setBootstrapinfoVersion(1);
|
||||
}
|
||||
abst.setProfile(0);
|
||||
if (starttime == 0){
|
||||
abst.setUpdate(false);
|
||||
|
@ -98,14 +101,14 @@ namespace Connector_HTTP {
|
|||
}
|
||||
}else{
|
||||
abst.setLive(true);
|
||||
abst.setCurrentMediaTime(0xFFFFFFFF);
|
||||
abst.setCurrentMediaTime(metadata["lastms"].asInt());
|
||||
}
|
||||
abst.setSmpteTimeCodeOffset(0);
|
||||
abst.setMovieIdentifier(MovieId);
|
||||
abst.setServerEntry(empty, 0);
|
||||
abst.setQualityEntry(empty, 0);
|
||||
abst.setDrmData(empty);
|
||||
abst.setMetaData(empty);
|
||||
//abst.setServerEntry(empty, 0);
|
||||
//abst.setQualityEntry(empty, 0);
|
||||
//abst.setDrmData(empty);
|
||||
//abst.setMetaData(empty);
|
||||
abst.setSegmentRunTable(asrt, 0);
|
||||
abst.setFragmentRunTable(afrt, 0);
|
||||
|
||||
|
@ -118,7 +121,7 @@ namespace Connector_HTTP {
|
|||
/// Returns a F4M-format manifest file
|
||||
std::string BuildManifest(std::string & MovieId, JSON::Value & metadata){
|
||||
std::string Result;
|
||||
if (metadata.isMember("length") && metadata["length"].asInt() > 0){
|
||||
if ( !metadata.isMember("keynum")){
|
||||
Result =
|
||||
"<?xml version=\"1.0\" encoding=\"utf-8\"?>\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"
|
||||
"<manifest xmlns=\"http://ns.adobe.com/f4m/1.0\">\n"
|
||||
"<id>" + MovieId + "</id>\n"
|
||||
"<duration>0.00</duration>\n"
|
||||
"<mimeType>video/mp4</mimeType>\n"
|
||||
"<streamType>live</streamType>\n"
|
||||
"<deliveryType>streaming</deliveryType>\n"
|
||||
"<bootstrapInfo profile=\"named\" id=\"bootstrap1\">" + Base64::encode(GenerateBootstrap(MovieId, metadata, 1, 0, 0)) + "</bootstrapInfo>\n"
|
||||
"<media streamId=\"1\" bootstrapInfoId=\"bootstrap1\" url=\"" + MovieId + "/\"></media>\n"
|
||||
"<bootstrapInfo profile=\"named\" id=\"bootstrap1\" url=\"" + MovieId + ".bootstrap\"></bootstrapInfo>\n"
|
||||
"<media bootstrapInfoId=\"bootstrap1\" url=\"" + MovieId + "/\">"
|
||||
"<metadata>AgAKb25NZXRhRGF0YQgAAAAAAA9tZXRhZGF0YWNyZWF0b3ICABBBbmV2aWEgVmlhTW90aW9uAAhoYXNBdWRpbwEBAAhoYXNWaWRlbwEBAAhkdXJhdGlvbgBBIWWYAAAAAAAPYXVkaW9zYW1wbGVyYXRlAEBIAAAAAAAAAA1hdWRpb2RhdGFyYXRlAEBgAAAAAAAAAAxhdWRpb2NvZGVjaWQCAARtcDRhAAZhYWNhb3QAQAAAAAAAAAAABXdpZHRoAECQAAAAAAAAAAZoZWlnaHQAQIIAAAAAAAAADXZpZGVvZGF0YXJhdGUAQJ9AAAAAAAAADHZpZGVvY29kZWNpZAIABEFWQzEACmF2Y3Byb2ZpbGUAQFNAAAAAAAAACGF2Y2xldmVsAEA/AAAAAAAAAAAJ</metadata>\n"
|
||||
"</media>\n"
|
||||
"</manifest>\n";
|
||||
}
|
||||
#if DEBUG >= 8
|
||||
|
@ -193,27 +199,38 @@ namespace Connector_HTTP {
|
|||
if (HTTP_R.Read(conn.Received().get())){
|
||||
#if DEBUG >= 4
|
||||
std::cout << "Received request: " << HTTP_R.getUrl() << std::endl;
|
||||
std::cout << "Received request: " << HTTP_R.BuildRequest() << std::endl;
|
||||
#endif
|
||||
conn.setHost(HTTP_R.GetHeader("X-Origin"));
|
||||
if (HTTP_R.url.find("f4m") == std::string::npos){
|
||||
streamname = HTTP_R.url.substr(1, HTTP_R.url.find("/", 1) - 1);
|
||||
if ( !ss){
|
||||
ss = Util::Stream::getStream(streamname);
|
||||
if ( !ss.connected()){
|
||||
streamname = HTTP_R.GetHeader("X-Stream");
|
||||
if ( !ss){
|
||||
ss = Util::Stream::getStream(streamname);
|
||||
if ( !ss.connected()){
|
||||
#if DEBUG >= 1
|
||||
fprintf(stderr, "Could not connect to server!\n");
|
||||
fprintf(stderr, "Could not connect to server!\n");
|
||||
#endif
|
||||
ss.close();
|
||||
HTTP_S.Clean();
|
||||
HTTP_S.SetBody("No such stream is available on the system. Please try again.\n");
|
||||
conn.SendNow(HTTP_S.BuildResponse("404", "Not found"));
|
||||
ready4data = false;
|
||||
continue;
|
||||
}
|
||||
ss.setBlocking(false);
|
||||
inited = true;
|
||||
ss.close();
|
||||
HTTP_S.Clean();
|
||||
HTTP_S.SetBody("No such stream is available on the system. Please try again.\n");
|
||||
conn.SendNow(HTTP_S.BuildResponse("404", "Not found"));
|
||||
ready4data = false;
|
||||
HTTP_R.Clean(); //clean for any possible next requests
|
||||
continue;
|
||||
}
|
||||
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"));
|
||||
temp = HTTP_R.url.find("Seg") + 3;
|
||||
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());
|
||||
Flash_RequestPending++;
|
||||
}else{
|
||||
streamname = HTTP_R.url.substr(1, HTTP_R.url.find("/", 1) - 1);
|
||||
if ( !Strm.metadata.isNull()){
|
||||
HTTP_S.Clean();
|
||||
HTTP_S.SetHeader("Content-Type", "text/xml");
|
||||
|
@ -284,6 +300,7 @@ namespace Connector_HTTP {
|
|||
}
|
||||
if (ss.spool()){
|
||||
while (Strm.parsePacket(ss.Received())){
|
||||
/*
|
||||
if (Strm.getPacket(0).isMember("time")){
|
||||
if ( !Strm.metadata.isMember("firsttime")){
|
||||
Strm.metadata["firsttime"] = Strm.getPacket(0)["time"];
|
||||
|
@ -294,6 +311,7 @@ namespace Connector_HTTP {
|
|||
}
|
||||
Strm.metadata["lasttime"] = Strm.getPacket(0)["time"];
|
||||
}
|
||||
*/
|
||||
if (pending_manifest){
|
||||
HTTP_S.Clean();
|
||||
HTTP_S.SetHeader("Content-Type", "text/xml");
|
||||
|
|
|
@ -31,12 +31,18 @@ namespace Connector_HTTP {
|
|||
if (metadata.isNull()){
|
||||
return result;
|
||||
}
|
||||
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);
|
||||
if( metadata.isMember( "keynum" ) ) {
|
||||
for (int i = 0; i < metadata["keynum"].size(); i++){
|
||||
result.push_back(metadata["keynum"][i].asInt());
|
||||
}
|
||||
}else{
|
||||
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;
|
||||
|
@ -61,7 +67,6 @@ namespace Connector_HTTP {
|
|||
"#EXT-X-MEDIA-SEQUENCE:0\r\n";
|
||||
//"#EXT-X-PLAYLIST-TYPE:VOD\r\n";
|
||||
int lastDuration = 0;
|
||||
bool writeOffset = true;
|
||||
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";
|
||||
|
@ -72,6 +77,12 @@ namespace Connector_HTTP {
|
|||
Result << "#EXTM3U\r\n"
|
||||
"#EXT-X-MEDIA-SEQUENCE:0\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
|
||||
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;
|
||||
#endif
|
||||
conn.setHost(HTTP_R.GetHeader("X-Origin"));
|
||||
if (HTTP_R.url.find(".m3u") == std::string::npos){
|
||||
streamname = HTTP_R.url.substr(5, HTTP_R.url.find("/", 5) - 5);
|
||||
if ( !ss){
|
||||
ss = Util::Stream::getStream(streamname);
|
||||
if ( !ss.connected()){
|
||||
streamname = HTTP_R.GetHeader("X-Stream");
|
||||
if ( !ss){
|
||||
ss = Util::Stream::getStream(streamname);
|
||||
if ( !ss.connected()){
|
||||
#if DEBUG >= 1
|
||||
fprintf(stderr, "Could not connect to server!\n");
|
||||
fprintf(stderr, "Could not connect to server!\n");
|
||||
#endif
|
||||
HTTP_S.Clean();
|
||||
HTTP_S.SetBody("No such stream is available on the system. Please try again.\n");
|
||||
conn.SendNow(HTTP_S.BuildResponse("404", "Not found"));
|
||||
ready4data = false;
|
||||
continue;
|
||||
}
|
||||
ss.setBlocking(false);
|
||||
inited = true;
|
||||
HTTP_S.Clean();
|
||||
HTTP_S.SetBody("No such stream is available on the system. Please try again.\n");
|
||||
conn.SendNow(HTTP_S.BuildResponse("404", "Not found"));
|
||||
ready4data = false;
|
||||
continue;
|
||||
}
|
||||
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;
|
||||
Segment = atoi(HTTP_R.url.substr(temp, HTTP_R.url.find("_", temp) - temp).c_str());
|
||||
temp = HTTP_R.url.find("_", temp) + 1;
|
||||
|
@ -163,7 +176,9 @@ namespace Connector_HTTP {
|
|||
ss.SendNow(sstream.str().c_str());
|
||||
Flash_RequestPending++;
|
||||
}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){
|
||||
manifestType = "audio/x-mpegurl";
|
||||
}else{
|
||||
|
|
|
@ -29,8 +29,13 @@ namespace Connector_HTTP {
|
|||
std::string BuildManifest(std::string & MovieId, JSON::Value & metadata){
|
||||
std::stringstream Result;
|
||||
Result << "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n";
|
||||
Result << "<SmoothStreamingMedia MajorVersion=\"2\" MinorVersion=\"0\" TimeScale=\"10000000\" Duration=\"" << metadata["lastms"].asInt()
|
||||
<< "\">\n";
|
||||
Result << "<SmoothStreamingMedia MajorVersion=\"2\" MinorVersion=\"0\" TimeScale=\"10000000\" ";
|
||||
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")){
|
||||
Result << " <StreamIndex Type=\"audio\" QualityLevels=\"1\" Name=\"audio\" Chunks=\"" << metadata["keytime"].size()
|
||||
<< "\" Url=\"Q({bitrate})/A({start time})\">\n";
|
||||
|
@ -45,7 +50,7 @@ namespace Connector_HTTP {
|
|||
for (int i = 0; i < metadata["keytime"].size() - 1; i++){
|
||||
Result << " <c ";
|
||||
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";
|
||||
}
|
||||
|
@ -71,7 +76,7 @@ namespace Connector_HTTP {
|
|||
for (int i = 0; i < metadata["keytime"].size() - 1; i++){
|
||||
Result << " <c ";
|
||||
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";
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue