diff --git a/lib/bitstream.cpp b/lib/bitstream.cpp index 01d5d5da..ef513913 100644 --- a/lib/bitstream.cpp +++ b/lib/bitstream.cpp @@ -158,10 +158,11 @@ namespace Utils { } void bitstreamLSBF::append(char * input, size_t bytes) { - append(std::string(input, bytes)); + data.append(input, bytes); + fixData(); } - void bitstreamLSBF::append(std::string input) { + void bitstreamLSBF::append(std::string & input) { data += input; fixData(); } @@ -203,11 +204,12 @@ namespace Utils { } void bitstreamLSBF::fixData() { + unsigned int pos=0; while (readBufferOffset <= 32 && data.size() != 0) { - //readBuffer = readBuffer & ((1 << readBufferOffset) - 1) | (data[0] << readBufferOffset); - readBuffer |= (((long long unsigned int)data[0]) << readBufferOffset); - data = data.substr(1); + readBuffer |= (((long long unsigned int)data[pos]) << readBufferOffset); + pos++; readBufferOffset += 8; } + data.erase(0, pos); } } diff --git a/lib/bitstream.h b/lib/bitstream.h index 29ad39f0..d34d6424 100644 --- a/lib/bitstream.h +++ b/lib/bitstream.h @@ -43,7 +43,7 @@ namespace Utils { return *this; }; void append(char * input, size_t bytes); - void append(std::string input); + void append(std::string & input); long long unsigned int size(); void skip(size_t count); long long unsigned int get(size_t count); diff --git a/lib/dtsc.cpp b/lib/dtsc.cpp index ded23de4..c7d88e46 100644 --- a/lib/dtsc.cpp +++ b/lib/dtsc.cpp @@ -172,7 +172,7 @@ void DTSC::Stream::endStream() { if (!metadata.tracks.size()) { return; } - for (std::map::iterator it = metadata.tracks.begin(); it != metadata.tracks.end(); it++) { + for (std::map::iterator it = metadata.tracks.begin(); it != metadata.tracks.end(); it++) { JSON::Value newPack; newPack["time"] = (long long)it->second.lastms; newPack["trackid"] = it->first; @@ -387,7 +387,7 @@ DTSC::datatype DTSC::Stream::lastType() { /// Returns true if the current stream contains at least one video track. bool DTSC::Stream::hasVideo() { - for (std::map::iterator it = metadata.tracks.begin(); it != metadata.tracks.end(); it++) { + for (std::map::iterator it = metadata.tracks.begin(); it != metadata.tracks.end(); it++) { if (it->second.type == "video") { return true; } @@ -397,7 +397,7 @@ bool DTSC::Stream::hasVideo() { /// Returns true if the current stream contains at least one audio track. bool DTSC::Stream::hasAudio() { - for (std::map::iterator it = metadata.tracks.begin(); it != metadata.tracks.end(); it++) { + for (std::map::iterator it = metadata.tracks.begin(); it != metadata.tracks.end(); it++) { if (it->second.type == "audio") { return true; } @@ -470,7 +470,7 @@ int DTSC::Stream::canSeekms(unsigned int ms) { return 1; } //loop trough all the tracks - for (std::map::iterator it = metadata.tracks.begin(); it != metadata.tracks.end(); it++) { + for (std::map::iterator it = metadata.tracks.begin(); it != metadata.tracks.end(); it++) { if (it->second.keys.size()) { if (it->second.keys[0].getTime() <= ms && it->second.keys[it->second.keys.size() - 1].getTime() >= ms) { return 0; @@ -488,10 +488,10 @@ int DTSC::Stream::canSeekms(unsigned int ms) { return 1; } -DTSC::livePos DTSC::Stream::msSeek(unsigned int ms, std::set & allowedTracks) { - std::set seekTracks = allowedTracks; +DTSC::livePos DTSC::Stream::msSeek(unsigned int ms, std::set & allowedTracks) { + std::set seekTracks = allowedTracks; livePos result = buffers.begin()->first; - for (std::set::iterator it = allowedTracks.begin(); it != allowedTracks.end(); it++) { + for (std::set::iterator it = allowedTracks.begin(); it != allowedTracks.end(); it++) { if (metadata.tracks[*it].type == "video") { int trackNo = *it; seekTracks.clear(); @@ -514,12 +514,12 @@ DTSC::livePos DTSC::Stream::msSeek(unsigned int ms, std::set & allowedTrack /// Returns whether the current position is the last currently available position within allowedTracks. /// Simply returns the result of getNext(pos, allowedTracks) == pos -bool DTSC::Stream::isNewest(DTSC::livePos & pos, std::set & allowedTracks) { +bool DTSC::Stream::isNewest(DTSC::livePos & pos, std::set & allowedTracks) { return getNext(pos, allowedTracks) == pos; } /// Returns the next available position within allowedTracks, or the current position if no next is availble. -DTSC::livePos DTSC::Stream::getNext(DTSC::livePos & pos, std::set & allowedTracks) { +DTSC::livePos DTSC::Stream::getNext(DTSC::livePos & pos, std::set & allowedTracks) { std::map::iterator iter = buffers.upper_bound(pos); while (iter != buffers.end()) { if (allowedTracks.count(iter->first.trackID)) { @@ -856,7 +856,10 @@ void DTSC::File::seekNext() { } } } - if (insert) { + if (insert){ + if (tmpPos.seekTime > 0xffffffffffffff00ll){ + tmpPos.seekTime = 0; + } currentPositions.insert(tmpPos); } else { seek_time(myPack.getTime() + 1, myPack.getTrackId(), true); @@ -865,8 +868,7 @@ void DTSC::File::seekNext() { } } - -void DTSC::File::parseNext() { +void DTSC::File::parseNext(){ lastreadpos = ftell(F); if (fread(buffer, 4, 1, F) != 1) { if (feof(F)) { @@ -947,7 +949,7 @@ DTSC::Packet & DTSC::File::getPacket() { return myPack; } -bool DTSC::File::seek_time(unsigned int ms, int trackNo, bool forceSeek) { +bool DTSC::File::seek_time(unsigned int ms, unsigned int trackNo, bool forceSeek) { seekPos tmpPos; tmpPos.trackID = trackNo; if (!forceSeek && myPack && ms > myPack.getTime() && trackNo >= myPack.getTrackId()) { @@ -1012,7 +1014,10 @@ bool DTSC::File::seek_time(unsigned int ms, int trackNo, bool forceSeek) { continue; } } - DEBUG_MSG(DLVL_HIGH, "Seek to %d:%d resulted in %lli", trackNo, ms, tmpPos.seekTime); + //DEBUG_MSG(DLVL_HIGH, "Seek to %u:%d resulted in %lli", trackNo, ms, tmpPos.seekTime); + if (tmpPos.seekTime > 0xffffffffffffff00ll){ + tmpPos.seekTime = 0; + } currentPositions.insert(tmpPos); return true; } @@ -1022,7 +1027,7 @@ bool DTSC::File::seek_time(unsigned int ms, int trackNo, bool forceSeek) { bool DTSC::File::seek_time(unsigned int ms) { currentPositions.clear(); if (selectedTracks.size()) { - for (std::set::iterator it = selectedTracks.begin(); it != selectedTracks.end(); it++) { + for (std::set::iterator it = selectedTracks.begin(); it != selectedTracks.end(); it++) { seek_time(ms, (*it), true); } } @@ -1070,7 +1075,7 @@ bool DTSC::File::atKeyframe() { return false; } -void DTSC::File::selectTracks(std::set & tracks) { +void DTSC::File::selectTracks(std::set & tracks) { selectedTracks = tracks; currentPositions.clear(); seek_time(0); diff --git a/lib/dtsc.h b/lib/dtsc.h index d05e08eb..6f07ce33 100644 --- a/lib/dtsc.h +++ b/lib/dtsc.h @@ -163,8 +163,8 @@ namespace DTSC { } return (trackID < rhs.trackID); } - volatile long long unsigned int seekTime; - volatile unsigned int trackID; + long long unsigned int seekTime; + unsigned int trackID; }; /// A part from the DTSC::Stream ringbuffer. @@ -267,7 +267,7 @@ namespace DTSC { std::vector keySizes; long long unsigned int partLen; Part * parts; - int trackID; + unsigned int trackID; unsigned long long firstms; unsigned long long lastms; int bps; @@ -318,7 +318,7 @@ namespace DTSC { inline operator bool() const { return vod || live; } - std::map tracks; + std::map tracks; bool vod; bool live; bool merged; @@ -352,7 +352,7 @@ namespace DTSC { bool isFixed(); void toPrettyString(std::ostream & str, int indent = 0, int verbosity = 0); //members: - std::map tracks; + std::map tracks; }; /// A simple wrapper class that will open a file and allow easy reading/writing of DTSC data from/to it. @@ -375,20 +375,20 @@ namespace DTSC { void parseNext(); DTSC::Packet & getPacket(); bool seek_time(unsigned int ms); - bool seek_time(unsigned int ms, int trackNo, bool forceSeek = false); + 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 & tracks); + void selectTracks(std::set & tracks); private: long int endPos; void readHeader(int pos); DTSC::Packet myPack; JSON::Value metaStorage; readOnlyMeta metadata; - std::map trackMapping; + std::map trackMapping; long long int currtime; long long int lastreadpos; int currframe; @@ -397,7 +397,7 @@ namespace DTSC { void * buffer; bool created; std::set currentPositions; - std::set selectedTracks; + std::set selectedTracks; }; //FileWriter @@ -425,10 +425,10 @@ namespace DTSC { unsigned int getTime(); void dropRing(Ring * ptr); int canSeekms(unsigned int ms); - livePos msSeek(unsigned int ms, std::set & allowedTracks); + livePos msSeek(unsigned int ms, std::set & allowedTracks); void setBufferTime(unsigned int ms); - bool isNewest(DTSC::livePos & pos, std::set & allowedTracks); - DTSC::livePos getNext(DTSC::livePos & pos, std::set & allowedTracks); + bool isNewest(DTSC::livePos & pos, std::set & allowedTracks); + DTSC::livePos getNext(DTSC::livePos & pos, std::set & allowedTracks); void endStream(); void waitForMeta(Socket::Connection & sourceSocket, bool closeOnError = true); void waitForPause(Socket::Connection & sourceSocket); @@ -442,7 +442,7 @@ namespace DTSC { datatype datapointertype; unsigned int buffercount; unsigned int buffertime; - std::map trackMapping; + std::map trackMapping; virtual void deletionCallback(livePos deleting); }; } diff --git a/lib/dtscmeta.cpp b/lib/dtscmeta.cpp index 4be9c40a..43f1d729 100644 --- a/lib/dtscmeta.cpp +++ b/lib/dtscmeta.cpp @@ -1285,6 +1285,7 @@ namespace DTSC { void Track::reset() { fragments.clear(); parts.clear(); + keySizes.clear(); keys.clear(); bps = 0; firstms = 0; @@ -1392,7 +1393,7 @@ namespace DTSC { live = rhs.live; merged = rhs.merged; bufferWindow = rhs.bufferWindow; - for (std::map::const_iterator it = rhs.tracks.begin(); it != rhs.tracks.end(); it++) { + for (std::map::const_iterator it = rhs.tracks.begin(); it != rhs.tracks.end(); it++) { tracks[it->first] = it->second; } moreheader = rhs.moreheader; @@ -1897,7 +1898,7 @@ namespace DTSC { ///\brief Determines the "packed" size of a read-only meta object unsigned int readOnlyMeta::getSendLen() { unsigned int dataLen = 16 + (vod ? 14 : 0) + (live ? 15 : 0) + (merged ? 17 : 0) + (bufferWindow ? 24 : 0) + 21; - for (std::map::iterator it = tracks.begin(); it != tracks.end(); it++) { + for (std::map::iterator it = tracks.begin(); it != tracks.end(); it++) { dataLen += it->second.getSendLen(); } return dataLen + 8; //add 8 bytes header length @@ -1909,7 +1910,7 @@ namespace DTSC { writePointer(p, DTSC::Magic_Header, 4); writePointer(p, convertInt(dataLen), 4); writePointer(p, "\340\000\006tracks\340", 10); - for (std::map::iterator it = tracks.begin(); it != tracks.end(); it++) { + for (std::map::iterator it = tracks.begin(); it != tracks.end(); it++) { it->second.writeTo(p); } writePointer(p, "\000\000\356", 3); @@ -1940,7 +1941,7 @@ namespace DTSC { conn.SendNow(DTSC::Magic_Header, 4); conn.SendNow(convertInt(dataLen), 4); conn.SendNow("\340\000\006tracks\340", 10); - for (std::map::iterator it = tracks.begin(); it != tracks.end(); it++) { + for (std::map::iterator it = tracks.begin(); it != tracks.end(); it++) { it->second.send(conn); } conn.SendNow("\000\000\356", 3); @@ -1968,7 +1969,7 @@ namespace DTSC { ///\brief Determines the "packed" size of a meta object unsigned int Meta::getSendLen() { unsigned int dataLen = 16 + (vod ? 14 : 0) + (live ? 15 : 0) + (merged ? 17 : 0) + (bufferWindow ? 24 : 0) + 21; - for (std::map::iterator it = tracks.begin(); it != tracks.end(); it++) { + for (std::map::iterator it = tracks.begin(); it != tracks.end(); it++) { dataLen += it->second.getSendLen(); } return dataLen + 8; //add 8 bytes header @@ -1980,7 +1981,7 @@ namespace DTSC { writePointer(p, DTSC::Magic_Header, 4); writePointer(p, convertInt(dataLen), 4); writePointer(p, "\340\000\006tracks\340", 10); - for (std::map::iterator it = tracks.begin(); it != tracks.end(); it++) { + for (std::map::iterator it = tracks.begin(); it != tracks.end(); it++) { it->second.writeTo(p); } writePointer(p, "\000\000\356", 3);//End tracks object @@ -2011,7 +2012,7 @@ namespace DTSC { conn.SendNow(DTSC::Magic_Header, 4); conn.SendNow(convertInt(dataLen), 4); conn.SendNow("\340\000\006tracks\340", 10); - for (std::map::iterator it = tracks.begin(); it != tracks.end(); it++) { + for (std::map::iterator it = tracks.begin(); it != tracks.end(); it++) { it->second.send(conn); } conn.SendNow("\000\000\356", 3);//End tracks object @@ -2136,7 +2137,7 @@ namespace DTSC { ///\brief Converts a meta object to a JSON::Value JSON::Value Meta::toJSON() { JSON::Value result; - for (std::map::iterator it = tracks.begin(); it != tracks.end(); it++) { + for (std::map::iterator it = tracks.begin(); it != tracks.end(); it++) { result["tracks"][it->second.getWritableIdentifier()] = it->second.toJSON(); } if (vod) { @@ -2160,7 +2161,7 @@ namespace DTSC { ///\param indent the amount of indentation needed ///\param verbosity How verbose the output needs to be void readOnlyMeta::toPrettyString(std::ostream & str, int indent, int verbosity) { - for (std::map::iterator it = tracks.begin(); it != tracks.end(); it++) { + for (std::map::iterator it = tracks.begin(); it != tracks.end(); it++) { it->second.toPrettyString(str, indent, verbosity); } if (vod) { @@ -2183,7 +2184,7 @@ namespace DTSC { ///\param indent the amount of indentation needed ///\param verbosity How verbose the output needs to be void Meta::toPrettyString(std::ostream & str, int indent, int verbosity) { - for (std::map::iterator it = tracks.begin(); it != tracks.end(); it++) { + for (std::map::iterator it = tracks.begin(); it != tracks.end(); it++) { it->second.toPrettyString(str, indent, verbosity); } if (vod) { @@ -2204,7 +2205,7 @@ namespace DTSC { ///\brief Converts a read-only meta object to a JSON::Value JSON::Value readOnlyMeta::toJSON() { JSON::Value result; - for (std::map::iterator it = tracks.begin(); it != tracks.end(); it++) { + for (std::map::iterator it = tracks.begin(); it != tracks.end(); it++) { result["tracks"][it->second.getWritableIdentifier()] = it->second.toJSON(); } if (vod) { @@ -2225,14 +2226,14 @@ namespace DTSC { ///\brief Resets a meta object, removes all unimportant meta values void Meta::reset() { - for (std::map::iterator it = tracks.begin(); it != tracks.end(); it++) { + for (std::map::iterator it = tracks.begin(); it != tracks.end(); it++) { it->second.reset(); } } ///\brief Returns whether a read-only meta object is fixed or not bool readOnlyMeta::isFixed() { - for (std::map::iterator it = tracks.begin(); it != tracks.end(); it++) { + for (std::map::iterator it = tracks.begin(); it != tracks.end(); it++) { if (!it->second.keyLen || !(it->second.keys[it->second.keyLen - 1].getBpos())) { return false; } @@ -2242,7 +2243,7 @@ namespace DTSC { ///\brief Returns whether a meta object is fixed or not bool Meta::isFixed() { - for (std::map::iterator it = tracks.begin(); it != tracks.end(); it++) { + for (std::map::iterator it = tracks.begin(); it != tracks.end(); it++) { if (it->second.type == "meta" || it->second.type == "") { continue; } diff --git a/lib/ogg.cpp b/lib/ogg.cpp new file mode 100644 index 00000000..3a95507a --- /dev/null +++ b/lib/ogg.cpp @@ -0,0 +1,637 @@ +#include "ogg.h" +#include "defines.h" +#include +#include +#include +#include +#include +#include + +namespace OGG { + + oggSegment::oggSegment(){ + isKeyframe = 0; + frameNumber = 0; + timeStamp = 0; + framesSinceKeyFrame = 0; + } + + std::deque decodeXiphSize(char * data, size_t len){ + std::deque res; + res.push_back(0); + for (int i = 0; i < len; i++){ + *res.rbegin() += data[i]; + if (data[i] != 0xFF){ + res.push_back(0); + } + } + if (*res.rbegin() == 0){ + res.resize(res.size() - 1); + } + return res; + } + inline long long unsigned int get_64(char * data){ + long long unsigned int temp = 0; + for (int i = 7; i >= 0; --i){ + temp <<= 8; + temp += data[i]; + } + return temp; + } + + inline long unsigned int get_32(char * data){ + long unsigned int temp = 0; + for (int i = 3; i >= 0; --i){ + temp <<= 8; + temp += data[i]; + } + return temp; + } + + inline void set_64(char * data, long unsigned int val){ + for (int i = 0; i < 8; ++i){ + data[i] = val & 0xFF; + val >>= 8; + } + } + + + inline void set_32(char * data, long unsigned int val){ + for (int i = 0; i < 4; ++i){ + data[i] = val & 0xFF; + val >>= 8; + } + } + + + Page::Page(){ + framesSeen = 0; + lastKeyFrame = 0; + sampleRate = 0; + firstSample = 0; + pageSequenceNumber = 0; + totalFrames = 0; + memset(data, 0, 282); + } + + Page::Page(const Page & rhs){ + framesSeen=rhs.framesSeen; + pageSequenceNumber = rhs.pageSequenceNumber; + lastKeyFrame = rhs.lastKeyFrame; + sampleRate = rhs.sampleRate; + firstSample = rhs.firstSample; + totalFrames= rhs.totalFrames; + memcpy(data, rhs.data, 282); + segments = rhs.segments; + } + + void Page::operator = (const Page & rhs){ + framesSeen=rhs.framesSeen; + pageSequenceNumber = rhs.pageSequenceNumber; + lastKeyFrame = rhs.lastKeyFrame; + firstSample = rhs.firstSample; + sampleRate = rhs.sampleRate; + totalFrames= rhs.totalFrames; + memcpy(data, rhs.data, 282); + segments = rhs.segments; + } + + unsigned int Page::calcPayloadSize(){ + unsigned int retVal = 0; + for (int i = 0; i < segments.size(); i++){ + retVal += segments[i].size(); + } + return retVal; + } + + /// Reads an OGG Page from the source and if valid, removes it from source. + bool Page::read(std::string & newData){ + int len = newData.size(); + segments.clear(); + if (newData.size() < 27){ + return false; + } + if (newData.substr(0, 4) != "OggS"){ + DEBUG_MSG(DLVL_FAIL, "Invalid Ogg page encountered (magic number wrong: %s) - cannot continue", newData.c_str()); + return false; + } + memcpy(data, newData.c_str(), 27);//copying the header, always 27 bytes + if (newData.size() < 27u + getPageSegments()){ //check input size + return false; + } + newData.erase(0, 27); + memcpy(data + 27, newData.c_str(), getPageSegments()); + newData.erase(0, getPageSegments()); + std::deque segSizes = decodeXiphSize(data + 27, getPageSegments()); + for (std::deque::iterator it = segSizes.begin(); it != segSizes.end(); it++){ + segments.push_back(std::string(newData.data(), *it)); + newData.erase(0, *it); + } + INFO_MSG("Erased %lu bytes from the input", len - newData.size()); + return true; + } + + + bool Page::read(FILE * inFile){ + segments.clear(); + int oriPos = ftell(inFile); + //INFO_MSG("pos: %d", oriPos); + if (!fread(data, 27, 1, inFile)){ + fseek(inFile, oriPos, SEEK_SET); + FAIL_MSG("failed to fread(data, 27, 1, inFile) @ pos %d", oriPos); + return false; + } + if (std::string(data, 4) != "OggS"){ + DEBUG_MSG(DLVL_FAIL, "Invalid Ogg page encountered (magic number wrong: %s) - cannot continue bytePos %d", data, oriPos); + return false; + } + if (!fread(data + 27, getPageSegments(), 1, inFile)){ + fseek(inFile, oriPos, SEEK_SET); + FAIL_MSG("failed to fread(data + 27, getPageSegments() %d, 1, inFile) @ pos %d", getPageSegments(), oriPos); + return false; + } + std::deque segSizes = decodeXiphSize(data + 27, getPageSegments()); + for (std::deque::iterator it = segSizes.begin(); it != segSizes.end(); it++){ + if (*it){ + char * thisSeg = (char *)malloc(*it * sizeof(char)); + if (!thisSeg){ + DEBUG_MSG(DLVL_WARN, "malloc failed"); + } + if (!fread(thisSeg, *it, 1, inFile)){ + DEBUG_MSG(DLVL_WARN, "Unable to read a segment @ pos %d segment size: %d getPageSegments: %d", oriPos, *it, getPageSegments()); + fseek(inFile, oriPos, SEEK_SET); + return false; + } + segments.push_back(std::string(thisSeg, *it)); + free(thisSeg); + }else{ + segments.push_back(std::string("", 0)); + } + + } + + return true; + } + + bool Page::getSegment(unsigned int index, std::string & ret){ + if (index >= segments.size()){ + ret.clear(); + return false; + } + ret = segments[index]; + return true; + } + + const char * Page::getSegment(unsigned int index){ + if (index >= segments.size()){ + return 0; + } + return segments[index].data(); + } + + unsigned long Page::getSegmentLen(unsigned int index){ + if (index >= segments.size()){ + return 0; + } + return segments[index].size(); + } + + void Page::setMagicNumber(){ + memcpy(data, "OggS", 4); + } + + char Page::getVersion(){ + return data[4]; + } + + void Page::setVersion(char newVal){ + data[4] = newVal; + } + + char Page::getHeaderType(){ + return data[5]; + } + + void Page::setHeaderType(char newVal){ + data[5] = newVal; + } + + long long unsigned int Page::getGranulePosition(){ + return get_64(data + 6); + } + + void Page::setGranulePosition(long long unsigned int newVal){ + set_64(data + 6, newVal); + } + + long unsigned int Page::getBitstreamSerialNumber(){ + //return ntohl(((long unsigned int*)(data+14))[0]); + return get_32(data + 14); + } + + void Page::setBitstreamSerialNumber(long unsigned int newVal){ + set_32(data + 14, newVal); + } + + long unsigned int Page::getPageSequenceNumber(){ + return get_32(data + 18); + } + + void Page::setPageSequenceNumber(long unsigned int newVal){ + set_32(data + 18, newVal); + } + + long unsigned int Page::getCRCChecksum(){ + return get_32(data + 22); + } + + void Page::setCRCChecksum(long unsigned int newVal){ + set_32(data + 22, newVal); + } + + char Page::getPageSegments(){ + return data[26]; + } + + inline void Page::setPageSegments(char newVal){ + data[26] = newVal; + } + + bool Page::verifyChecksum(){ + if (getCRCChecksum() == calcChecksum()){ //NOTE: calcChecksum is currently not functional (it will always return 0) + return true; + } else { + return false; + } + } + + bool Page::possiblyContinued(){ + if (getPageSegments() == 255){ + if (data[281] == 255){ + return true; + } + } + return false; + } + + std::string Page::toPrettyString(size_t indent){ + std::stringstream r; + r << std::string(indent, ' ') << "Ogg page" << std::endl; + r << std::string(indent + 2, ' ') << "Version: " << (int)getVersion() << std::endl; + 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"; + } + } + r << " (" << (int)getHeaderType() << ")" << std::endl; + r << std::string(indent + 2, ' ') << "Granule position: " << std::hex << std::setw(16) << std::setfill('0') << getGranulePosition() << std::dec << std::endl; + r << std::string(indent + 2, ' ') << "Bitstream number: " << getBitstreamSerialNumber() << std::endl; + r << std::string(indent + 2, ' ') << "Sequence number: " << getPageSequenceNumber() << std::endl; + r << std::string(indent + 2, ' ') << "Checksum Correct: " << verifyChecksum() << std::endl; + //r << " Calced Checksum: " << std::hex << calcChecksum() << std::dec << std::endl; + r << std::string(indent + 2, ' ') << "Checksum: " << getCRCChecksum() << std::endl; + r << std::string(indent + 2, ' ') << (int)getPageSegments() << " segments:" << std::endl; + r << std::string(indent + 3, ' '); + for (int i = 0; i < segments.size(); i++){ + r << " " << segments[i].size(); + } + r << std::endl; + return r.str(); + } + + inline unsigned int crc32(unsigned int crc, const char * data, size_t len){ + static const unsigned int table[256] = { + 0x00000000U, 0x04C11DB7U, 0x09823B6EU, 0x0D4326D9U, + 0x130476DCU, 0x17C56B6BU, 0x1A864DB2U, 0x1E475005U, + 0x2608EDB8U, 0x22C9F00FU, 0x2F8AD6D6U, 0x2B4BCB61U, + 0x350C9B64U, 0x31CD86D3U, 0x3C8EA00AU, 0x384FBDBDU, + 0x4C11DB70U, 0x48D0C6C7U, 0x4593E01EU, 0x4152FDA9U, + 0x5F15ADACU, 0x5BD4B01BU, 0x569796C2U, 0x52568B75U, + 0x6A1936C8U, 0x6ED82B7FU, 0x639B0DA6U, 0x675A1011U, + 0x791D4014U, 0x7DDC5DA3U, 0x709F7B7AU, 0x745E66CDU, + 0x9823B6E0U, 0x9CE2AB57U, 0x91A18D8EU, 0x95609039U, + 0x8B27C03CU, 0x8FE6DD8BU, 0x82A5FB52U, 0x8664E6E5U, + 0xBE2B5B58U, 0xBAEA46EFU, 0xB7A96036U, 0xB3687D81U, + 0xAD2F2D84U, 0xA9EE3033U, 0xA4AD16EAU, 0xA06C0B5DU, + 0xD4326D90U, 0xD0F37027U, 0xDDB056FEU, 0xD9714B49U, + 0xC7361B4CU, 0xC3F706FBU, 0xCEB42022U, 0xCA753D95U, + 0xF23A8028U, 0xF6FB9D9FU, 0xFBB8BB46U, 0xFF79A6F1U, + 0xE13EF6F4U, 0xE5FFEB43U, 0xE8BCCD9AU, 0xEC7DD02DU, + 0x34867077U, 0x30476DC0U, 0x3D044B19U, 0x39C556AEU, + 0x278206ABU, 0x23431B1CU, 0x2E003DC5U, 0x2AC12072U, + 0x128E9DCFU, 0x164F8078U, 0x1B0CA6A1U, 0x1FCDBB16U, + 0x018AEB13U, 0x054BF6A4U, 0x0808D07DU, 0x0CC9CDCAU, + 0x7897AB07U, 0x7C56B6B0U, 0x71159069U, 0x75D48DDEU, + 0x6B93DDDBU, 0x6F52C06CU, 0x6211E6B5U, 0x66D0FB02U, + 0x5E9F46BFU, 0x5A5E5B08U, 0x571D7DD1U, 0x53DC6066U, + 0x4D9B3063U, 0x495A2DD4U, 0x44190B0DU, 0x40D816BAU, + 0xACA5C697U, 0xA864DB20U, 0xA527FDF9U, 0xA1E6E04EU, + 0xBFA1B04BU, 0xBB60ADFCU, 0xB6238B25U, 0xB2E29692U, + 0x8AAD2B2FU, 0x8E6C3698U, 0x832F1041U, 0x87EE0DF6U, + 0x99A95DF3U, 0x9D684044U, 0x902B669DU, 0x94EA7B2AU, + 0xE0B41DE7U, 0xE4750050U, 0xE9362689U, 0xEDF73B3EU, + 0xF3B06B3BU, 0xF771768CU, 0xFA325055U, 0xFEF34DE2U, + 0xC6BCF05FU, 0xC27DEDE8U, 0xCF3ECB31U, 0xCBFFD686U, + 0xD5B88683U, 0xD1799B34U, 0xDC3ABDEDU, 0xD8FBA05AU, + 0x690CE0EEU, 0x6DCDFD59U, 0x608EDB80U, 0x644FC637U, + 0x7A089632U, 0x7EC98B85U, 0x738AAD5CU, 0x774BB0EBU, + 0x4F040D56U, 0x4BC510E1U, 0x46863638U, 0x42472B8FU, + 0x5C007B8AU, 0x58C1663DU, 0x558240E4U, 0x51435D53U, + 0x251D3B9EU, 0x21DC2629U, 0x2C9F00F0U, 0x285E1D47U, + 0x36194D42U, 0x32D850F5U, 0x3F9B762CU, 0x3B5A6B9BU, + 0x0315D626U, 0x07D4CB91U, 0x0A97ED48U, 0x0E56F0FFU, + 0x1011A0FAU, 0x14D0BD4DU, 0x19939B94U, 0x1D528623U, + 0xF12F560EU, 0xF5EE4BB9U, 0xF8AD6D60U, 0xFC6C70D7U, + 0xE22B20D2U, 0xE6EA3D65U, 0xEBA91BBCU, 0xEF68060BU, + 0xD727BBB6U, 0xD3E6A601U, 0xDEA580D8U, 0xDA649D6FU, + 0xC423CD6AU, 0xC0E2D0DDU, 0xCDA1F604U, 0xC960EBB3U, + 0xBD3E8D7EU, 0xB9FF90C9U, 0xB4BCB610U, 0xB07DABA7U, + 0xAE3AFBA2U, 0xAAFBE615U, 0xA7B8C0CCU, 0xA379DD7BU, + 0x9B3660C6U, 0x9FF77D71U, 0x92B45BA8U, 0x9675461FU, + 0x8832161AU, 0x8CF30BADU, 0x81B02D74U, 0x857130C3U, + 0x5D8A9099U, 0x594B8D2EU, 0x5408ABF7U, 0x50C9B640U, + 0x4E8EE645U, 0x4A4FFBF2U, 0x470CDD2BU, 0x43CDC09CU, + 0x7B827D21U, 0x7F436096U, 0x7200464FU, 0x76C15BF8U, + 0x68860BFDU, 0x6C47164AU, 0x61043093U, 0x65C52D24U, + 0x119B4BE9U, 0x155A565EU, 0x18197087U, 0x1CD86D30U, + 0x029F3D35U, 0x065E2082U, 0x0B1D065BU, 0x0FDC1BECU, + 0x3793A651U, 0x3352BBE6U, 0x3E119D3FU, 0x3AD08088U, + 0x2497D08DU, 0x2056CD3AU, 0x2D15EBE3U, 0x29D4F654U, + 0xC5A92679U, 0xC1683BCEU, 0xCC2B1D17U, 0xC8EA00A0U, + 0xD6AD50A5U, 0xD26C4D12U, 0xDF2F6BCBU, 0xDBEE767CU, + 0xE3A1CBC1U, 0xE760D676U, 0xEA23F0AFU, 0xEEE2ED18U, + 0xF0A5BD1DU, 0xF464A0AAU, 0xF9278673U, 0xFDE69BC4U, + 0x89B8FD09U, 0x8D79E0BEU, 0x803AC667U, 0x84FBDBD0U, + 0x9ABC8BD5U, 0x9E7D9662U, 0x933EB0BBU, 0x97FFAD0CU, + 0xAFB010B1U, 0xAB710D06U, 0xA6322BDFU, 0xA2F33668U, + 0xBCB4666DU, 0xB8757BDAU, 0xB5365D03U, 0xB1F740B4U, + }; + + while (len > 0){ + crc = table[*data ^ ((crc >> 24) & 0xff)] ^ (crc << 8); + data++; + len--; + } + return crc; + } + + long unsigned int Page::calcChecksum(){ //implement in sending out page, probably delete this -- probably don't delete this because this function appears to be in use + long unsigned int retVal = 0; + /* + long unsigned int oldChecksum = getCRCChecksum(); + std::string fullPayload; + for (int i = 0; i < segments.size(); i++){ + fullPayload += segments[i]; + } + setCRCChecksum (0); + retVal = crc32( + crc32(0, data, 27 + getPageSegments()),//checksum over pageheader + fullPayload.data(), + fullPayload.size() + );//checksum over content + setCRCChecksum (oldChecksum); + */ + return retVal; + } + + int Page::getPayloadSize(){ + size_t res = 0; + for (int i = 0; i < segments.size(); i++){ + res += segments[i].size(); + } + return res; + } + + const std::deque & Page::getAllSegments(){ + return segments; + } + + void Page::prepareNext(bool continueMe){ + clear(0, -1, getBitstreamSerialNumber(), getPageSequenceNumber() + 1); + if (continueMe){ //noting that the page will be continued + setHeaderType(OGG::Continued); + } + } + + void Page::clear(char HeaderType, long long unsigned int GranPos, long unsigned int BSN, long unsigned int PSN){ + memset(data, 0, 27); + setMagicNumber(); + setVersion(); + setHeaderType(HeaderType); + setGranulePosition(GranPos); + setBitstreamSerialNumber(BSN); + setPageSequenceNumber(PSN); + } + + + unsigned int Page::addSegment(const std::string & payload){ //returns added bytes + segments.push_back(payload); + return payload.size(); + } + + unsigned int Page::addSegment(const char * content, unsigned int length){ + segments.push_back(std::string(content, length)); + return length; + } + + unsigned int Page::overFlow(){ //returns the amount of bytes that don't fit in this page from the segments; + unsigned int retVal = 0; + unsigned int curSegNum = 0;//the current segment number we are looking at + unsigned int segAmount = 0; + for (unsigned int i = 0; i < segments.size(); i++){ + segAmount = (segments[i].size() / 255) + 1; + if (segAmount + curSegNum > 255){ + retVal += ((segAmount - (255 - curSegNum + 1)) * 255) + (segments[i].size() % 255);//calculate the extra bytes that overflow + curSegNum = 255;//making sure the segment numbers are at maximum + } else { + curSegNum += segAmount; + } + } + return retVal; + } + + void Page::vorbisStuff(){ + Utils::bitstreamLSBF packet; + packet.append(oggSegments.rbegin()->dataString);//this is a heavy operation, it needs to be optimised //todo? + int curPCMSamples = 0; + long long unsigned int packetType = packet.get(1); + if (packetType == 0){ + int tempModes = vorbis::ilog(vorbisModes.size() - 1); + int tempPacket = packet.get(tempModes); + int curBlockFlag = vorbisModes[tempPacket].blockFlag; + curPCMSamples = (1 << blockSize[curBlockFlag]); + if (prevBlockFlag != -1){ + if (curBlockFlag == prevBlockFlag){ + curPCMSamples /= 2; + } else { + curPCMSamples -= (1 << blockSize[0]) / 4 + (1 << blockSize[1]) / 4; + } + } + prevBlockFlag = curBlockFlag; + } else { + ERROR_MSG("Error, Vorbis packet type !=0 actual type: %llu",packetType ); + } + //add to granule position + lastKeyFrame += curPCMSamples; + oggSegments.rbegin()->lastKeyFrameSeen = lastKeyFrame; + } + + ///this calculates the granule position for a DTSC packet + long long unsigned int Page::calculateGranule(oggSegment & currentSegment){ + long long unsigned int tempGranule = 0; + if (codec == OGG::THEORA){ + tempGranule = (currentSegment.lastKeyFrameSeen << split) | currentSegment.framesSinceKeyFrame; + } else if (codec == OGG::VORBIS){ + tempGranule = currentSegment.lastKeyFrameSeen; + } + return tempGranule; + } + + + bool Page::shouldSend(){ + unsigned int totalSegmentSize = 0; + if (!oggSegments.size()){ + return false; + } + if (oggSegments.rbegin()->isKeyframe){ + return true; + } + if (codec == OGG::VORBIS){ + if (lastKeyFrame - firstSample >= sampleRate){ + return true; + } + } + + for (unsigned int i = 0; i < oggSegments.size(); i++){ + totalSegmentSize += (oggSegments[i].dataString.size() / 255) + 1; + } + if (totalSegmentSize >= 255) return true; + + return false; + } + + ///\todo Rewrite this + void Page::sendTo(Socket::Connection & destination, int calcGranule){ //combines all data and sends it to socket + if (!oggSegments.size()){ + DEBUG_MSG(DLVL_HIGH, "!segments.size()"); + return; + } + if (codec == OGG::VORBIS){ + firstSample = lastKeyFrame; + } + int temp = 0; + long unsigned int checksum = 0; //reset checksum + setCRCChecksum(0); + unsigned int numSegments = oggSegments.size(); + int tableIndex = 0; + char tableSize = 0; + //char table[255]; + char * table = (char *)malloc(255); + int bytesLeft = 0; + for (unsigned int i = 0; i < numSegments; i++){ + //calculate amount of 255 bytes needed to store size (remainder not counted) + temp = (oggSegments[i].dataString.size() / 255); + //if everything still fits in the table + if ((temp + tableIndex + 1) <= 255){ + //set the 255 bytes + memset(table + tableIndex, 255, temp); + //increment tableIndex with 255 byte count + tableIndex += temp; + //set the last table entry to the remainder, and increase tableIndex with one + table[tableIndex++] = (oggSegments[i].dataString.size() % 255); + //update tableSize to be equal to tableIndex + tableSize = tableIndex; + bytesLeft = 0; + } else { + //stuff doesn't fit + //set the rest of the table to 255s + memset(table + tableIndex, 255, (255 - tableIndex)); + //table size is full table in use + tableSize = 255; + //space left on current page, for this segment: (255-tableIndex)*255 + bytesLeft = (255 - tableIndex) * 255; + if (oggSegments[i].dataString.size() == bytesLeft){ + bytesLeft = 0; //segment barely fits. + } + break; + } + } + + if (calcGranule < -1){ + if (numSegments == 1 && bytesLeft){ //no segment ends on this page. + granules = -1; + } else { + unsigned int tempIndex = numSegments - 1; + if (bytesLeft != 0){ + tempIndex = numSegments - 2; + } + granules = calculateGranule(oggSegments[tempIndex]); + } + } else { + granules = calcGranule; //force granule + } + setGranulePosition(granules); + + checksum = crc32(checksum, data, 22);//calculating the checksum over the first part of the page + checksum = crc32(checksum, &tableSize, 1); //calculating the checksum over the segment Table Size + checksum = crc32(checksum, table, tableSize);//calculating the checksum over the segment Table + + DEBUG_MSG(DLVL_DONTEVEN, "numSegments: %d", numSegments); + + for (unsigned int i = 0; i < numSegments; i++){ + //INFO_MSG("checksum, i: %d", i); + if (bytesLeft != 0 && ((i + 1) == numSegments)){ + checksum = crc32(checksum, oggSegments[i].dataString.data(), bytesLeft); + //take only part of this segment + } else { //take the entire segment + checksum = crc32(checksum, oggSegments[i].dataString.data(), oggSegments[i].dataString.size()); + } + } + + setCRCChecksum(checksum); + + destination.SendNow(data, 26); + destination.SendNow(&tableSize, 1); + destination.SendNow(table, tableSize); + + + for (unsigned int i = 0; i < numSegments; i++){ + if (bytesLeft != 0 && ((i + 1) == numSegments)){ + destination.SendNow(oggSegments.begin()->dataString.data(), bytesLeft); + oggSegments.begin()->dataString.erase(0, bytesLeft); + setHeaderType(OGG::Continued);//set continuation flag + break; + //for loop WILL exit after this. + } else { + destination.SendNow(oggSegments.begin()->dataString.data(), oggSegments.begin()->dataString.size()); + //this segment WILL be deleted + oggSegments.erase(oggSegments.begin()); + setHeaderType(OGG::Plain);//not a continuation + } + + } + + //done sending, assume start of new page. + //inc. page num, write to header + pageSequenceNumber++; + setPageSequenceNumber(pageSequenceNumber); + //granule still requires setting! + free(table); + return; + + + } +} + + + + diff --git a/lib/ogg.h b/lib/ogg.h new file mode 100644 index 00000000..e5a7f139 --- /dev/null +++ b/lib/ogg.h @@ -0,0 +1,141 @@ +#pragma once +#include +#include +#include +#include +#include +#include "dtsc.h" +#include "theora.h" +#include "vorbis.h" +#include "socket.h" + +namespace OGG { + + class oggSegment { + public: + oggSegment(); + std::string dataString; + int isKeyframe; + long long unsigned int lastKeyFrameSeen; + long long unsigned int framesSinceKeyFrame; + unsigned int frameNumber; + long long unsigned int timeStamp; + }; + + enum oggCodec {THEORA, VORBIS, OPUS}; + + enum HeaderType { + Plain = 0, + Continued = 1, + BeginOfStream = 2, + EndOfStream = 4 + }; + + std::deque decodeXiphSize(char * data, size_t len); + + + + + class Page { + public: + Page(); + Page(const Page & rhs); + void operator = (const Page & rhs); + bool read(std::string & newData); + bool read(FILE * inFile); + bool getSegment(unsigned int index, std::string & ret); + const char * getSegment(unsigned int index); + unsigned long getSegmentLen(unsigned int index); + void setMagicNumber(); + char getVersion(); + void setVersion(char newVal = 0); + char getHeaderType(); + void setHeaderType(char newVal); + long long unsigned int getGranulePosition(); + void setGranulePosition(long long unsigned int newVal); + long unsigned int getBitstreamSerialNumber(); + void setBitstreamSerialNumber(long unsigned int newVal); + long unsigned int getCRCChecksum(); + void setCRCChecksum(long unsigned int newVal); + long unsigned int getPageSequenceNumber(); + void setPageSequenceNumber(long unsigned int newVal); + char getPageSegments();//get the amount of page segments + inline void setPageSegments(char newVal);//set the amount of page segments + int getPayloadSize(); + const std::deque & getAllSegments(); + + bool possiblyContinued(); + + std::string toPrettyString(size_t indent = 0); + + long unsigned int calcChecksum(); + bool verifyChecksum(); + unsigned int calcPayloadSize(); + //void clear(); + void clear(char HeaderType, long long unsigned int GranPos, long unsigned int BSN, long unsigned int PSN); + void prepareNext(bool continueMe = false);//prepare the page to become the next page + bool setPayload(char * newData, unsigned int length); //probably obsolete + unsigned int addSegment(const std::string & content); //add a segment to the page, returns added bytes + unsigned int addSegment(const char * content, unsigned int length); //add a segment to the page, returns added bytes + void sendTo(Socket::Connection & destination, int calcGranule = -2); //combines all data and sends it to socket + unsigned int setNextSegmentTableEntry(unsigned int entrySize);//returns the size that could not be added to the table + unsigned int overFlow();//returns the amount of bytes that don't fit in this page from the segments; + + long long unsigned int calculateGranule(oggSegment & currentSegment); + bool shouldSend(); + void vorbisStuff();//process most recent segment + long long unsigned int totalFrames; + int granules; + OGG::oggCodec codec; + std::deque oggSegments; //used for ogg output + unsigned int pageSequenceNumber; + + unsigned int framesSeen; + unsigned int lastKeyFrame; + unsigned int firstSample;//for vorbis, to handle "when to send the page" + unsigned int sampleRate;//for vorbis, to handle the sampleRate + int prevBlockFlag; + char blockSize[2]; + std::deque vorbisModes;//modes for vorbis + unsigned int split; //KFGShift for theora + private: + char data[282];//Fulldata + std::deque segments; + + + }; + + class oggTrack { + public: + oggTrack() : KFGShift(0), lastTime(0), parsedHeaders(false), lastPageOffset(0), nxtSegment(0){ } + oggCodec codec; + std::string name; + std::string contBuffer;//buffer for continuing pages + long long unsigned int dtscID; + char KFGShift; + double lastTime; + long long unsigned int lastGran; + bool parsedHeaders; + long long unsigned int lastPageOffset; + unsigned int nxtSegment; + double msPerFrame; + Page myPage; + //Codec specific elements + //theora + // theora::header idHeader;//needed to determine keyframe //bullshit? + //vorbis + std::deque vModes; + char channels; + long long unsigned int blockSize[2]; + //unsigned long getBlockSize(unsigned int vModeIndex); + }; + + class headerPages { + public: + std::map DTSCID2OGGSerial; + std::map DTSCID2seqNum; + std::string parsedPages; + }; +} + + diff --git a/lib/theora.cpp b/lib/theora.cpp index 5d7348c9..72f6a02c 100644 --- a/lib/theora.cpp +++ b/lib/theora.cpp @@ -3,12 +3,13 @@ #include #include #include +#include "defines.h" namespace theora { - bool header::checkDataSize(unsigned int size) { - if (size > datasize) { + bool header::checkDataSize(unsigned int size){ + if (size > datasize){ void * tmp = realloc(data, size); - if (tmp) { + if (tmp){ data = (char *)tmp; datasize = size; return true; @@ -20,286 +21,241 @@ namespace theora { } } - uint32_t header::getInt32(size_t index) { - if (datasize >= (index + 3)) { + uint32_t header::getInt32(size_t index){ + if (datasize >= (index + 3)){ return (data[index] << 24) + (data[index + 1] << 16) + (data[index + 2] << 8) + data[index + 3]; } return 0; } - uint32_t header::getInt24(size_t index) { - if (datasize >= (index + 2)) { + uint32_t header::getInt24(size_t index){ + if (datasize >= (index + 2)){ return 0 + (data[index] << 16) + (data[index + 1] << 8) + data[index + 2]; } return 0; } - uint16_t header::getInt16(size_t index) { - if (datasize >= (index + 1)) { + uint16_t header::getInt16(size_t index){ + if (datasize >= (index + 1)){ return 0 + (data[index] << 8) + data[index + 1]; } return 0; } - uint32_t header::commentLen(size_t index) { - if (datasize >= index + 3) { + uint32_t header::commentLen(size_t index){ + if (datasize >= index + 3){ return data[index] + (data[index + 1] << 8) + (data[index + 2] << 16) + (data[index + 3] << 24); } return 0; } - header::header() { - data = NULL; - datasize = 0; + header::header(char * newData, unsigned int length){ + data = newData; + datasize = length; } - header::header(char * newData, unsigned int length) { - data = NULL; - datasize = 0; - read(newData, length); + header::~header(){ } - bool header::validateIdentificationHeader() { - if (datasize != 42) { + bool isHeader(const char * newData, unsigned int length){ + if (length < 7){ return false; } - if (getHeaderType() != 0) { + if (! newData[0] & 0x80){ + DEBUG_MSG(DLVL_FAIL, "newdata != 0x80: %0.2X", newData[0]); return false; } - if (getVMAJ() != 3) { - return false; - } - if (getVMIN() != 2) { - return false; - } - if (getFMBW() == 0) { - return false; - } - if (getFMBH() == 0) { - return false; - } - if ((short)getPICW() > getFMBW() * 16) { - return false; - } - if ((short)getPICH() > getFMBH() * 16) { - return false; - } - if ((short)getPICX() > (getFMBW() * 16) - (short)getPICW()) { - return false; - } - if ((short)getPICY() > (getFMBH() * 16) - (short)getPICH()) { - return false; - } - if (getFRN() == 0) { - return false; - } - if (getFRD() == 0) { + if (memcmp(newData + 1, "theora", 6) != 0){ return false; } return true; } - bool header::read(char * newData, unsigned int length) { - if (length < 7) { - return false; - } - if (!(newData[0] & 0x80)) { - return false; - } - if (memcmp(newData + 1, "theora", 6) != 0) { - return false; - } - if (checkDataSize(length)) { - memcpy(data, newData, length); - } else { - return false; - } - switch (getHeaderType()) { - case 0: - return validateIdentificationHeader(); - break; - case 1: - ///\todo Read Comment header - break; - case 2: - ///\todo Read Setup Header - break; - } - return true; - } - - int header::getHeaderType() { + int header::getHeaderType(){ return (data[0] & 0x7F); } - char header::getVMAJ() { - if (getHeaderType() == 0) { + char header::getVMAJ(){ + if (getHeaderType() == 0){ return data[7]; } return 0; } - char header::getVMIN() { - if (getHeaderType() == 0) { + char header::getVMIN(){ + if (getHeaderType() == 0){ return data[8]; } return 0; } - char header::getVREV() { - if (getHeaderType() == 0) { + char header::getVREV(){ + if (getHeaderType() == 0){ return data[9]; } return 0; } - short header::getFMBW() { - if (getHeaderType() == 0) { + short header::getFMBW(){ + if (getHeaderType() == 0){ return getInt16(10); } return 0; } - short header::getFMBH() { - if (getHeaderType() == 0) { + short header::getFMBH(){ + if (getHeaderType() == 0){ return getInt16(12); } return 0; } - char header::getPICX() { - if (getHeaderType() == 0) { + char header::getPICX(){ + if (getHeaderType() == 0){ return data[20]; } return 0; } - char header::getPICY() { - if (getHeaderType() == 0) { + char header::getPICY(){ + if (getHeaderType() == 0){ return data[21]; } return 0; } - char header::getKFGShift() { - if (getHeaderType() == 0) { + char header::getKFGShift(){ + if (getHeaderType() == 0){ return (getInt16(40) >> 5) & 0x1F; } return 0; } - long unsigned int header::getFRN() { - if (getHeaderType() == 0) { + long unsigned int header::getFRN(){ + if (getHeaderType() == 0){ return getInt32(22); } return 0; } - long unsigned int header::getPICH() { - if (getHeaderType() == 0) { + long unsigned int header::getPICH(){ + if (getHeaderType() == 0){ return getInt24(17); } return 0; } - long unsigned int header::getPICW() { - if (getHeaderType() == 0) { + long unsigned int header::getPICW(){ + if (getHeaderType() == 0){ return getInt24(14); } return 0; } - long unsigned int header::getFRD() { - if (getHeaderType() == 0) { + long unsigned int header::getFRD(){ + if (getHeaderType() == 0){ return getInt32(26); } return 0; } - long unsigned int header::getPARN() { - if (getHeaderType() == 0) { + long unsigned int header::getPARN(){ + if (getHeaderType() == 0){ return getInt24(30); } return 0; } - long unsigned int header::getPARD() { - if (getHeaderType() == 0) { + long unsigned int header::getPARD(){ + if (getHeaderType() == 0){ return getInt24(33); } return 0; } - char header::getCS() { - if (getHeaderType() == 0) { + char header::getCS(){ + if (getHeaderType() == 0){ return data[36]; } return 0; } - long unsigned int header::getNOMBR() { - if (getHeaderType() == 0) { + long unsigned int header::getNOMBR(){ + if (getHeaderType() == 0){ return getInt24(37); } return 0; } - char header::getQUAL() { - if (getHeaderType() == 0) { + char header::getQUAL(){ + if (getHeaderType() == 0){ return (data[40] >> 3) & 0x1F; } return 0; } - char header::getPF() { - if (getHeaderType() == 0) { + char header::getPF(){ + if (getHeaderType() == 0){ return (data[41] >> 3) & 0x03; } return 0; } - std::string header::getVendor() { - if (getHeaderType() != 1) { + std::string header::getVendor(){ + if (getHeaderType() != 1){ return ""; } return std::string(data + 11, commentLen(7)); } - long unsigned int header::getNComments() { - if (getHeaderType() != 1) { + long unsigned int header::getNComments(){ + if (getHeaderType() != 1){ return 0; } int offset = 11 + commentLen(7); return commentLen(offset); } - char header::getLFLIMS(size_t index) { - if (getHeaderType() != 2) { + char header::getLFLIMS(size_t index){ + if (getHeaderType() != 2){ return 0; } - if (index >= 64) { + if (index >= 64){ return 0; } char NBITS = (data[0] >> 5) & 0x07; return NBITS; } - std::string header::getUserComment(size_t index) { - if (index >= getNComments()) { + std::string header::getUserComment(size_t index){ + if (index >= getNComments()){ return ""; } int offset = 11 + commentLen(7) + 4; - for (size_t i = 0; i < index; i++) { + for (size_t i = 0; i < index; i++){ offset += 4 + commentLen(offset); } return std::string(data + offset + 4, commentLen(offset)); } - std::string header::toPrettyString(size_t indent) { + char header::getFTYPE(){ + return (data[0] >> 6) & 0x01; + } + + bool header::isHeader(){ + return ::theora::isHeader(data, datasize); + } + + std::string header::toPrettyString(size_t indent){ std::stringstream result; + if(!isHeader()){ + result << std::string(indent, ' ') << "Theora Frame" << std::endl; + result << std::string(indent + 2, ' ') << "FType: " << (int)getFTYPE() << std::endl; + return result.str(); + } result << std::string(indent, ' ') << "Theora header" << std::endl; result << std::string(indent + 2, ' ') << "HeaderType: " << getHeaderType() << std::endl; - switch (getHeaderType()) { + switch (getHeaderType()){ case 0: result << std::string(indent + 2, ' ') << "VMAJ: " << (int)getVMAJ() << std::endl; result << std::string(indent + 2, ' ') << "VMIN: " << (int)getVMIN() << std::endl; @@ -322,7 +278,7 @@ namespace theora { case 1: result << std::string(indent + 2, ' ') << "Vendor: " << getVendor() << std::endl; result << std::string(indent + 2, ' ') << "User Comments (" << getNComments() << "):" << std::endl; - for (long unsigned int i = 0; i < getNComments(); i++) { + for (long unsigned int i = 0; i < getNComments(); i++){ result << std::string(indent + 4, ' ') << "[" << i << "] " << getUserComment(i) << std::endl; } break; @@ -331,69 +287,79 @@ namespace theora { } return result.str(); } + /* + frame::frame(){ + data = NULL; + datasize = 0; + } - frame::frame() { - data = NULL; - datasize = 0; - } + frame::~frame(){ + if (data){ + free(data); + } + data = 0; + } - bool frame::checkDataSize(unsigned int size) { - if (size > datasize) { - void * tmp = realloc(data, size); - if (tmp) { - data = (char *)tmp; - datasize = size; + bool frame::checkDataSize(unsigned int size){ + if (size > datasize){ + void * tmp = realloc(data, size); + if (tmp){ + data = (char *)tmp; + datasize = size; + return true; + } else { + return false; + } + } else { return true; + } + } + + bool frame::read(const char * newData, unsigned int length){ + if (length < 7){ + return false; + } + if ((newData[0] & 0x80)){ + return false; + } + if (checkDataSize(length)){ + memcpy(data, newData, length); } else { return false; } - } else { return true; } - } - bool frame::read(char * newData, unsigned int length) { - if (length < 7) { - return false; - } - if ((newData[0] & 0x80)) { - return false; - } - if (checkDataSize(length)) { - memcpy(data, newData, length); - } else { - return false; - } - return true; - } - char frame::getFTYPE() { - return (data[0] >> 6) & 0x01; - } - - char frame::getNQIS() { - return 0; - } - - char frame::getQIS(size_t index) { - if (index >= 3) { + char frame::getNQIS(){ return 0; } - return 0; - } - long long unsigned int header::parseGranuleUpper(long long unsigned int granPos) { - return granPos >> getKFGShift(); - } + char frame::getQIS(size_t index){ + if (index >= 3){ + return 0; + } + return 0; + } +*/ +/* + long long unsigned int header::parseGranuleUpper(long long unsigned int granPos){ + return granPos >> getKFGShift(); + } - long long unsigned int header::parseGranuleLower(long long unsigned int granPos) { - return (granPos & ((1 << getKFGShift()) - 1)); - } - - std::string frame::toPrettyString(size_t indent) { - std::stringstream result; - result << std::string(indent, ' ') << "Theora Frame" << std::endl; - result << std::string(indent + 2, ' ') << "FType: " << (int)getFTYPE() << std::endl; - return result.str(); - } + long long unsigned int header::parseGranuleLower(long long unsigned int granPos){ + return (granPos & ((1 << getKFGShift()) - 1)); + }*/ +/* + std::string frame::toPrettyString(size_t indent){ + std::stringstream result; + result << std::string(indent, ' ') << "Theora Frame" << std::endl; + result << std::string(indent + 2, ' ') << "FType: " << (int)getFTYPE() << std::endl; + return result.str(); + }*/ } + + + + + diff --git a/lib/theora.h b/lib/theora.h index a5f04786..28c066e6 100644 --- a/lib/theora.h +++ b/lib/theora.h @@ -4,11 +4,12 @@ #include namespace theora { + + bool isHeader(const char * newData, unsigned int length); class header { - public: - header(); - header(char * newData, unsigned int length); - bool read(char * newData, unsigned int length); + public: + ~header(); + header(char * newData, unsigned int length); // if managed is true, this class manages the data pointer int getHeaderType(); char getVMAJ(); char getVMIN(); @@ -32,9 +33,13 @@ namespace theora { long unsigned int getNComments(); std::string getUserComment(size_t index); char getLFLIMS(size_t index); - std::string toPrettyString(size_t indent = 0); - long long unsigned int parseGranuleUpper(long long unsigned int granPos); - long long unsigned int parseGranuleLower(long long unsigned int granPos); + std::string toPrettyString(size_t indent = 0); //update this, it should check (header) type and output relevant stuff only. + //long long unsigned int parseGranuleUpper(long long unsigned int granPos); + //long long unsigned int parseGranuleLower(long long unsigned int granPos); + ///\todo put this back in pravate + unsigned int datasize; + bool isHeader(); + char getFTYPE();//for frames protected: uint32_t getInt32(size_t index); uint32_t getInt24(size_t index); @@ -42,22 +47,22 @@ namespace theora { uint32_t commentLen(size_t index); private: char * data; - unsigned int datasize; - bool checkDataSize(unsigned int size); - bool validateIdentificationHeader(); - }; - - class frame { - public: - frame(); - bool read(char * newData, unsigned int length); - char getFTYPE(); - char getNQIS(); - char getQIS(size_t index); - std::string toPrettyString(size_t indent = 0); - private: - char * data; - unsigned int datasize; - bool checkDataSize(unsigned int size); + bool checkDataSize(unsigned int size); }; + /* + class frame{ // we don't need this. I hope. + public: + frame(); + ~frame(); + bool read(const char* newData, unsigned int length); + char getFTYPE(); + char getNQIS(); + char getQIS(size_t index); + std::string toPrettyString(size_t indent = 0); + private: + char * data; + unsigned int datasize; + bool checkDataSize(unsigned int size); + };*/ } + diff --git a/lib/vorbis.cpp b/lib/vorbis.cpp index 72e66c58..0e088c70 100644 --- a/lib/vorbis.cpp +++ b/lib/vorbis.cpp @@ -10,224 +10,236 @@ #include #include -namespace vorbis { - long long unsigned int reverseByte16(long long unsigned int input) { +namespace vorbis{ + long long unsigned int reverseByte16(long long unsigned int input){ return ((input & 0xFF00) >> 8) | ((input & 0xFF) << 8); } - long long unsigned int reverseByte24(long long unsigned int input) { - return ((input & 0xFF0000) >> 16) | (input & 0xFF00) | ((input & 0xFF) << 16); + long long unsigned int reverseByte24(long long unsigned int input){ + return ((input & 0xFF0000) >> 16)| (input & 0xFF00) | ((input & 0xFF) << 16); } - long long unsigned int reverseByte32(long long unsigned int input) { - return ((input & 0xFF000000) >> 24) | ((input & 0xFF0000) >> 8) | ((input & 0xFF00) << 8) | ((input & 0xFF) << 24); + long long unsigned int reverseByte32(long long unsigned int input){ + return ((input & 0xFF000000) >> 24)| ((input & 0xFF0000) >> 8) | ((input & 0xFF00) << 8) | ((input & 0xFF) << 24); } - - header::header() { - data = NULL; - datasize = 0; + header::header(char * newData, unsigned int length){ + data = newData; + datasize = length; + } + + header::~header(){ } - header::header(char * newData, unsigned int length) { - data = NULL; - datasize = 0; - read(newData, length); - } - - int header::getHeaderType() { + int header::getHeaderType(){ return (int)(data[0]); } - - long unsigned int header::getVorbisVersion() { - if (getHeaderType() == 1) { + + long unsigned int header::getVorbisVersion(){ + if (getHeaderType() == 1){ return getInt32(7); - } else { + }else{ return 0; } } - - char header::getAudioChannels() { - if (getHeaderType() == 1) { + + char header::getAudioChannels(){ + if (getHeaderType() == 1){ return data[11]; - } else { + }else{ return 0; } } - - long unsigned int header::getAudioSampleRate() { - if (getHeaderType() == 1) { + + long unsigned int header::getAudioSampleRate(){ + if (getHeaderType() == 1){ return ntohl(getInt32(12)); - } else { + }else{ return 0; } } - - long unsigned int header::getBitrateMaximum() { - if (getHeaderType() == 1) { + + long unsigned int header::getBitrateMaximum(){ + if (getHeaderType() == 1){ return getInt32(16); - } else { + }else{ return 0; } } - - long unsigned int header::getBitrateNominal() { - if (getHeaderType() == 1) { + + long unsigned int header::getBitrateNominal(){ + if (getHeaderType() == 1){ return getInt32(20); - } else { + }else{ return 0; } } - - long unsigned int header::getBitrateMinimum() { - if (getHeaderType() == 1) { + + long unsigned int header::getBitrateMinimum(){ + if (getHeaderType() == 1){ return getInt32(24); - } else { + }else{ return 0; } } - - char header::getBlockSize0() { - if (getHeaderType() == 1) { + + char header::getBlockSize0(){ + if (getHeaderType() == 1){ return data[28] & 0x0F; - } else { + }else{ return 0; } } - char header::getBlockSize1() { - if (getHeaderType() == 1) { - return (data[28] >> 4) & 0x0F; - } else { + char header::getBlockSize1(){ + if (getHeaderType() == 1){ + return (data[28]>>4) & 0x0F; + }else{ return 0; } } - - char header::getFramingFlag() { - if (getHeaderType() == 1) { + + char header::getFramingFlag(){ + if (getHeaderType() == 1){ return data[29]; - } else { + }else{ return 0; } } - - bool header::checkDataSize(unsigned int size) { - if (size > datasize) { - void * tmp = realloc(data, size); - if (tmp) { - data = (char *)tmp; + + bool header::checkDataSize(unsigned int size){ + if (size > datasize){ + void* tmp = realloc(data,size); + if (tmp){ + data = (char*)tmp; datasize = size; return true; - } else { + }else{ return false; } - } else { + }else{ return true; } } - bool header::validate() { - switch (getHeaderType()) { + bool header::validate(){ + switch(getHeaderType()){ case 1://ID header - if (datasize != 30) { + if (datasize!=30){ return false; } - if (getVorbisVersion() != 0) { + if (getVorbisVersion()!=0){ return false; } - if (getAudioChannels() <= 0) { + if (getAudioChannels()<=0){ return false; }; - if (getAudioSampleRate() <= 0) { + if (getAudioSampleRate()<=0) { return false; } - if (getBlockSize0() > getBlockSize1()) { + if (getBlockSize0()>getBlockSize1()){ return false; }; - if (getFramingFlag() != 1) { + if (getFramingFlag()!=1){ return false; }; - break; + break; case 3://comment header - break; + break; case 5://init header - break; + break; default: return false; - break; + break; } return true; } - - bool header::read(char * newData, unsigned int length) { - if (length < 7) { + + bool isHeader(const char * newData, unsigned int length){ + if (length < 7){ return false; } - if (memcmp(newData + 1, "vorbis", 6) != 0) { + if(memcmp(newData+1, "vorbis", 6)!=0){ + return false; + } + return true; + } + + bool header::isHeader(){ + return ::vorbis::isHeader(data, datasize); + } + + +/* + bool header::read(const char* newData, unsigned int length){ + if (length < 7){ + return false; + } + if(memcmp(newData+1, "vorbis", 6)!=0){ return false; } - if (checkDataSize(length)) { + if (checkDataSize(length)){ memcpy(data, newData, length); - } else { + }else{ return false; } return true; - } - - std::deque header::readModeDeque(char audioChannels) { + }*/ + + std::deque header::readModeDeque(char audioChannels){ Utils::bitstreamLSBF stream; - stream.append(data, datasize); + stream.append(data,datasize); stream.skip(28); //skipping common header part stream.skip(28); //skipping common header part char codebook_count = stream.get(8) + 1; - for (int i = 0; i < codebook_count; i++) { + 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); + 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); unsigned int codebook_entries = stream.get(24); bool orderedFlag = stream.get(1); - if (!orderedFlag) { + if (!orderedFlag){ bool sparseFlag = stream.get(1); - if (sparseFlag) { //sparse flag + if (sparseFlag){//sparse flag //sparse handling - for (unsigned int o = 0; o < codebook_entries; o++) { - if (stream.get(1)) { + for (unsigned int o = 0; o < codebook_entries; o++){ + if (stream.get(1)){ stream.skip(5); } } - } else { - for (unsigned int o = 0; o < codebook_entries; o++) { + }else{ + for (unsigned int o = 0; o < codebook_entries; o++){ stream.skip(5); } } - } else { + }else{ //ordered handling stream.skip(5); - for (unsigned int o = 0; o < codebook_entries; o++) { - int readnow = (std::log(codebook_entries - o)) / (std::log(2)) + 1; - o += stream.get(readnow); - + for (unsigned int o = 0; o < codebook_entries; o++){ + int readnow = (std::log(codebook_entries-o))/(std::log(2))+1; + o+=stream.get(readnow); + } } char codebook_lookup_type = stream.get(4); - if (codebook_lookup_type != 0) { + if (codebook_lookup_type != 0){ stream.skip(32); stream.skip(32); char codebook_value_bits = stream.get(4) + 1; stream.skip(1); unsigned int codebook_lookup_value; - if (codebook_lookup_type == 1) { - codebook_lookup_value = std::pow(codebook_entries, (1.0 / codebook_dimensions)); - } else { + if (codebook_lookup_type == 1){ + codebook_lookup_value = std::pow(codebook_entries, (1.0/codebook_dimensions)); + }else{ codebook_lookup_value = codebook_entries * codebook_dimensions; } - for (unsigned int i = 0; i < codebook_lookup_value; i++) { + for (unsigned int i = 0; i < codebook_lookup_value; i++){ stream.skip(codebook_value_bits); } } @@ -235,140 +247,140 @@ namespace vorbis { //end of codebooks //time domain transforms long long unsigned int TDT = stream.get(6) + 1; - for (unsigned int i = 0; i < TDT; i++) { + for (unsigned int i = 0; i < TDT; i++){ stream.skip(16); } //Floors long long unsigned int floors = stream.get(6) + 1; - for (unsigned int i = 0; i < floors; i++) { + for (unsigned int i = 0; i < floors; i++){ long long unsigned int floorType = stream.get(16); - switch (floorType) { - case 0: { - DEBUG_MSG(DLVL_WARN, "FloorType 0 in vorbis setup header not tested!"); - stream.skip(8);//order - stream.skip(16);//rate - stream.skip(16);//bark_map_size - stream.skip(6);//amplitude bits - stream.skip(8);//amplitude offset - long long unsigned int numberOfBooks = stream.get(4) + 1; - for (unsigned int o = 0; o < numberOfBooks; o++) { - stream.skip(8);//book list array - } - break; + switch(floorType){ + case 0:{ + DEBUG_MSG(DLVL_WARN, "FloorType 0 in vorbis setup header not tested!"); + stream.skip(8);//order + stream.skip(16);//rate + stream.skip(16);//bark_map_size + stream.skip(6);//amplitude bits + stream.skip(8);//amplitude offset + long long unsigned int numberOfBooks = stream.get(4)+1; + for (unsigned int o = 0; o < numberOfBooks; o++){ + stream.skip(8);//book list array } - case 1: { - long long unsigned int floorPartitions = stream.get(5); - long long int max = -1; - std::deque partition_class; - for (unsigned int o = 0; o < floorPartitions; o++) { - long long int temp = stream.get(4); - partition_class.push_back(temp); - if (temp > max) max = temp; - } - std::deque class_dimensions; - for (int o = 0; o <= max; o++) { - class_dimensions.push_back(stream.get(3) + 1); //class dimensions PUT IN ARRAY! - int class_subclass = stream.get(2); - if (class_subclass != 0) { - stream.skip(8);//class_master_books - } - for (int p = 0; p < (1 << class_subclass); p++) { - stream.skip(8); - } - } - stream.skip(2);//floor1_multiplier - int rangebits = stream.get(4);//rangebits - long long unsigned int count = 0; - long long unsigned int skipper = 0; - for (unsigned int o = 0; o < floorPartitions; o++) { - count += class_dimensions[(partition_class[o])]; - while (skipper < count) { - stream.skip(rangebits); - skipper ++; - } - } - break; + break; + } + case 1:{ + long long unsigned int floorPartitions = stream.get(5); + long long int max = -1; + std::deque partition_class; + for (unsigned int o = 0; o < floorPartitions; o++){ + long long int temp = stream.get(4); + partition_class.push_back(temp); + if (temp>max) max = temp; } + std::deque class_dimensions; + for (int o = 0; o <= max; o++){ + class_dimensions.push_back(stream.get(3)+1);//class dimensions PUT IN ARRAY! + int class_subclass = stream.get(2); + if (class_subclass !=0){ + stream.skip(8);//class_master_books + } + for (int p = 0; p < (1< residueCascade; long long unsigned int residueType = stream.get(16); - if (residueType <= 2) { + if(residueType<=2){ stream.skip(24);//residue begin stream.skip(24);//residue end stream.skip(24);//residue partition size - long long unsigned int residueClass = stream.get(6) + 1; //residue classifications + long long unsigned int residueClass = stream.get(6)+1;//residue classifications stream.skip(8);//residue classbook - for (unsigned int o = 0; o < residueClass; o++) { + for (unsigned int o = 0; o < residueClass; o++){ char temp = stream.get(3);//low bits bool bitFlag = stream.get(1); - if (bitFlag) { + if (bitFlag){ temp += stream.get(5) << 3; } residueCascade.push_back(temp); } - for (unsigned int o = 0; o < residueClass; o++) { - for (unsigned int p = 0; p < 7; p++) { - if (((residueCascade[o] >> p) & 1) == 1) { + for (unsigned int o = 0; o < residueClass; o++){ + for (unsigned int p = 0; p < 7; p++){ + if (((residueCascade[o] >> p) & 1) == 1){ stream.skip(8); - } else { + }else{ } } } - } else { + }else{ exit(0); } } //Mappings long long unsigned int mappings = stream.get(6) + 1; - for (unsigned int i = 0; i < mappings; i++) { + for(unsigned int i = 0; i < mappings; i++){ long long unsigned int mapType = stream.get(16); - if (mapType == 0) { + if (mapType == 0){ char mappingSubmaps = 1; - if (stream.get(1) == 1) { + if (stream.get(1)==1){ mappingSubmaps = stream.get(4);//vorbis mapping submaps } long long unsigned int coupling_steps = 0; - if (stream.get(1) == 1) { - coupling_steps = stream.get(8) + 1; - for (unsigned int o = 0; o < coupling_steps; o++) { - int temp = (std::log((audioChannels - o) - 1)) / (std::log(2)) + 1; - if (temp > 0) { + if (stream.get(1)==1){ + coupling_steps = stream.get(8)+1; + for (unsigned int o = 0; o0){ stream.skip(temp);//mapping magnitude stream.skip(temp);//mapping angle } } } char meh = stream.get(2); - if (meh != 0) { + if (meh != 0){ DEBUG_MSG(DLVL_ERROR, "Sanity check ==0 : %i", (int)meh); exit(0); } - if (mappingSubmaps > 1) { - for (int o = 0; o < audioChannels; o++) { + if (mappingSubmaps > 1){ + for (int o = 0; o < audioChannels; o++){ stream.skip(4); } } - for (int o = 0; o < mappingSubmaps; o++) { + for (int o = 0; o < mappingSubmaps; o++){ stream.skip(8);//placeholder stream.skip(8);//vorbis Mapping subfloor stream.skip(8);//vorbis mapping submap residue } - - } else { + + }else{ exit(0); } } //Modes long long unsigned int modes = stream.get(6) + 1; std::deque retVal; - for (unsigned int i = 0; i < modes; i++) { + for (unsigned int i = 0; i < modes; i++){ mode temp; temp.blockFlag = stream.get(1); temp.windowType = stream.get(16); @@ -380,46 +392,46 @@ namespace vorbis { return retVal; } - uint32_t header::getInt32(size_t index) { - if (datasize >= (index + 3)) { + uint32_t header::getInt32(size_t index){ + if (datasize >= (index + 3)){ return (data[index] << 24) + (data[index + 1] << 16) + (data[index + 2] << 8) + data[index + 3]; } return 0; } - uint32_t header::getInt24(size_t index) { - if (datasize >= (index + 2)) { + uint32_t header::getInt24(size_t index){ + if (datasize >= (index + 2)){ return 0 + (data[index] << 16) + (data[index + 1] << 8) + data[index + 2]; } return 0; } - uint16_t header::getInt16(size_t index) { - if (datasize >= (index + 1)) { + uint16_t header::getInt16(size_t index){ + if (datasize >= (index + 1)){ return 0 + (data[index] << 8) + data[index + 1]; } return 0; } - - std::string header::toPrettyString(size_t indent) { + + std::string header::toPrettyString(size_t indent){ std::stringstream r; - r << std::string(indent + 1, ' ') << "Vorbis Header" << std::endl; - r << std::string(indent + 2, ' ') << "Magic Number: " << std::string(data + 1, 6) << std::endl; - r << std::string(indent + 2, ' ') << "Header Type: " << getHeaderType() << std::endl; - if (getHeaderType() == 1) { - r << std::string(indent + 2, ' ') << "ID Header" << std::endl; - r << std::string(indent + 2, ' ') << "VorbisVersion: " << getVorbisVersion() << std::endl; - r << std::string(indent + 2, ' ') << "AudioChannels: " << (int)getAudioChannels() << std::endl; - r << std::string(indent + 2, ' ') << "BitrateMaximum: " << std::hex << getBitrateMaximum() << std::dec << std::endl; - r << std::string(indent + 2, ' ') << "BitrateNominal: " << std::hex << getBitrateNominal() << std::dec << std::endl; - r << std::string(indent + 2, ' ') << "BitrateMinimum: " << std::hex << getBitrateMinimum() << std::dec << std::endl; - r << std::string(indent + 2, ' ') << "BlockSize0: " << (int)getBlockSize0() << std::endl; - r << std::string(indent + 2, ' ') << "BlockSize1: " << (int)getBlockSize1() << std::endl; - r << std::string(indent + 2, ' ') << "FramingFlag: " << (int)getFramingFlag() << std::endl; - } else if (getHeaderType() == 3) { - r << std::string(indent + 2, ' ') << "Comment Header" << std::endl; - } else if (getHeaderType() == 5) { - r << std::string(indent + 2, ' ') << "Setup Header" << std::endl; + r << std::string(indent+1,' ') << "Vorbis Header" << std::endl; + r << std::string(indent+2,' ') << "Magic Number: " << std::string(data + 1,6) << std::endl; + r << std::string(indent+2,' ') << "Header Type: " << getHeaderType() << std::endl; + if (getHeaderType() == 1){ + r << std::string(indent+2,' ') << "ID Header" << std::endl; + r << std::string(indent+2,' ') << "VorbisVersion: " << getVorbisVersion() << std::endl; + r << std::string(indent+2,' ') << "AudioChannels: " << (int)getAudioChannels() << std::endl; + r << std::string(indent+2,' ') << "BitrateMaximum: " << std::hex << getBitrateMaximum() << std::dec << std::endl; + r << std::string(indent+2,' ') << "BitrateNominal: " << std::hex << getBitrateNominal() << std::dec << std::endl; + r << std::string(indent+2,' ') << "BitrateMinimum: " << std::hex << getBitrateMinimum() << std::dec << std::endl; + r << std::string(indent+2,' ') << "BlockSize0: " << (int)getBlockSize0() << std::endl; + r << std::string(indent+2,' ') << "BlockSize1: " << (int)getBlockSize1() << std::endl; + r << std::string(indent+2,' ') << "FramingFlag: " << (int)getFramingFlag() << std::endl; + } else if (getHeaderType() == 3){ + r << std::string(indent+2,' ') << "Comment Header" << std::endl; + } else if (getHeaderType() == 5){ + r << std::string(indent+2,' ') << "Setup Header" << std::endl; } return r.str(); } diff --git a/lib/vorbis.h b/lib/vorbis.h index 8d2e20db..a5c885c9 100644 --- a/lib/vorbis.h +++ b/lib/vorbis.h @@ -5,23 +5,23 @@ #include #include -namespace vorbis { - struct mode { +namespace vorbis{ + struct mode{ bool blockFlag; unsigned short windowType; unsigned short transformType; char mapping; }; - - inline unsigned int ilog(unsigned int input) { - return (std::log(input)) / (std::log(2)) + 1; + + inline unsigned int ilog(unsigned int input){ + return (std::log(input))/(std::log(2))+1; } - - class header { - public: - header(); - header(char * newData, unsigned int length); - bool read(char * newData, unsigned int length); + + bool isHeader(const char * newData, unsigned int length); + class header{ + public: + ~header(); + header(char* newData, unsigned int length); int getHeaderType(); long unsigned int getVorbisVersion(); char getAudioChannels(); @@ -34,15 +34,19 @@ namespace vorbis { char getFramingFlag(); std::string toPrettyString(size_t indent = 0); std::deque readModeDeque(char audioChannels); + bool isHeader(); + unsigned int getDataSize(){ + return datasize; + } protected: uint32_t getInt32(size_t index); uint32_t getInt24(size_t index); uint16_t getInt16(size_t index); private: std::deque modes; - char * data; + char* data; unsigned int datasize; bool checkDataSize(unsigned int size); bool validate(); - }; + }; }