Added HLS input
This commit is contained in:
parent
30beda61ce
commit
a9c5334833
6 changed files with 2104 additions and 442 deletions
|
@ -339,6 +339,7 @@ macro(makeInput inputName format)
|
||||||
)
|
)
|
||||||
endmacro()
|
endmacro()
|
||||||
|
|
||||||
|
makeInput(HLS hls)
|
||||||
makeInput(DTSC dtsc)
|
makeInput(DTSC dtsc)
|
||||||
makeInput(DTSCCrypt dtsccrypt)
|
makeInput(DTSCCrypt dtsccrypt)
|
||||||
makeInput(MP3 mp3)
|
makeInput(MP3 mp3)
|
||||||
|
|
1105
lib/ts_stream.cpp
1105
lib/ts_stream.cpp
File diff suppressed because it is too large
Load diff
|
@ -17,6 +17,28 @@ namespace TS {
|
||||||
ID3 = 0x15
|
ID3 = 0x15
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class ADTSRemainder{
|
||||||
|
private:
|
||||||
|
char * data;
|
||||||
|
uint32_t max;
|
||||||
|
uint32_t now;
|
||||||
|
uint32_t len;
|
||||||
|
uint32_t bpos;
|
||||||
|
public:
|
||||||
|
void setRemainder(const aac::adts & p, const void * source, const uint32_t avail, const uint32_t bPos);
|
||||||
|
|
||||||
|
ADTSRemainder();
|
||||||
|
~ADTSRemainder();
|
||||||
|
uint32_t getLength();
|
||||||
|
uint32_t getBpos();
|
||||||
|
uint32_t getTodo();
|
||||||
|
char* getData();
|
||||||
|
|
||||||
|
void append(const char *p,uint32_t pLen);
|
||||||
|
bool isComplete();
|
||||||
|
void clear();
|
||||||
|
};
|
||||||
|
|
||||||
class Stream{
|
class Stream{
|
||||||
public:
|
public:
|
||||||
Stream(bool _threaded = false);
|
Stream(bool _threaded = false);
|
||||||
|
@ -26,25 +48,33 @@ namespace TS {
|
||||||
void parse(Packet & newPack, unsigned long long bytePos);
|
void parse(Packet & newPack, unsigned long long bytePos);
|
||||||
void parse(char * newPack, unsigned long long bytePos);
|
void parse(char * newPack, unsigned long long bytePos);
|
||||||
void parse(unsigned long tid);
|
void parse(unsigned long tid);
|
||||||
|
void parseNal(uint32_t tid, const char *pesPayload, const char * packetPtr, bool &isKeyFrame);
|
||||||
bool hasPacketOnEachTrack() const;
|
bool hasPacketOnEachTrack() const;
|
||||||
bool hasPacket(unsigned long tid) const;
|
bool hasPacket(unsigned long tid) const;
|
||||||
|
bool hasPacket() const;
|
||||||
void getPacket(unsigned long tid, DTSC::Packet & pack);
|
void getPacket(unsigned long tid, DTSC::Packet & pack);
|
||||||
void getEarliestPacket(DTSC::Packet & pack);
|
void getEarliestPacket(DTSC::Packet & pack);
|
||||||
void initializeMetadata(DTSC::Meta & meta, unsigned long tid = 0);
|
void initializeMetadata(DTSC::Meta & meta, unsigned long tid = 0, unsigned long mappingId = 0);
|
||||||
|
void partialClear();
|
||||||
void clear();
|
void clear();
|
||||||
|
void finish();
|
||||||
void eraseTrack(unsigned long tid);
|
void eraseTrack(unsigned long tid);
|
||||||
bool isDataTrack(unsigned long tid);
|
bool isDataTrack(unsigned long tid);
|
||||||
|
void parseBitstream(uint32_t tid, const char * pesPayload, uint32_t realPayloadSize,uint64_t timeStamp, int64_t timeOffset, uint64_t bPos);
|
||||||
std::set<unsigned long> getActiveTracks();
|
std::set<unsigned long> getActiveTracks();
|
||||||
private:
|
private:
|
||||||
unsigned long long lastPAT;
|
unsigned long long lastPAT;
|
||||||
ProgramAssociationTable associationTable;
|
ProgramAssociationTable associationTable;
|
||||||
|
std::map<unsigned long, ADTSRemainder> remainders;
|
||||||
|
|
||||||
|
bool firstPacketFound;
|
||||||
std::map<unsigned long, unsigned long long> lastPMT;
|
std::map<unsigned long, unsigned long long> lastPMT;
|
||||||
std::map<unsigned long, ProgramMappingTable> mappingTable;
|
std::map<unsigned long, ProgramMappingTable> mappingTable;
|
||||||
|
|
||||||
std::map<unsigned long, std::deque<Packet> > pesStreams;
|
std::map<unsigned long, std::deque<Packet> > pesStreams;
|
||||||
std::map<unsigned long, std::deque<unsigned long long> > pesPositions;
|
std::map<unsigned long, std::deque<unsigned long long> > pesPositions;
|
||||||
std::map<unsigned long, std::deque<DTSC::Packet> > outPackets;
|
std::map<unsigned long, std::deque<DTSC::Packet> > outPackets;
|
||||||
|
std::map<unsigned long, DTSC::Packet> buildPacket;
|
||||||
std::map<unsigned long, unsigned long> pidToCodec;
|
std::map<unsigned long, unsigned long> pidToCodec;
|
||||||
std::map<unsigned long, aac::adts > adtsInfo;
|
std::map<unsigned long, aac::adts > adtsInfo;
|
||||||
std::map<unsigned long, std::string > spsInfo;
|
std::map<unsigned long, std::string > spsInfo;
|
||||||
|
@ -52,13 +82,13 @@ namespace TS {
|
||||||
std::map<unsigned long, h265::initData > hevcInfo;
|
std::map<unsigned long, h265::initData > hevcInfo;
|
||||||
std::map<unsigned long, std::string> metaInit;
|
std::map<unsigned long, std::string> metaInit;
|
||||||
std::map<unsigned long, std::string> descriptors;
|
std::map<unsigned long, std::string> descriptors;
|
||||||
|
std::map<unsigned long, std::string> partialBuffer;
|
||||||
mutable IPC::semaphore globalSem;
|
mutable IPC::semaphore globalSem;
|
||||||
|
|
||||||
bool threaded;
|
bool threaded;
|
||||||
|
|
||||||
std::set<unsigned long> pmtTracks;
|
std::set<unsigned long> pmtTracks;
|
||||||
|
|
||||||
void parsePES(unsigned long tid);
|
void parsePES(unsigned long tid, bool finished = false);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
1216
src/input/input_hls.cpp
Normal file
1216
src/input/input_hls.cpp
Normal file
File diff suppressed because it is too large
Load diff
148
src/input/input_hls.h
Normal file
148
src/input/input_hls.h
Normal file
|
@ -0,0 +1,148 @@
|
||||||
|
#pragma once
|
||||||
|
#include "input.h"
|
||||||
|
#include <mist/dtsc.h>
|
||||||
|
#include <mist/nal.h>
|
||||||
|
#include <mist/ts_packet.h>
|
||||||
|
#include <mist/ts_stream.h>
|
||||||
|
#include <fstream>
|
||||||
|
#include <string>
|
||||||
|
#include <set>
|
||||||
|
#include <vector>
|
||||||
|
//#include <stdint.h>
|
||||||
|
|
||||||
|
#define BUFFERTIME 10
|
||||||
|
|
||||||
|
namespace Mist {
|
||||||
|
|
||||||
|
enum PlaylistType { VOD, LIVE, EVENT };
|
||||||
|
|
||||||
|
|
||||||
|
struct playListEntries
|
||||||
|
{
|
||||||
|
std::string filename;
|
||||||
|
uint64_t bytePos;
|
||||||
|
float duration;
|
||||||
|
unsigned int timestamp;
|
||||||
|
unsigned int wait;
|
||||||
|
};
|
||||||
|
|
||||||
|
class Playlist {
|
||||||
|
public:
|
||||||
|
Playlist();
|
||||||
|
std::string codecs;
|
||||||
|
std::string video;
|
||||||
|
std::string audio;
|
||||||
|
std::string uri;
|
||||||
|
std::string uri_root;
|
||||||
|
|
||||||
|
std::string source;
|
||||||
|
const char *packetPtr;
|
||||||
|
|
||||||
|
int id;
|
||||||
|
bool playlistEnd;
|
||||||
|
int noChangeCount;
|
||||||
|
int version;
|
||||||
|
int targetDuration;
|
||||||
|
uint64_t media_sequence;
|
||||||
|
int lastFileIndex;
|
||||||
|
int waitTime;
|
||||||
|
bool vodLive;
|
||||||
|
PlaylistType playlistType;
|
||||||
|
std::deque<playListEntries> entries;
|
||||||
|
int entryCount;
|
||||||
|
int programId;
|
||||||
|
int bandwidth;
|
||||||
|
unsigned int lastTimestamp;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct entryBuffer
|
||||||
|
{
|
||||||
|
int timestamp;
|
||||||
|
playListEntries entry;
|
||||||
|
int playlistIndex;
|
||||||
|
};
|
||||||
|
|
||||||
|
class inputHLS : public Input {
|
||||||
|
public:
|
||||||
|
inputHLS(Util::Config * cfg);
|
||||||
|
~inputHLS();
|
||||||
|
bool needsLock();
|
||||||
|
bool openStreamSource();
|
||||||
|
protected:
|
||||||
|
//Private Functions
|
||||||
|
|
||||||
|
unsigned int startTime;
|
||||||
|
PlaylistType playlistType;
|
||||||
|
int version;
|
||||||
|
int targetDuration;
|
||||||
|
int media_sequence;
|
||||||
|
bool endPlaylist;
|
||||||
|
int currentPlaylist;
|
||||||
|
|
||||||
|
bool initDone;
|
||||||
|
std::string init_source;
|
||||||
|
|
||||||
|
//std::vector<playListEntries> entries;
|
||||||
|
std::vector<Playlist> playlists;
|
||||||
|
//std::vector<int> pidMapping;
|
||||||
|
std::map<int,int> pidMapping;
|
||||||
|
std::map<int,int> pidMappingR;
|
||||||
|
|
||||||
|
std::string playlistFile;
|
||||||
|
std::string playlistRootPath;
|
||||||
|
std::vector<int> reloadNext;
|
||||||
|
|
||||||
|
|
||||||
|
bool liveStream;
|
||||||
|
int currentIndex;
|
||||||
|
std::string currentFile;
|
||||||
|
std::ifstream in;
|
||||||
|
bool isUrl;
|
||||||
|
|
||||||
|
TS::Stream tsStream;///<Used for parsing the incoming ts stream
|
||||||
|
bool pushing;
|
||||||
|
Socket::UDPConnection udpCon;
|
||||||
|
std::string udpDataBuffer;
|
||||||
|
Socket::Connection conn;
|
||||||
|
TS::Packet tsBuf;
|
||||||
|
|
||||||
|
int getFirstPlaylistToReload();
|
||||||
|
|
||||||
|
int firstSegment();
|
||||||
|
bool getNextSegment();
|
||||||
|
void readPMT();
|
||||||
|
bool setup();
|
||||||
|
bool preSetup();
|
||||||
|
bool readHeader();
|
||||||
|
void getNext(bool smart = true);
|
||||||
|
void seek(int seekTime);
|
||||||
|
void trackSelect(std::string trackSpec);
|
||||||
|
FILE * inFile;
|
||||||
|
FILE * tsFile;
|
||||||
|
bool openURL(std::string urlString, Playlist &p);
|
||||||
|
|
||||||
|
|
||||||
|
void printContent();
|
||||||
|
void printBuffer();
|
||||||
|
bool readIndex();
|
||||||
|
bool initPlaylist(std::string uri);
|
||||||
|
bool readPlaylist(std::string uri);
|
||||||
|
bool reloadPlaylist(Playlist &p);
|
||||||
|
bool readNextFile();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void parseStreamHeader();
|
||||||
|
void addEntryToPlaylist(Playlist &p, std::string filename, float duration, uint64_t &totalBytes);
|
||||||
|
|
||||||
|
int getMappedTrackId(int id);
|
||||||
|
int getMappedTrackPlaylist(int id);
|
||||||
|
int getOriginalTrackId(int playlistId, int id);
|
||||||
|
int getEntryId(int playlistId, uint64_t bytePos);
|
||||||
|
int cleanLine(std::string &s);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef Mist::inputHLS mistIn;
|
||||||
|
|
|
@ -130,7 +130,6 @@ namespace Mist {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
///Live Setup of TS Input
|
///Live Setup of TS Input
|
||||||
bool inputTS::setup() {
|
bool inputTS::setup() {
|
||||||
const std::string & inpt = config->getString("input");
|
const std::string & inpt = config->getString("input");
|
||||||
|
@ -205,7 +204,17 @@ namespace Mist {
|
||||||
}
|
}
|
||||||
myMeta.update(headerPack);
|
myMeta.update(headerPack);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DTSC::Packet headerPack;
|
||||||
|
tsStream.getEarliestPacket(headerPack);
|
||||||
|
|
||||||
|
while (headerPack) {
|
||||||
|
if (!myMeta.tracks.count(headerPack.getTrackId()) || !myMeta.tracks[headerPack.getTrackId()].codec.size()) {
|
||||||
|
tsStream.initializeMetadata(myMeta, headerPack.getTrackId());
|
||||||
|
}
|
||||||
|
myMeta.update(headerPack);
|
||||||
|
tsStream.getEarliestPacket(headerPack);
|
||||||
}
|
}
|
||||||
|
|
||||||
fseek(inFile, 0, SEEK_SET);
|
fseek(inFile, 0, SEEK_SET);
|
||||||
|
@ -230,9 +239,6 @@ namespace Mist {
|
||||||
hasPacket = (selectedTracks.size() == 1 ? tsStream.hasPacket(*selectedTracks.begin()) : tsStream.hasPacketOnEachTrack());
|
hasPacket = (selectedTracks.size() == 1 ? tsStream.hasPacket(*selectedTracks.begin()) : tsStream.hasPacketOnEachTrack());
|
||||||
}
|
}
|
||||||
if (!hasPacket) {
|
if (!hasPacket) {
|
||||||
if (!feof(inFile)) {
|
|
||||||
getNext();
|
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (selectedTracks.size() == 1) {
|
if (selectedTracks.size() == 1) {
|
||||||
|
@ -264,14 +270,12 @@ namespace Mist {
|
||||||
}
|
}
|
||||||
|
|
||||||
//Clear leaves the PMT in place
|
//Clear leaves the PMT in place
|
||||||
tsStream.clear();
|
tsStream.partialClear();
|
||||||
|
|
||||||
|
|
||||||
//Restore original file position
|
//Restore original file position
|
||||||
if (fseek(inFile, bpos, SEEK_SET)) {
|
if (fseek(inFile, bpos, SEEK_SET)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
///Seeks to a specific time
|
///Seeks to a specific time
|
||||||
|
|
Loading…
Add table
Reference in a new issue