diff --git a/Makefile b/Makefile index 4ed110cf..55923ac4 100644 --- a/Makefile +++ b/Makefile @@ -132,14 +132,14 @@ MistOutRaw: src/output/mist_out.cpp src/output/output.cpp src/output/output_raw. outputs: MistOutHTTPTS MistOutHTTPTS: override LDLIBS += $(THREADLIB) -MistOutHTTPTS: override CPPFLAGS += "-DOUTPUTTYPE=\"output_httpts.h\"" -MistOutHTTPTS: src/output/mist_out.cpp src/output/output.cpp src/output/output_http.cpp src/output/output_httpts.cpp +MistOutHTTPTS: override CPPFLAGS += -DOUTPUTTYPE=\"output_httpts.h\" -DTS_BASECLASS=HTTPOutput +MistOutHTTPTS: src/output/mist_out.cpp src/output/output.cpp src/output/output_http.cpp src/output/output_httpts.cpp src/output/output_ts_base.cpp $(CXX) $(LDFLAGS) $(CPPFLAGS) $^ $(LDLIBS) -o $@ outputs: MistOutTS MistOutTS: override LDLIBS += $(THREADLIB) MistOutTS: override CPPFLAGS += "-DOUTPUTTYPE=\"output_ts.h\"" -MistOutTS: src/output/mist_out.cpp src/output/output.cpp src/output/output_ts.cpp +MistOutTS: src/output/mist_out.cpp src/output/output.cpp src/output/output_ts.cpp src/output/output_ts_base.cpp $(CXX) $(LDFLAGS) $(CPPFLAGS) $^ $(LDLIBS) -o $@ outputs: MistOutHTTP @@ -156,8 +156,8 @@ MistOutHSS: src/output/mist_out.cpp src/output/output.cpp src/output/output_http outputs: MistOutHLS MistOutHLS: override LDLIBS += $(THREADLIB) -MistOutHLS: override CPPFLAGS += "-DOUTPUTTYPE=\"output_hls.h\"" -MistOutHLS: src/output/mist_out.cpp src/output/output.cpp src/output/output_http.cpp src/output/output_hls.cpp +MistOutHLS: override CPPFLAGS += -DOUTPUTTYPE=\"output_hls.h\" -DTS_BASECLASS=HTTPOutput +MistOutHLS: src/output/mist_out.cpp src/output/output.cpp src/output/output_http.cpp src/output/output_hls.cpp src/output/output_ts_base.cpp $(CXX) $(LDFLAGS) $(CPPFLAGS) $^ $(LDLIBS) -o $@ outputs: MistOutHDS diff --git a/src/output/output_hls.cpp b/src/output/output_hls.cpp index 35082e4d..96ec58bb 100644 --- a/src/output/output_hls.cpp +++ b/src/output/output_hls.cpp @@ -88,10 +88,8 @@ namespace Mist { } //liveIndex - OutHLS::OutHLS(Socket::Connection & conn) : HTTPOutput(conn) { - haveAvcc = false; + OutHLS::OutHLS(Socket::Connection & conn) : TSOutput(conn){ realTime = 0; - setBlocking(true); } OutHLS::~OutHLS() {} @@ -110,122 +108,6 @@ namespace Mist { capa["methods"][0u]["priority"] = 9ll; } - void OutHLS::fillPacket(bool & first, const char * data, size_t dataLen, char & ContCounter){ - static std::map contCounter; - if (!PackData.BytesFree()){ - if (PacketNumber % 42 == 0){ - TS::Packet tmpPack; - tmpPack.FromPointer(TS::PAT); - tmpPack.continuityCounter(++contCounter[tmpPack.PID()]); - H.Chunkify(tmpPack.ToString(), 188, myConn); - tmpPack.FromPointer(TS::createPMT(selectedTracks, myMeta).c_str()); - tmpPack.continuityCounter(++contCounter[tmpPack.PID()]); - H.Chunkify(tmpPack.ToString(), 188, myConn); - PacketNumber += 2; - } - H.Chunkify(PackData.ToString(), 188, myConn); - PacketNumber ++; - PackData.Clear(); - } - - if (!dataLen){return;} - - if (PackData.BytesFree() == 184){ - PackData.PID(0x100 - 1 + currentPacket.getTrackId()); - PackData.continuityCounter(ContCounter++); - if (first){ - PackData.unitStart(1); - if (myMeta.tracks[currentPacket.getTrackId()].type == "video"){ - if (currentPacket.getInt("keyframe")){ - PackData.randomAccess(1); - } - PackData.PCR(currentPacket.getTime() * 27000); - } - first = false; - } - - } - - int tmp = PackData.FillFree(data, dataLen); - if (tmp != dataLen){ - fillPacket(first, data+tmp, dataLen-tmp, ContCounter); - } - } - - void OutHLS::sendNext(){ - bool first = true; - char * dataPointer = 0; - unsigned int dataLen = 0; - currentPacket.getString("data", dataPointer, dataLen); //data - - if (currentPacket.getTime() >= until){ - stop(); - wantRequest = true; - parseData = false; - H.Chunkify("", 0, myConn); - H.Clean(); - return; - } - - std::string bs; - //prepare bufferstring - if (myMeta.tracks[currentPacket.getTrackId()].type == "video"){ - bs = TS::Packet::getPESVideoLeadIn(0ul, currentPacket.getTime() * 90, currentPacket.getInt("offset") * 90); - fillPacket(first, bs.data(), bs.size(), VideoCounter); - if (myMeta.tracks[currentPacket.getTrackId()].codec == "H264"){ - //End of previous nal unit, somehow needed for h264 - fillPacket(first, "\000\000\000\001\011\360", 6, VideoCounter); - } - - if (currentPacket.getInt("keyframe")){ - if (!haveAvcc){ - avccbox.setPayload(myMeta.tracks[currentPacket.getTrackId()].init); - haveAvcc = true; - bs = avccbox.asAnnexB(); - fillPacket(first, bs.data(), bs.size(), VideoCounter); - } - } - - unsigned int i = 0; - while (i + 4 < (unsigned int)dataLen){ - unsigned int ThisNaluSize = (dataPointer[i] << 24) + (dataPointer[i+1] << 16) + (dataPointer[i+2] << 8) + dataPointer[i+3]; - if (ThisNaluSize + i + 4 > (unsigned int)dataLen){ - DEBUG_MSG(DLVL_WARN, "Too big NALU detected (%u > %d) - skipping!", ThisNaluSize + i + 4, dataLen); - break; - } - fillPacket(first, "\000\000\000\001",4, VideoCounter); - fillPacket(first, dataPointer+i+4,ThisNaluSize, VideoCounter); - i += ThisNaluSize+4; - } - if (PackData.BytesFree() < 184){ - PackData.AddStuffing(); - fillPacket(first, 0, 0, VideoCounter); - } - }else if (myMeta.tracks[currentPacket.getTrackId()].type == "audio"){ - long long unsigned int tempTime; - if (AppleCompat){ - tempTime = lastVid; - }else{ - tempTime = currentPacket.getTime() * 90; - } - long unsigned int tempLen = dataLen; - if ( myMeta.tracks[currentPacket.getTrackId()].codec == "AAC"){ - tempLen += 7; - } - bs = TS::Packet::getPESAudioLeadIn(tempLen, tempTime); - fillPacket(first, bs.data(), bs.size(), AudioCounter); - if (myMeta.tracks[currentPacket.getTrackId()].codec == "AAC"){ - bs = TS::GetAudioHeader(dataLen, myMeta.tracks[currentPacket.getTrackId()].init); - fillPacket(first, bs.data(), bs.size(), AudioCounter); - } - fillPacket(first, dataPointer,dataLen, AudioCounter); - if (PackData.BytesFree() < 184){ - PackData.AddStuffing(); - fillPacket(first, 0, 0, AudioCounter); - } - } - } - int OutHLS::canSeekms(unsigned int ms){ //no tracks? Frame too new by definition. if ( !myMeta.tracks.size()){ @@ -246,8 +128,23 @@ namespace Mist { } void OutHLS::onHTTP(){ - AppleCompat = (H.GetHeader("User-Agent").find("Apple") != std::string::npos); - VLCworkaround = false; + if (H.url == "/crossdomain.xml"){ + H.Clean(); + H.SetHeader("Content-Type", "text/xml"); + H.SetHeader("Server", "mistserver/" PACKAGE_VERSION "/" + Util::Config::libver); + H.SetBody(""); + H.SendResponse("200", "OK", myConn); + H.Clean(); //clean for any possible next requests + return; + } //crossdomain.xml + + if (H.url.find("hls") == std::string::npos){ + myConn.close(); + return; + } + + appleCompat = (H.GetHeader("User-Agent").find("Apple") != std::string::npos); + bool VLCworkaround = false; if (H.GetHeader("User-Agent").substr(0, 3) == "VLC"){ std::string vlcver = H.GetHeader("User-Agent").substr(4); if (vlcver[0] == '0' || vlcver[0] == '1' || (vlcver[0] == '2' && vlcver[2] < '2')){ @@ -308,7 +205,7 @@ namespace Mist { H.SetHeader("Content-Type", "video/mp2t"); H.StartResponse(H, myConn, VLCworkaround); - PacketNumber = 0; + packCounter = 0; parseData = true; wantRequest = false; }else{ @@ -332,4 +229,9 @@ namespace Mist { H.SendResponse("200", "OK", myConn); } } + + + void OutHLS::sendTS(const char * tsData, unsigned int len){ + H.Chunkify(tsData, len, myConn); + } } diff --git a/src/output/output_hls.h b/src/output/output_hls.h index 8476a4ea..29afcc63 100644 --- a/src/output/output_hls.h +++ b/src/output/output_hls.h @@ -1,34 +1,19 @@ +#include "output_ts_base.h" #include "output_http.h" -#include -#include -#include namespace Mist { - class OutHLS : public HTTPOutput { + class OutHLS : public TSOutput{ public: OutHLS(Socket::Connection & conn); ~OutHLS(); static void init(Util::Config * cfg); - void onHTTP(); - void sendNext(); - protected: - std::string createPMT(); - void fillPacket(bool & first, const char * data, size_t dataLen, char & ContCounter); + void sendTS(const char * tsData, unsigned int len=188); + void onHTTP(); + protected: std::string liveIndex(); std::string liveIndex(int tid); int canSeekms(unsigned int ms); - int keysToSend; - long long int playUntil; - TS::Packet PackData; - unsigned int PacketNumber; - bool haveAvcc; - char VideoCounter; - char AudioCounter; - MP4::AVCC avccbox; - bool AppleCompat; - bool VLCworkaround; - long long unsigned int lastVid; - long long unsigned int until; + int keysToSend; unsigned int vidTrack; unsigned int audTrack; }; diff --git a/src/output/output_http.h b/src/output/output_http.h index 272c68ce..6fe05c03 100644 --- a/src/output/output_http.h +++ b/src/output/output_http.h @@ -1,3 +1,4 @@ +#pragma once #include #include #include "output.h" diff --git a/src/output/output_httpts.cpp b/src/output/output_httpts.cpp index 613d1974..a391ee48 100644 --- a/src/output/output_httpts.cpp +++ b/src/output/output_httpts.cpp @@ -5,10 +5,7 @@ #include namespace Mist { - OutHTTPTS::OutHTTPTS(Socket::Connection & conn) : HTTPOutput(conn) { - haveAvcc = false; - myConn.setBlocking(true); - } + OutHTTPTS::OutHTTPTS(Socket::Connection & conn) : TSOutput(conn) {} OutHTTPTS::~OutHTTPTS() {} @@ -27,102 +24,18 @@ namespace Mist { capa["methods"][0u]["priority"] = 1ll; } - void OutHTTPTS::fillPacket(bool & first, const char * data, size_t dataLen, char & ContCounter){ - if (!PackData.BytesFree()){ - if (PacketNumber % 42 == 0){ - H.Chunkify(TS::PAT, 188, myConn); - H.Chunkify(TS::createPMT(selectedTracks, myMeta), myConn); - PacketNumber += 2; - } - H.Chunkify(PackData.ToString(), 188, myConn); - PacketNumber ++; - PackData.Clear(); - } - if (!dataLen){return;} - if (PackData.BytesFree() == 184){ - PackData.PID(0x100 - 1 + currentPacket.getTrackId()); - PackData.continuityCounter(ContCounter++); - if (first){ - PackData.unitStart(1); - if (currentPacket.getInt("keyframe")){ - PackData.randomAccess(1); - PackData.PCR(currentPacket.getTime() * 27000); - } - first = false; - } - } - int tmp = PackData.FillFree(data, dataLen); - if (tmp != dataLen){ - fillPacket(first, data+tmp, dataLen-tmp, ContCounter); - } - } - - void OutHTTPTS::sendNext(){ - bool first = true; - char * ContCounter = 0; - char * dataPointer = 0; - unsigned int dataLen = 0; - currentPacket.getString("data", dataPointer, dataLen); //data - - std::string bs; - //prepare bufferstring - if (myMeta.tracks[currentPacket.getTrackId()].type == "video"){ - bs = TS::Packet::getPESVideoLeadIn(0ul, currentPacket.getTime() * 90, currentPacket.getInt("offset") * 90); - fillPacket(first, bs.data(), bs.size(), VideoCounter); - - if (currentPacket.getInt("keyframe")){ - if (!haveAvcc){ - avccbox.setPayload(myMeta.tracks[currentPacket.getTrackId()].init); - haveAvcc = true; - } - bs = avccbox.asAnnexB(); - fillPacket(first, bs.data(), bs.size(), VideoCounter); - } - - unsigned int i = 0; - while (i + 4 < (unsigned int)dataLen){ - unsigned int ThisNaluSize = (dataPointer[i] << 24) + (dataPointer[i+1] << 16) + (dataPointer[i+2] << 8) + dataPointer[i+3]; - if (ThisNaluSize + i + 4 > (unsigned int)dataLen){ - DEBUG_MSG(DLVL_WARN, "Too big NALU detected (%u > %d) - skipping!", ThisNaluSize + i + 4, dataLen); - break; - } - fillPacket(first, "\000\000\000\001",4, VideoCounter); - fillPacket(first, dataPointer+i+4,ThisNaluSize, VideoCounter); - i += ThisNaluSize+4; - } - if (PackData.BytesFree() < 184){ - PackData.AddStuffing(); - fillPacket(first, 0, 0, VideoCounter); - } - }else if (myMeta.tracks[currentPacket.getTrackId()].type == "audio"){ - unsigned int tempLen = dataLen; - if ( myMeta.tracks[currentPacket.getTrackId()].codec == "AAC"){ - tempLen += 7; - } - bs = TS::Packet::getPESAudioLeadIn(tempLen, currentPacket.getTime() * 90); - fillPacket(first, bs.data(), bs.size(), AudioCounter); - if (myMeta.tracks[currentPacket.getTrackId()].codec == "AAC"){ - bs = TS::GetAudioHeader(dataLen, myMeta.tracks[currentPacket.getTrackId()].init); - fillPacket(first, bs.data(), bs.size(), AudioCounter); - } - ContCounter = &AudioCounter; - fillPacket(first, dataPointer,dataLen, AudioCounter); - if (PackData.BytesFree() < 184){ - PackData.AddStuffing(); - fillPacket(first, 0, 0, AudioCounter); - } - } - } - void OutHTTPTS::onHTTP(){ - initialize(); H.Clean(); H.SetHeader("Content-Type", "video/mp2t"); - H.StartResponse(H, myConn); - PacketNumber = 0; + H.StartResponse(H, myConn); parseData = true; wantRequest = false; H.Clean(); //clean for any possible next requests } + + void OutHTTPTS::sendTS(const char * tsData, unsigned int len){ + H.Chunkify(tsData, len, myConn); + } + } diff --git a/src/output/output_httpts.h b/src/output/output_httpts.h index 2b73a542..84ebb85f 100644 --- a/src/output/output_httpts.h +++ b/src/output/output_httpts.h @@ -1,29 +1,17 @@ +#include "output_ts_base.h" #include "output_http.h" -#include -#include -#include -#include namespace Mist { - class OutHTTPTS : public HTTPOutput { + class OutHTTPTS : public TSOutput{ public: OutHTTPTS(Socket::Connection & conn); ~OutHTTPTS(); static void init(Util::Config * cfg); void onHTTP(); - void sendNext(); - protected: - std::string createPMT(); - void fillPacket(bool & first, const char * data, size_t dataLen, char & ContCounter); + void sendTS(const char * tsData, unsigned int len=188); + protected: int keysToSend; - long long int playUntil; - TS::Packet PackData; - unsigned int PacketNumber; - bool haveAvcc; - char VideoCounter; - char AudioCounter; - MP4::AVCC avccbox; - bool AppleCompat; + long long int playUntil; long long unsigned int lastVid; long long unsigned int until; unsigned int vidTrack; diff --git a/src/output/output_ts.cpp b/src/output/output_ts.cpp index 02c7e0c1..516a32cc 100644 --- a/src/output/output_ts.cpp +++ b/src/output/output_ts.cpp @@ -3,10 +3,7 @@ #include namespace Mist { - OutTS::OutTS(Socket::Connection & conn) : Output(conn){ - haveAvcc = false; - AudioCounter = 0; - VideoCounter = 0; + OutTS::OutTS(Socket::Connection & conn) : TSOutput(conn){ streamName = config->getString("streamname"); parseData = true; wantRequest = false; @@ -57,92 +54,8 @@ namespace Mist { cfg->addConnectorOptions(8888, capa); config = cfg; } - - void OutTS::fillPacket(bool & first, const char * data, size_t dataLen, char & ContCounter){ - if (!PackData.BytesFree()){ - myConn.SendNow(PackData.ToString(), 188); - PackData.Clear(); - } - - if (!dataLen){return;} - - if (PackData.BytesFree() == 184){ - PackData.PID(0x100 - 1 + currentPacket.getTrackId()); - PackData.continuityCounter(ContCounter++); - if (first){ - PackData.unitStart(1); - if (currentPacket.getInt("keyframe")){ - PackData.randomAccess(1); - PackData.PCR(currentPacket.getTime() * 27000); - } - first = false; - } - } - - unsigned int tmp = PackData.FillFree(data, dataLen); - if (tmp != dataLen){ - fillPacket(first, data+tmp, dataLen-tmp, ContCounter); - } - - } - - - void OutTS::sendNext(){ - char * dataPointer = 0; - unsigned int dataLen = 0; - currentPacket.getString("data", dataPointer, dataLen); //data - - bool first = true; - std::string bs; - //prepare bufferstring - if (myMeta.tracks[currentPacket.getTrackId()].type == "video"){ - bs = TS::Packet::getPESVideoLeadIn(0ul, currentPacket.getTime() * 90, currentPacket.getInt("offset") * 90); - fillPacket(first, bs.data(), bs.size(),VideoCounter); - - if (currentPacket.getInt("keyframe")){ - if (!haveAvcc){ - avccbox.setPayload(myMeta.tracks[currentPacket.getTrackId()].init); - haveAvcc = true; - } - bs = avccbox.asAnnexB(); - fillPacket(first, bs.data(), bs.size(),VideoCounter); - } - unsigned int i = 0; - while (i + 4 < (unsigned int)dataLen){ - unsigned int ThisNaluSize = (dataPointer[i] << 24) + (dataPointer[i+1] << 16) + (dataPointer[i+2] << 8) + dataPointer[i+3]; - if (ThisNaluSize + i + 4 > (unsigned int)dataLen){ - DEBUG_MSG(DLVL_WARN, "Too big NALU detected (%u > %d) - skipping!", ThisNaluSize + i + 4, dataLen); - break; - } - fillPacket(first, "\000\000\000\001",4,VideoCounter); - fillPacket(first, dataPointer+i+4,ThisNaluSize,VideoCounter); - i += ThisNaluSize+4; - } - }else if (myMeta.tracks[currentPacket.getTrackId()].type == "audio"){ - unsigned int tempLen = dataLen; - if (myMeta.tracks[currentPacket.getTrackId()].codec == "AAC"){ - tempLen += 7; - } - bs = TS::Packet::getPESAudioLeadIn(tempLen, currentPacket.getTime() * 90); - fillPacket(first, bs.data(), bs.size(),AudioCounter); - if (myMeta.tracks[currentPacket.getTrackId()].codec == "AAC"){ - bs = TS::GetAudioHeader(dataLen, myMeta.tracks[currentPacket.getTrackId()].init); - fillPacket(first, bs.data(), bs.size(),AudioCounter); - }else{ - } - fillPacket(first, dataPointer,dataLen,AudioCounter); - } - - if (PackData.BytesFree() < 184){ - PackData.AddStuffing(); - fillPacket(first, 0,0,VideoCounter); - } - } - void OutTS::sendHeader(){ - myConn.SendNow(TS::PAT, 188); - myConn.SendNow(TS::createPMT(selectedTracks, myMeta)); - sentHeader = true; + void OutTS::sendTS(const char * tsData, unsigned int len){ + myConn.SendNow(tsData, len); } - } diff --git a/src/output/output_ts.h b/src/output/output_ts.h index 6c63c845..dfc55be3 100644 --- a/src/output/output_ts.h +++ b/src/output/output_ts.h @@ -1,25 +1,12 @@ -#include "output.h" -#include -#include -#include +#include "output_ts_base.h" namespace Mist { - class OutTS : public Output { + class OutTS : public TSOutput{ public: OutTS(Socket::Connection & conn); ~OutTS(); static void init(Util::Config * cfg); - void sendNext(); - void sendHeader(); - protected: - TS::Packet PackData; - unsigned int PacketNumber; - bool haveAvcc; - char VideoCounter; - char AudioCounter; - MP4::AVCC avccbox; - std::string createPMT(); - void fillPacket(bool & first, const char * data, size_t dataLen, char & ContCounter); + void sendTS(const char * tsData, unsigned int len=188); }; } diff --git a/src/output/output_ts_base.cpp b/src/output/output_ts_base.cpp new file mode 100644 index 00000000..1a0b453c --- /dev/null +++ b/src/output/output_ts_base.cpp @@ -0,0 +1,174 @@ +#include "output_ts_base.h" + +namespace Mist { + TSOutput::TSOutput(Socket::Connection & conn) : TS_BASECLASS(conn){ + packCounter=0; + haveAvcc = false; + until=0xFFFFFFFFFFFFFFFFull; + setBlocking(true); + sendRepeatingHeaders = false; + appleCompat=false; + } + + void TSOutput::fillPacket(const char * data, const size_t dataLen){ + + if (!packData.getBytesFree()){ + ///\todo only resend the PAT/PMT for HLS + if ( (sendRepeatingHeaders && packCounter % 42 == 0) || !packCounter){ + TS::Packet tmpPack; + tmpPack.FromPointer(TS::PAT); + tmpPack.setContinuityCounter(++contCounters[tmpPack.getPID()]); + sendTS(tmpPack.checkAndGetBuffer()); + sendTS(TS::createPMT(selectedTracks, myMeta, ++contCounters[tmpPack.getPID()])); + packCounter += 2; + } + sendTS(packData.checkAndGetBuffer()); + packCounter ++; + packData.clear(); + } + + if (!dataLen){return;} + + if (packData.getBytesFree() == 184){ + packData.clear(); + packData.setPID(0x100 - 1 + currentPacket.getTrackId()); + packData.setContinuityCounter(++contCounters[packData.getPID()]); + if (first[currentPacket.getTrackId()]){ + packData.setUnitStart(1); + if (myMeta.tracks[currentPacket.getTrackId()].type == "video"){ + if (currentPacket.getInt("keyframe")){ + packData.setRandomAccess(1); + } + packData.setPCR(currentPacket.getTime() * 27000); + } + first[currentPacket.getTrackId()] = false; + } + } + + int tmp = packData.fillFree(data, dataLen); + if (tmp != dataLen){ + return fillPacket(data+tmp, dataLen-tmp); + } + } + + void TSOutput::sendNext(){ + first[currentPacket.getTrackId()] = true; + char * dataPointer = 0; + unsigned int dataLen = 0; + currentPacket.getString("data", dataPointer, dataLen); //data + if (currentPacket.getTime() >= until){ //this if should only trigger for HLS + stop(); + wantRequest = true; + parseData = false; + sendTS("",0); + return; + } + std::string bs; + //prepare bufferstring + if (myMeta.tracks[currentPacket.getTrackId()].type == "video"){ + unsigned int extraSize = 0; + //dataPointer[4] & 0x1f is used to check if this should be done later: fillPacket("\000\000\000\001\011\360", 6); + if (myMeta.tracks[currentPacket.getTrackId()].codec == "H264" && (dataPointer[4] & 0x1f) != 0x09){ + extraSize += 6; + } + if (currentPacket.getInt("keyframe")){ + if (myMeta.tracks[currentPacket.getTrackId()].codec == "H264"){ + if (!haveAvcc){ + avccbox.setPayload(myMeta.tracks[currentPacket.getTrackId()].init); + haveAvcc = true; + } + bs = avccbox.asAnnexB(); + extraSize += bs.size(); + } + } + + unsigned int watKunnenWeIn1Ding = 65490-13; + unsigned int splitCount = (dataLen+extraSize) / watKunnenWeIn1Ding; + unsigned int currPack = 0; + unsigned int ThisNaluSize = 0; + unsigned int i = 0; + + while (currPack <= splitCount){ + unsigned int alreadySent = 0; + bs = TS::Packet::getPESVideoLeadIn((currPack != splitCount ? watKunnenWeIn1Ding : dataLen+extraSize - currPack*watKunnenWeIn1Ding), currentPacket.getTime() * 90, currentPacket.getInt("offset") * 90, !currPack); + fillPacket(bs.data(), bs.size()); + if (!currPack){ + if (myMeta.tracks[currentPacket.getTrackId()].codec == "H264" && (dataPointer[4] & 0x1f) != 0x09){ + //End of previous nal unit, if not already present + fillPacket("\000\000\000\001\011\360", 6); + alreadySent += 6; + } + if (currentPacket.getInt("keyframe")){ + if (myMeta.tracks[currentPacket.getTrackId()].codec == "H264"){ + bs = avccbox.asAnnexB(); + fillPacket(bs.data(), bs.size()); + alreadySent += bs.size(); + } + } + } + while (i + 4 < (unsigned int)dataLen){ + if (!ThisNaluSize){ + ThisNaluSize = (dataPointer[i] << 24) + (dataPointer[i+1] << 16) + (dataPointer[i+2] << 8) + dataPointer[i+3]; + if (ThisNaluSize + i + 4 > (unsigned int)dataLen){ + DEBUG_MSG(DLVL_WARN, "Too big NALU detected (%u > %d) - skipping!", ThisNaluSize + i + 4, dataLen); + break; + } + if (alreadySent + 4 > watKunnenWeIn1Ding){ + /// \todo Houd rekening met deze relatief zelfdzame sub-optimale situatie + //Kom op, wat is de kans nou? ~_~ + FAIL_MSG("Encountered lazy coders. Maybe someone should fix this."); + } + fillPacket("\000\000\000\001",4); + alreadySent += 4; + i += 4; + } + if (alreadySent + ThisNaluSize > watKunnenWeIn1Ding){ + fillPacket(dataPointer+i,watKunnenWeIn1Ding-alreadySent); + i += watKunnenWeIn1Ding-alreadySent; + ThisNaluSize -= watKunnenWeIn1Ding-alreadySent; + alreadySent += watKunnenWeIn1Ding-alreadySent; + }else{ + fillPacket(dataPointer+i,ThisNaluSize); + alreadySent += ThisNaluSize; + i += ThisNaluSize; + ThisNaluSize = 0; + } + if (alreadySent == watKunnenWeIn1Ding){ + packData.addStuffing(); + fillPacket(0, 0); + first[currentPacket.getTrackId()] = true; + break; + } + } + currPack++; + } + }else if (myMeta.tracks[currentPacket.getTrackId()].type == "audio"){ + long unsigned int tempLen = dataLen; + if ( myMeta.tracks[currentPacket.getTrackId()].codec == "AAC"){ + tempLen += 7; + } + long long unsigned int tempTime; + if (appleCompat){ + tempTime = 0;// myMeta.tracks[currentPacket.getTrackId()].rate / 1000; + }else{ + tempTime = currentPacket.getTime() * 90; + } + ///\todo stuur 70ms aan audio per PES pakket om applecompat overbodig te maken. + //static unsigned long long lastSent=currentPacket.getTime() * 90; + //if( (currentPacket.getTime() * 90)-lastSent >= 70*90 ){ + // lastSent=(currentPacket.getTime() * 90); + //} + bs = TS::Packet::getPESAudioLeadIn(tempLen, tempTime);// myMeta.tracks[currentPacket.getTrackId()].rate / 1000 ); + fillPacket(bs.data(), bs.size()); + if (myMeta.tracks[currentPacket.getTrackId()].codec == "AAC"){ + bs = TS::getAudioHeader(dataLen, myMeta.tracks[currentPacket.getTrackId()].init); + fillPacket(bs.data(), bs.size()); + } + fillPacket(dataPointer,dataLen); + } + if (packData.getBytesFree() < 184){ + packData.addStuffing(); + fillPacket(0, 0); + } + } +} diff --git a/src/output/output_ts_base.h b/src/output/output_ts_base.h new file mode 100644 index 00000000..1f7bbfa0 --- /dev/null +++ b/src/output/output_ts_base.h @@ -0,0 +1,32 @@ +#include +#include "output.h" +#include "output_http.h" +#include +#include + +#ifndef TS_BASECLASS +#define TS_BASECLASS Output +#endif + +namespace Mist { + + class TSOutput : public TS_BASECLASS { + public: + TSOutput(Socket::Connection & conn); + virtual ~TSOutput(){}; + void sendNext(); + virtual void sendTS(const char * tsData, unsigned int len=188){}; + void fillPacket(const char * data, const size_t dataLen); + protected: + std::map first; + std::map contCounters; + unsigned int packCounter; ///\todo update constructors? + TS::Packet packData; + bool haveAvcc; + MP4::AVCC avccbox; + bool appleCompat; + bool sendRepeatingHeaders; + long long unsigned int until; + long long unsigned int lastVid; + }; +}