Updated MistConnHTTPLive for DTSC2, fixed a bug in fragmentizing.
This commit is contained in:
parent
0d5011a89a
commit
c6aabfa4bf
3 changed files with 81 additions and 26 deletions
|
@ -111,8 +111,10 @@ int main(int argc, char** argv){
|
|||
JSON::Value last_pack;
|
||||
|
||||
bool meta_sent = false;
|
||||
int playUntil = -1;
|
||||
long long now, lastTime = 0; //for timing of sending packets
|
||||
long long bench = 0; //for benchmarking
|
||||
std::set<int> newSelect;
|
||||
Stats sts;
|
||||
CYG_DEFI
|
||||
|
||||
|
@ -182,6 +184,11 @@ int main(int argc, char** argv){
|
|||
playing = -1;
|
||||
lastTime = 0;
|
||||
in_out.setBlocking(false);
|
||||
if (in_out.Received().get().size() >= 2){
|
||||
playUntil = atoi(in_out.Received().get().substr(2).c_str());
|
||||
}else{
|
||||
playUntil = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'o': { //once-play
|
||||
|
@ -199,7 +206,7 @@ int main(int argc, char** argv){
|
|||
break;
|
||||
}
|
||||
case 't': {
|
||||
std::set<int> newSelect;
|
||||
newSelect.clear();
|
||||
std::string tmp = in_out.Received().get().substr(2);
|
||||
while (tmp != ""){
|
||||
newSelect.insert(atoi(tmp.substr(0,tmp.find(' ')).c_str()));
|
||||
|
@ -239,6 +246,9 @@ int main(int argc, char** argv){
|
|||
--playing;
|
||||
}
|
||||
}
|
||||
if ( playUntil && playUntil < source.getJSON()["time"].asInt()){
|
||||
playing = 0;
|
||||
}
|
||||
if (playing == 0){
|
||||
#if DEBUG >= 4
|
||||
std::cerr << "Completed VoD request in MistPlayer (" << (Util::getMS() - bench) << "ms)" << std::endl;
|
||||
|
|
|
@ -29,36 +29,54 @@ namespace Connector_HTTP {
|
|||
///\param metadata The current metadata, used to generate the index.
|
||||
///\return The index file for HTTP Live Streaming.
|
||||
std::string liveIndex(JSON::Value & metadata){
|
||||
std::stringstream Result;
|
||||
if ( !metadata.isMember("live")){
|
||||
std::stringstream result;
|
||||
if (metadata.isMember("tracks")){
|
||||
result << "#EXTM3U\r\n";
|
||||
int audioId = -1;
|
||||
std::string audioName;
|
||||
bool defAudio = false;//set default audio track;
|
||||
for (JSON::ObjIter trackIt = metadata["tracks"].ObjBegin(); trackIt != metadata["tracks"].ObjEnd(); trackIt++){
|
||||
if (trackIt->second["type"].asString() == "audio"){
|
||||
audioId = trackIt->second["trackid"].asInt();
|
||||
audioName = trackIt->first;
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (JSON::ObjIter trackIt = metadata["tracks"].ObjBegin(); trackIt != metadata["tracks"].ObjEnd(); trackIt++){
|
||||
if (trackIt->second["type"].asString() == "video"){
|
||||
int bWidth = trackIt->second["maxbps"].asInt();
|
||||
if (audioId != -1){
|
||||
bWidth += (metadata["tracks"][audioName]["maxbps"].asInt() * 2);
|
||||
}
|
||||
result << "#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=" << bWidth * 8 << "\r\n";
|
||||
result << trackIt->second["trackid"].asInt();
|
||||
if (audioId != -1){
|
||||
result << "_" << audioId;
|
||||
}
|
||||
result << "/index.m3u8\r\n";
|
||||
}
|
||||
}
|
||||
}else{
|
||||
//parse single track
|
||||
int longestFragment = 0;
|
||||
for (JSON::ArrIter ai = metadata["frags"].ArrBegin(); ai != metadata["frags"].ArrEnd(); ai++){
|
||||
if ((*ai)["dur"].asInt() > longestFragment){
|
||||
longestFragment = (*ai)["dur"].asInt();
|
||||
}
|
||||
}
|
||||
Result << "#EXTM3U\r\n"
|
||||
result << "#EXTM3U\r\n"
|
||||
"#EXT-X-TARGETDURATION:" << (longestFragment / 1000) + 1 << "\r\n"
|
||||
"#EXT-X-MEDIA-SEQUENCE:0\r\n";
|
||||
"#EXT-X-MEDIA-SEQUENCE:" << metadata["trackid"].asInt() << "\r\n";
|
||||
for (JSON::ArrIter ai = metadata["frags"].ArrBegin(); ai != metadata["frags"].ArrEnd(); ai++){
|
||||
Result << "#EXTINF:" << (*ai)["dur"].asInt() / 1000 << ", no desc\r\n" << (*ai)["num"].asInt() << "_" << (*ai)["len"].asInt() << ".ts\r\n";
|
||||
}
|
||||
Result << "#EXT-X-ENDLIST";
|
||||
}else{
|
||||
if (metadata["missed_frags"].asInt() < 0){
|
||||
metadata["missed_frags"] = 0ll;
|
||||
}
|
||||
Result << "#EXTM3U\r\n"
|
||||
"#EXT-X-MEDIA-SEQUENCE:" << metadata["missed_frags"].asInt() <<"\r\n"
|
||||
"#EXT-X-TARGETDURATION:30\r\n";
|
||||
for (JSON::ArrIter ai = metadata["frags"].ArrBegin(); ai != metadata["frags"].ArrEnd(); ai++){
|
||||
Result << "#EXTINF:" << (*ai)["dur"].asInt() / 1000 << ", no desc\r\n" << (*ai)["num"].asInt() << "_" << (*ai)["len"].asInt() << ".ts\r\n";
|
||||
result << "#EXTINF:" << (*ai)["dur"].asInt() / 1000 << ", no desc\r\n"
|
||||
<< metadata["keys"][(*ai)["num"].asInt() - 1]["time"].asInt() << "_" << (*ai)["dur"].asInt() + metadata["keys"][(*ai)["num"].asInt() - 1]["time"].asInt() << ".ts\r\n";
|
||||
}
|
||||
result << "#EXT-X-ENDLIST";
|
||||
}
|
||||
#if DEBUG >= 8
|
||||
std::cerr << "Sending this index:" << std::endl << Result.str() << std::endl;
|
||||
#endif
|
||||
return Result.str();
|
||||
return result.str();
|
||||
} //liveIndex
|
||||
|
||||
///\brief Main function for the HTTP Live Connector
|
||||
|
@ -92,6 +110,8 @@ namespace Connector_HTTP {
|
|||
|
||||
int Segment = -1;
|
||||
int temp;
|
||||
int trackID = 0;
|
||||
int audioTrackID = 0;
|
||||
unsigned int lastStats = 0;
|
||||
conn.setBlocking(false); //do not block on conn.spool() when no data is available
|
||||
|
||||
|
@ -137,6 +157,10 @@ namespace Connector_HTTP {
|
|||
}
|
||||
if (HTTP_R.url.find(".m3u") == std::string::npos){
|
||||
temp = HTTP_R.url.find("/", 5) + 1;
|
||||
std::string allTracks = HTTP_R.url.substr(temp, HTTP_R.url.find("/", temp) - temp);
|
||||
trackID = atoi(allTracks.c_str());
|
||||
audioTrackID = atoi(allTracks.substr(allTracks.find("_")+1).c_str());
|
||||
temp = HTTP_R.url.find("/", temp) + 1;
|
||||
Segment = atoi(HTTP_R.url.substr(temp, HTTP_R.url.find("_", temp) - temp).c_str());
|
||||
temp = HTTP_R.url.find("_", temp) + 1;
|
||||
int frameCount = atoi(HTTP_R.url.substr(temp, HTTP_R.url.find(".ts", temp) - temp).c_str());
|
||||
|
@ -159,13 +183,19 @@ namespace Connector_HTTP {
|
|||
continue;
|
||||
}
|
||||
}
|
||||
std::stringstream sstream;
|
||||
sstream << "f " << Segment << "\n";
|
||||
for (int i = 0; i < frameCount; i++){
|
||||
sstream << "o \n";
|
||||
for (int i = 0; i < allTracks.size(); i++){
|
||||
if (allTracks[i] == '_'){
|
||||
allTracks[i] = ' ';
|
||||
}
|
||||
}
|
||||
std::stringstream sstream;
|
||||
sstream << "t " << allTracks << "\n";
|
||||
sstream << "s " << Segment << "\n";
|
||||
sstream << "p " << frameCount << "\n";
|
||||
ss.SendNow(sstream.str().c_str());
|
||||
fprintf(stderr,"Sending %s to player\n", sstream.str().c_str());
|
||||
}else{
|
||||
std::string request = HTTP_R.url.substr(HTTP_R.url.find("/", 5) + 1);
|
||||
if (HTTP_R.url.find(".m3u8") != std::string::npos){
|
||||
manifestType = "audio/x-mpegurl";
|
||||
}else{
|
||||
|
@ -174,7 +204,13 @@ namespace Connector_HTTP {
|
|||
HTTP_S.Clean();
|
||||
HTTP_S.SetHeader("Content-Type", manifestType);
|
||||
HTTP_S.SetHeader("Cache-Control", "no-cache");
|
||||
std::string manifest = liveIndex(Strm.metadata);
|
||||
std::string manifest;
|
||||
if (request.find("/") == std::string::npos){
|
||||
manifest = liveIndex(Strm.metadata);
|
||||
}else{
|
||||
int selectId = atoi(request.substr(0,request.find("/")).c_str());
|
||||
manifest = liveIndex(Strm.getTrackById(selectId));
|
||||
}
|
||||
HTTP_S.SetBody(manifest);
|
||||
conn.SendNow(HTTP_S.BuildResponse("200", "OK"));
|
||||
}
|
||||
|
@ -209,7 +245,7 @@ namespace Connector_HTTP {
|
|||
TSBuf.str("");
|
||||
}
|
||||
if ( !haveAvcc){
|
||||
avccbox.setPayload(Strm.metadata["video"]["init"].asString());
|
||||
avccbox.setPayload(Strm.getTrackById(trackID)["init"].asString());
|
||||
haveAvcc = true;
|
||||
}
|
||||
if (Strm.lastType() == DTSC::VIDEO || Strm.lastType() == DTSC::AUDIO){
|
||||
|
@ -246,7 +282,7 @@ namespace Connector_HTTP {
|
|||
PIDno = 0x100;
|
||||
ContCounter = &VideoCounter;
|
||||
}else if (Strm.lastType() == DTSC::AUDIO){
|
||||
ToPack.append(TS::GetAudioHeader(Strm.lastData().size(), Strm.metadata["audio"]["init"].asString()));
|
||||
ToPack.append(TS::GetAudioHeader(Strm.lastData().size(), Strm.getTrackById(audioTrackID)["init"].asString()));
|
||||
ToPack.append(Strm.lastData());
|
||||
ToPack.prepend(TS::Packet::getPESAudioLeadIn(ToPack.bytes(1073741824ul), Strm.getPacket(0)["time"].asInt() * 90));
|
||||
PIDno = 0x101;
|
||||
|
|
|
@ -216,25 +216,34 @@ namespace Converters {
|
|||
//calculate fragments
|
||||
meta["tracks"][it->first]["frags"].null();
|
||||
long long int currFrag = -1;
|
||||
long long int maxBps = 0;
|
||||
for (JSON::ArrIter arrIt = meta["tracks"][it->first]["keys"].ArrBegin(); arrIt != meta["tracks"][it->first]["keys"].ArrEnd(); arrIt++) {
|
||||
if ((*arrIt)["time"].asInt() / 10000 > currFrag){
|
||||
currFrag = (*arrIt)["time"].asInt() / 10000;
|
||||
long long int fragLen = 1;
|
||||
long long int fragDur = (*arrIt)["len"].asInt();
|
||||
for (JSON::ArrIter it2 = arrIt; it2 != meta["tracks"][it->first]["keys"].ArrEnd(); it2++){
|
||||
long long int fragSize = (*arrIt)["size"].asInt();
|
||||
for (JSON::ArrIter it2 = arrIt + 1; it2 != meta["tracks"][it->first]["keys"].ArrEnd(); it2++){
|
||||
if ((*it2)["time"].asInt() / 10000 > currFrag || (it2 + 1) == meta["tracks"][it->first]["keys"].ArrEnd()){
|
||||
JSON::Value thisFrag;
|
||||
thisFrag["num"] = (*arrIt)["num"].asInt();
|
||||
thisFrag["len"] = fragLen;
|
||||
thisFrag["dur"] = fragDur;
|
||||
thisFrag["size"] = fragSize;
|
||||
thisFrag["bps"] = fragSize / (fragDur / 1000);
|
||||
if (maxBps < (fragSize / (fragDur / 1000))){
|
||||
maxBps = (fragSize / (fragDur / 1000));
|
||||
}
|
||||
meta["tracks"][it->first]["frags"].append(thisFrag);
|
||||
break;
|
||||
}
|
||||
fragLen ++;
|
||||
fragDur += (*it2)["len"].asInt();
|
||||
fragSize += (*it2)["size"].asInt();
|
||||
}
|
||||
}
|
||||
}
|
||||
meta["tracks"][it->first]["maxbps"] = maxBps;
|
||||
}
|
||||
|
||||
meta["firstms"] = firstms;
|
||||
|
|
Loading…
Add table
Reference in a new issue