Shared Memory updates

This commit is contained in:
Thulinma 2014-04-04 02:08:05 +02:00
parent 330b9f871d
commit 0e5d838a20
24 changed files with 2420 additions and 612 deletions

View file

@ -32,6 +32,8 @@
bool Util::Config::is_active = false;
std::string Util::Config::libver = PACKAGE_VERSION;
Util::Config::Config(){}
/// Creates a new configuration manager.
Util::Config::Config(std::string cmd, std::string version){
vals.null();

View file

@ -24,6 +24,7 @@ namespace Util {
static std::string libver; ///< Version number of the library as a string.
static bool is_active; ///< Set to true by activate(), set to false by the signal handler.
//functions
Config();
Config(std::string cmd, std::string version);
void addOption(std::string optname, JSON::Value option);
void printHelp(std::ostream & output);

View file

@ -540,7 +540,7 @@ DTSC::File & DTSC::File::operator =(const File & rhs){
F = 0;
}
endPos = rhs.endPos;
strbuffer = rhs.strbuffer;
myPack = rhs.myPack;
metaStorage = rhs.metaStorage;
metadata = metaStorage;
currtime = rhs.currtime;
@ -581,6 +581,32 @@ DTSC::File::File(std::string filename, bool create){
fseek(F, 0, SEEK_END);
endPos = ftell(F);
bool sepHeader = false;
if (!create){
fseek(F, 0, SEEK_SET);
if (fread(buffer, 4, 1, F) != 1){
DEBUG_MSG(DLVL_ERROR, "Can't read file contents of %s", filename.c_str());
fclose(F);
F = 0;
return;
}
if (memcmp(buffer, DTSC::Magic_Header, 4) != 0){
if (memcmp(buffer, DTSC::Magic_Packet2, 4) != 0){
File Fhead(filename + ".dtsh");
if (Fhead){
metadata = Fhead.metadata;
sepHeader = true;
}else{
DEBUG_MSG(DLVL_ERROR, "%s is not a valid DTSC file", filename.c_str());
fclose(F);
F = 0;
return;
}
}else{
metadata.moreheader = -1;
}
}
}
//we now know the first 4 bytes are DTSC::Magic_Header and we have a valid file
fseek(F, 4, SEEK_SET);
if (fread(buffer, 4, 1, F) != 1){
@ -591,8 +617,20 @@ DTSC::File::File(std::string filename, bool create){
uint32_t * ubuffer = (uint32_t *)buffer;
headerSize = ntohl(ubuffer[0]);
}
readHeader(0);
fseek(F, 8 + headerSize, SEEK_SET);
if (metadata.moreheader != -1){
if (!sepHeader){
readHeader(0);
fseek(F, 8 + headerSize, SEEK_SET);
}else{
fseek(F, 0, SEEK_SET);
}
}else{
fseek(F, 0, SEEK_SET);
File Fhead(filename + ".dtsh");
if (Fhead){
metadata = Fhead.metadata;
}
}
currframe = 0;
}
@ -655,33 +693,29 @@ void DTSC::File::readHeader(int pos){
}else{
DEBUG_MSG(DLVL_ERROR, "Could not read header @ %d", pos);
}
strbuffer = "";
metadata = readOnlyMeta();
return;
}
if (memcmp(buffer, DTSC::Magic_Header, 4) != 0){
DEBUG_MSG(DLVL_ERROR, "Invalid header - %.4s != %.4s @ %i", buffer, DTSC::Magic_Header, pos);
strbuffer = "";
metadata = readOnlyMeta();
return;
}
if (fread(buffer, 4, 1, F) != 1){
DEBUG_MSG(DLVL_ERROR, "Could not read header size @ %i", pos);
strbuffer = "";
metadata = readOnlyMeta();
return;
}
uint32_t * ubuffer = (uint32_t *)buffer;
long packSize = ntohl(ubuffer[0]);
strbuffer.resize(packSize);
long packSize = ntohl(((uint32_t*)buffer)[0]);
std::string strBuffer;
strBuffer.resize(packSize);
if (packSize){
if (fread((void*)strbuffer.c_str(), packSize, 1, F) != 1){
if (fread((void*)strBuffer.c_str(), packSize, 1, F) != 1){
DEBUG_MSG(DLVL_ERROR, "Could not read header packet @ %i", pos);
strbuffer = "";
metadata = readOnlyMeta();
return;
}
JSON::fromDTMI(strbuffer, metaStorage);
JSON::fromDTMI(strBuffer, metaStorage);
metadata = readOnlyMeta(metaStorage);//make readonly
}
//if there is another header, read it and replace metadata with that one.
@ -713,15 +747,12 @@ bool DTSC::File::reachedEOF(){
void DTSC::File::seekNext(){
if ( !currentPositions.size()){
DEBUG_MSG(DLVL_HIGH, "No seek positions set - returning empty packet.");
strbuffer = "";
jsonbuffer.null();
myPack.null();
return;
}
DEBUG_MSG(DLVL_HIGH, "Seeking to %uT%lli @ %llu", currentPositions.begin()->trackID, currentPositions.begin()->seekTime, currentPositions.begin()->bytePos);
fseek(F,currentPositions.begin()->bytePos, SEEK_SET);
if ( reachedEOF()){
strbuffer = "";
jsonbuffer.null();
myPack.null();
return;
}
clearerr(F);
@ -737,12 +768,11 @@ void DTSC::File::seekNext(){
}else{
DEBUG_MSG(DLVL_ERROR, "Could not seek to next @ %i", (int)lastreadpos);
}
strbuffer = "";
jsonbuffer.null();
myPack.null();
return;
}
if (memcmp(buffer, DTSC::Magic_Header, 4) == 0){
seek_time(jsonbuffer["time"].asInt() + 1, jsonbuffer["trackid"].asInt(), true);
seek_time(myPack.getTime() + 1, myPack.getTrackId(), true);
return seekNext();
}
long long unsigned int version = 0;
@ -754,32 +784,28 @@ void DTSC::File::seekNext(){
}
if (version == 0){
DEBUG_MSG(DLVL_ERROR, "Invalid packet header @ %#x - %.4s != %.4s @ %d", (unsigned int)lastreadpos, buffer, DTSC::Magic_Packet2, (int)lastreadpos);
strbuffer = "";
jsonbuffer.null();
myPack.null();
return;
}
if (fread(buffer, 4, 1, F) != 1){
DEBUG_MSG(DLVL_ERROR, "Could not read packet size @ %d", (int)lastreadpos);
strbuffer = "";
jsonbuffer.null();
myPack.null();
return;
}
uint32_t * ubuffer = (uint32_t *)buffer;
long packSize = ntohl(ubuffer[0]);
strbuffer.resize(packSize);
if (fread((void*)strbuffer.c_str(), packSize, 1, F) != 1){
long packSize = ntohl(((uint32_t*)buffer)[0]);
std::string strBuffer = "DTP2";
if (version == 1){
strBuffer = "DTPD";
}
strBuffer.append(buffer, 4);
strBuffer.resize(packSize + 8);
if (fread((void*)(strBuffer.c_str() + 8), packSize, 1, F) != 1){
DEBUG_MSG(DLVL_ERROR, "Could not read packet @ %d", (int)lastreadpos);
strbuffer = "";
jsonbuffer.null();
myPack.null();
return;
}
if (version == 2){
JSON::fromDTMI2(strbuffer, jsonbuffer);
}else{
if (version == 1){
JSON::fromDTMI(strbuffer, jsonbuffer);
}
}
const char * tmp = strBuffer.data();
myPack.reInit(tmp, strBuffer.size());
if ( metadata.merged){
int tempLoc = getBytePos();
char newHeader[20];
@ -795,9 +821,9 @@ void DTSC::File::seekNext(){
tmpPos.seekTime += ntohl(((int*)newHeader)[4]);
insert = true;
}else{
long tid = jsonbuffer["trackid"].asInt();
long tid = myPack.getTrackId();
for (unsigned int i = 0; i != metadata.tracks[tid].keyLen; i++){
if (metadata.tracks[tid].keys[i].getTime() > jsonbuffer["time"].asInt()){
if (metadata.tracks[tid].keys[i].getTime() > myPack.getTime()){
tmpPos.seekTime = metadata.tracks[tid].keys[i].getTime();
tmpPos.bytePos = metadata.tracks[tid].keys[i].getBpos();
tmpPos.trackID = tid;
@ -819,8 +845,9 @@ void DTSC::File::seekNext(){
if (insert){
currentPositions.insert(tmpPos);
}else{
seek_time(jsonbuffer["time"].asInt() + 1, jsonbuffer["trackid"].asInt(), true);
seek_time(myPack.getTime() + 1, myPack.getTrackId(), true);
}
seek_bpos(tempLoc);
}
}
@ -833,31 +860,31 @@ void DTSC::File::parseNext(){
}else{
DEBUG_MSG(DLVL_ERROR, "Could not read header @ %d", (int)lastreadpos);
}
strbuffer = "";
jsonbuffer.null();
myPack.null();
return;
}
if (memcmp(buffer, DTSC::Magic_Header, 4) == 0){
if (lastreadpos != 0){
readHeader(lastreadpos);
jsonbuffer = metadata.toJSON();
std::string tmp = metaStorage.toNetPacked();
myPack.reInit(tmp.data(), tmp.size());
DEBUG_MSG(DLVL_DEVEL,"Does this ever even happen?");
}else{
if (fread(buffer, 4, 1, F) != 1){
DEBUG_MSG(DLVL_ERROR, "Could not read header size @ %d", (int)lastreadpos);
strbuffer = "";
jsonbuffer.null();
myPack.null();
return;
}
uint32_t * ubuffer = (uint32_t *)buffer;
long packSize = ntohl(ubuffer[0]);
strbuffer.resize(packSize);
if (fread((void*)strbuffer.c_str(), packSize, 1, F) != 1){
long packSize = ntohl(((uint32_t*)buffer)[0]);
std::string strBuffer = "DTSC";
strBuffer.append(buffer, 4);
strBuffer.resize(packSize + 8);
if (fread((void*)(strBuffer.c_str() + 8), packSize, 1, F) != 1){
DEBUG_MSG(DLVL_ERROR, "Could not read header @ %d", (int)lastreadpos);
strbuffer = "";
jsonbuffer.null();
myPack.null();
return;
}
JSON::fromDTMI(strbuffer, jsonbuffer);
myPack.reInit(strBuffer.data(), strBuffer.size());
}
return;
}
@ -870,30 +897,27 @@ void DTSC::File::parseNext(){
}
if (version == 0){
DEBUG_MSG(DLVL_ERROR, "Invalid packet header @ %#x - %.4s != %.4s @ %d", (unsigned int)lastreadpos, buffer, DTSC::Magic_Packet2, (int)lastreadpos);
strbuffer = "";
jsonbuffer.null();
myPack.null();
return;
}
if (fread(buffer, 4, 1, F) != 1){
DEBUG_MSG(DLVL_ERROR, "Could not read packet size @ %d", (int)lastreadpos);
strbuffer = "";
jsonbuffer.null();
myPack.null();
return;
}
uint32_t * ubuffer = (uint32_t *)buffer;
long packSize = ntohl(ubuffer[0]);
strbuffer.resize(packSize);
if (fread((void*)strbuffer.c_str(), packSize, 1, F) != 1){
long packSize = ntohl(((uint32_t*)buffer)[0]);
std::string strBuffer = "DTP2";
if (version == 1){
strBuffer = "DTPD";
}
strBuffer.append(buffer, 4);
strBuffer.resize(packSize + 8);
if (fread((void*)(strBuffer.c_str() + 8), packSize, 1, F) != 1){
DEBUG_MSG(DLVL_ERROR, "Could not read packet @ %d", (int)lastreadpos);
strbuffer = "";
jsonbuffer.null();
myPack.null();
return;
}
if (version == 2){
JSON::fromDTMI2(strbuffer, jsonbuffer);
}else{
JSON::fromDTMI(strbuffer, jsonbuffer);
}
myPack.reInit(strBuffer.data(), strBuffer.size());
}
/// Returns the byte positon of the start of the last packet that was read.
@ -902,32 +926,29 @@ long long int DTSC::File::getLastReadPos(){
}
/// Returns the internal buffer of the last read packet in raw binary format.
std::string & DTSC::File::getPacket(){
return strbuffer;
}
/// Returns the internal buffer of the last read packet in JSON format.
JSON::Value & DTSC::File::getJSON(){
return jsonbuffer;
DTSC::Packet & DTSC::File::getPacket(){
return myPack;
}
bool DTSC::File::seek_time(unsigned int ms, int trackNo, bool forceSeek){
seekPos tmpPos;
tmpPos.trackID = trackNo;
if (!forceSeek && jsonbuffer && ms > jsonbuffer["time"].asInt() && trackNo >= jsonbuffer["trackid"].asInt()){
tmpPos.seekTime = jsonbuffer["time"].asInt();
if (!forceSeek && myPack && ms > myPack.getTime() && trackNo >= myPack.getTrackId()){
tmpPos.seekTime = myPack.getTime();
tmpPos.bytePos = getBytePos();
}else{
tmpPos.seekTime = 0;
tmpPos.bytePos = 0;
}
for (unsigned int i = 0; i < metadata.tracks[trackNo].keyLen; i++){
if (metadata.tracks[trackNo].keys[i].getTime() > ms){
DTSC::readOnlyTrack & trackRef = metadata.tracks[trackNo];
for (unsigned int i = 0; i < trackRef.keyLen; i++){
long keyTime = trackRef.keys[i].getTime();
if (keyTime > ms){
break;
}
if ((long long unsigned int)metadata.tracks[trackNo].keys[i].getTime() > tmpPos.seekTime){
tmpPos.seekTime = metadata.tracks[trackNo].keys[i].getTime();
tmpPos.bytePos = metadata.tracks[trackNo].keys[i].getBpos();
if ((long long unsigned int)keyTime > tmpPos.seekTime){
tmpPos.seekTime = keyTime;
tmpPos.bytePos = trackRef.keys[i].getBpos();
}
}
if (reachedEOF()){
@ -1007,14 +1028,14 @@ void DTSC::File::writePacket(JSON::Value & newPacket){
}
bool DTSC::File::atKeyframe(){
if (getJSON().isMember("keyframe")){
if (myPack.getFlag("keyframe")){
return true;
}
long long int bTime = jsonbuffer["time"].asInt();
int trackid = jsonbuffer["trackid"].asInt();
for (unsigned int i = 0; i < metadata.tracks[trackid].keyLen; i++){
if (metadata.tracks[trackid].keys[i].getTime() >= bTime){
return (metadata.tracks[trackid].keys[i].getTime() == bTime);
long long int bTime = myPack.getTime();
DTSC::readOnlyTrack & trackRef = metadata.tracks[myPack.getTrackId()];
for (unsigned int i = 0; i < trackRef.keyLen; i++){
if (trackRef.keys[i].getTime() >= bTime){
return (trackRef.keys[i].getTime() == bTime);
}
}
return false;

View file

@ -16,8 +16,8 @@
namespace DTSC {
bool isFixed(JSON::Value & metadata);
/// This enum holds all possible datatypes for DTSC packets.
enum datatype{
///\brief This enum holds all possible datatypes for DTSC packets.
enum datatype {
AUDIO, ///< Stream Audio data
VIDEO, ///< Stream Video data
META, ///< Stream Metadata
@ -30,50 +30,98 @@ namespace DTSC {
extern char Magic_Packet[]; ///< The magic bytes for a DTSC packet
extern char Magic_Packet2[]; ///< The magic bytes for a DTSC packet version 2
/// A simple structure used for ordering byte seek positions.
///\brief A simple structure used for ordering byte seek positions.
struct seekPos {
bool operator < (const seekPos& rhs) const {
if (seekTime < rhs.seekTime){
///\brief Less-than comparison for seekPos structures.
///\param rhs The seekPos to compare with.
///\return Whether this object is smaller than rhs.
bool operator < (const seekPos & rhs) const {
if (seekTime < rhs.seekTime) {
return true;
}else{
if (seekTime == rhs.seekTime){
if (trackID < rhs.trackID){
} else {
if (seekTime == rhs.seekTime) {
if (trackID < rhs.trackID) {
return true;
}
}
}
return false;
}
long long unsigned int seekTime;
long long unsigned int bytePos;
unsigned int trackID;
long long unsigned int seekTime;///< Stores the timestamp of the DTSC packet referenced by this structure.
long long unsigned int bytePos;///< Stores the byteposition of the DTSC packet referenced by this structure.
unsigned int trackID;///< Stores the track the DTSC packet referenced by this structure is associated with.
};
enum packType{
DTSC_INVALID,
DTSC_HEAD,
DTSC_V1,
DTSC_V2
};
/// DTSC::Packets can currently be three types:
/// DTSC_HEAD packets are the "DTSC" header string, followed by 4 bytes len and packed content.
/// DTSC_V1 packets are "DTPD", followed by 4 bytes len and packed content.
/// DTSC_V2 packets are "DTP2", followed by 4 bytes len, 4 bytes trackID, 8 bytes time, and packed content.
/// The len is always without the first 8 bytes counted.
class Packet {
public:
Packet();
Packet(const Packet & rhs);
Packet(const char * data_, unsigned int len, bool noCopy = false);
~Packet();
void null();
void operator = (const Packet & rhs);
operator bool() const;
packType getVersion();
void reInit(const char * data_, unsigned int len, bool noCopy = false);
void getString(const char * identifier, char *& result, int & len);
void getString(const char * identifier, std::string & result);
void getInt(const char * identifier, int & result);
int getInt(const char * identifier);
void getFlag(const char * identifier, bool & result);
bool getFlag(const char * identifier);
bool hasMember(const char * identifier);
long long unsigned int getTime();
long int getTrackId();
char * getData();
int getDataLen();
JSON::Value toJSON();
protected:
bool master;
packType version;
char * findIdentifier(const char * identifier);
void resize(unsigned int size);
char * data;
unsigned int bufferLen;
unsigned int dataLen;
};
/// A simple structure used for ordering byte seek positions.
struct livePos {
livePos(){
livePos() {
seekTime = 0;
trackID = 0;
}
livePos(const livePos & rhs){
livePos(const livePos & rhs) {
seekTime = rhs.seekTime;
trackID = rhs.trackID;
}
void operator = (const livePos& rhs) {
void operator = (const livePos & rhs) {
seekTime = rhs.seekTime;
trackID = rhs.trackID;
}
bool operator == (const livePos& rhs) {
bool operator == (const livePos & rhs) {
return seekTime == rhs.seekTime && trackID == rhs.trackID;
}
bool operator != (const livePos& rhs) {
bool operator != (const livePos & rhs) {
return seekTime != rhs.seekTime || trackID != rhs.trackID;
}
bool operator < (const livePos& rhs) const {
if (seekTime < rhs.seekTime){
bool operator < (const livePos & rhs) const {
if (seekTime < rhs.seekTime) {
return true;
}else{
if (seekTime > rhs.seekTime){
} else {
if (seekTime > rhs.seekTime) {
return false;
}
}
@ -85,7 +133,7 @@ namespace DTSC {
/// A part from the DTSC::Stream ringbuffer.
/// Holds information about a buffer that will stay consistent
class Ring{
class Ring {
public:
Ring(livePos v);
livePos b;
@ -96,7 +144,9 @@ namespace DTSC {
volatile int playCount;
};
class Part{
///\brief Basic class for storage of data associated with single DTSC packets, a.k.a. parts.
class Part {
public:
long getSize();
void setSize(long newSize);
@ -104,12 +154,21 @@ namespace DTSC {
void setDuration(short newDuration);
long getOffset();
void setOffset(long newOffset);
char* getData();
char * getData();
void toPrettyString(std::stringstream & str, int indent = 0);
private:
///\brief Data storage for this packet.
///
/// - 3 bytes: MSB storage of the payload size of this packet in bytes.
/// - 2 bytes: MSB storage of the duration of this packet in milliseconds.
/// - 4 bytes: MSB storage of the presentation time offset of this packet in milliseconds.
char data[9];
};
class Key{
///\brief Basic class for storage of data associated with keyframes.
///
/// When deleting this object, make sure to remove all DTSC::Part associated with it, if any. If you fail doing this, it *will* cause data corruption.
class Key {
public:
long long unsigned int getBpos();
void setBpos(long long unsigned int newBpos);
@ -121,12 +180,21 @@ namespace DTSC {
void setParts(short newParts);
long getTime();
void setTime(long newTime);
char* getData();
char * getData();
void toPrettyString(std::stringstream & str, int indent = 0);
private:
///\brief Data storage for this packet.
///
/// - 5 bytes: MSB storage of the position of the first packet of this keyframe within the file.
/// - 3 bytes: MSB storage of the duration of this keyframe.
/// - 2 bytes: MSB storage of the number of this keyframe.
/// - 2 bytes: MSB storage of the amount of parts in this keyframe.
/// - 4 bytes: MSB storage of the timestamp associated with this keyframe's first packet.
char data[16];
};
class Fragment{
///\brief Basic class for storage of data associated with fragments.
class Fragment {
public:
long getDuration();
void setDuration(long newDuration);
@ -136,26 +204,28 @@ namespace DTSC {
void setNumber(short newNumber);
long getSize();
void setSize(long newSize);
char* getData();
char * getData();
void toPrettyString(std::stringstream & str, int indent = 0);
private:
char data[11];
};
class readOnlyTrack{
class readOnlyTrack {
public:
readOnlyTrack();
readOnlyTrack(JSON::Value & trackRef);
int getSendLen();
void send(Socket::Connection & conn);
void writeTo(char *& p);
std::string getIdentifier();
std::string getWritableIdentifier();
JSON::Value toJSON();
long long unsigned int fragLen;
Fragment* fragments;
Fragment * fragments;
long long unsigned int keyLen;
Key* keys;
Key * keys;
long long unsigned int partLen;
Part* parts;
Part * parts;
int trackID;
int firstms;
int lastms;
@ -175,6 +245,7 @@ namespace DTSC {
//vorbis and theora only
std::string idHeader;
std::string commentHeader;
void toPrettyString(std::stringstream & str, int indent = 0, int verbosity = 0);
};
class Track : public readOnlyTrack {
@ -182,32 +253,42 @@ namespace DTSC {
Track();
Track(const readOnlyTrack & rhs);
Track(JSON::Value & trackRef);
inline operator bool() const {return parts.size();}
inline operator bool() const {
return parts.size();
}
void update(DTSC::Packet & pack);
void update(JSON::Value & pack);
int getSendLen();
void send(Socket::Connection & conn);
void writeTo(char *& p);
JSON::Value toJSON();
std::deque<Fragment> fragments;
std::deque<Key> keys;
std::deque<Part> parts;
Key & getKey(unsigned int keyNum);
void reset();
void toPrettyString(std::stringstream & str, int indent = 0, int verbosity = 0);
};
class readOnlyMeta {
public:
readOnlyMeta();
readOnlyMeta(JSON::Value & meta);
inline operator bool() const {return vod || live;}
std::map<int,readOnlyTrack> tracks;
inline operator bool() const {
return vod || live;
}
std::map<int, readOnlyTrack> tracks;
bool vod;
bool live;
bool merged;
long long int moreheader;
long long int bufferWindow;
unsigned int getSendLen();
void send(Socket::Connection & conn);
void writeTo(char * p);
JSON::Value toJSON();
bool isFixed();
void toPrettyString(std::stringstream & str, int indent = 0, int verbosity = 0);
};
class Meta : public readOnlyMeta {
@ -215,16 +296,20 @@ namespace DTSC {
Meta();
Meta(const readOnlyMeta & meta);
Meta(JSON::Value & meta);
std::map<int,Track> tracks;
std::map<int, Track> tracks;
void update(DTSC::Packet & pack);
void update(JSON::Value & pack);
unsigned int getSendLen();
void send(Socket::Connection & conn);
void writeTo(char * p);
JSON::Value toJSON();
void reset();
bool isFixed();
void toPrettyString(std::stringstream & str, int indent = 0, int verbosity = 0);
};
/// A simple wrapper class that will open a file and allow easy reading/writing of DTSC data from/to it.
class File{
class File {
public:
File();
File(const File & rhs);
@ -241,8 +326,7 @@ namespace DTSC {
bool reachedEOF();
void seekNext();
void parseNext();
std::string & getPacket();
JSON::Value & getJSON();
DTSC::Packet & getPacket();
bool seek_time(unsigned int ms);
bool seek_time(unsigned int ms, int trackNo, bool forceSeek = false);
bool seek_bpos(int bpos);
@ -254,11 +338,10 @@ namespace DTSC {
private:
long int endPos;
void readHeader(int pos);
std::string strbuffer;
JSON::Value jsonbuffer;
DTSC::Packet myPack;
JSON::Value metaStorage;
readOnlyMeta metadata;
std::map<int,std::string> trackMapping;
std::map<int, std::string> trackMapping;
long long int currtime;
long long int lastreadpos;
int currframe;
@ -274,7 +357,7 @@ namespace DTSC {
/// Holds temporary data for a DTSC stream and provides functions to utilize it.
/// Optionally also acts as a ring buffer of a certain requested size.
/// If ring buffering mode is enabled, it will automatically grow in size to always contain at least one keyframe.
class Stream{
class Stream {
public:
Stream();
virtual ~Stream();
@ -302,17 +385,18 @@ namespace DTSC {
void endStream();
void waitForMeta(Socket::Connection & sourceSocket);
void waitForPause(Socket::Connection & sourceSocket);
protected:
protected:
void cutOneBuffer();
void resetStream();
std::map<livePos,JSON::Value> buffers;
std::map<int,std::set<livePos> > keyframes;
std::map<livePos, JSON::Value> buffers;
std::map<int, std::set<livePos> > keyframes;
virtual void addPacket(JSON::Value & newPack);
virtual void addMeta(JSON::Value & newMeta);
datatype datapointertype;
unsigned int buffercount;
unsigned int buffertime;
std::map<int,std::string> trackMapping;
std::map<int, std::string> trackMapping;
virtual void deletionCallback(livePos deleting);
};
}

File diff suppressed because it is too large Load diff

View file

@ -366,132 +366,111 @@ FLV::Tag & FLV::Tag::operator=(const FLV::Tag& O){
/// FLV loader function from DTSC.
/// Takes the DTSC data and makes it into FLV.
bool FLV::Tag::DTSCLoader(DTSC::Stream & S){
std::string tmp = S.getPacket().toNetPacked();
DTSC::Packet tmpPack(tmp.data(), tmp.size());
return DTSCLoader(tmpPack, S.metadata.tracks[S.getPacket()["trackid"].asInt()]);
}
bool FLV::Tag::DTSCLoader(DTSC::Packet & packData, DTSC::Track & track){
std::string meta_str;
DTSC::Track & track = S.metadata.tracks[S.getPacket()["trackid"].asInt()];
switch (S.lastType()){
case DTSC::VIDEO:
len = S.lastData().length() + 16;
if (track.codec == "H264"){
len += 4;
}
break;
case DTSC::AUDIO:
len = S.lastData().length() + 16;
if (track.codec == "AAC"){
len += 1;
}
break;
case DTSC::META:{
AMF::Object amfdata("root", AMF::AMF0_DDV_CONTAINER);
amfdata.addContent(AMF::Object("", "onMetaData"));
amfdata.addContent(AMF::Object("", AMF::AMF0_ECMA_ARRAY));
for (JSON::ObjIter it = S.getPacket()["data"].ObjBegin(); it != S.getPacket()["data"].ObjEnd(); it++){
if (it->second.asInt()){
amfdata.getContentP(1)->addContent(AMF::Object(it->first, it->second.asInt(), AMF::AMF0_NUMBER));
}else{
amfdata.getContentP(1)->addContent(AMF::Object(it->first, it->second.asString(), AMF::AMF0_STRING));
}
}
meta_str = amfdata.Pack();
len = meta_str.length() + 15;
break;
len = 0;
if (track.type == "video"){
char * tmpData = 0;
packData.getString("data", tmpData, len);
len += 16;
if (track.codec == "H264"){
len += 4;
}
default: //ignore all other types (there are currently no other types...)
return false;
break;
}
if (len > 0){
if ( !checkBufferSize()){
return false;
}
switch (S.lastType()){
case DTSC::VIDEO:
if ((unsigned int)len == S.lastData().length() + 16){
memcpy(data + 12, S.lastData().c_str(), S.lastData().length());
}else{
memcpy(data + 16, S.lastData().c_str(), S.lastData().length());
if (S.getPacket().isMember("nalu")){
data[12] = 1;
}else{
data[12] = 2;
}
offset(S.getPacket()["offset"].asInt());
}
data[11] = 0;
if (track.codec == "H264"){
data[11] += 7;
}
if (track.codec == "H263"){
data[11] += 2;
}
if (S.getPacket().isMember("keyframe")){
data[11] += 0x10;
}
if (S.getPacket().isMember("interframe")){
data[11] += 0x20;
}
if (S.getPacket().isMember("disposableframe")){
data[11] += 0x30;
}
break;
case DTSC::AUDIO: {
if ((unsigned int)len == S.lastData().length() + 16){
memcpy(data + 12, S.lastData().c_str(), S.lastData().length());
}else{
memcpy(data + 13, S.lastData().c_str(), S.lastData().length());
data[12] = 1; //raw AAC data, not sequence header
}
data[11] = 0;
if (track.codec == "AAC"){
data[11] += 0xA0;
}
if (track.codec == "MP3"){
data[11] += 0x20;
}
unsigned int datarate = track.rate;
if (datarate >= 44100){
data[11] += 0x0C;
}else if (datarate >= 22050){
data[11] += 0x08;
}else if (datarate >= 11025){
data[11] += 0x04;
}
if (track.size == 16){
data[11] += 0x02;
}
if (track.channels > 1){
data[11] += 0x01;
}
break;
if (track.codec == "H264"){
memcpy(data + 16, tmpData, len - 20);
if (packData.getFlag("nalu")){
data[12] = 1;
}else{
data[12] = 2;
}
case DTSC::META:
memcpy(data + 11, meta_str.c_str(), meta_str.length());
break;
default:
break;
if (packData.getInt("offset") < 0){
offset(0);
}else{
offset(packData.getInt("offset"));
}
}else{
memcpy(data + 12, tmpData, len - 16);
}
data[11] = 0;
if (track.codec == "H264"){
data[11] += 7;
}
if (track.codec == "H263"){
data[11] += 2;
}
if (packData.getFlag("keyframe")){
data[11] += 0x10;
}
if (packData.getFlag("interframe")){
data[11] += 0x20;
}
if (packData.getFlag("disposableframe")){
data[11] += 0x30;
}
}
setLen();
switch (S.lastType()){
case DTSC::VIDEO:
data[0] = 0x09;
break;
case DTSC::AUDIO:
data[0] = 0x08;
break;
case DTSC::META:
data[0] = 0x12;
break;
default:
break;
if (track.type == "audio"){
char * tmpData = 0;
packData.getString("data", tmpData, len);
len += 16;
if (track.codec == "AAC"){
len ++;
}
if ( !checkBufferSize()){
return false;
}
if (track.codec == "AAC"){
memcpy(data + 13, tmpData, len - 17);
data[12] = 1; //raw AAC data, not sequence header
}else{
memcpy(data + 12, tmpData, len - 16);
}
data[11] = 0;
if (track.codec == "AAC"){
data[11] += 0xA0;
}
if (track.codec == "MP3"){
data[11] += 0x20;
}
unsigned int datarate = track.rate;
if (datarate >= 44100){
data[11] += 0x0C;
}else if (datarate >= 22050){
data[11] += 0x08;
}else if (datarate >= 11025){
data[11] += 0x04;
}
if (track.size == 16){
data[11] += 0x02;
}
if (track.channels > 1){
data[11] += 0x01;
}
}
if (!len){
return false;
}
setLen();
if (track.type == "video"){data[0] = 0x09;}
if (track.type == "audio"){data[0] = 0x08;}
if (track.type == "meta"){data[0] = 0x12;}
data[1] = ((len - 15) >> 16) & 0xFF;
data[2] = ((len - 15) >> 8) & 0xFF;
data[3] = (len - 15) & 0xFF;
data[8] = 0;
data[9] = 0;
data[10] = 0;
tagTime(S.getPacket()["time"].asInt());
tagTime(packData.getTime());
if (packData.getInt("offset")){
tagTime(packData.getTime() + packData.getInt("offset"));
}
return true;
}
@ -586,6 +565,86 @@ bool FLV::Tag::DTSCAudioInit(DTSC::Track & audio){
return true;
}
bool FLV::Tag::DTSCMetaInit(DTSC::Meta & M, std::set<long unsigned int> & selTracks){
AMF::Object amfdata("root", AMF::AMF0_DDV_CONTAINER);
amfdata.addContent(AMF::Object("", "onMetaData"));
amfdata.addContent(AMF::Object("", AMF::AMF0_ECMA_ARRAY));
AMF::Object trinfo = AMF::Object("trackinfo", AMF::AMF0_STRICT_ARRAY);
int i = 0;
int mediaLen = 0;
for (std::set<long unsigned int>::iterator it = selTracks.begin(); it != selTracks.end(); it++){
if (M.tracks[*it].lastms - M.tracks[*it].firstms > mediaLen){
mediaLen = M.tracks[*it].lastms - M.tracks[*it].firstms;
}
if (M.tracks[*it].type == "video"){
trinfo.addContent(AMF::Object("", AMF::AMF0_OBJECT));
trinfo.getContentP(i)->addContent(AMF::Object("length", ((double)M.tracks[*it].lastms / 1000) * ((double)M.tracks[*it].fpks / 1000.0), AMF::AMF0_NUMBER));
trinfo.getContentP(i)->addContent(AMF::Object("timescale", ((double)M.tracks[*it].fpks / 1000.0), AMF::AMF0_NUMBER));
trinfo.getContentP(i)->addContent(AMF::Object("sampledescription", AMF::AMF0_STRICT_ARRAY));
amfdata.getContentP(1)->addContent(AMF::Object("hasVideo", 1, AMF::AMF0_BOOL));
if (M.tracks[*it].codec == "H264"){
amfdata.getContentP(1)->addContent(AMF::Object("videocodecid", (std::string)"avc1"));
trinfo.getContentP(i)->getContentP(2)->addContent(AMF::Object("sampletype", (std::string)"avc1"));
}
if (M.tracks[*it].codec == "VP6"){
amfdata.getContentP(1)->addContent(AMF::Object("videocodecid", 4, AMF::AMF0_NUMBER));
trinfo.getContentP(i)->getContentP(2)->addContent(AMF::Object("sampletype", (std::string)"vp6"));
}
if (M.tracks[*it].codec == "H263"){
amfdata.getContentP(1)->addContent(AMF::Object("videocodecid", 2, AMF::AMF0_NUMBER));
trinfo.getContentP(i)->getContentP(2)->addContent(AMF::Object("sampletype", (std::string)"h263"));
}
amfdata.getContentP(1)->addContent(AMF::Object("width", M.tracks[*it].width, AMF::AMF0_NUMBER));
amfdata.getContentP(1)->addContent(AMF::Object("height", M.tracks[*it].height, AMF::AMF0_NUMBER));
amfdata.getContentP(1)->addContent(AMF::Object("videoframerate", (double)M.tracks[*it].fpks / 1000.0, AMF::AMF0_NUMBER));
amfdata.getContentP(1)->addContent(AMF::Object("videodatarate", (double)M.tracks[*it].bps * 128.0, AMF::AMF0_NUMBER));
++i;
}
if (M.tracks[*it].type == "audio"){
trinfo.addContent(AMF::Object("", AMF::AMF0_OBJECT));
trinfo.getContentP(i)->addContent(AMF::Object("length", ((double)M.tracks[*it].lastms) * ((double)M.tracks[*it].rate), AMF::AMF0_NUMBER));
trinfo.getContentP(i)->addContent(AMF::Object("timescale", M.tracks[*it].rate, AMF::AMF0_NUMBER));
trinfo.getContentP(i)->addContent(AMF::Object("sampledescription", AMF::AMF0_STRICT_ARRAY));
amfdata.getContentP(1)->addContent(AMF::Object("hasAudio", 1, AMF::AMF0_BOOL));
amfdata.getContentP(1)->addContent(AMF::Object("audiodelay", 0, AMF::AMF0_NUMBER));
if (M.tracks[*it].codec == "AAC"){
amfdata.getContentP(1)->addContent(AMF::Object("audiocodecid", (std::string)"mp4a"));
trinfo.getContentP(i)->getContentP(2)->addContent(AMF::Object("sampletype", (std::string)"mp4a"));
}
if (M.tracks[*it].codec == "MP3"){
amfdata.getContentP(1)->addContent(AMF::Object("audiocodecid", (std::string)"mp3"));
trinfo.getContentP(i)->getContentP(2)->addContent(AMF::Object("sampletype", (std::string)"mp3"));
}
amfdata.getContentP(1)->addContent(AMF::Object("audiochannels", M.tracks[*it].channels, AMF::AMF0_NUMBER));
amfdata.getContentP(1)->addContent(AMF::Object("audiosamplerate", M.tracks[*it].rate, AMF::AMF0_NUMBER));
amfdata.getContentP(1)->addContent(AMF::Object("audiosamplesize", M.tracks[*it].size, AMF::AMF0_NUMBER));
amfdata.getContentP(1)->addContent(AMF::Object("audiodatarate", (double)M.tracks[*it].bps * 128.0, AMF::AMF0_NUMBER));
++i;
}
}
if (M.vod){
amfdata.getContentP(1)->addContent(AMF::Object("duration", mediaLen/1000, AMF::AMF0_NUMBER));
}
amfdata.getContentP(1)->addContent(trinfo);
std::string tmp = amfdata.Pack();
len = tmp.length() + 15;
if (len <= 0 || !checkBufferSize()){
return false;
}
memcpy(data + 11, tmp.data(), len - 15);
setLen();
data[0] = 0x12;
data[1] = ((len - 15) >> 16) & 0xFF;
data[2] = ((len - 15) >> 8) & 0xFF;
data[3] = (len - 15) & 0xFF;
data[8] = 0;
data[9] = 0;
data[10] = 0;
tagTime(0);
return true;
}
/// FLV metadata loader function from DTSC.
/// Takes the DTSC metadata and makes it into FLV.
/// Assumes metadata is available - so check before calling!
@ -691,7 +750,7 @@ bool FLV::Tag::DTSCMetaInit(DTSC::Stream & S, DTSC::Track & videoRef, DTSC::Trac
if (len <= 0 || !checkBufferSize()){
return false;
}
memcpy(data + 11, tmp.c_str(), len - 15);
memcpy(data + 11, tmp.data(), len - 15);
setLen();
data[0] = 0x12;
data[1] = ((len - 15) >> 16) & 0xFF;

View file

@ -47,8 +47,10 @@ namespace FLV {
//loader functions
bool ChunkLoader(const RTMPStream::Chunk& O);
bool DTSCLoader(DTSC::Stream & S);
bool DTSCLoader(DTSC::Packet & packData, DTSC::Track & track);
bool DTSCVideoInit(DTSC::Track & video);
bool DTSCAudioInit(DTSC::Track & audio);
bool DTSCMetaInit(DTSC::Meta & M, std::set<long unsigned int> & selTracks);
bool DTSCMetaInit(DTSC::Stream & S, DTSC::Track & videoRef, DTSC::Track & audioRef);
JSON::Value toJSON(DTSC::Meta & metadata);
bool MemLoader(char * D, unsigned int S, unsigned int & P);

View file

@ -143,7 +143,9 @@ JSON::Value::Value(std::istream & fromstream){
null();
bool reading_object = false;
bool reading_array = false;
while (fromstream.good()){
bool negative = false;
bool stop = false;
while (!stop && fromstream.good()){
int c = fromstream.peek();
switch (c){
case '{':
@ -167,12 +169,16 @@ JSON::Value::Value(std::istream & fromstream){
if ( !reading_object){
myType = STRING;
strVal = read_string(c, fromstream);
return;
stop = true;
}else{
std::string tmpstr = read_string(c, fromstream);
( *this)[tmpstr] = JSON::Value(fromstream);
}
break;
case '-':
c = fromstream.get();
negative = true;
break;
case '0':
case '1':
case '2':
@ -189,7 +195,10 @@ JSON::Value::Value(std::istream & fromstream){
intVal += c - '0';
break;
case ',':
if ( !reading_object && !reading_array) return;
if ( !reading_object && !reading_array){
stop = true;
break;
}
c = fromstream.get();
if (reading_array){
append(JSON::Value(fromstream));
@ -199,33 +208,33 @@ JSON::Value::Value(std::istream & fromstream){
if (reading_object){
c = fromstream.get();
}
return;
stop = true;
break;
case ']':
if (reading_array){
c = fromstream.get();
}
return;
stop = true;
break;
case 't':
case 'T':
skipToEnd(fromstream);
myType = BOOL;
intVal = 1;
return;
stop = true;
break;
case 'f':
case 'F':
skipToEnd(fromstream);
myType = BOOL;
intVal = 0;
return;
stop = true;
break;
case 'n':
case 'N':
skipToEnd(fromstream);
myType = EMPTY;
return;
stop = true;
break;
default:
c = fromstream.get(); //ignore this character
@ -233,6 +242,9 @@ JSON::Value::Value(std::istream & fromstream){
break;
}
}
if (negative){
intVal *= -1;
}
}
/// Sets this JSON::Value to the given string.
@ -1119,10 +1131,10 @@ JSON::Value JSON::fromDTMI2(std::string & data){
void JSON::fromDTMI2(const unsigned char * data, unsigned int len, unsigned int &i, JSON::Value & ret){
if (len < 13){return;}
long long int tmpTrackID = ntohl(((int*)data)[0]);
long long int tmpTime = ntohl(((int*)data)[1]);
long long int tmpTrackID = ntohl(((int*)(data+i))[0]);
long long int tmpTime = ntohl(((int*)(data+i))[1]);
tmpTime <<= 32;
tmpTime += ntohl(((int*)data)[2]);
tmpTime += ntohl(((int*)(data+i))[2]);
i += 12;
fromDTMI(data, len, i, ret);
ret["time"] = tmpTime;

View file

@ -58,9 +58,10 @@ namespace OGG{
if (newData.size()<27){
return false;
}
/*if (getMagicNumber() != 0x4f676753){
if (newData.substr(0, 4) != "OggS"){
DEBUG_MSG(DLVL_FAIL, "Invalid Ogg page encountered - cannot continue");
return false;
}*/
}
dataSum = 0;
if (!checkDataSize(27)){
return false;
@ -81,20 +82,72 @@ namespace OGG{
}
if (newData.size() < 27 + getPageSegments() + dataSum){//check input size
dataSum = 0;
return false;
}
if(!checkDataSize(27 + getPageSegments()+dataSum)){
dataSum = 0;
return false;
}
memcpy(data + 27 + getPageSegments(), newData.c_str() + 27 + getPageSegments(), dataSum);
newData.erase(0, getPageSize());
return true;
}
long unsigned int Page::getMagicNumber(){
return ntohl(((long unsigned int*)(data))[0]);
bool Page::read(FILE * inFile){
segmentTableDeque.clear();
int oriPos = ftell(inFile);
dataSum = 0;
if (!checkDataSize(27)){
DEBUG_MSG(DLVL_WARN,"Unable to read a page: memory allocation");
return false;
}
if (!fread(data, 27, 1, inFile)){
DEBUG_MSG(DLVL_WARN,"Unable to read a page: fread");
fseek(inFile, oriPos, SEEK_SET);
return false;
}
if(!checkDataSize(27 + getPageSegments())){
DEBUG_MSG(DLVL_WARN,"Unable to read a page: memory allocation1");
return false;
}
if (!fread(data + 27, getPageSegments(), 1, inFile)){
DEBUG_MSG(DLVL_WARN,"Unable to read a page: fread1");
fseek(inFile, oriPos, SEEK_SET);
return false;
}
for (unsigned int i = 0; i < getPageSegments(); i++){
dataSum += data[27 + i];
}
if (!checkDataSize(27 + getPageSegments() + dataSum)){
DEBUG_MSG(DLVL_WARN,"Unable to read a page: memory allocation2");
dataSum = 0;
return false;
}
if ( !fread(data + 27 + getPageSegments(), dataSum, 1, inFile)){
DEBUG_MSG(DLVL_WARN,"Unable to read a page: fread2");
fseek(inFile, oriPos, SEEK_SET);
dataSum = 0;
return false;
}
return true;
}
bool Page::getSegment(unsigned int index, char * ret, unsigned int & len){
if (index > segmentTableDeque.size()){
ret = NULL;
len = 0;
return false;
}
ret = getFullPayload();
for (int i = 0; i < index; i++){
ret += segmentTableDeque[i];
}
len = segmentTableDeque[index];
return true;
}
void Page::setMagicNumber(){
if(checkDataSize(4)){
memcpy(data, "OggS", 4);
@ -208,34 +261,26 @@ namespace OGG{
DEBUG_MSG(DLVL_ERROR, "Segment too big, create a continue page");
}
/// \todo MAKE FIX HERE
bool Page::setSegmentTable(std::vector<unsigned int> layout){
dataSum=0;
for (unsigned int i = 0; i < layout.size(); i++){
dataSum += layout[i];
}
unsigned int place = 0;
char table[255];
char table[256];
for (unsigned int i = 0; i < layout.size(); i++){
while (layout[i]>=255){
if (place > 255){
STerrMSG();
return false;
}
table[place] = 255;
layout[i] -= 255;
place++;
}
if (place > 255){
int amount = (layout[i]/255) + 1;
if (i == layout.size() - 1 && place + amount > (255 + (layout[i] % 255 == 0))){
STerrMSG();
return false;
}
if (layout[i] >= 0){//fix somewhere here
table[place] = layout[i];
if (place<255){//last segment does not need a closing 0
place++;
}
}
memset(table + place, 255, amount - 1);
table[place + amount - 1] = layout[i] % 255;
place += amount;
}
//Don't send element 256, even if it was filled.
if (place > 255){
place = 255;
}
setPageSegments(place);
setSegmentTable(table,place);
@ -260,92 +305,42 @@ namespace OGG{
return data + 27 + getPageSegments();
}
bool Page::typeBOS(){
if (getHeaderType() & 0x02){
return true;
}
return false;
}
bool Page::typeEOS(){
if (getHeaderType() & 0x04){
return true;
}
return false;
}
bool Page::typeContinue(){
if (getHeaderType() & 0x01){
return true;
}
return false;
}
bool Page::typeNone(){
if ((getHeaderType() & 0x07) == 0x00){
return true;
}
return false;
}
void Page::setInternalCodec(std::string myCodec){
codec = myCodec;
}
std::string Page::toPrettyString(size_t indent){
std::stringstream r;
r << std::string(indent,' ') << "OGG Page (" << getPageSize() << ")" << std::endl;
r << std::string(indent + 2,' ') << "Magic Number: " << std::string(data, 4) << std::endl;
r << std::string(indent,' ') << "Ogg page (" << getPageSize() << ")" << std::endl;
r << std::string(indent + 2,' ') << "Version: " << (int)getVersion() << std::endl;
r << std::string(indent + 2,' ') << "Headertype: " << std::hex << (int)getHeaderType() << std::dec;
if (typeContinue()){
r << " continued";
r << std::string(indent + 2,' ') << "Header type:";
if ( !getHeaderType()){
r << " Normal";
}else{
if (getHeaderType() & Continued){
r << " Continued";
}
if (getHeaderType() & BeginOfStream){
r << " BeginOfStream";
}
if (getHeaderType() & EndOfStream){
r << " EndOfStream";
}
}
if (typeBOS()){
r << " bos";
}
if (typeEOS()){
r << " eos";
}
r << std::endl;
r << std::string(indent + 2,' ') << "Granule Position: " << std::hex << getGranulePosition() << std::dec << std::endl;
r << std::string(indent + 2,' ') << "Bitstream Number: " << getBitstreamSerialNumber() << std::endl;
r << std::string(indent + 2,' ') << "Sequence Number: " << getPageSequenceNumber() << std::endl;
r << " (" << (int)getHeaderType() << ")" << std::endl;
r << std::string(indent + 2,' ') << "Granule position: " << getGranulePosition() << std::endl;
r << std::string(indent + 2,' ') << "Bitstream number: " << getBitstreamSerialNumber() << std::endl;
r << std::string(indent + 2,' ') << "Sequence number: " << getPageSequenceNumber() << std::endl;
r << std::string(indent + 2,' ') << "Checksum: " << std::hex << getCRCChecksum() << std::dec << std::endl;
//r << " Calced Checksum: " << std::hex << calcChecksum() << std::dec << std::endl;
//r << "CRC_checksum write: " << std::hex << getCRCChecksum()<< std::dec << std::endl;
r << std::string(indent + 2,' ') << "Segments: " << (int)getPageSegments() << std::endl;
r << std::string(indent + 2,' ') << "Payloadsize: " << dataSum << std::endl;
r << std::string(indent + 2,' ') << (int)getPageSegments() << " segments:" << std::endl;
r << std::string(indent + 3,' ');
std::deque<unsigned int> temp = getSegmentTableDeque();
for (std::deque<unsigned int>::iterator i = temp.begin(); i != temp.end(); i++){
r << std::string(indent + 4,' ') << (*i) << std::endl;
}
r << std::string(indent + 2,' ') << "Payloadsize: " << dataSum << std::endl;
if (codec == "theora"){
int offset = 0;
for (unsigned int i = 0; i < getSegmentTableDeque().size(); i++){
theora::header tmpHeader;
int len = getSegmentTableDeque()[i];
if (tmpHeader.read(getFullPayload()+offset,len)){
r << tmpHeader.toPrettyString(indent + 4);
}
theora::frame tmpFrame;
if (tmpFrame.read(getFullPayload()+offset,len)){
r << tmpFrame.toPrettyString(indent + 4);
}
offset += len;
}
}else if(codec == "vorbis"){
r << "Vorbis Data" << std::endl;
int offset = 0;
for (unsigned int i = 0; i < getSegmentTableDeque().size(); i++){
vorbis::header tmpHeader;
int len = getSegmentTableDeque()[i];
if (tmpHeader.read(getFullPayload()+offset,len)){
r << tmpHeader.toPrettyString(indent + 4);
}
offset += len;
}
r << " " << (*i);
}
r << std::endl;
return r.str();
}

View file

@ -1,4 +1,5 @@
#pragma once
#include <cstdlib>
#include <string>
#include <vector>
#include <deque>
@ -8,12 +9,20 @@
#include "json.h"
namespace OGG{
enum HeaderType{
Continued = 1,
BeginOfStream = 2,
EndOfStream = 4
};
class Page{
public:
Page();
~Page();
bool read(std::string & newData);
long unsigned int getMagicNumber();
bool read(FILE * inFile);
bool getSegment(unsigned int index, char * data, unsigned int & len);
void setMagicNumber();
char getVersion();
void setVersion(char newVal = 0);
@ -37,10 +46,6 @@ namespace OGG{
unsigned long int getPageSize();
char* getFullPayload();//returns all segments in the page
int getPayloadSize();
bool typeBOS();
bool typeEOS();
bool typeContinue();
bool typeNone();
std::string toPrettyString(size_t indent = 0);
void setInternalCodec(std::string myCodec);
long unsigned int calcChecksum();

View file

@ -648,7 +648,7 @@ bool Util::Procs::isActive(std::string name){
std::map<pid_t, std::string>::iterator it;
for (it = listcopy.begin(); it != listcopy.end(); it++){
if (( *it).second == name){
if (kill(( *it).first, 0) == 0){
if (childRunning(( *it).first)){
return true;
}else{
plist.erase(( *it).first);

608
lib/shared_memory.cpp Normal file
View file

@ -0,0 +1,608 @@
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <cerrno>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <unistd.h>
#include "defines.h"
#include "shared_memory.h"
namespace IPC {
/// Stores a long value of val in network order to the pointer p.
static void htobl(char * p, long val) {
p[0] = (val >> 24) & 0xFF;
p[1] = (val >> 16) & 0xFF;
p[2] = (val >> 8) & 0xFF;
p[3] = val & 0xFF;
}
static void htobll(char * p, long long val) {
p[0] = (val >> 56) & 0xFF;
p[1] = (val >> 48) & 0xFF;
p[2] = (val >> 40) & 0xFF;
p[3] = (val >> 32) & 0xFF;
p[4] = (val >> 24) & 0xFF;
p[5] = (val >> 16) & 0xFF;
p[6] = (val >> 8) & 0xFF;
p[7] = val & 0xFF;
}
static void btohl(char * p, long & val) {
val = ((long)p[0] << 24) | ((long)p[1] << 16) | ((long)p[2] << 8) | p[3];
}
static void btohll(char * p, long long & val) {
val = ((long long)p[0] << 56) | ((long long)p[1] << 48) | ((long long)p[2] << 40) | ((long long)p[3] << 32) | ((long long)p[4] << 24) | ((long long)p[5] << 16) | ((long long)p[6] << 8) | p[7];
}
sharedPage::sharedPage(std::string name_, unsigned int len_, bool master_, bool autoBackoff) : handle(0), name(name_), len(len_), master(master_), mapped(NULL) {
handle = 0;
name = name_;
len = len_;
master = master_;
mapped = 0;
init(name_,len_,master_, autoBackoff);
}
sharedPage::sharedPage(const sharedPage & rhs){
handle = 0;
name = "";
len = 0;
master = false;
mapped = 0;
init(rhs.name, rhs.len, rhs.master);
}
sharedPage::operator bool() const {
return mapped != 0;
}
void sharedPage::operator =(sharedPage & rhs){
init(rhs.name, rhs.len, rhs.master);
rhs.master = false;//Make sure the memory does not get unlinked
}
void sharedPage::init(std::string name_, unsigned int len_, bool master_, bool autoBackoff) {
if (mapped && len){
munmap(mapped,len);
}
if(master){
shm_unlink(name.c_str());
}
if (handle > 0){
close(handle);
}
handle = 0;
name = name_;
len = len_;
master = master_;
mapped = 0;
if (name.size()){
handle = shm_open(name.c_str(), ( master ? O_CREAT | O_EXCL : 0 )| O_RDWR, ACCESSPERMS);
if (handle == -1) {
if (master){
DEBUG_MSG(DLVL_HIGH, "Overwriting old page for %s", name.c_str());
handle = shm_open(name.c_str(), O_CREAT | O_RDWR, ACCESSPERMS);
}else{
int i = 0;
while (i < 10 && handle == -1 && autoBackoff){
i++;
Util::sleep(1000);
handle = shm_open(name.c_str(), O_RDWR, ACCESSPERMS);
}
}
}
if (handle == -1) {
perror(std::string("shm_open for page " + name + " failed").c_str());
return;
}
if (master){
if (ftruncate(handle, 0) < 0) {
perror(std::string("ftruncate to zero for page " + name + " failed").c_str());
return;
}
if (ftruncate(handle, len) < 0) {
perror(std::string("ftruncate to len for page " + name + " failed").c_str());
return;
}
}else{
struct stat buffStats;
int xRes = fstat(handle, &buffStats);
if (xRes < 0){
return;
}
len = buffStats.st_size;
}
mapped = (char*)mmap(0, len, PROT_READ | PROT_WRITE, MAP_SHARED, handle, 0);
if (mapped == MAP_FAILED){
mapped = 0;
return;
}
}
}
sharedPage::~sharedPage(){
if (mapped && len){
munmap(mapped,len);
}
if(master){
shm_unlink(name.c_str());
}
if (handle > 0){
close(handle);
}
}
sharedFile::sharedFile(std::string name_, unsigned int len_, bool master_, bool autoBackoff) : handle(0), name(name_), len(len_), master(master_), mapped(NULL) {
handle = 0;
name = name_;
len = len_;
master = master_;
mapped = 0;
init(name_,len_,master_, autoBackoff);
}
sharedFile::sharedFile(const sharedPage & rhs){
handle = 0;
name = "";
len = 0;
master = false;
mapped = 0;
init(rhs.name, rhs.len, rhs.master);
}
sharedFile::operator bool() const {
return mapped != 0;
}
void sharedFile::operator =(sharedFile & rhs){
init(rhs.name, rhs.len, rhs.master);
rhs.master = false;//Make sure the memory does not get unlinked
}
void sharedFile::init(std::string name_, unsigned int len_, bool master_, bool autoBackoff) {
if (mapped && len){
munmap(mapped,len);
}
if(master){
unlink(name.c_str());
}
if (handle > 0){
close(handle);
}
handle = 0;
name = name_;
len = len_;
master = master_;
mapped = 0;
if (name.size()){
/// \todo Use ACCESSPERMS instead of 0600?
handle = open(name.c_str(), ( master ? O_CREAT | O_TRUNC | O_EXCL : 0 )| O_RDWR, (mode_t)0600);
if (handle == -1) {
if (master){
DEBUG_MSG(DLVL_HIGH, "Overwriting old file for %s", name.c_str());
handle = open(name.c_str(), O_CREAT | O_TRUNC | O_RDWR, (mode_t)0600);
}else{
int i = 0;
while (i < 10 && handle == -1 && autoBackoff){
i++;
Util::sleep(1000);
handle = open(name.c_str(), O_RDWR, (mode_t)0600);
}
}
}
if (handle == -1) {
perror(std::string("open for file " + name + " failed").c_str());
return;
}
if (master){
if (ftruncate(handle, len) < 0) {
perror(std::string("ftruncate to len for file " + name + " failed").c_str());
return;
}
}else{
struct stat buffStats;
int xRes = fstat(handle, &buffStats);
if (xRes < 0){
return;
}
len = buffStats.st_size;
}
mapped = (char*)mmap(0, len, PROT_READ | PROT_WRITE, MAP_SHARED, handle, 0);
if (mapped == MAP_FAILED){
mapped = 0;
return;
}
}
}
sharedFile::~sharedFile(){
if (mapped && len){
munmap(mapped,len);
}
if(master){
unlink(name.c_str());
}
if (handle > 0){
close(handle);
}
}
statExchange::statExchange(char * _data) : data(_data) {}
void statExchange::now(long long int time) {
htobll(data, time);
}
long long int statExchange::now() {
long long int result;
btohll(data, result);
return result;
}
void statExchange::time(long time) {
htobl(data + 8, time);
}
long statExchange::time() {
long result;
btohl(data + 8, result);
return result;
}
void statExchange::lastSecond(long time) {
htobl(data + 12, time);
}
long statExchange::lastSecond() {
long result;
btohl(data + 12, result);
return result;
}
void statExchange::down(long long int bytes) {
htobll(data + 16, bytes);
}
long long int statExchange::down() {
long long int result;
btohll(data + 16, result);
return result;
}
void statExchange::up(long long int bytes) {
htobll(data + 24, bytes);
}
long long int statExchange::up() {
long long int result;
btohll(data + 24, result);
return result;
}
void statExchange::host(std::string name) {
memcpy(data + 32, name.c_str(), std::min((int)name.size(), 16));
}
std::string statExchange::host() {
return std::string(data + 32, std::min((int)strlen(data + 32), 16));
}
void statExchange::streamName(std::string name) {
memcpy(data + 48, name.c_str(), std::min((int)name.size(), 20));
}
std::string statExchange::streamName() {
return std::string(data + 48, std::min((int)strlen(data + 48), 20));
}
void statExchange::connector(std::string name) {
memcpy(data + 68, name.c_str(), std::min((int)name.size(), 20));
}
std::string statExchange::connector() {
return std::string(data + 68, std::min((int)strlen(data + 68), 20));
}
semGuard::semGuard(sem_t * semaphore) : mySemaphore(semaphore) {
sem_wait(mySemaphore);
}
semGuard::~semGuard() {
sem_post(mySemaphore);
}
sharedServer::sharedServer(){
mySemaphore = 0;
payLen = 0;
hasCounter = false;
amount = 0;
}
sharedServer::sharedServer(std::string name, int len, bool withCounter){
sharedServer();
init(name, len, withCounter);
}
void sharedServer::init(std::string name, int len, bool withCounter){
amount = 0;
if (mySemaphore != SEM_FAILED) {
sem_close(mySemaphore);
}
if (baseName != ""){
sem_unlink(std::string("/" + baseName).c_str());
}
myPages.clear();
baseName = name;
payLen = len;
hasCounter = withCounter;
mySemaphore = sem_open(std::string("/" + baseName).c_str(), O_CREAT | O_EXCL | O_RDWR, ACCESSPERMS, 1);
if (mySemaphore == SEM_FAILED) {
mySemaphore = sem_open(std::string("/" + baseName).c_str(), O_CREAT | O_RDWR, ACCESSPERMS, 1);
}
if (mySemaphore == SEM_FAILED) {
perror("Creating semaphore failed");
return;
}
newPage();
newPage();
newPage();
newPage();
newPage();
}
sharedServer::~sharedServer() {
if (mySemaphore != SEM_FAILED) {
sem_close(mySemaphore);
}
sem_unlink(std::string("/" + baseName).c_str());
}
sharedServer::operator bool() const {
return myPages.size();
}
void sharedServer::newPage() {
semGuard tmpGuard(mySemaphore);
sharedPage tmp(std::string(baseName + (char)(myPages.size() + (int)'A')), (4096 << myPages.size()), true);
myPages.insert(tmp);
tmp.master = false;
DEBUG_MSG(DLVL_WARN, "Added a new page: %s", tmp.name.c_str());
}
void sharedServer::deletePage() {
if (myPages.size() == 1) {
DEBUG_MSG(DLVL_WARN, "Can't remove last page for %s", baseName.c_str());
return;
}
semGuard tmpGuard(mySemaphore);
myPages.erase((*myPages.rbegin()));
}
bool sharedServer::isInUse(unsigned int id){
unsigned int i = 0;
for (std::set<sharedPage>::iterator it = myPages.begin(); it != myPages.end(); it++) {
//return if we reached the end
if (!it->mapped || !it->len){
return false;
}
//not on this page? skip to next.
if (it->len < (id - i)*payLen){
i += it->len / payLen;
continue;
}
if (hasCounter){
//counter? return true if it is non-zero.
return (it->mapped[(id - i)*payLen] != 0);
}else{
//no counter - check the entire size for being all zeroes.
for (unsigned int j = 0; j < payLen; ++j){
if (it->mapped[(id-i)*payLen+j]){
return true;
}
}
return false;
}
}
//only happens if we run out of pages
return false;
}
void sharedServer::parseEach(void (*callback)(char * data, size_t len, unsigned int id)) {
char * empty = 0;
if (!hasCounter) {
empty = (char *)malloc(payLen * sizeof(char));
memset(empty, 0, payLen);
}
unsigned int id = 0;
for (std::set<sharedPage>::iterator it = myPages.begin(); it != myPages.end(); it++) {
if (!it->mapped || !it->len){
DEBUG_MSG(DLVL_FAIL, "Something went terribly wrong?");
break;
}
unsigned int offset = 0;
while (offset + payLen + (hasCounter ? 1 : 0) <= it->len) {
if (hasCounter){
if (it->mapped[offset] != 0) {
int counter = it->mapped[offset];
//increase the count if needed
if (id >= amount){
amount = id+1;
DEBUG_MSG(DLVL_DEVEL, "Shared memory %s is now at count %u", baseName.c_str(), amount);
}
callback(it->mapped + offset + 1, payLen, id);
switch (counter) {
case 127:
DEBUG_MSG(DLVL_HIGH, "Client %u requested disconnect", id);
break;
case 126:
DEBUG_MSG(DLVL_HIGH, "Client %u timed out", id);
break;
case 255:
DEBUG_MSG(DLVL_HIGH, "Client %u disconnected on request", id);
break;
case 254:
DEBUG_MSG(DLVL_HIGH, "Client %u disconnect timed out", id);
break;
default:
break;
}
if (counter == 127 || counter == 126 || counter == 255 || counter == 254) {
memset(it->mapped + offset + 1, 0, payLen);
it->mapped[offset] = 0;
} else {
it->mapped[offset] ++;
}
}else{
//stop if we're past the amount counted and we're empty
if (id >= amount - 1){
//bring the counter down if this was the last element
if (id == amount - 1){
amount = id;
DEBUG_MSG(DLVL_DEVEL, "Shared memory %s is now at count %u", baseName.c_str(), amount);
}
//stop, we're guaranteed no more pages are full at this point
return;
}
}
}else{
if (memcmp(empty, it->mapped + offset, payLen)) {
//increase the count if needed
if (id >= amount){
amount = id+1;
DEBUG_MSG(DLVL_DEVEL, "Shared memory %s is now at count %u", baseName.c_str(), amount);
}
callback(it->mapped + offset, payLen, id);
}else{
//stop if we're past the amount counted and we're empty
if (id >= amount - 1){
//bring the counter down if this was the last element
if (id == amount - 1){
amount = id;
DEBUG_MSG(DLVL_DEVEL, "Shared memory %s is now at count %u", baseName.c_str(), amount);
}
//stop, we're guaranteed no more pages are full at this point
if (empty){
free(empty);
}
return;
}
}
}
offset += payLen + (hasCounter ? 1 : 0);
id ++;
}
}
if (empty){
free(empty);
}
}
sharedClient::sharedClient() {
hasCounter = 0;
payLen = 0;
offsetOnPage = 0;
}
sharedClient::sharedClient(const sharedClient & rhs ) {
baseName = rhs.baseName;
payLen = rhs.payLen;
hasCounter = rhs.hasCounter;
mySemaphore = sem_open(std::string("/" + baseName).c_str(), O_RDWR);
if (mySemaphore == SEM_FAILED) {
perror("Creating semaphore failed");
return;
}
semGuard tmpGuard(mySemaphore);
myPage.init(rhs.myPage.name,rhs.myPage.len,rhs.myPage.master);
offsetOnPage = rhs.offsetOnPage;
}
void sharedClient::operator =(const sharedClient & rhs ) {
baseName = rhs.baseName;
payLen = rhs.payLen;
hasCounter = rhs.hasCounter;
mySemaphore = sem_open(std::string("/" + baseName).c_str(), O_RDWR);
if (mySemaphore == SEM_FAILED) {
perror("Creating semaphore failed");
return;
}
semGuard tmpGuard(mySemaphore);
myPage.init(rhs.myPage.name,rhs.myPage.len,rhs.myPage.master);
offsetOnPage = rhs.offsetOnPage;
}
sharedClient::sharedClient(std::string name, int len, bool withCounter) : baseName(name), payLen(len), offsetOnPage(-1), hasCounter(withCounter) {
mySemaphore = sem_open(std::string("/" + baseName).c_str(), O_RDWR);
if (mySemaphore == SEM_FAILED) {
perror("Creating semaphore failed");
return;
}
semGuard tmpGuard(mySemaphore);
char * empty = 0;
if (!hasCounter) {
empty = (char *)malloc(payLen * sizeof(char));
if (!empty){
DEBUG_MSG(DLVL_FAIL, "Failed to allocate %u bytes for empty payload!", payLen);
return;
}
memset(empty, 0, payLen);
}
for (char i = 'A'; i <= 'Z'; i++) {
myPage.init(baseName + i, (4096 << (i - 'A')));
int offset = 0;
while (offset + payLen + (hasCounter ? 1 : 0) <= myPage.len) {
if ((hasCounter && myPage.mapped[offset] == 0) || (!hasCounter && !memcmp(myPage.mapped + offset, empty, payLen))) {
offsetOnPage = offset;
if (hasCounter) {
myPage.mapped[offset] = 1;
}
break;
}
offset += payLen + (hasCounter ? 1 : 0);
}
if (offsetOnPage != -1) {
break;
}
}
free(empty);
}
sharedClient::~sharedClient() {
if (hasCounter){
finish();
}
if (mySemaphore != SEM_FAILED) {
sem_close(mySemaphore);
}
}
void sharedClient::write(char * data, int len) {
if (hasCounter) {
keepAlive();
}
memcpy(myPage.mapped + offsetOnPage + (hasCounter ? 1 : 0), data, std::min(len, payLen));
}
void sharedClient::finish() {
if (!hasCounter) {
DEBUG_MSG(DLVL_WARN, "Trying to time-out an element without counters");
return;
}
if (myPage.mapped){
myPage.mapped[offsetOnPage] = 127;
}
}
void sharedClient::keepAlive() {
if (!hasCounter) {
DEBUG_MSG(DLVL_WARN, "Trying to keep-alive an element without counters");
return;
}
if (myPage.mapped[offsetOnPage] < 128){
myPage.mapped[offsetOnPage] = 1;
}else{
DEBUG_MSG(DLVL_WARN, "Trying to keep-alive an element that needs to timeout, ignoring");
}
}
char * sharedClient::getData() {
if (!myPage.mapped){return 0;}
return (myPage.mapped + offsetOnPage + (hasCounter ? 1 : 0));
}
}

116
lib/shared_memory.h Normal file
View file

@ -0,0 +1,116 @@
#pragma once
#include <string>
#include <set>
#include <semaphore.h>
#include "timing.h"
namespace IPC {
class statExchange {
public:
statExchange(char * _data);
void now(long long int time);
long long int now();
void time(long time);
long time();
void lastSecond(long time);
long lastSecond();
void down(long long int bytes);
long long int down();
void up(long long int bytes);
long long int up();
void host(std::string name);
std::string host();
void streamName(std::string name);
std::string streamName();
void connector(std::string name);
std::string connector();
private:
char * data;
};
class semGuard {
public:
semGuard(sem_t * semaphore);
~semGuard();
private:
sem_t * mySemaphore;
};
class sharedPage{
public:
sharedPage(std::string name_ = "", unsigned int len_ = 0, bool master_ = false, bool autoBackoff = true);
sharedPage(const sharedPage & rhs);
~sharedPage();
operator bool() const;
void init(std::string name_, unsigned int len_, bool master_ = false, bool autoBackoff = true);
void operator =(sharedPage & rhs);
bool operator < (const sharedPage & rhs) const {
return name < rhs.name;
}
int handle;
std::string name;
long long int len;
bool master;
char * mapped;
};
class sharedFile{
public:
sharedFile(std::string name_ = "", unsigned int len_ = 0, bool master_ = false, bool autoBackoff = true);
sharedFile(const sharedPage & rhs);
~sharedFile();
operator bool() const;
void init(std::string name_, unsigned int len_, bool master_ = false, bool autoBackoff = true);
void operator =(sharedFile & rhs);
bool operator < (const sharedFile & rhs) const {
return name < rhs.name;
}
int handle;
std::string name;
long long int len;
bool master;
char * mapped;
};
class sharedServer{
public:
sharedServer();
sharedServer(std::string name, int len, bool withCounter = false);
void init(std::string name, int len, bool withCounter = false);
~sharedServer();
void parseEach(void (*callback)(char * data, size_t len, unsigned int id));
operator bool() const;
unsigned int amount;
private:
bool isInUse(unsigned int id);
void newPage();
void deletePage();
std::string baseName;
unsigned int payLen;
std::set<sharedPage> myPages;
sem_t * mySemaphore;
bool hasCounter;
};
class sharedClient{
public:
sharedClient();
sharedClient(const sharedClient & rhs);
sharedClient(std::string name, int len, bool withCounter = false);
void operator = (const sharedClient & rhs);
~sharedClient();
void write(char * data, int len);
void finish();
void keepAlive();
char * getData();
private:
std::string baseName;
sharedPage myPage;
sem_t * mySemaphore;
int payLen;
int offsetOnPage;
bool hasCounter;
};
}

View file

@ -153,6 +153,11 @@ std::string & Socket::Buffer::get(){
}
}
/// Completely empties the buffer
void Socket::Buffer::clear(){
data.clear();
}
/// Create a new base socket. This is a basic constructor for converting any valid socket to a Socket::Connection.
/// \param sockNo Integer representing the socket to convert.
Socket::Connection::Connection(int sockNo){
@ -387,6 +392,11 @@ bool Socket::Connection::connected() const{
return (sock >= 0) || ((pipes[0] >= 0) && (pipes[1] >= 0));
}
/// Returns the time this socket has been connected.
unsigned int Socket::Connection::connTime(){
return conntime;
}
/// Returns total amount of bytes sent.
unsigned int Socket::Connection::dataUp(){
return up;
@ -647,6 +657,48 @@ Socket::Connection::operator bool() const{
return connected();
}
/// Returns true if the given address can be matched with the remote host.
/// Can no longer return true after any socket error have occurred.
bool Socket::Connection::isAddress(std::string addr){
struct addrinfo *result, *rp, hints;
memset( &hints, 0, sizeof(struct addrinfo));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_ADDRCONFIG | AI_V4MAPPED;
hints.ai_protocol = 0;
hints.ai_canonname = NULL;
hints.ai_addr = NULL;
hints.ai_next = NULL;
int s = getaddrinfo(addr.c_str(), 0, &hints, &result);
DEBUG_MSG(DLVL_DEVEL, "Meh: %s", addr.c_str());
if (s != 0){
return false;
}
char newaddr[INET_ADDRSTRLEN];
newaddr[0] = 0;
for (rp = result; rp != NULL; rp = rp->ai_next){
if (rp->ai_family == AF_INET && inet_ntop(rp->ai_family, &(((sockaddr_in*)rp->ai_addr)->sin_addr), newaddr, INET_ADDRSTRLEN)){
DEBUG_MSG(DLVL_DEVEL, "Comparing: '%s' to '%s'", remotehost.c_str(), newaddr);
if (remotehost == newaddr){
return true;
}
DEBUG_MSG(DLVL_DEVEL, "Comparing: '%s' to '::ffff:%s'", remotehost.c_str(), newaddr);
if (remotehost == std::string("::ffff:")+newaddr){
return true;
}
}
if (rp->ai_family == AF_INET6 && inet_ntop(rp->ai_family, &(((sockaddr_in6*)rp->ai_addr)->sin6_addr), newaddr, INET_ADDRSTRLEN)){
DEBUG_MSG(DLVL_DEVEL, "Comparing: '%s' to '%s'", remotehost.c_str(), newaddr);
if (remotehost == newaddr){
return true;
}
}
}
freeaddrinfo(result);
return false;
}
/// Create a new base Server. The socket is never connected, and a placeholder for later connections.
Socket::Server::Server(){
sock = -1;

View file

@ -39,6 +39,7 @@ namespace Socket {
bool available(unsigned int count);
std::string remove(unsigned int count);
std::string copy(unsigned int count);
void clear();
};
//Buffer
@ -76,6 +77,7 @@ namespace Socket {
int getSocket(); ///< Returns internal socket number.
std::string getError(); ///< Returns a string describing the last error that occured.
bool connected() const; ///< Returns the connected-state for this socket.
bool isAddress(std::string addr);
//buffered i/o methods
bool spool(); ///< Updates the downbuffer and upbuffer internal variables.
bool flush(); ///< Updates the downbuffer and upbuffer internal variables until upbuffer is empty.
@ -87,6 +89,7 @@ namespace Socket {
void SendNow(const char * data); ///< Will not buffer anything but always send right away. Blocks.
void SendNow(const char * data, size_t len); ///< Will not buffer anything but always send right away. Blocks.
//stats related methods
unsigned int connTime();///< Returns the time this socket has been connected.
unsigned int dataUp(); ///< Returns total amount of bytes sent.
unsigned int dataDown(); ///< Returns total amount of bytes received.
std::string getStats(std::string C); ///< Returns a std::string of stats, ended by a newline.

View file

@ -60,20 +60,56 @@ void Util::Stream::sanitizeName(std::string & streamname){
}
Socket::Connection Util::Stream::getLive(std::string streamname){
return Socket::Connection(getTmpFolder() + "stream_" + streamname);
JSON::Value ServConf = JSON::fromFile(getTmpFolder() + "streamlist");
static unsigned long long counter = 0;
std::stringstream name;
name << "MistInBuffer " << (counter++);
std::string player_bin = Util::getMyPath() + "MistInBuffer";
DEBUG_MSG(DLVL_WARN, "Starting %s -p -s %s", player_bin.c_str(), streamname.c_str());
char* argv[15] = {(char*)player_bin.c_str(), (char*)"-p", (char*)"-s", (char*)streamname.c_str(), (char*)0};
int argNum = 4;
if (ServConf["streams"][streamname].isMember("DVR")){
std::string bufferTime = ServConf["streams"][streamname]["DVR"].asString();
argv[argNum++] = (char*)"-b";
argv[argNum++] = (char*)bufferTime.c_str();
argv[argNum++] = (char*)0;
}
int pid = fork();
if (pid){
execvp(argv[0], argv);
_exit(42);
}else if(pid == -1){
perror("Could not start vod");
}
return Socket::Connection();
}
/// Starts a process for a VoD stream.
Socket::Connection Util::Stream::getVod(std::string filename, std::string streamname){
static unsigned long long counter = 0;
std::stringstream name;
name << "MistPlayer " << (counter++);
std::string player_bin = Util::getMyPath() + "MistPlayer";
char* const argv[] = {(char*)player_bin.c_str(), (char*)filename.c_str(), (char*)"-s", (char*)streamname.c_str(), (char*)0};
int fdin = -1, fdout = -1, fderr = fileno(stderr);
Util::Procs::StartPiped(name.str(), argv, &fdin, &fdout, &fderr);
// if StartPiped fails then fdin and fdout will be unmodified (-1)
return Socket::Connection(fdin, fdout);
name << "MistInDTSC " << (counter++);
std::string player_bin = Util::getMyPath() + "MistInDTSC";
if (filename.substr(filename.size()-5) == ".ismv"){
name.str("MistInISMV " + filename);
player_bin = Util::getMyPath() + "MistInISMV";
}
if (filename.substr(filename.size()-4) == ".flv"){
name.str("MistInFLV " + filename);
player_bin = Util::getMyPath() + "MistInFLV";
}
DEBUG_MSG(DLVL_WARN, "Starting %s -p -s %s %s", player_bin.c_str(), streamname.c_str(), filename.c_str());
char* const argv[] = {(char*)player_bin.c_str(), (char*)"-p", (char*)"-s", (char*)streamname.c_str(), (char*)filename.c_str(), (char*)0};
int pid = fork();
if (pid){
execvp(argv[0], argv);
_exit(42);
}else if(pid == -1){
perror("Could not start vod");
}
return Socket::Connection();
}
/// Probe for available streams. Currently first VoD, then Live.
@ -84,7 +120,7 @@ Socket::Connection Util::Stream::getStream(std::string streamname){
if (ServConf["streams"][streamname]["source"].asString()[0] == '/'){
return getVod(ServConf["streams"][streamname]["source"].asString(), streamname);
}else{
return Socket::Connection(getTmpFolder() + "stream_" + streamname);
return getLive(streamname);
}
}
DEBUG_MSG(DLVL_ERROR, "Stream not found: %s", streamname.c_str());

View file

@ -53,6 +53,12 @@ namespace theora{
datasize = 0;
}
header::header(char * newData, unsigned int length){
data = NULL;
datasize = 0;
read(newData, length);
}
bool header::validateIdentificationHeader(){
if (datasize != 42){return false;}
if (getHeaderType() != 0){return false;}

View file

@ -7,6 +7,7 @@ namespace theora{
class header{
public:
header();
header(char* newData, unsigned int length);
bool read(char* newData, unsigned int length);
int getHeaderType();
char getVMAJ();

View file

@ -42,6 +42,20 @@ long long int Util::getMS(){
return ((long long int)t.tv_sec) * 1000 + t.tv_nsec / 1000000;
}
/// Gets the current time in microseconds.
long long unsigned int Util::getMicros(){
struct timespec t;
clock_gettime(CLOCK_REALTIME, &t);
return ((long long unsigned int)t.tv_sec) * 1000000 + t.tv_nsec / 1000;
}
/// Gets the time difference in microseconds.
long long unsigned int Util::getMicros(long long unsigned int previous){
struct timespec t;
clock_gettime(CLOCK_REALTIME, &t);
return ((long long unsigned int)t.tv_sec) * 1000000 + t.tv_nsec / 1000 - previous;
}
/// Gets the amount of seconds since 01/01/1970.
long long int Util::epoch(){
return time(0);

View file

@ -6,5 +6,7 @@
namespace Util {
void sleep(int ms); ///< Sleeps for the indicated amount of milliseconds or longer.
long long int getMS(); ///< Gets the current time in milliseconds.
long long unsigned int getMicros();///<Gets the current time in microseconds.
long long unsigned int getMicros(long long unsigned int previous);///<Gets the time difference in microseconds.
long long int epoch(); ///< Gets the amount of seconds since 01/01/1970.
}

View file

@ -422,7 +422,7 @@ unsigned int TS::Packet::AddStuffing(int NumBytes){
strBuf.resize(5 + strBuf[4]);
strBuf[4] += NumBytes;
for (int i = 0; i < NumBytes; i++){
strBuf.append(FILLER_DATA + (i % sizeof(FILLER_DATA)), 1);
strBuf.append(FILLER_DATA[i % sizeof(FILLER_DATA)], 0);
}
}else{
AdaptationField(3);

View file

@ -77,6 +77,19 @@ namespace TS {
/// A standard Program Association Table, as generated by FFMPEG.
/// Seems to be independent of the stream.
//0x47 = sync byte
//0x4000 = transport error(1) = 0, payload unit start(1) = 1, priority(1) = 0, PID(13) = 0
//0x10 = transportscrambling(2) = 0, adaptation(2) = 1, continuity(4) = 0
//0x00 = pointer = 0
//0x00 = table ID = 0 = PAT
//0xB00D = section syntax(1) = 1, 0(1)=0, reserved(2) = 3, section_len(12) = 13
//0x0001 = transport stream id = 1
//0xC1 = reserved(2) = 3, version(5)=0, curr_next_indi(1) = 1
//0x00 = section_number = 0
//0x00 = last_section_no = 0
//0x0001 = ProgNo = 1
//0xF000 = reserved(3) = 7, network pid = 4096
//0x2AB104B2 = CRC32
static char PAT[188] = {0x47, 0x40, 0x00, 0x10, 0x00, 0x00, 0xB0, 0x0D, 0x00, 0x01, 0xC1, 0x00, 0x00, 0x00, 0x01, 0xF0, 0x00, 0x2A, 0xB1, 0x04,
0xB2, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
@ -88,6 +101,25 @@ namespace TS {
/// A standard Program Mapping Table, as generated by FFMPEG.
/// Contains both Audio and Video mappings, works also on video- or audio-only streams.
//0x47 = sync byte
//0x5000 = transport error(1) = 0, payload unit start(1) = 1, priority(1) = 0, PID(13) = 4096
//0x10 = transportscrambling(2) = 0, adaptation(2) = 1, continuity(4) = 0
//0x00 = pointer = 0
//0x02 = table ID = 2 = PMT
//0xB017 = section syntax(1) = 1, 0(1)=0, reserved(2) = 3, section_len(12) = 23
//0x0001 = ProgNo = 1
//0xC1 = reserved(2) = 3, version(5)=0, curr_next_indi(1) = 1
//0x00 = section_number = 0
//0x00 = last_section_no = 0
//0xE100 = reserved(3) = 7, PCR_PID(13) = 0x100
//0xF000 = reserved(4) = 15, proginfolen = 0
//0x1B = streamtype = 27 = H264
//0xE100 = reserved(3) = 7, elem_ID(13) = 0x100
//0xF000 = reserved(4) = 15, es_info_len = 0
//0x0F = streamtype = 15 = audio with ADTS transport syntax
//0xE101 = reserved(3) = 7, elem_ID(13) = 0x101
//0xF000 = reserved(4) = 15, es_info_len = 0
//0x2F44B99B = CRC32
static char PMT[188] = {0x47, 0x50, 0x00, 0x10, 0x00, 0x02, 0xB0, 0x17, 0x00, 0x01, 0xC1, 0x00, 0x00, 0xE1, 0x00, 0xF0, 0x00, 0x1B, 0xE1, 0x00,
0xF0, 0x00, 0x0F, 0xE1, 0x01, 0xF0, 0x00, 0x2F, 0x44, 0xB9, 0x9B, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,

View file

@ -28,6 +28,12 @@ namespace vorbis{
data = NULL;
datasize = 0;
}
header::header(char * newData, unsigned int length){
data = NULL;
datasize = 0;
read(newData, length);
}
int header::getHeaderType(){
return (int)(data[0]);
@ -51,7 +57,7 @@ namespace vorbis{
long unsigned int header::getAudioSampleRate(){
if (getHeaderType() == 1){
return getInt32(12);
return ntohl(getInt32(12));
}else{
return 0;
}
@ -180,6 +186,7 @@ namespace vorbis{
for (int i = 0; i < codebook_count; i++){
long long unsigned int CMN = stream.get(24);
if (CMN != 0x564342){
DEBUG_MSG(DLVL_WARN,"Is dit het? VCB != %c%c%c", (char)(CMN >> 16), (char)(CMN >> 8), (char)CMN);
exit(1);
}
unsigned short codebook_dimensions = stream.get(16);

View file

@ -20,6 +20,7 @@ namespace vorbis{
class header{
public:
header();
header(char* newData, unsigned int length);
bool read(char* newData, unsigned int length);
int getHeaderType();
long unsigned int getVorbisVersion();