475 lines
16 KiB
C++
475 lines
16 KiB
C++
/// \file dtsc.h
|
|
/// Holds all headers for DDVTECH Stream Container parsing/generation.
|
|
|
|
#pragma once
|
|
#include "json.h"
|
|
#include "socket.h"
|
|
#include "timing.h"
|
|
#include <deque>
|
|
#include <iostream>
|
|
#include <set>
|
|
#include <stdint.h> //for uint64_t
|
|
#include <stdio.h> //for FILE
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
#define DTSC_INT 0x01
|
|
#define DTSC_STR 0x02
|
|
#define DTSC_OBJ 0xE0
|
|
#define DTSC_ARR 0x0A
|
|
#define DTSC_CON 0xFF
|
|
|
|
// Increase this value every time the DTSH file format changes in an incompatible way
|
|
// Changelog:
|
|
// Version 0-2: Undocumented changes
|
|
// Version 3: switched to bigMeta-style by default, Parts layout switched from 3/2/4 to 3/3/3 bytes
|
|
// Version 4: renamed bps to maxbps (peak bit rate) and added new value bps (average bit rate)
|
|
#define DTSH_VERSION 4
|
|
|
|
namespace DTSC{
|
|
|
|
///\brief This enum holds all possible datatypes for DTSC packets.
|
|
enum datatype{
|
|
AUDIO, ///< Stream Audio data
|
|
VIDEO, ///< Stream Video data
|
|
META, ///< Stream Metadata
|
|
PAUSEMARK, ///< Pause marker
|
|
MODIFIEDHEADER, ///< Modified header data.
|
|
INVALID ///< Anything else or no data available.
|
|
};
|
|
|
|
extern char Magic_Header[]; ///< The magic bytes for a DTSC header
|
|
extern char Magic_Packet[]; ///< The magic bytes for a DTSC packet
|
|
extern char Magic_Packet2[]; ///< The magic bytes for a DTSC packet version 2
|
|
extern char Magic_Command[]; ///< The magic bytes for a DTCM packet
|
|
|
|
///\brief A simple structure used for ordering byte seek positions.
|
|
struct seekPos{
|
|
///\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){return true;}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
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, DTCM};
|
|
|
|
/// This class allows scanning through raw binary format DTSC data.
|
|
/// It can be used as an iterator or as a direct accessor.
|
|
class Scan{
|
|
public:
|
|
Scan();
|
|
Scan(char *pointer, size_t len);
|
|
operator bool() const;
|
|
std::string toPrettyString(size_t indent = 0) const;
|
|
bool hasMember(const std::string &indice) const;
|
|
bool hasMember(const char *indice, size_t ind_len) const;
|
|
Scan getMember(const std::string &indice) const;
|
|
Scan getMember(const char *indice) const;
|
|
Scan getMember(const char *indice, size_t ind_len) const;
|
|
void nullMember(const std::string &indice);
|
|
void nullMember(const char *indice, size_t ind_len);
|
|
Scan getIndice(size_t num) const;
|
|
std::string getIndiceName(size_t num) const;
|
|
size_t getSize() const;
|
|
|
|
char getType() const;
|
|
bool asBool() const;
|
|
int64_t asInt() const;
|
|
std::string asString() const;
|
|
void getString(char *&result, size_t &len) const;
|
|
JSON::Value asJSON() const;
|
|
|
|
private:
|
|
char *p;
|
|
size_t len;
|
|
};
|
|
|
|
/// 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);
|
|
virtual ~Packet();
|
|
void null();
|
|
void operator=(const Packet &rhs);
|
|
operator bool() const;
|
|
packType getVersion() const;
|
|
void reInit(Socket::Connection &src);
|
|
void reInit(const char *data_, unsigned int len, bool noCopy = false);
|
|
void genericFill(long long packTime, long long packOffset, long long packTrack,
|
|
const char *packData, long long packDataSize, uint64_t packBytePos,
|
|
bool isKeyframe, int64_t bootMsOffset = 0);
|
|
void appendData(const char *appendData, uint32_t appendLen);
|
|
void getString(const char *identifier, char *&result, size_t &len) const;
|
|
void getString(const char *identifier, std::string &result) const;
|
|
void getInt(const char *identifier, uint64_t &result) const;
|
|
uint64_t getInt(const char *identifier) const;
|
|
void getFlag(const char *identifier, bool &result) const;
|
|
bool getFlag(const char *identifier) const;
|
|
bool hasMember(const char *identifier) const;
|
|
void appendNal(const char *appendData, uint32_t appendLen);
|
|
void upgradeNal(const char *appendData, uint32_t appendLen);
|
|
void setKeyFrame(bool kf);
|
|
virtual uint64_t getTime() const;
|
|
void setTime(uint64_t _time);
|
|
void nullMember(const std::string &memb);
|
|
size_t getTrackId() const;
|
|
char *getData() const;
|
|
size_t getDataLen() const;
|
|
size_t getPayloadLen() const;
|
|
size_t getDataStringLen();
|
|
size_t getDataStringLenOffset();
|
|
JSON::Value toJSON() const;
|
|
std::string toSummary() const;
|
|
Scan getScan() const;
|
|
Scan getScan();
|
|
|
|
protected:
|
|
bool master;
|
|
packType version;
|
|
void resize(size_t size);
|
|
char *data;
|
|
size_t bufferLen;
|
|
size_t dataLen;
|
|
|
|
uint64_t prevNalSize;
|
|
};
|
|
|
|
/// A child class of DTSC::Packet, which allows overriding the packet time efficiently.
|
|
class RetimedPacket : public Packet{
|
|
public:
|
|
RetimedPacket(uint64_t reTime){timeOverride = reTime;}
|
|
RetimedPacket(uint64_t reTime, const Packet &rhs) : Packet(rhs){timeOverride = reTime;}
|
|
RetimedPacket(uint64_t reTime, const char *data_, unsigned int len, bool noCopy = false)
|
|
: Packet(data_, len, noCopy){
|
|
timeOverride = reTime;
|
|
}
|
|
virtual uint64_t getTime() const{return timeOverride;}
|
|
|
|
protected:
|
|
uint64_t timeOverride;
|
|
};
|
|
|
|
/// A simple structure used for ordering byte seek positions.
|
|
struct livePos{
|
|
livePos(){
|
|
seekTime = 0;
|
|
trackID = 0;
|
|
}
|
|
livePos(const livePos &rhs){
|
|
seekTime = rhs.seekTime;
|
|
trackID = rhs.trackID;
|
|
}
|
|
void operator=(const livePos &rhs){
|
|
seekTime = rhs.seekTime;
|
|
trackID = rhs.trackID;
|
|
}
|
|
bool operator==(const livePos &rhs){
|
|
return seekTime == rhs.seekTime && trackID == rhs.trackID;
|
|
}
|
|
bool operator!=(const livePos &rhs){
|
|
return seekTime != rhs.seekTime || trackID != rhs.trackID;
|
|
}
|
|
bool operator<(const livePos &rhs) const{
|
|
if (seekTime < rhs.seekTime){
|
|
return true;
|
|
}else{
|
|
if (seekTime > rhs.seekTime){return false;}
|
|
}
|
|
return (trackID < rhs.trackID);
|
|
}
|
|
long long unsigned int seekTime;
|
|
unsigned int trackID;
|
|
};
|
|
|
|
/*LTS-START*/
|
|
///\brief Basic class supporting initialization Vectors.
|
|
///
|
|
/// These are used for encryption of data.
|
|
class Ivec{
|
|
public:
|
|
Ivec();
|
|
Ivec(long long int iVec);
|
|
void setIvec(long long int iVec);
|
|
void setIvec(std::string iVec);
|
|
void setIvec(const char *iVec, int len);
|
|
long long int asInt();
|
|
char *getData();
|
|
|
|
private:
|
|
///\brief Data storage for this initialization vector.
|
|
///
|
|
/// - 8 bytes: MSB storage of the initialization vector.
|
|
char data[8];
|
|
};
|
|
/*LTS-END*/
|
|
|
|
///\brief Basic class for storage of data associated with single DTSC packets, a.k.a. parts.
|
|
class Part{
|
|
public:
|
|
uint32_t getSize();
|
|
void setSize(uint32_t newSize);
|
|
uint32_t getDuration();
|
|
void setDuration(uint32_t newDuration);
|
|
uint32_t getOffset();
|
|
void setOffset(uint32_t newOffset);
|
|
char *getData();
|
|
void toPrettyString(std::ostream &str, int indent = 0);
|
|
|
|
private:
|
|
#define PACKED_PART_SIZE 9
|
|
///\brief Data storage for this Part.
|
|
///
|
|
/// - 3 bytes: MSB storage of the payload size of this packet in bytes.
|
|
/// - 3 bytes: MSB storage of the duration of this packet in milliseconds.
|
|
/// - 3 bytes: MSB storage of the presentation time offset of this packet in milliseconds.
|
|
char data[PACKED_PART_SIZE];
|
|
};
|
|
|
|
///\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:
|
|
unsigned long long getBpos();
|
|
void setBpos(unsigned long long newBpos);
|
|
unsigned long getLength();
|
|
void setLength(unsigned long newLength);
|
|
unsigned long getNumber();
|
|
void setNumber(unsigned long newNumber);
|
|
unsigned short getParts();
|
|
void setParts(unsigned short newParts);
|
|
unsigned long long getTime();
|
|
void setTime(unsigned long long newTime);
|
|
char *getData();
|
|
void toPrettyString(std::ostream &str, int indent = 0);
|
|
|
|
private:
|
|
#define PACKED_KEY_SIZE 25
|
|
///\brief Data storage for this Key.
|
|
///
|
|
/// - 8 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.
|
|
/// - 4 bytes: MSB storage of the number of this keyframe.
|
|
/// - 2 bytes: MSB storage of the amount of parts in this keyframe.
|
|
/// - 8 bytes: MSB storage of the timestamp associated with this keyframe's first packet.
|
|
char data[PACKED_KEY_SIZE];
|
|
};
|
|
|
|
///\brief Basic class for storage of data associated with fragments.
|
|
class Fragment{
|
|
public:
|
|
unsigned long getDuration();
|
|
void setDuration(unsigned long newDuration);
|
|
char getLength();
|
|
void setLength(char newLength);
|
|
unsigned long getNumber();
|
|
void setNumber(unsigned long newNumber);
|
|
unsigned long getSize();
|
|
void setSize(unsigned long newSize);
|
|
char *getData();
|
|
void toPrettyString(std::ostream &str, int indent = 0);
|
|
|
|
private:
|
|
#define PACKED_FRAGMENT_SIZE 13
|
|
///\brief Data storage for this Fragment.
|
|
///
|
|
/// - 4 bytes: duration (in milliseconds)
|
|
/// - 1 byte: length (amount of keyframes)
|
|
/// - 4 bytes: number of first keyframe in fragment
|
|
/// - 4 bytes: size of fragment in bytes
|
|
char data[PACKED_FRAGMENT_SIZE];
|
|
};
|
|
|
|
///\brief Class for storage of track data
|
|
class Track{
|
|
public:
|
|
Track();
|
|
Track(JSON::Value &trackRef);
|
|
Track(Scan &trackRef);
|
|
void clearParts();
|
|
|
|
inline operator bool() const{
|
|
return (parts.size() && keySizes.size() && (keySizes.size() == keys.size()));
|
|
}
|
|
/*
|
|
void update(long long packTime, long long packOffset, long long packDataSize, uint64_t
|
|
packBytePos, bool isKeyframe, long long packSendSize, unsigned long segment_size = 1900);
|
|
*/
|
|
void update(long long packTime, long long packOffset, long long packDataSize,
|
|
uint64_t packBytePos, bool isKeyframe, long long packSendSize,
|
|
unsigned long segment_size = 1900, const char *iVec = 0);
|
|
int getSendLen(bool skipDynamic = false);
|
|
void send(Socket::Connection &conn, bool skipDynamic = false);
|
|
void writeTo(char *&p);
|
|
JSON::Value toJSON(bool skipDynamic = false);
|
|
std::deque<Fragment> fragments;
|
|
std::deque<Key> keys;
|
|
std::deque<unsigned long> keySizes;
|
|
std::deque<Part> parts;
|
|
std::deque<Ivec> ivecs; /*LTS*/
|
|
Key &getKey(unsigned int keyNum);
|
|
Fragment &getFrag(unsigned int fragNum);
|
|
unsigned int timeToKeynum(unsigned int timestamp);
|
|
uint32_t timeToFragnum(uint64_t timestamp);
|
|
void reset();
|
|
void toPrettyString(std::ostream &str, int indent = 0, int verbosity = 0);
|
|
void finalize();
|
|
uint32_t biggestFragment();
|
|
|
|
std::string getIdentifier();
|
|
std::string getWritableIdentifier();
|
|
unsigned int trackID;
|
|
uint64_t firstms;
|
|
uint64_t lastms;
|
|
int bps;
|
|
int max_bps;
|
|
int missedFrags;
|
|
std::string init;
|
|
std::string codec;
|
|
std::string type;
|
|
std::string lang; ///< ISO 639-2 Language of track, empty or und if unknown.
|
|
uint32_t minKeepAway; ///< Time in MS to never seek closer than live point to
|
|
// audio only
|
|
int rate;
|
|
int size;
|
|
int channels;
|
|
// video only
|
|
int width;
|
|
int height;
|
|
int fpks;
|
|
void removeFirstKey();
|
|
uint32_t secsSinceFirstFragmentInsert();
|
|
|
|
private:
|
|
std::string cachedIdent;
|
|
std::deque<uint32_t> fragInsertTime;
|
|
};
|
|
|
|
///\brief Class for storage of meta data
|
|
class Meta{
|
|
/// \todo Make toJSON().toNetpacked() shorter
|
|
public:
|
|
Meta();
|
|
Meta(const DTSC::Packet &source);
|
|
Meta(JSON::Value &meta);
|
|
bool nextIsKey;
|
|
|
|
inline operator bool() const{// returns if the object contains valid meta data BY LOOKING AT vod/live FLAGS
|
|
return vod || live;
|
|
}
|
|
void reinit(const DTSC::Packet &source);
|
|
void update(const DTSC::Packet &pack, unsigned long segment_size = 1900);
|
|
void updatePosOverride(DTSC::Packet &pack, uint64_t bpos);
|
|
void update(JSON::Value &pack, unsigned long segment_size = 1900);
|
|
/*LTS
|
|
void update(long long packTime, long long packOffset, long long packTrack, long long
|
|
packDataSize, uint64_t packBytePos, bool isKeyframe, long long packSendSize = 0, unsigned long
|
|
segment_size = 1900); LTS*/
|
|
void update(long long packTime, long long packOffset, long long packTrack,
|
|
long long packDataSize, uint64_t packBytePos, bool isKeyframe,
|
|
long long packSendSize = 0, unsigned long segment_size = 1900, const char *iVec = 0);
|
|
unsigned int getSendLen(bool skipDynamic = false,
|
|
std::set<unsigned long> selectedTracks = std::set<unsigned long>());
|
|
void send(Socket::Connection &conn, bool skipDynamic = false,
|
|
std::set<unsigned long> selectedTracks = std::set<unsigned long>());
|
|
void writeTo(char *p);
|
|
JSON::Value toJSON();
|
|
void reset();
|
|
bool toFile(const std::string &fileName);
|
|
void toPrettyString(std::ostream &str, int indent = 0, int verbosity = 0);
|
|
// members:
|
|
std::map<unsigned int, Track> tracks;
|
|
Track &mainTrack();
|
|
uint32_t biggestFragment();
|
|
bool vod;
|
|
bool live;
|
|
bool merged;
|
|
uint16_t version;
|
|
int64_t moreheader;
|
|
int64_t bufferWindow;
|
|
int64_t bootMsOffset; ///< Millis to add to packet timestamps to get millis since system boot.
|
|
std::string sourceURI;
|
|
JSON::Value inputLocalVars;
|
|
};
|
|
|
|
/// An iterator helper for easily iterating over the parts in a Fragment.
|
|
class PartIter{
|
|
public:
|
|
PartIter(Track &Trk, Fragment &frag);
|
|
Part &operator*() const; ///< Dereferences into a Value reference.
|
|
Part *operator->() const; ///< Dereferences into a Value reference.
|
|
operator bool() const; ///< True if not done iterating.
|
|
PartIter &operator++(); ///< Go to next iteration.
|
|
private:
|
|
uint32_t lastKey;
|
|
uint32_t currInKey;
|
|
Track *tRef;
|
|
std::deque<Part>::iterator pIt;
|
|
std::deque<Key>::iterator kIt;
|
|
};
|
|
|
|
/// A simple wrapper class that will open a file and allow easy reading/writing of DTSC data from/to it.
|
|
class File{
|
|
public:
|
|
File();
|
|
File(const File &rhs);
|
|
File(std::string filename, bool create = false);
|
|
File &operator=(const File &rhs);
|
|
operator bool() const;
|
|
~File();
|
|
Meta &getMeta();
|
|
long long int getLastReadPos();
|
|
bool writeHeader(std::string &header, bool force = false);
|
|
long long int addHeader(std::string &header);
|
|
long int getBytePosEOF();
|
|
long int getBytePos();
|
|
bool reachedEOF();
|
|
void seekNext();
|
|
void parseNext();
|
|
DTSC::Packet &getPacket();
|
|
bool seek_time(unsigned int ms);
|
|
bool seek_time(unsigned int ms, unsigned int trackNo, bool forceSeek = false);
|
|
bool seek_bpos(int bpos);
|
|
void rewritePacket(std::string &newPacket, int bytePos);
|
|
void writePacket(std::string &newPacket);
|
|
void writePacket(JSON::Value &newPacket);
|
|
bool atKeyframe();
|
|
void selectTracks(std::set<unsigned long> &tracks);
|
|
|
|
private:
|
|
long int endPos;
|
|
void readHeader(int pos);
|
|
DTSC::Packet myPack;
|
|
Meta metadata;
|
|
std::map<unsigned int, std::string> trackMapping;
|
|
long long int currtime;
|
|
long long int lastreadpos;
|
|
int currframe;
|
|
FILE *F;
|
|
unsigned long headerSize;
|
|
void *buffer;
|
|
bool created;
|
|
std::set<seekPos> currentPositions;
|
|
std::set<unsigned long> selectedTracks;
|
|
};
|
|
// FileWriter
|
|
|
|
}// namespace DTSC
|