Added xap smooth player file in smooth connector and fixed embed for this file
This commit is contained in:
parent
51d0d26a6e
commit
fd4ea27a94
4 changed files with 24737 additions and 186 deletions
|
@ -65,7 +65,7 @@ MistConnHTTPProgressiveMP4_SOURCES=connectors/conn_http_progressive_mp4.cpp ../V
|
||||||
MistConnHTTPProgressiveOGG_SOURCES=connectors/conn_http_progressive_ogg.cpp ../VERSION
|
MistConnHTTPProgressiveOGG_SOURCES=connectors/conn_http_progressive_ogg.cpp ../VERSION
|
||||||
MistConnHTTPSRT_SOURCES=connectors/conn_http_srt.cpp ../VERSION
|
MistConnHTTPSRT_SOURCES=connectors/conn_http_srt.cpp ../VERSION
|
||||||
MistConnHTTPDynamic_SOURCES=connectors/conn_http_dynamic.cpp ../VERSION
|
MistConnHTTPDynamic_SOURCES=connectors/conn_http_dynamic.cpp ../VERSION
|
||||||
MistConnHTTPSmooth_SOURCES=connectors/conn_http_smooth.cpp ../VERSION
|
MistConnHTTPSmooth_SOURCES=connectors/xap.h connectors/conn_http_smooth.cpp ../VERSION
|
||||||
MistConnHTTPLive_SOURCES=connectors/conn_http_live.cpp ../VERSION
|
MistConnHTTPLive_SOURCES=connectors/conn_http_live.cpp ../VERSION
|
||||||
MistConnTS_SOURCES=connectors/conn_ts.cpp ../VERSION
|
MistConnTS_SOURCES=connectors/conn_ts.cpp ../VERSION
|
||||||
MistConnHTTPSRT_SOURCES=connectors/conn_http_srt.cpp ../VERSION
|
MistConnHTTPSRT_SOURCES=connectors/conn_http_srt.cpp ../VERSION
|
||||||
|
|
|
@ -214,211 +214,228 @@ namespace Connector_HTTP {
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
if (HTTP_R.url.find(".xap") != std::string::npos){
|
||||||
|
#include "xap.h"
|
||||||
|
|
||||||
if (HTTP_R.url.find("Manifest") == std::string::npos){
|
std::cout << "! sending xap player file" << std::endl;
|
||||||
//We have a non-manifest request, parse it.
|
HTTP_S.Clean();
|
||||||
Quality = HTTP_R.url.substr(HTTP_R.url.find("/Q(", 8) + 3);
|
HTTP_S.SetHeader("Content-Type", "application/siverlight");
|
||||||
Quality = Quality.substr(0, Quality.find(")"));
|
HTTP_S.SetHeader("Cache-Control", "cache");
|
||||||
parseString = HTTP_R.url.substr(HTTP_R.url.find(")/") + 2);
|
HTTP_S.SetBody("");
|
||||||
wantsAudio = false;
|
HTTP_S.SetHeader("Content-Length", xap_len);
|
||||||
wantsVideo = false;
|
HTTP_S.SendResponse("200", "OK", conn);
|
||||||
if (parseString[0] == 'A'){
|
conn.SendNow((const char *)xap_data, xap_len);
|
||||||
wantsAudio = true;
|
}else{
|
||||||
}
|
if (HTTP_R.url.find("Manifest") == std::string::npos){
|
||||||
if (parseString[0] == 'V'){
|
//We have a non-manifest request, parse it.
|
||||||
wantsVideo = true;
|
std::cout << "! NON manifest sauce file" << std::endl;
|
||||||
}
|
|
||||||
parseString = parseString.substr(parseString.find("(") + 1);
|
Quality = HTTP_R.url.substr(HTTP_R.url.find("/Q(", 8) + 3);
|
||||||
requestedTime = atoll(parseString.substr(0, parseString.find(")")).c_str());
|
Quality = Quality.substr(0, Quality.find(")"));
|
||||||
if (Strm.metadata.isMember("live")){
|
parseString = HTTP_R.url.substr(HTTP_R.url.find(")/") + 2);
|
||||||
///\todo Fix this for live stuff
|
wantsAudio = false;
|
||||||
int seekable = Strm.canSeekms(requestedTime / 10000);
|
wantsVideo = false;
|
||||||
if (seekable == 0){
|
if (parseString[0] == 'A'){
|
||||||
// iff the fragment in question is available, check if the next is available too
|
wantsAudio = true;
|
||||||
for (int i = 0; i < Strm.metadata["keytime"].size(); i++){
|
}
|
||||||
if (Strm.metadata["keytime"][i].asInt() >= (requestedTime / 10000)){
|
if (parseString[0] == 'V'){
|
||||||
if (i + 1 == Strm.metadata["keytime"].size()){
|
wantsVideo = true;
|
||||||
seekable = 1;
|
}
|
||||||
|
parseString = parseString.substr(parseString.find("(") + 1);
|
||||||
|
requestedTime = atoll(parseString.substr(0, parseString.find(")")).c_str());
|
||||||
|
if (Strm.metadata.isMember("live")){
|
||||||
|
///\todo Fix this for live stuff
|
||||||
|
int seekable = Strm.canSeekms(requestedTime / 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() >= (requestedTime / 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");
|
||||||
|
conn.SendNow(HTTP_S.BuildResponse("412", "Fragment out of range"));
|
||||||
|
HTTP_R.Clean(); //clean for any possible next requests
|
||||||
|
std::cout << "Fragment @ " << requestedTime / 10000 << "ms too old (" << Strm.metadata["keytime"][0u].asInt() << " - " << Strm.metadata["keytime"][Strm.metadata["keytime"].size() - 1].asInt() << " ms)" << std::endl;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (seekable > 0){
|
||||||
|
HTTP_S.Clean();
|
||||||
|
HTTP_S.SetBody("Proxy, re-request this in a second or two.\n");
|
||||||
|
conn.SendNow(HTTP_S.BuildResponse("208", "Ask again later"));
|
||||||
|
HTTP_R.Clean(); //clean for any possible next requests
|
||||||
|
std::cout << "Fragment @ " << requestedTime / 10000 << "ms not available yet (" << Strm.metadata["keytime"][0u].asInt() << " - " << Strm.metadata["keytime"][Strm.metadata["keytime"].size() - 1].asInt() << " ms)" << std::endl;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//Seek to the right place and send a play-once for a single fragment.
|
||||||
|
std::stringstream sstream;
|
||||||
|
JSON::Value myRef;
|
||||||
|
long long int selectedQuality = atoll(Quality.c_str()) / 8;
|
||||||
|
if (wantsVideo){
|
||||||
|
//Select the correct track ID
|
||||||
|
for (JSON::ObjIter vIt = allVideo.ObjBegin(); vIt != allVideo.ObjEnd(); vIt++){
|
||||||
|
if (vIt->second["bps"].asInt() == selectedQuality){
|
||||||
|
myRef = vIt->second;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (wantsAudio){
|
||||||
|
//Select the correct track ID
|
||||||
|
for (JSON::ObjIter aIt = allAudio.ObjBegin(); aIt != allAudio.ObjEnd(); aIt++){
|
||||||
|
if (aIt->second["bps"].asInt() == selectedQuality){
|
||||||
|
myRef = aIt->second;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
long long mstime = 0;
|
||||||
|
long long mslen = 0;
|
||||||
|
if (myRef.isMember("keys")){
|
||||||
|
for (JSON::ArrIter it = myRef["keys"].ArrBegin(); it != myRef["keys"].ArrEnd(); it++){
|
||||||
|
if ((*it)["time"].asInt() >= (requestedTime / 10000)){
|
||||||
|
mstime = (*it)["time"].asInt();
|
||||||
|
mslen = (*it)["len"].asInt();
|
||||||
|
if (Strm.metadata.isMember("live")){
|
||||||
|
if (it == myRef["keys"].ArrEnd() - 2){
|
||||||
|
HTTP_S.Clean();
|
||||||
|
HTTP_S.SetBody("Proxy, re-request this in a second or two.\n");
|
||||||
|
conn.SendNow(HTTP_S.BuildResponse("208", "Ask again later"));
|
||||||
|
HTTP_R.Clean(); //clean for any possible next requests
|
||||||
|
std::cout << "Fragment after fragment @ " << (requestedTime / 10000) << " not available yet" << std::endl;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (seekable < 0){
|
if (HTTP_R.url == "/"){continue;}//Don't continue, but continue instead.
|
||||||
HTTP_S.Clean();
|
if (Strm.metadata.isMember("live")){
|
||||||
HTTP_S.SetBody("The requested fragment is no longer kept in memory on the server and cannot be served.\n");
|
if (mstime == 0 && (requestedTime / 10000) > 1){
|
||||||
conn.SendNow(HTTP_S.BuildResponse("412", "Fragment out of range"));
|
HTTP_S.Clean();
|
||||||
HTTP_R.Clean(); //clean for any possible next requests
|
HTTP_S.SetBody("The requested fragment is no longer kept in memory on the server and cannot be served.\n");
|
||||||
std::cout << "Fragment @ " << requestedTime / 10000 << "ms too old (" << Strm.metadata["keytime"][0u].asInt() << " - " << Strm.metadata["keytime"][Strm.metadata["keytime"].size() - 1].asInt() << " ms)" << std::endl;
|
conn.SendNow(HTTP_S.BuildResponse("412", "Fragment out of range"));
|
||||||
continue;
|
HTTP_R.Clean(); //clean for any possible next requests
|
||||||
}
|
std::cout << "Fragment @ " << (requestedTime / 10000) << " too old" << std::endl;
|
||||||
if (seekable > 0){
|
continue;
|
||||||
HTTP_S.Clean();
|
|
||||||
HTTP_S.SetBody("Proxy, re-request this in a second or two.\n");
|
|
||||||
conn.SendNow(HTTP_S.BuildResponse("208", "Ask again later"));
|
|
||||||
HTTP_R.Clean(); //clean for any possible next requests
|
|
||||||
std::cout << "Fragment @ " << requestedTime / 10000 << "ms not available yet (" << Strm.metadata["keytime"][0u].asInt() << " - " << Strm.metadata["keytime"][Strm.metadata["keytime"].size() - 1].asInt() << " ms)" << std::endl;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//Seek to the right place and send a play-once for a single fragment.
|
|
||||||
std::stringstream sstream;
|
|
||||||
JSON::Value myRef;
|
|
||||||
long long int selectedQuality = atoll(Quality.c_str()) / 8;
|
|
||||||
if (wantsVideo){
|
|
||||||
//Select the correct track ID
|
|
||||||
for (JSON::ObjIter vIt = allVideo.ObjBegin(); vIt != allVideo.ObjEnd(); vIt++){
|
|
||||||
if (vIt->second["bps"].asInt() == selectedQuality){
|
|
||||||
myRef = vIt->second;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if (wantsAudio){
|
|
||||||
//Select the correct track ID
|
|
||||||
for (JSON::ObjIter aIt = allAudio.ObjBegin(); aIt != allAudio.ObjEnd(); aIt++){
|
|
||||||
if (aIt->second["bps"].asInt() == selectedQuality){
|
|
||||||
myRef = aIt->second;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
long long mstime = 0;
|
|
||||||
long long mslen = 0;
|
sstream << "t " << myRef["trackid"].asInt() << "\n";
|
||||||
if (myRef.isMember("keys")){
|
sstream << "s " << (requestedTime / 10000) << "\n";
|
||||||
for (JSON::ArrIter it = myRef["keys"].ArrBegin(); it != myRef["keys"].ArrEnd(); it++){
|
sstream << "o\n";
|
||||||
if ((*it)["time"].asInt() >= (requestedTime / 10000)){
|
|
||||||
mstime = (*it)["time"].asInt();
|
ss.SendNow(sstream.str().c_str());
|
||||||
mslen = (*it)["len"].asInt();
|
|
||||||
if (Strm.metadata.isMember("live")){
|
unsigned int myDuration;
|
||||||
if (it == myRef["keys"].ArrEnd() - 2){
|
|
||||||
HTTP_S.Clean();
|
//Wrap everything in mp4 boxes
|
||||||
HTTP_S.SetBody("Proxy, re-request this in a second or two.\n");
|
MP4::MFHD mfhd_box;
|
||||||
conn.SendNow(HTTP_S.BuildResponse("208", "Ask again later"));
|
JSON::Value trackRef;
|
||||||
HTTP_R.Clean(); //clean for any possible next requests
|
if (wantsVideo){
|
||||||
std::cout << "Fragment after fragment @ " << (requestedTime / 10000) << " not available yet" << std::endl;
|
trackRef = allVideo.ObjBegin()->second;
|
||||||
}
|
}
|
||||||
}
|
if (wantsAudio){
|
||||||
|
trackRef = allAudio.ObjBegin()->second;
|
||||||
|
}
|
||||||
|
//Also obtain the associated keyframe;
|
||||||
|
JSON::Value keyObj;
|
||||||
|
for (JSON::ArrIter keyIt = trackRef["keys"].ArrBegin(); keyIt != trackRef["keys"].ArrEnd(); keyIt++){
|
||||||
|
if ((*keyIt)["time"].asInt() >= (requestedTime / 10000)){
|
||||||
|
keyObj = (*keyIt);
|
||||||
|
mfhd_box.setSequenceNumber((*keyIt)["num"].asInt());
|
||||||
|
myDuration = (*keyIt)["len"].asInt() * 10000;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if (HTTP_R.url == "/"){continue;}//Don't continue, but continue instead.
|
MP4::TFHD tfhd_box;
|
||||||
if (Strm.metadata.isMember("live")){
|
tfhd_box.setFlags(MP4::tfhdSampleFlag);
|
||||||
if (mstime == 0 && (requestedTime / 10000) > 1){
|
tfhd_box.setTrackID(1);
|
||||||
HTTP_S.Clean();
|
tfhd_box.setDefaultSampleFlags(0x000000C0 | MP4::noIPicture | MP4::noDisposable | MP4::noKeySample);
|
||||||
HTTP_S.SetBody("The requested fragment is no longer kept in memory on the server and cannot be served.\n");
|
|
||||||
conn.SendNow(HTTP_S.BuildResponse("412", "Fragment out of range"));
|
MP4::TRUN trun_box;
|
||||||
HTTP_R.Clean(); //clean for any possible next requests
|
trun_box.setFlags(MP4::trundataOffset | MP4::trunfirstSampleFlags | MP4::trunsampleDuration | MP4::trunsampleSize);
|
||||||
std::cout << "Fragment @ " << (requestedTime / 10000) << " too old" << std::endl;
|
trun_box.setDataOffset(42);
|
||||||
continue;
|
trun_box.setFirstSampleFlags(0x00000040 | MP4::isIPicture | MP4::noDisposable | MP4::isKeySample);
|
||||||
|
for (int i = 0; i < keyObj["parts"].size(); i++){
|
||||||
|
MP4::trunSampleInformation trunSample;
|
||||||
|
trunSample.sampleSize = keyObj["parts"][i].asInt();
|
||||||
|
//Guesstimate sample duration.
|
||||||
|
trunSample.sampleDuration = ((double)(keyObj["len"].asInt() * 10000) / keyObj["parts"].size());
|
||||||
|
trun_box.setSampleInformation(trunSample, i);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
MP4::SDTP sdtp_box;
|
||||||
sstream << "t " << myRef["trackid"].asInt() << "\n";
|
sdtp_box.setVersion(0);
|
||||||
sstream << "s " << (requestedTime / 10000) << "\n";
|
sdtp_box.setValue(0x24, 4);
|
||||||
sstream << "o\n";
|
for (int i = 1; i < keyObj["parts"].size(); i++){
|
||||||
|
sdtp_box.setValue(0x14, 4 + i);
|
||||||
ss.SendNow(sstream.str().c_str());
|
|
||||||
|
|
||||||
unsigned int myDuration;
|
|
||||||
|
|
||||||
//Wrap everything in mp4 boxes
|
|
||||||
MP4::MFHD mfhd_box;
|
|
||||||
JSON::Value trackRef;
|
|
||||||
if (wantsVideo){
|
|
||||||
trackRef = allVideo.ObjBegin()->second;
|
|
||||||
}
|
|
||||||
if (wantsAudio){
|
|
||||||
trackRef = allAudio.ObjBegin()->second;
|
|
||||||
}
|
|
||||||
//Also obtain the associated keyframe;
|
|
||||||
JSON::Value keyObj;
|
|
||||||
for (JSON::ArrIter keyIt = trackRef["keys"].ArrBegin(); keyIt != trackRef["keys"].ArrEnd(); keyIt++){
|
|
||||||
if ((*keyIt)["time"].asInt() >= (requestedTime / 10000)){
|
|
||||||
keyObj = (*keyIt);
|
|
||||||
mfhd_box.setSequenceNumber((*keyIt)["num"].asInt());
|
|
||||||
myDuration = (*keyIt)["len"].asInt() * 10000;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
MP4::TFHD tfhd_box;
|
MP4::TRAF traf_box;
|
||||||
tfhd_box.setFlags(MP4::tfhdSampleFlag);
|
traf_box.setContent(tfhd_box, 0);
|
||||||
tfhd_box.setTrackID(1);
|
traf_box.setContent(trun_box, 1);
|
||||||
tfhd_box.setDefaultSampleFlags(0x000000C0 | MP4::noIPicture | MP4::noDisposable | MP4::noKeySample);
|
traf_box.setContent(sdtp_box, 2);
|
||||||
|
|
||||||
MP4::TRUN trun_box;
|
//If the stream is live, we want to have a fragref box if possible
|
||||||
trun_box.setFlags(MP4::trundataOffset | MP4::trunfirstSampleFlags | MP4::trunsampleDuration | MP4::trunsampleSize);
|
if (Strm.metadata.isMember("live")){
|
||||||
trun_box.setDataOffset(42);
|
///\todo Fix this for live
|
||||||
trun_box.setFirstSampleFlags(0x00000040 | MP4::isIPicture | MP4::noDisposable | MP4::isKeySample);
|
MP4::UUID_TrackFragmentReference fragref_box;
|
||||||
for (int i = 0; i < keyObj["parts"].size(); i++){
|
fragref_box.setVersion(1);
|
||||||
MP4::trunSampleInformation trunSample;
|
fragref_box.setFragmentCount(0);
|
||||||
trunSample.sampleSize = keyObj["parts"][i].asInt();
|
int fragCount = 0;
|
||||||
//Guesstimate sample duration.
|
for (int i = 0; i < Strm.metadata["keytime"].size(); i++){
|
||||||
trunSample.sampleDuration = ((double)(keyObj["len"].asInt() * 10000) / keyObj["parts"].size());
|
if (Strm.metadata["keytime"][i].asInt() > (requestedTime / 10000)){
|
||||||
trun_box.setSampleInformation(trunSample, i);
|
fragref_box.setTime(fragCount, Strm.metadata["keytime"][i].asInt() * 10000);
|
||||||
}
|
fragref_box.setDuration(fragCount, Strm.metadata["keylen"][i].asInt() * 10000);
|
||||||
|
fragref_box.setFragmentCount(++fragCount);
|
||||||
MP4::SDTP sdtp_box;
|
}
|
||||||
sdtp_box.setVersion(0);
|
|
||||||
sdtp_box.setValue(0x24, 4);
|
|
||||||
for (int i = 1; i < keyObj["parts"].size(); i++){
|
|
||||||
sdtp_box.setValue(0x14, 4 + i);
|
|
||||||
}
|
|
||||||
|
|
||||||
MP4::TRAF traf_box;
|
|
||||||
traf_box.setContent(tfhd_box, 0);
|
|
||||||
traf_box.setContent(trun_box, 1);
|
|
||||||
traf_box.setContent(sdtp_box, 2);
|
|
||||||
|
|
||||||
//If the stream is live, we want to have a fragref box if possible
|
|
||||||
if (Strm.metadata.isMember("live")){
|
|
||||||
///\todo Fix this for live
|
|
||||||
MP4::UUID_TrackFragmentReference fragref_box;
|
|
||||||
fragref_box.setVersion(1);
|
|
||||||
fragref_box.setFragmentCount(0);
|
|
||||||
int fragCount = 0;
|
|
||||||
for (int i = 0; i < Strm.metadata["keytime"].size(); i++){
|
|
||||||
if (Strm.metadata["keytime"][i].asInt() > (requestedTime / 10000)){
|
|
||||||
fragref_box.setTime(fragCount, Strm.metadata["keytime"][i].asInt() * 10000);
|
|
||||||
fragref_box.setDuration(fragCount, Strm.metadata["keylen"][i].asInt() * 10000);
|
|
||||||
fragref_box.setFragmentCount(++fragCount);
|
|
||||||
}
|
}
|
||||||
|
traf_box.setContent(fragref_box, 3);
|
||||||
}
|
}
|
||||||
traf_box.setContent(fragref_box, 3);
|
|
||||||
|
MP4::MOOF moof_box;
|
||||||
|
moof_box.setContent(mfhd_box, 0);
|
||||||
|
moof_box.setContent(traf_box, 1);
|
||||||
|
|
||||||
|
//Setting the correct offsets.
|
||||||
|
trun_box.setDataOffset(moof_box.boxedSize() + 8);
|
||||||
|
traf_box.setContent(trun_box, 1);
|
||||||
|
moof_box.setContent(traf_box, 1);
|
||||||
|
|
||||||
|
HTTP_S.Clean();
|
||||||
|
HTTP_S.SetHeader("Content-Type", "video/mp4");
|
||||||
|
HTTP_S.StartResponse(HTTP_R, conn);
|
||||||
|
HTTP_S.Chunkify(moof_box.asBox(), moof_box.boxedSize(), conn);
|
||||||
|
int size = htonl(keyObj["size"].asInt() + 8);
|
||||||
|
HTTP_S.Chunkify((char*)&size, 4, conn);
|
||||||
|
HTTP_S.Chunkify("mdat", 4, conn);
|
||||||
|
handlingRequest = true;
|
||||||
|
}else{
|
||||||
|
//We have a request for a Manifest, generate and send it.
|
||||||
|
|
||||||
|
std::cout << "! sending manifest player file" << std::endl;
|
||||||
|
HTTP_S.Clean();
|
||||||
|
HTTP_S.SetHeader("Content-Type", "text/xml");
|
||||||
|
HTTP_S.SetHeader("Cache-Control", "no-cache");
|
||||||
|
std::string manifest = smoothIndex(Strm.metadata);
|
||||||
|
HTTP_S.SetBody(manifest);
|
||||||
|
HTTP_S.SendResponse("200", "OK", conn);
|
||||||
}
|
}
|
||||||
|
|
||||||
MP4::MOOF moof_box;
|
|
||||||
moof_box.setContent(mfhd_box, 0);
|
|
||||||
moof_box.setContent(traf_box, 1);
|
|
||||||
|
|
||||||
//Setting the correct offsets.
|
|
||||||
trun_box.setDataOffset(moof_box.boxedSize() + 8);
|
|
||||||
traf_box.setContent(trun_box, 1);
|
|
||||||
moof_box.setContent(traf_box, 1);
|
|
||||||
|
|
||||||
HTTP_S.Clean();
|
|
||||||
HTTP_S.SetHeader("Content-Type", "video/mp4");
|
|
||||||
HTTP_S.StartResponse(HTTP_R, conn);
|
|
||||||
HTTP_S.Chunkify(moof_box.asBox(), moof_box.boxedSize(), conn);
|
|
||||||
int size = htonl(keyObj["size"].asInt() + 8);
|
|
||||||
HTTP_S.Chunkify((char*)&size, 4, conn);
|
|
||||||
HTTP_S.Chunkify("mdat", 4, conn);
|
|
||||||
handlingRequest = true;
|
|
||||||
}else{
|
|
||||||
//We have a request for a Manifest, generate and send it.
|
|
||||||
HTTP_S.Clean();
|
|
||||||
HTTP_S.SetHeader("Content-Type", "text/xml");
|
|
||||||
HTTP_S.SetHeader("Cache-Control", "no-cache");
|
|
||||||
std::string manifest = smoothIndex(Strm.metadata);
|
|
||||||
HTTP_S.SetBody(manifest);
|
|
||||||
conn.SendNow(HTTP_S.BuildResponse("200", "OK"));
|
|
||||||
}
|
}
|
||||||
ready4data = true;
|
ready4data = true;
|
||||||
//Clean for any possible next requests
|
//Clean for any possible next requests
|
||||||
HTTP_R.Clean();
|
HTTP_R.Clean();
|
||||||
}
|
}
|
||||||
|
|
||||||
}else{
|
}else{
|
||||||
//Wait 250ms before checking for new data.
|
//Wait 250ms before checking for new data.
|
||||||
Util::sleep(250);
|
Util::sleep(250);
|
||||||
|
|
|
@ -145,7 +145,7 @@ function mistembed(streamname)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'silverlight':
|
case 'silverlight':
|
||||||
container.innerHTML = '<object data="data:application/x-silverlight," type="application/x-silverlight" width="' + videowidth + '" height="' + videoheight + '"><param name="source" value="SmoothStreamingSamplePlayer.xap"/><param name="onerror" value="onSilverlightError" /><param name="autoUpgrade" value="true" /><param name="background" value="white" /><param name="enableHtmlAccess" value="true" /><param name="minRuntimeVersion" value="3.0.40624.0" /><param name="initparams" value =\'autoload=false,autoplay=true,displaytimecode=false,enablecaptions=true,joinLive=true,muted=false,playlist=<playList><playListItems><playListItem title="Test" description="testing" mediaSource="' + encodeURI(src.url) + '" adaptiveStreaming="true" thumbSource="" frameRate="25.0" width="" height=""></playListItem></playListItems></playList>\' /><a href="http://go.microsoft.com/fwlink/?LinkID=124807" style="text-decoration: none;"> <img src="http://go.microsoft.com/fwlink/?LinkId=108181" alt="Get Microsoft Silverlight" style="border-style: none" /></a></object>';
|
container.innerHTML = '<object data="data:application/x-silverlight," type="application/x-silverlight" width="' + videowidth + '" height="' + videoheight + '"><param name="source" value="' + encodeURI(src.url) + '/player.xap"/><param name="onerror" value="onSilverlightError" /><param name="autoUpgrade" value="true" /><param name="background" value="white" /><param name="enableHtmlAccess" value="true" /><param name="minRuntimeVersion" value="3.0.40624.0" /><param name="initparams" value =\'autoload=false,autoplay=true,displaytimecode=false,enablecaptions=true,joinLive=true,muted=false,playlist=<playList><playListItems><playListItem title="Test" description="testing" mediaSource="' + encodeURI(src.url) + '" adaptiveStreaming="true" thumbSource="" frameRate="25.0" width="" height=""></playListItem></playListItems></playList>\' /><a href="http://go.microsoft.com/fwlink/?LinkID=124807" style="text-decoration: none;"> <img src="http://go.microsoft.com/fwlink/?LinkId=108181" alt="Get Microsoft Silverlight" style="border-style: none" /></a></object>';
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
||||||
|
|
24534
src/connectors/xap.h
Normal file
24534
src/connectors/xap.h
Normal file
File diff suppressed because it is too large
Load diff
Loading…
Add table
Reference in a new issue