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; bool Util::Config::is_active = false;
std::string Util::Config::libver = PACKAGE_VERSION; std::string Util::Config::libver = PACKAGE_VERSION;
Util::Config::Config(){}
/// Creates a new configuration manager. /// Creates a new configuration manager.
Util::Config::Config(std::string cmd, std::string version){ Util::Config::Config(std::string cmd, std::string version){
vals.null(); vals.null();

View file

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

View file

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

View file

@ -16,8 +16,8 @@
namespace DTSC { namespace DTSC {
bool isFixed(JSON::Value & metadata); bool isFixed(JSON::Value & metadata);
/// This enum holds all possible datatypes for DTSC packets. ///\brief This enum holds all possible datatypes for DTSC packets.
enum datatype{ enum datatype {
AUDIO, ///< Stream Audio data AUDIO, ///< Stream Audio data
VIDEO, ///< Stream Video data VIDEO, ///< Stream Video data
META, ///< Stream Metadata META, ///< Stream Metadata
@ -30,50 +30,98 @@ namespace DTSC {
extern char Magic_Packet[]; ///< The magic bytes for a DTSC packet extern char Magic_Packet[]; ///< The magic bytes for a DTSC packet
extern char Magic_Packet2[]; ///< The magic bytes for a DTSC packet version 2 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 { struct seekPos {
bool operator < (const seekPos& rhs) const { ///\brief Less-than comparison for seekPos structures.
if (seekTime < rhs.seekTime){ ///\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; return true;
}else{ } else {
if (seekTime == rhs.seekTime){ if (seekTime == rhs.seekTime) {
if (trackID < rhs.trackID){ if (trackID < rhs.trackID) {
return true; return true;
} }
} }
} }
return false; return false;
} }
long long unsigned int seekTime; long long unsigned int seekTime;///< Stores the timestamp of the DTSC packet referenced by this structure.
long long unsigned int bytePos; long long unsigned int bytePos;///< Stores the byteposition of the DTSC packet referenced by this structure.
unsigned int trackID; 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. /// A simple structure used for ordering byte seek positions.
struct livePos { struct livePos {
livePos(){ livePos() {
seekTime = 0; seekTime = 0;
trackID = 0; trackID = 0;
} }
livePos(const livePos & rhs){ livePos(const livePos & rhs) {
seekTime = rhs.seekTime; seekTime = rhs.seekTime;
trackID = rhs.trackID; trackID = rhs.trackID;
} }
void operator = (const livePos& rhs) { void operator = (const livePos & rhs) {
seekTime = rhs.seekTime; seekTime = rhs.seekTime;
trackID = rhs.trackID; trackID = rhs.trackID;
} }
bool operator == (const livePos& rhs) { bool operator == (const livePos & rhs) {
return seekTime == rhs.seekTime && trackID == rhs.trackID; return seekTime == rhs.seekTime && trackID == rhs.trackID;
} }
bool operator != (const livePos& rhs) { bool operator != (const livePos & rhs) {
return seekTime != rhs.seekTime || trackID != rhs.trackID; return seekTime != rhs.seekTime || trackID != rhs.trackID;
} }
bool operator < (const livePos& rhs) const { bool operator < (const livePos & rhs) const {
if (seekTime < rhs.seekTime){ if (seekTime < rhs.seekTime) {
return true; return true;
}else{ } else {
if (seekTime > rhs.seekTime){ if (seekTime > rhs.seekTime) {
return false; return false;
} }
} }
@ -85,7 +133,7 @@ namespace DTSC {
/// A part from the DTSC::Stream ringbuffer. /// A part from the DTSC::Stream ringbuffer.
/// Holds information about a buffer that will stay consistent /// Holds information about a buffer that will stay consistent
class Ring{ class Ring {
public: public:
Ring(livePos v); Ring(livePos v);
livePos b; livePos b;
@ -96,7 +144,9 @@ namespace DTSC {
volatile int playCount; volatile int playCount;
}; };
class Part{
///\brief Basic class for storage of data associated with single DTSC packets, a.k.a. parts.
class Part {
public: public:
long getSize(); long getSize();
void setSize(long newSize); void setSize(long newSize);
@ -104,12 +154,21 @@ namespace DTSC {
void setDuration(short newDuration); void setDuration(short newDuration);
long getOffset(); long getOffset();
void setOffset(long newOffset); void setOffset(long newOffset);
char* getData(); char * getData();
void toPrettyString(std::stringstream & str, int indent = 0);
private: 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]; 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: public:
long long unsigned int getBpos(); long long unsigned int getBpos();
void setBpos(long long unsigned int newBpos); void setBpos(long long unsigned int newBpos);
@ -121,12 +180,21 @@ namespace DTSC {
void setParts(short newParts); void setParts(short newParts);
long getTime(); long getTime();
void setTime(long newTime); void setTime(long newTime);
char* getData(); char * getData();
void toPrettyString(std::stringstream & str, int indent = 0);
private: 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]; char data[16];
}; };
class Fragment{ ///\brief Basic class for storage of data associated with fragments.
class Fragment {
public: public:
long getDuration(); long getDuration();
void setDuration(long newDuration); void setDuration(long newDuration);
@ -136,26 +204,28 @@ namespace DTSC {
void setNumber(short newNumber); void setNumber(short newNumber);
long getSize(); long getSize();
void setSize(long newSize); void setSize(long newSize);
char* getData(); char * getData();
void toPrettyString(std::stringstream & str, int indent = 0);
private: private:
char data[11]; char data[11];
}; };
class readOnlyTrack{ class readOnlyTrack {
public: public:
readOnlyTrack(); readOnlyTrack();
readOnlyTrack(JSON::Value & trackRef); readOnlyTrack(JSON::Value & trackRef);
int getSendLen(); int getSendLen();
void send(Socket::Connection & conn); void send(Socket::Connection & conn);
void writeTo(char *& p);
std::string getIdentifier(); std::string getIdentifier();
std::string getWritableIdentifier(); std::string getWritableIdentifier();
JSON::Value toJSON(); JSON::Value toJSON();
long long unsigned int fragLen; long long unsigned int fragLen;
Fragment* fragments; Fragment * fragments;
long long unsigned int keyLen; long long unsigned int keyLen;
Key* keys; Key * keys;
long long unsigned int partLen; long long unsigned int partLen;
Part* parts; Part * parts;
int trackID; int trackID;
int firstms; int firstms;
int lastms; int lastms;
@ -175,6 +245,7 @@ namespace DTSC {
//vorbis and theora only //vorbis and theora only
std::string idHeader; std::string idHeader;
std::string commentHeader; std::string commentHeader;
void toPrettyString(std::stringstream & str, int indent = 0, int verbosity = 0);
}; };
class Track : public readOnlyTrack { class Track : public readOnlyTrack {
@ -182,32 +253,42 @@ namespace DTSC {
Track(); Track();
Track(const readOnlyTrack & rhs); Track(const readOnlyTrack & rhs);
Track(JSON::Value & trackRef); 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); void update(JSON::Value & pack);
int getSendLen(); int getSendLen();
void send(Socket::Connection & conn); void send(Socket::Connection & conn);
void writeTo(char *& p);
JSON::Value toJSON(); JSON::Value toJSON();
std::deque<Fragment> fragments; std::deque<Fragment> fragments;
std::deque<Key> keys; std::deque<Key> keys;
std::deque<Part> parts; std::deque<Part> parts;
Key & getKey(unsigned int keyNum); Key & getKey(unsigned int keyNum);
void reset(); void reset();
void toPrettyString(std::stringstream & str, int indent = 0, int verbosity = 0);
}; };
class readOnlyMeta { class readOnlyMeta {
public: public:
readOnlyMeta(); readOnlyMeta();
readOnlyMeta(JSON::Value & meta); readOnlyMeta(JSON::Value & meta);
inline operator bool() const {return vod || live;} inline operator bool() const {
std::map<int,readOnlyTrack> tracks; return vod || live;
}
std::map<int, readOnlyTrack> tracks;
bool vod; bool vod;
bool live; bool live;
bool merged; bool merged;
long long int moreheader; long long int moreheader;
long long int bufferWindow; long long int bufferWindow;
unsigned int getSendLen();
void send(Socket::Connection & conn); void send(Socket::Connection & conn);
void writeTo(char * p);
JSON::Value toJSON(); JSON::Value toJSON();
bool isFixed(); bool isFixed();
void toPrettyString(std::stringstream & str, int indent = 0, int verbosity = 0);
}; };
class Meta : public readOnlyMeta { class Meta : public readOnlyMeta {
@ -215,16 +296,20 @@ namespace DTSC {
Meta(); Meta();
Meta(const readOnlyMeta & meta); Meta(const readOnlyMeta & meta);
Meta(JSON::Value & 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); void update(JSON::Value & pack);
unsigned int getSendLen();
void send(Socket::Connection & conn); void send(Socket::Connection & conn);
void writeTo(char * p);
JSON::Value toJSON(); JSON::Value toJSON();
void reset(); void reset();
bool isFixed(); 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. /// 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: public:
File(); File();
File(const File & rhs); File(const File & rhs);
@ -241,8 +326,7 @@ namespace DTSC {
bool reachedEOF(); bool reachedEOF();
void seekNext(); void seekNext();
void parseNext(); void parseNext();
std::string & getPacket(); DTSC::Packet & getPacket();
JSON::Value & getJSON();
bool seek_time(unsigned int ms); bool seek_time(unsigned int ms);
bool seek_time(unsigned int ms, int trackNo, bool forceSeek = false); bool seek_time(unsigned int ms, int trackNo, bool forceSeek = false);
bool seek_bpos(int bpos); bool seek_bpos(int bpos);
@ -254,11 +338,10 @@ namespace DTSC {
private: private:
long int endPos; long int endPos;
void readHeader(int pos); void readHeader(int pos);
std::string strbuffer; DTSC::Packet myPack;
JSON::Value jsonbuffer;
JSON::Value metaStorage; JSON::Value metaStorage;
readOnlyMeta metadata; readOnlyMeta metadata;
std::map<int,std::string> trackMapping; std::map<int, std::string> trackMapping;
long long int currtime; long long int currtime;
long long int lastreadpos; long long int lastreadpos;
int currframe; int currframe;
@ -274,7 +357,7 @@ namespace DTSC {
/// Holds temporary data for a DTSC stream and provides functions to utilize it. /// 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. /// 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. /// If ring buffering mode is enabled, it will automatically grow in size to always contain at least one keyframe.
class Stream{ class Stream {
public: public:
Stream(); Stream();
virtual ~Stream(); virtual ~Stream();
@ -302,17 +385,18 @@ namespace DTSC {
void endStream(); void endStream();
void waitForMeta(Socket::Connection & sourceSocket); void waitForMeta(Socket::Connection & sourceSocket);
void waitForPause(Socket::Connection & sourceSocket); void waitForPause(Socket::Connection & sourceSocket);
protected: protected:
void cutOneBuffer(); void cutOneBuffer();
void resetStream(); void resetStream();
std::map<livePos,JSON::Value> buffers; std::map<livePos, JSON::Value> buffers;
std::map<int,std::set<livePos> > keyframes; std::map<int, std::set<livePos> > keyframes;
virtual void addPacket(JSON::Value & newPack); virtual void addPacket(JSON::Value & newPack);
virtual void addMeta(JSON::Value & newMeta); virtual void addMeta(JSON::Value & newMeta);
datatype datapointertype; datatype datapointertype;
unsigned int buffercount; unsigned int buffercount;
unsigned int buffertime; unsigned int buffertime;
std::map<int,std::string> trackMapping; std::map<int, std::string> trackMapping;
virtual void deletionCallback(livePos deleting); 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. /// FLV loader function from DTSC.
/// Takes the DTSC data and makes it into FLV. /// Takes the DTSC data and makes it into FLV.
bool FLV::Tag::DTSCLoader(DTSC::Stream & S){ 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; std::string meta_str;
DTSC::Track & track = S.metadata.tracks[S.getPacket()["trackid"].asInt()]; len = 0;
switch (S.lastType()){ if (track.type == "video"){
case DTSC::VIDEO: char * tmpData = 0;
len = S.lastData().length() + 16; packData.getString("data", tmpData, len);
if (track.codec == "H264"){ len += 16;
len += 4; 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;
} }
default: //ignore all other types (there are currently no other types...)
return false;
break;
}
if (len > 0){
if ( !checkBufferSize()){ if ( !checkBufferSize()){
return false; return false;
} }
switch (S.lastType()){ if (track.codec == "H264"){
case DTSC::VIDEO: memcpy(data + 16, tmpData, len - 20);
if ((unsigned int)len == S.lastData().length() + 16){ if (packData.getFlag("nalu")){
memcpy(data + 12, S.lastData().c_str(), S.lastData().length()); data[12] = 1;
}else{ }else{
memcpy(data + 16, S.lastData().c_str(), S.lastData().length()); data[12] = 2;
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;
} }
case DTSC::META: if (packData.getInt("offset") < 0){
memcpy(data + 11, meta_str.c_str(), meta_str.length()); offset(0);
break; }else{
default: offset(packData.getInt("offset"));
break; }
}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(); if (track.type == "audio"){
switch (S.lastType()){ char * tmpData = 0;
case DTSC::VIDEO: packData.getString("data", tmpData, len);
data[0] = 0x09; len += 16;
break; if (track.codec == "AAC"){
case DTSC::AUDIO: len ++;
data[0] = 0x08; }
break; if ( !checkBufferSize()){
case DTSC::META: return false;
data[0] = 0x12; }
break; if (track.codec == "AAC"){
default: memcpy(data + 13, tmpData, len - 17);
break; 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[1] = ((len - 15) >> 16) & 0xFF;
data[2] = ((len - 15) >> 8) & 0xFF; data[2] = ((len - 15) >> 8) & 0xFF;
data[3] = (len - 15) & 0xFF; data[3] = (len - 15) & 0xFF;
data[8] = 0; data[8] = 0;
data[9] = 0; data[9] = 0;
data[10] = 0; data[10] = 0;
tagTime(S.getPacket()["time"].asInt()); tagTime(packData.getTime());
if (packData.getInt("offset")){
tagTime(packData.getTime() + packData.getInt("offset"));
}
return true; return true;
} }
@ -586,6 +565,86 @@ bool FLV::Tag::DTSCAudioInit(DTSC::Track & audio){
return true; 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. /// FLV metadata loader function from DTSC.
/// Takes the DTSC metadata and makes it into FLV. /// Takes the DTSC metadata and makes it into FLV.
/// Assumes metadata is available - so check before calling! /// 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()){ if (len <= 0 || !checkBufferSize()){
return false; return false;
} }
memcpy(data + 11, tmp.c_str(), len - 15); memcpy(data + 11, tmp.data(), len - 15);
setLen(); setLen();
data[0] = 0x12; data[0] = 0x12;
data[1] = ((len - 15) >> 16) & 0xFF; data[1] = ((len - 15) >> 16) & 0xFF;

View file

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

View file

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

View file

@ -58,9 +58,10 @@ namespace OGG{
if (newData.size()<27){ if (newData.size()<27){
return false; return false;
} }
/*if (getMagicNumber() != 0x4f676753){ if (newData.substr(0, 4) != "OggS"){
DEBUG_MSG(DLVL_FAIL, "Invalid Ogg page encountered - cannot continue");
return false; return false;
}*/ }
dataSum = 0; dataSum = 0;
if (!checkDataSize(27)){ if (!checkDataSize(27)){
return false; return false;
@ -81,9 +82,11 @@ namespace OGG{
} }
if (newData.size() < 27 + getPageSegments() + dataSum){//check input size if (newData.size() < 27 + getPageSegments() + dataSum){//check input size
dataSum = 0;
return false; return false;
} }
if(!checkDataSize(27 + getPageSegments()+dataSum)){ if(!checkDataSize(27 + getPageSegments()+dataSum)){
dataSum = 0;
return false; return false;
} }
memcpy(data + 27 + getPageSegments(), newData.c_str() + 27 + getPageSegments(), dataSum); memcpy(data + 27 + getPageSegments(), newData.c_str() + 27 + getPageSegments(), dataSum);
@ -91,8 +94,58 @@ namespace OGG{
return true; 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(){ void Page::setMagicNumber(){
@ -208,34 +261,26 @@ namespace OGG{
DEBUG_MSG(DLVL_ERROR, "Segment too big, create a continue page"); DEBUG_MSG(DLVL_ERROR, "Segment too big, create a continue page");
} }
/// \todo MAKE FIX HERE
bool Page::setSegmentTable(std::vector<unsigned int> layout){ bool Page::setSegmentTable(std::vector<unsigned int> layout){
dataSum=0; dataSum=0;
for (unsigned int i = 0; i < layout.size(); i++){ for (unsigned int i = 0; i < layout.size(); i++){
dataSum += layout[i]; dataSum += layout[i];
} }
unsigned int place = 0; unsigned int place = 0;
char table[255]; char table[256];
for (unsigned int i = 0; i < layout.size(); i++){ for (unsigned int i = 0; i < layout.size(); i++){
while (layout[i]>=255){ int amount = (layout[i]/255) + 1;
if (place > 255){ if (i == layout.size() - 1 && place + amount > (255 + (layout[i] % 255 == 0))){
STerrMSG();
return false;
}
table[place] = 255;
layout[i] -= 255;
place++;
}
if (place > 255){
STerrMSG(); STerrMSG();
return false; return false;
} }
if (layout[i] >= 0){//fix somewhere here memset(table + place, 255, amount - 1);
table[place] = layout[i]; table[place + amount - 1] = layout[i] % 255;
if (place<255){//last segment does not need a closing 0 place += amount;
place++; }
} //Don't send element 256, even if it was filled.
} if (place > 255){
place = 255;
} }
setPageSegments(place); setPageSegments(place);
setSegmentTable(table,place); setSegmentTable(table,place);
@ -260,92 +305,42 @@ namespace OGG{
return data + 27 + getPageSegments(); 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){ void Page::setInternalCodec(std::string myCodec){
codec = myCodec; codec = myCodec;
} }
std::string Page::toPrettyString(size_t indent){ std::string Page::toPrettyString(size_t indent){
std::stringstream r; std::stringstream r;
r << std::string(indent,' ') << "OGG Page (" << getPageSize() << ")" << std::endl; 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 + 2,' ') << "Version: " << (int)getVersion() << std::endl; r << std::string(indent + 2,' ') << "Version: " << (int)getVersion() << std::endl;
r << std::string(indent + 2,' ') << "Headertype: " << std::hex << (int)getHeaderType() << std::dec; r << std::string(indent + 2,' ') << "Header type:";
if (typeContinue()){ if ( !getHeaderType()){
r << " continued"; r << " Normal";
}else{
if (getHeaderType() & Continued){
r << " Continued";
}
if (getHeaderType() & BeginOfStream){
r << " BeginOfStream";
}
if (getHeaderType() & EndOfStream){
r << " EndOfStream";
}
} }
if (typeBOS()){ r << " (" << (int)getHeaderType() << ")" << std::endl;
r << " bos"; r << std::string(indent + 2,' ') << "Granule position: " << getGranulePosition() << std::endl;
} r << std::string(indent + 2,' ') << "Bitstream number: " << getBitstreamSerialNumber() << std::endl;
if (typeEOS()){ r << std::string(indent + 2,' ') << "Sequence number: " << getPageSequenceNumber() << std::endl;
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 << std::string(indent + 2,' ') << "Checksum: " << std::hex << getCRCChecksum() << std::dec << 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 << " 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,' ') << "Payloadsize: " << dataSum << std::endl;
r << std::string(indent + 2,' ') << "Segments: " << (int)getPageSegments() << std::endl; r << std::string(indent + 2,' ') << (int)getPageSegments() << " segments:" << std::endl;
r << std::string(indent + 3,' ');
std::deque<unsigned int> temp = getSegmentTableDeque(); std::deque<unsigned int> temp = getSegmentTableDeque();
for (std::deque<unsigned int>::iterator i = temp.begin(); i != temp.end(); i++){ for (std::deque<unsigned int>::iterator i = temp.begin(); i != temp.end(); i++){
r << std::string(indent + 4,' ') << (*i) << std::endl; r << " " << (*i);
}
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 << std::endl;
return r.str(); return r.str();
} }

View file

@ -1,4 +1,5 @@
#pragma once #pragma once
#include <cstdlib>
#include <string> #include <string>
#include <vector> #include <vector>
#include <deque> #include <deque>
@ -8,12 +9,20 @@
#include "json.h" #include "json.h"
namespace OGG{ namespace OGG{
enum HeaderType{
Continued = 1,
BeginOfStream = 2,
EndOfStream = 4
};
class Page{ class Page{
public: public:
Page(); Page();
~Page(); ~Page();
bool read(std::string & newData); 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(); void setMagicNumber();
char getVersion(); char getVersion();
void setVersion(char newVal = 0); void setVersion(char newVal = 0);
@ -37,10 +46,6 @@ namespace OGG{
unsigned long int getPageSize(); unsigned long int getPageSize();
char* getFullPayload();//returns all segments in the page char* getFullPayload();//returns all segments in the page
int getPayloadSize(); int getPayloadSize();
bool typeBOS();
bool typeEOS();
bool typeContinue();
bool typeNone();
std::string toPrettyString(size_t indent = 0); std::string toPrettyString(size_t indent = 0);
void setInternalCodec(std::string myCodec); void setInternalCodec(std::string myCodec);
long unsigned int calcChecksum(); 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; std::map<pid_t, std::string>::iterator it;
for (it = listcopy.begin(); it != listcopy.end(); it++){ for (it = listcopy.begin(); it != listcopy.end(); it++){
if (( *it).second == name){ if (( *it).second == name){
if (kill(( *it).first, 0) == 0){ if (childRunning(( *it).first)){
return true; return true;
}else{ }else{
plist.erase(( *it).first); 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. /// 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. /// \param sockNo Integer representing the socket to convert.
Socket::Connection::Connection(int sockNo){ Socket::Connection::Connection(int sockNo){
@ -387,6 +392,11 @@ bool Socket::Connection::connected() const{
return (sock >= 0) || ((pipes[0] >= 0) && (pipes[1] >= 0)); 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. /// Returns total amount of bytes sent.
unsigned int Socket::Connection::dataUp(){ unsigned int Socket::Connection::dataUp(){
return up; return up;
@ -647,6 +657,48 @@ Socket::Connection::operator bool() const{
return connected(); 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. /// Create a new base Server. The socket is never connected, and a placeholder for later connections.
Socket::Server::Server(){ Socket::Server::Server(){
sock = -1; sock = -1;

View file

@ -39,6 +39,7 @@ namespace Socket {
bool available(unsigned int count); bool available(unsigned int count);
std::string remove(unsigned int count); std::string remove(unsigned int count);
std::string copy(unsigned int count); std::string copy(unsigned int count);
void clear();
}; };
//Buffer //Buffer
@ -76,6 +77,7 @@ namespace Socket {
int getSocket(); ///< Returns internal socket number. int getSocket(); ///< Returns internal socket number.
std::string getError(); ///< Returns a string describing the last error that occured. std::string getError(); ///< Returns a string describing the last error that occured.
bool connected() const; ///< Returns the connected-state for this socket. bool connected() const; ///< Returns the connected-state for this socket.
bool isAddress(std::string addr);
//buffered i/o methods //buffered i/o methods
bool spool(); ///< Updates the downbuffer and upbuffer internal variables. bool spool(); ///< Updates the downbuffer and upbuffer internal variables.
bool flush(); ///< Updates the downbuffer and upbuffer internal variables until upbuffer is empty. 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); ///< 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. void SendNow(const char * data, size_t len); ///< Will not buffer anything but always send right away. Blocks.
//stats related methods //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 dataUp(); ///< Returns total amount of bytes sent.
unsigned int dataDown(); ///< Returns total amount of bytes received. 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. 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){ 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. /// Starts a process for a VoD stream.
Socket::Connection Util::Stream::getVod(std::string filename, std::string streamname){ Socket::Connection Util::Stream::getVod(std::string filename, std::string streamname){
static unsigned long long counter = 0; static unsigned long long counter = 0;
std::stringstream name; std::stringstream name;
name << "MistPlayer " << (counter++); name << "MistInDTSC " << (counter++);
std::string player_bin = Util::getMyPath() + "MistPlayer"; std::string player_bin = Util::getMyPath() + "MistInDTSC";
char* const argv[] = {(char*)player_bin.c_str(), (char*)filename.c_str(), (char*)"-s", (char*)streamname.c_str(), (char*)0}; if (filename.substr(filename.size()-5) == ".ismv"){
int fdin = -1, fdout = -1, fderr = fileno(stderr); name.str("MistInISMV " + filename);
Util::Procs::StartPiped(name.str(), argv, &fdin, &fdout, &fderr); player_bin = Util::getMyPath() + "MistInISMV";
// if StartPiped fails then fdin and fdout will be unmodified (-1) }
return Socket::Connection(fdin, fdout); 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. /// 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] == '/'){ if (ServConf["streams"][streamname]["source"].asString()[0] == '/'){
return getVod(ServConf["streams"][streamname]["source"].asString(), streamname); return getVod(ServConf["streams"][streamname]["source"].asString(), streamname);
}else{ }else{
return Socket::Connection(getTmpFolder() + "stream_" + streamname); return getLive(streamname);
} }
} }
DEBUG_MSG(DLVL_ERROR, "Stream not found: %s", streamname.c_str()); DEBUG_MSG(DLVL_ERROR, "Stream not found: %s", streamname.c_str());

View file

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

View file

@ -7,6 +7,7 @@ namespace theora{
class header{ class header{
public: public:
header(); header();
header(char* newData, unsigned int length);
bool read(char* newData, unsigned int length); bool read(char* newData, unsigned int length);
int getHeaderType(); int getHeaderType();
char getVMAJ(); 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; 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. /// Gets the amount of seconds since 01/01/1970.
long long int Util::epoch(){ long long int Util::epoch(){
return time(0); return time(0);

View file

@ -6,5 +6,7 @@
namespace Util { namespace Util {
void sleep(int ms); ///< Sleeps for the indicated amount of milliseconds or longer. 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 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. 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.resize(5 + strBuf[4]);
strBuf[4] += NumBytes; strBuf[4] += NumBytes;
for (int i = 0; i < NumBytes; i++){ 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{ }else{
AdaptationField(3); AdaptationField(3);

View file

@ -77,6 +77,19 @@ namespace TS {
/// A standard Program Association Table, as generated by FFMPEG. /// A standard Program Association Table, as generated by FFMPEG.
/// Seems to be independent of the stream. /// 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, 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, 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, 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. /// A standard Program Mapping Table, as generated by FFMPEG.
/// Contains both Audio and Video mappings, works also on video- or audio-only streams. /// 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, 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, 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, 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

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

View file

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