Added MistOutHTTPTS, also minor cleanup in output.cpp
This commit is contained in:
parent
435633180c
commit
fc5e86d7c2
4 changed files with 212 additions and 2 deletions
6
Makefile
6
Makefile
|
@ -152,6 +152,12 @@ MistOutRaw: override CPPFLAGS += "-DOUTPUTTYPE=\"output_raw.h\""
|
||||||
MistOutRaw: src/output/mist_out.cpp src/output/output.cpp src/output/output_raw.cpp
|
MistOutRaw: src/output/mist_out.cpp src/output/output.cpp src/output/output_raw.cpp
|
||||||
$(CXX) $(LDFLAGS) $(CPPFLAGS) $^ $(LDLIBS) -o $@
|
$(CXX) $(LDFLAGS) $(CPPFLAGS) $^ $(LDLIBS) -o $@
|
||||||
|
|
||||||
|
outputs: MistOutHTTPTS
|
||||||
|
MistOutHTTPTS: override LDLIBS += $(THREADLIB)
|
||||||
|
MistOutHTTPTS: override CPPFLAGS += "-DOUTPUTTYPE=\"output_httpts.h\""
|
||||||
|
MistOutHTTPTS: src/output/mist_out_http.cpp src/output/output.cpp src/output/output_httpts.cpp
|
||||||
|
$(CXX) $(LDFLAGS) $(CPPFLAGS) $^ $(LDLIBS) -o $@
|
||||||
|
|
||||||
outputs: MistOutTS
|
outputs: MistOutTS
|
||||||
MistOutTS: override LDLIBS += $(THREADLIB)
|
MistOutTS: override LDLIBS += $(THREADLIB)
|
||||||
MistOutTS: override CPPFLAGS += "-DOUTPUTTYPE=\"output_ts.h\""
|
MistOutTS: override CPPFLAGS += "-DOUTPUTTYPE=\"output_ts.h\""
|
||||||
|
|
|
@ -68,7 +68,6 @@ namespace Mist {
|
||||||
if (streamIndex.mapped){
|
if (streamIndex.mapped){
|
||||||
DTSC::Packet tmpMeta(streamIndex.mapped, streamIndex.len, true);
|
DTSC::Packet tmpMeta(streamIndex.mapped, streamIndex.len, true);
|
||||||
if (tmpMeta.getVersion()){
|
if (tmpMeta.getVersion()){
|
||||||
/// \todo Make sure this doesn't go wrong when overwritten by MistInBuffer during parse
|
|
||||||
myMeta.reinit(tmpMeta);
|
myMeta.reinit(tmpMeta);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -232,7 +231,7 @@ namespace Mist {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
isInitialized = true;
|
isInitialized = true;
|
||||||
streamIndex.init(streamName,8 * 1024 * 1024);
|
streamIndex.init(streamName, 8 * 1024 * 1024);
|
||||||
if (!streamIndex.mapped){
|
if (!streamIndex.mapped){
|
||||||
DEBUG_MSG(DLVL_FAIL, "Could not connect to server for %s\n", streamName.c_str());
|
DEBUG_MSG(DLVL_FAIL, "Could not connect to server for %s\n", streamName.c_str());
|
||||||
onFail();
|
onFail();
|
||||||
|
|
168
src/output/output_httpts.cpp
Normal file
168
src/output/output_httpts.cpp
Normal file
|
@ -0,0 +1,168 @@
|
||||||
|
#include "output_httpts.h"
|
||||||
|
#include <mist/defines.h>
|
||||||
|
#include <mist/http_parser.h>
|
||||||
|
#include <mist/stream.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
namespace Mist {
|
||||||
|
OutHTTPTS::OutHTTPTS(Socket::Connection & conn) : Output(conn) {
|
||||||
|
haveAvcc = false;
|
||||||
|
myConn.setHost(config->getString("ip"));
|
||||||
|
myConn.setBlocking(true);
|
||||||
|
streamName = config->getString("streamname");
|
||||||
|
}
|
||||||
|
|
||||||
|
OutHTTPTS::~OutHTTPTS() {}
|
||||||
|
|
||||||
|
void OutHTTPTS::onFail(){
|
||||||
|
HTTP_S.Clean(); //make sure no parts of old requests are left in any buffers
|
||||||
|
HTTP_S.SetBody("Stream not found. Sorry, we tried.");
|
||||||
|
HTTP_S.SendResponse("404", "Stream not found", myConn);
|
||||||
|
Output::onFail();
|
||||||
|
}
|
||||||
|
|
||||||
|
void OutHTTPTS::init(Util::Config * cfg){
|
||||||
|
Output::init(cfg);
|
||||||
|
capa["name"] = "HTTPTS";
|
||||||
|
capa["desc"] = "Enables HTTP protocol MPEG2/TS pseudostreaming.";
|
||||||
|
capa["deps"] = "HTTP";
|
||||||
|
capa["url_rel"] = "/$.ts";
|
||||||
|
capa["url_match"] = "/$.ts";
|
||||||
|
capa["socket"] = "http_ts";
|
||||||
|
capa["codecs"][0u][0u].append("H264");
|
||||||
|
capa["codecs"][0u][1u].append("AAC");
|
||||||
|
capa["codecs"][0u][1u].append("MP3");
|
||||||
|
capa["methods"][0u]["handler"] = "http";
|
||||||
|
capa["methods"][0u]["type"] = "html5/video/mp2t";
|
||||||
|
capa["methods"][0u]["priority"] = 1ll;
|
||||||
|
cfg->addBasicConnectorOptions(capa);
|
||||||
|
config = cfg;
|
||||||
|
}
|
||||||
|
|
||||||
|
///this function generates the PMT packet
|
||||||
|
std::string OutHTTPTS::createPMT(){
|
||||||
|
TS::ProgramMappingTable PMT;
|
||||||
|
PMT.PID(4096);
|
||||||
|
PMT.setTableId(2);
|
||||||
|
PMT.setSectionLength(0xB017);
|
||||||
|
PMT.setProgramNumber(1);
|
||||||
|
PMT.setVersionNumber(0);
|
||||||
|
PMT.setCurrentNextIndicator(0);
|
||||||
|
PMT.setSectionNumber(0);
|
||||||
|
PMT.setLastSectionNumber(0);
|
||||||
|
PMT.setPCRPID(0x100 + (*(selectedTracks.begin())) - 1);
|
||||||
|
PMT.setProgramInfoLength(0);
|
||||||
|
short id = 0;
|
||||||
|
//for all selected tracks
|
||||||
|
for (std::set<long unsigned int>::iterator it = selectedTracks.begin(); it != selectedTracks.end(); it++){
|
||||||
|
if (myMeta.tracks[*it].codec == "H264"){
|
||||||
|
PMT.setStreamType(0x1B,id);
|
||||||
|
}else if (myMeta.tracks[*it].codec == "AAC"){
|
||||||
|
PMT.setStreamType(0x0F,id);
|
||||||
|
}else if (myMeta.tracks[*it].codec == "MP3"){
|
||||||
|
PMT.setStreamType(0x03,id);
|
||||||
|
}
|
||||||
|
PMT.setElementaryPID(0x100 + (*it) - 1, id);
|
||||||
|
PMT.setESInfoLength(0,id);
|
||||||
|
id++;
|
||||||
|
}
|
||||||
|
PMT.calcCRC();
|
||||||
|
return PMT.getStrBuf();
|
||||||
|
}
|
||||||
|
|
||||||
|
void OutHTTPTS::fillPacket(bool & first, const char * data, size_t dataLen, char & ContCounter){
|
||||||
|
if (!PackData.BytesFree()){
|
||||||
|
HTTP_S.Chunkify(PackData.ToString(), 188, myConn);
|
||||||
|
PacketNumber ++;
|
||||||
|
PackData.Clear();
|
||||||
|
if (PacketNumber % 42 == 0){
|
||||||
|
HTTP_S.Chunkify(TS::PAT, 188, myConn);
|
||||||
|
std::string PMT = createPMT();
|
||||||
|
HTTP_S.Chunkify(PMT, myConn);
|
||||||
|
PacketNumber += 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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);
|
||||||
|
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"){
|
||||||
|
bs = TS::Packet::getPESAudioLeadIn(7+dataLen, currentPacket.getTime() * 90);
|
||||||
|
fillPacket(first, bs.data(), bs.size(), AudioCounter);
|
||||||
|
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::onRequest(){
|
||||||
|
while (HTTP_R.Read(myConn)){
|
||||||
|
DEBUG_MSG(DLVL_MEDIUM, "Received request: %s", HTTP_R.getUrl().c_str());
|
||||||
|
initialize();
|
||||||
|
HTTP_S.Clean();
|
||||||
|
HTTP_S.SetHeader("Content-Type", "video/mp2t");
|
||||||
|
HTTP_S.StartResponse(HTTP_R, myConn);
|
||||||
|
PacketNumber = 0;
|
||||||
|
parseData = true;
|
||||||
|
wantRequest = false;
|
||||||
|
HTTP_R.Clean(); //clean for any possible next requests
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
37
src/output/output_httpts.h
Normal file
37
src/output/output_httpts.h
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
#include "output.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 Output {
|
||||||
|
public:
|
||||||
|
OutHTTPTS(Socket::Connection & conn);
|
||||||
|
~OutHTTPTS();
|
||||||
|
static void init(Util::Config * cfg);
|
||||||
|
void onRequest();
|
||||||
|
void onFail();
|
||||||
|
void sendNext();
|
||||||
|
protected:
|
||||||
|
HTTP::Parser HTTP_S;
|
||||||
|
HTTP::Parser HTTP_R;
|
||||||
|
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;
|
||||||
|
unsigned int audTrack;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef Mist::OutHTTPTS mistOut;
|
Loading…
Add table
Reference in a new issue