#include "output_http.h" #include #include namespace Mist{ class keyPart{ public: bool operator<(const keyPart &rhs) const{ if (time < rhs.time){return true;} if (time > rhs.time){return false;} if (trackID < rhs.trackID){return true;} return (trackID == rhs.trackID && index < rhs.index); } size_t trackID; uint64_t time; uint64_t byteOffset; // Stores relative bpos for fragmented MP4 uint64_t index; size_t sampleSize; uint16_t sampleDuration; uint16_t sampleOffset; }; class SortSet{ private: Util::ResizeablePointer ptr; Util::ResizeablePointer avail; size_t entries; size_t currBegin; void findBegin(); bool hasBegin; public: SortSet(); const keyPart & begin(); void erase(); bool empty(); void insert(const keyPart & part); }; /// Class that implements a tiny subset of std::map, optimized for speed for our type of usage. template class QuickMap{ private: Util::ResizeablePointer ptr; size_t entries; public: QuickMap(){ entries = 0; } ~QuickMap(){ size_t len = 8 + sizeof(T*); for (size_t i = 0; i < entries; ++i){ delete *(T**)(void*)(ptr+len*i+8); } } T & get(uint64_t idx){ static T blank; size_t len = 8 + sizeof(T*); for (size_t i = 0; i < entries; ++i){ if (*((uint64_t*)(void*)(ptr+len*i)) == idx){ return **(T**)(void*)(ptr+len*i+8); } } return blank; } void insert(uint64_t idx, T elem){ size_t i = 0; size_t len = 8 + sizeof(T*); for (i = 0; i < entries; ++i){ if (*((uint64_t*)(void*)(ptr+len*i)) == idx){ *(T**)(void*)(ptr+len*i+8) = new T(elem); return; } } entries = i+1; ptr.allocate(len*entries); *(T**)(void*)(ptr+len*i+8) = new T(elem); *((uint64_t*)(void*)(ptr+len*i)) = idx; } }; struct fragSet{ uint64_t firstPart; uint64_t lastPart; uint64_t firstTime; uint64_t lastTime; }; class OutMP4 : public HTTPOutput{ public: OutMP4(Socket::Connection &conn); ~OutMP4(); static void init(Util::Config *cfg); uint64_t mp4HeaderSize(uint64_t &fileSize, int fragmented = 0) const; bool mp4Header(Util::ResizeablePointer & headOut, uint64_t &size, int fragmented = 0); uint64_t mp4moofSize(uint64_t startFragmentTime, uint64_t endFragmentTime, uint64_t &mdatSize) const; virtual void sendFragmentHeaderTime(uint64_t startFragmentTime, uint64_t endFragmentTime); // this builds the moof box for fragmented MP4 void findSeekPoint(uint64_t byteStart, uint64_t &seekPoint, uint64_t headerSize); void appendSinglePacketMoof(Util::ResizeablePointer& moofOut, size_t extraBytes = 0); size_t fragmentHeaderSize(std::deque& sortedTracks, std::set& trunOrder, uint64_t startFragmentTime, uint64_t endFragmentTime); void respondHTTP(const HTTP::Parser & req, bool headersOnly); void sendNext(); void sendHeader(); bool doesWebsockets() { return true; } void onWebsocketConnect(); void onWebsocketFrame(); void onIdle(); virtual bool onFinish(); protected: void sendWebsocketCodecData(const std::string& type); bool handleWebsocketSeek(JSON::Value& command); bool handleWebsocketSetSpeed(JSON::Value& command); bool stayLive; double target_rate; ///< Target playback speed rate (1.0 = normal, 0 = auto) uint64_t fileSize; uint64_t byteStart; uint64_t byteEnd; int64_t leftOver; uint64_t currPos; uint64_t seekPoint; uint64_t forwardTo; uint64_t nextHeaderTime; uint64_t headerSize; size_t prevVidTrack; // variables for standard MP4 std::set sortSet; // needed for unfragmented MP4, remembers the order of keyparts // variables for fragmented size_t fragSeqNum; // the sequence number of the next keyframe/fragment when producing // fragmented MP4's size_t vidTrack; // the video track we use as fragmenting base uint64_t realBaseOffset; // base offset for every moof packet // from sendnext bool sending3GP; uint64_t startTime; uint64_t endTime; bool chromeWorkaround; int keysOnly; uint64_t estimateFileSize() const; // This is a dirty solution... but it prevents copying and copying and copying again std::map currentPartSet; std::string protectionHeader(size_t idx); Util::ResizeablePointer webBuf; }; }// namespace Mist typedef Mist::OutMP4 mistOut;