Shared Memory updates
This commit is contained in:
		
							parent
							
								
									330b9f871d
								
							
						
					
					
						commit
						0e5d838a20
					
				
					 24 changed files with 2420 additions and 612 deletions
				
			
		| 
						 | 
				
			
			@ -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();
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										195
									
								
								lib/dtsc.cpp
									
										
									
									
									
								
							
							
						
						
									
										195
									
								
								lib/dtsc.cpp
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -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;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										176
									
								
								lib/dtsc.h
									
										
									
									
									
								
							
							
						
						
									
										176
									
								
								lib/dtsc.h
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -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);
 | 
			
		||||
  };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										1235
									
								
								lib/dtscmeta.cpp
									
										
									
									
									
								
							
							
						
						
									
										1235
									
								
								lib/dtscmeta.cpp
									
										
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
							
								
								
									
										283
									
								
								lib/flv_tag.cpp
									
										
									
									
									
								
							
							
						
						
									
										283
									
								
								lib/flv_tag.cpp
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -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;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										34
									
								
								lib/json.cpp
									
										
									
									
									
								
							
							
						
						
									
										34
									
								
								lib/json.cpp
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -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;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										187
									
								
								lib/ogg.cpp
									
										
									
									
									
								
							
							
						
						
									
										187
									
								
								lib/ogg.cpp
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -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();
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										15
									
								
								lib/ogg.h
									
										
									
									
									
								
							
							
						
						
									
										15
									
								
								lib/ogg.h
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -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();
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
									
								
							
							
						
						
									
										608
									
								
								lib/shared_memory.cpp
									
										
									
									
									
										Normal 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
									
								
							
							
						
						
									
										116
									
								
								lib/shared_memory.h
									
										
									
									
									
										Normal 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;
 | 
			
		||||
  };
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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());
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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;}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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();
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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.
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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();
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue