Merged TS unification edits by Wouter Spruit.
This commit is contained in:
parent
3ef9f70ef7
commit
95f19c4259
10 changed files with 260 additions and 365 deletions
10
Makefile
10
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
|
||||
|
|
|
@ -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<int, int> 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("<?xml version=\"1.0\"?><!DOCTYPE cross-domain-policy SYSTEM \"http://www.adobe.com/xml/dtds/cross-domain-policy.dtd\"><cross-domain-policy><allow-access-from domain=\"*\" /><site-control permitted-cross-domain-policies=\"all\"/></cross-domain-policy>");
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,34 +1,19 @@
|
|||
#include "output_ts_base.h"
|
||||
#include "output_http.h"
|
||||
#include <mist/ts_packet.h>
|
||||
#include <mist/mp4.h>
|
||||
#include <mist/mp4_generic.h>
|
||||
|
||||
namespace Mist {
|
||||
class OutHLS : public HTTPOutput {
|
||||
class OutHLS : public TSOutput{
|
||||
public:
|
||||
OutHLS(Socket::Connection & conn);
|
||||
~OutHLS();
|
||||
static void init(Util::Config * cfg);
|
||||
void sendTS(const char * tsData, unsigned int len=188);
|
||||
void onHTTP();
|
||||
void sendNext();
|
||||
protected:
|
||||
std::string createPMT();
|
||||
void fillPacket(bool & first, const char * data, size_t dataLen, char & ContCounter);
|
||||
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;
|
||||
unsigned int vidTrack;
|
||||
unsigned int audTrack;
|
||||
};
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
#pragma once
|
||||
#include <mist/defines.h>
|
||||
#include <mist/http_parser.h>
|
||||
#include "output.h"
|
||||
|
|
|
@ -5,10 +5,7 @@
|
|||
#include <unistd.h>
|
||||
|
||||
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;
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,29 +1,17 @@
|
|||
#include "output_ts_base.h"
|
||||
#include "output_http.h"
|
||||
#include <mist/http_parser.h>
|
||||
#include <mist/ts_packet.h>
|
||||
#include <mist/mp4.h>
|
||||
#include <mist/mp4_generic.h>
|
||||
|
||||
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();
|
||||
void sendTS(const char * tsData, unsigned int len=188);
|
||||
protected:
|
||||
std::string createPMT();
|
||||
void fillPacket(bool & first, const char * data, size_t dataLen, char & ContCounter);
|
||||
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 unsigned int lastVid;
|
||||
long long unsigned int until;
|
||||
unsigned int vidTrack;
|
||||
|
|
|
@ -3,10 +3,7 @@
|
|||
#include <mist/defines.h>
|
||||
|
||||
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;
|
||||
|
@ -58,91 +55,7 @@ namespace Mist {
|
|||
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;
|
||||
void OutTS::sendTS(const char * tsData, unsigned int len){
|
||||
myConn.SendNow(tsData, len);
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,25 +1,12 @@
|
|||
#include "output.h"
|
||||
#include <mist/mp4_generic.h>
|
||||
#include <mist/ts_packet.h>
|
||||
#include <string>
|
||||
#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);
|
||||
};
|
||||
}
|
||||
|
||||
|
|
174
src/output/output_ts_base.cpp
Normal file
174
src/output/output_ts_base.cpp
Normal file
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
32
src/output/output_ts_base.h
Normal file
32
src/output/output_ts_base.h
Normal file
|
@ -0,0 +1,32 @@
|
|||
#include <mist/defines.h>
|
||||
#include "output.h"
|
||||
#include "output_http.h"
|
||||
#include <mist/mp4_generic.h>
|
||||
#include <mist/ts_packet.h>
|
||||
|
||||
#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<unsigned int, bool> first;
|
||||
std::map<unsigned int, int> 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;
|
||||
};
|
||||
}
|
Loading…
Add table
Reference in a new issue