/// \file dtsc.h /// Holds all headers for DDVTECH Stream Container parsing/generation. #pragma once #include #include #include //for uint64_t #include #include #include #include //for FILE #include "json.h" #include "socket.h" #include "timing.h" /// Holds all DDVTECH Stream Container classes and parsers. ///length (int, length in seconds, if available) ///video: /// - codec (string: H264, H263, VP6) /// - width (int, pixels) /// - height (int, pixels) /// - fpks (int, frames per kilosecond (FPS * 1000)) /// - bps (int, bytes per second) /// - init (string, init data) /// - keycount (int, count of keyframes) /// - keyms (int, average ms per keyframe) /// - keyvar (int, max ms per keyframe variance) /// - keys (array of byte position ints - first is first keyframe, last is last keyframe, in between have ~equal spacing) /// ///audio: /// - codec (string: AAC, MP3) /// - rate (int, Hz) /// - size (int, bitsize) /// - bps (int, bytes per second) /// - channels (int, channelcount) /// - init (string, init data) /// ///All packets: /// - datatype (string: audio, video, meta (unused)) /// - data (string: data) /// - time (int: ms into video) /// ///Video packets: /// - keyframe (int, if set, is a seekable keyframe) /// - interframe (int, if set, is a non-seekable interframe) /// - disposableframe (int, if set, is a disposable interframe) /// ///H264 video packets: /// - nalu (int, if set, is a nalu) /// - nalu_end (int, if set, is a end-of-sequence) /// - offset (int, unsigned version of signed int! Holds the ms offset between timestamp and proper display time for B-frames) namespace DTSC { /// 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 /// A simple structure used for ordering byte seek positions. struct seekPos { bool operator < (const seekPos& rhs) const { if (seekTime < rhs.seekTime){ return true; }else{ if (seekTime == rhs.seekTime){ if (seekPos < rhs.seekPos){ return true; }else{ if (trackID < rhs.trackID){ return true; } } } } return false; } long long unsigned int seekTime; long long unsigned int seekPos; unsigned int trackID; }; /// 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); ~File(); JSON::Value & getMeta(); JSON::Value & getFirstMeta(); 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(); std::string & getPacket(); JSON::Value & getJSON(); JSON::Value & getTrackById(int trackNo); bool seek_time(int seconds); bool seek_time(int seconds, int trackNo); bool seek_bpos(int bpos); void writePacket(std::string & newPacket); void writePacket(JSON::Value & newPacket); bool atKeyframe(); void selectTracks(std::set & tracks); private: long int endPos; void readHeader(int pos); std::string strbuffer; JSON::Value jsonbuffer; JSON::Value metadata; JSON::Value firstmetadata; std::map trackMapping; long long int currtime; long long int lastreadpos; int currframe; FILE * F; unsigned long headerSize; char buffer[4]; bool created; std::set currentPositions; std::set selectedTracks; }; //FileWriter /// 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){ if (trackID < rhs.trackID){ return true; } } } return false; } volatile long long unsigned int seekTime; volatile unsigned int trackID; }; /// A part from the DTSC::Stream ringbuffer. /// Holds information about a buffer that will stay consistent class Ring{ public: Ring(livePos v); livePos b; //volatile unsigned int b; ///< Holds current number of buffer. May and is intended to change unexpectedly! volatile bool waiting; ///< If true, this Ring is currently waiting for a buffer fill. volatile bool starved; ///< If true, this Ring can no longer receive valid data. volatile bool updated; ///< If true, this Ring should write a new header. volatile int playCount; }; /// 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{ public: Stream(); ~Stream(); Stream(unsigned int buffers, unsigned int bufferTime = 0); JSON::Value metadata; JSON::Value & getPacket(); JSON::Value & getPacket(livePos num); JSON::Value & getTrackById(int trackNo); datatype lastType(); std::string & lastData(); bool hasVideo(); bool hasAudio(); bool parsePacket(std::string & buffer); bool parsePacket(Socket::Buffer & buffer); std::string & outPacket(); std::string & outPacket(livePos num); std::string & outHeader(); Ring * getRing(); unsigned int getTime(); void dropRing(Ring * ptr); int canSeekms(unsigned int ms); livePos msSeek(unsigned int ms, std::set & allowedTracks); void setBufferTime(unsigned int ms); bool isNewest(DTSC::livePos & pos); DTSC::livePos getNext(DTSC::livePos & pos, std::set & allowedTracks); void endStream(); private: std::map buffers; std::map > keyframes; void addPacket(JSON::Value & newPack); datatype datapointertype; unsigned int buffercount; unsigned int buffertime; std::map trackMapping; }; }