From 3f66afff241f8eae82ee3d2894ed9edfd5308101 Mon Sep 17 00:00:00 2001 From: Oswald Auguste de Bruin Date: Fri, 18 Oct 2013 16:33:42 +0200 Subject: [PATCH] Ogg optimises. --- lib/bitstream.cpp | 214 ++++++++++++++++++++++++++++++ lib/bitstream.h | 56 ++++++++ lib/ogg.cpp | 6 +- lib/vorbis.cpp | 326 +++++++++++++++++++++++++++++++++++++++++++--- lib/vorbis.h | 23 +++- 5 files changed, 601 insertions(+), 24 deletions(-) create mode 100644 lib/bitstream.cpp create mode 100644 lib/bitstream.h diff --git a/lib/bitstream.cpp b/lib/bitstream.cpp new file mode 100644 index 00000000..7994f00a --- /dev/null +++ b/lib/bitstream.cpp @@ -0,0 +1,214 @@ +#include"bitstream.h" +#include +#include +#include + +namespace Utils{ + bitstream::bitstream(){ + data = NULL; + offset = 0; + dataSize = 0; + bufferSize = 0; + } + + bool bitstream::checkBufferSize(unsigned int size){ + if (size > bufferSize){ + void* temp = realloc(data, size); + if (temp){ + data = (char*) temp; + bufferSize = size; + return true; + }else{ + return false; + } + }else{ + return true; + } + } + + void bitstream::append(char* input, size_t bytes){ + if (checkBufferSize(dataSize+bytes)){ + memcpy(data+dataSize, input, bytes); + dataSize += bytes; + } + //std::cout << std::hex << std::string(data, dataSize) << std::dec << std::endl; + } + + void bitstream::append(std::string input){ + append((char*)input.c_str(), input.size()); + } + + bool bitstream::peekOffset(size_t peekOffset){ + peekOffset += offset; + return ((data[peekOffset >> 3]) >> (7 - (peekOffset & 7))) & 1; + } + + long long unsigned int bitstream::peek(size_t count){ + if (count > 64){ + std::cerr << "Utils::bitstream: Warning; Can not read "<< count <<" bits into a long long unsigned int!" << std::endl; + //return 0; + } + if (count > size()){ + std::cerr << "Utils::bitstream: not enough bits left in stream. Left: " << size() << " requested: " << count << std::endl; + return 0; + } + long long unsigned int retval = 0; + size_t curPlace = 0; + size_t readSize; + size_t readOff; + char readBuff; + while (curPlace < count){ + readBuff = data[(int)((offset+curPlace)/8)]; + readSize = 8; + readOff = (offset + curPlace) % 8; //the reading offset within the byte + if (readOff != 0){ + //if we start our read not on the start of a byte + //curplace and retval should both be 0 + //this should be the first read that aligns reading to bytes, if we read over the end of read byte + //we cut the MSb off of the buffer by bit mask + readSize -= readOff;//defining starting bit + readBuff = readBuff & ((1 << readSize) - 1);//bitmasking + } + //up until here we assume we read to the end of the byte + if (count - curPlace < readSize){//if we do not read to the end of the byte + //we cut off the LSb off of the read buffer by bitshift + readSize = count - curPlace; + readBuff = readBuff >> (8 - readSize - readOff); + } + retval = (retval << readSize) + readBuff; + curPlace += readSize; + } + return retval; + } + + long long unsigned int bitstream::get(size_t count){ + if(count <= size()){ + long long unsigned int retVal; + retVal = peek(count); + skip(count); + return retVal; + }else{ + return 0; + } + } + + void bitstream::skip(size_t count){ + if(count <= size()){ + offset += count; + }else{ + offset = dataSize*8; + } + + } + + long long unsigned int bitstream::size(){ + return (dataSize * 8) - offset; + } + + void bitstream::clear(){ + dataSize = 0; + offset = 0; + } + + void bitstream::flush(){ + memmove(data, data + (offset/8), dataSize - (offset/8)); + dataSize -= offset / 8; + offset %= 8; + } + + long long unsigned int bitstream::golombPeeker(){ + for (size_t i = 0; i < 64 && i < size(); i++){ + if (peekOffset(i)){ + return peek((i * 2) + 1 ); + } + } + return 0; + } + + long long unsigned int bitstream::golombGetter(){ + for (size_t i = 0; i < 64 && i < size(); i++){ + if (peekOffset(i)){ + return get((i * 2) + 1); + } + } + return 0; + } + + long long int bitstream::getExpGolomb(){ + long long unsigned int temp = golombGetter(); + return (temp >> 1) * (1 - ((temp & 1) << 1)); //Is actually return (temp / 2) * (1 - (temp & 1) * 2); + } + + long long unsigned int bitstream::getUExpGolomb(){ + return golombGetter() - 1; + } + + long long int bitstream::peekExpGolomb(){ + long long unsigned int temp = golombPeeker(); + return (temp >> 1) * (1 - ((temp & 1) << 1)); //Is actually return (temp / 2) * (1 - (temp & 1) * 2); + } + + long long unsigned int bitstream::peekUExpGolomb(){ + return golombPeeker() - 1; + } + +//Note: other bitstream here + bitstreamLSBF::bitstreamLSBF(){ + readBufferOffset = 0; + readBuffer = 0; + } + + void bitstreamLSBF::append (char* input, size_t bytes){ + append(std::string(input,bytes)); + } + + void bitstreamLSBF::append (std::string input){ + data += input; + fixData(); + } + + long long unsigned int bitstreamLSBF::size(){ + return data.size() * 8 + readBufferOffset; + } + + long long unsigned int bitstreamLSBF::get(size_t count){ + if (count <= 32 && count <= readBufferOffset){ + long long unsigned int retval = readBuffer & (((long long unsigned int)1 << count) - 1); + readBuffer = readBuffer >> count; + readBufferOffset -= count; + fixData(); + return retval; + } + return 42; + } + + void bitstreamLSBF::skip(size_t count){ + if (count <= 32 && count <= readBufferOffset){ + readBuffer = readBuffer >> count; + readBufferOffset -= count; + fixData(); + } + } + + long long unsigned int bitstreamLSBF::peek(size_t count){ + if (count <= 32 && count <= readBufferOffset){ + return readBuffer & ((1 << count) - 1); + } + return 0; + } + + void bitstreamLSBF::clear(){ + data = ""; + readBufferOffset = 0; + readBuffer = 0; + } + + void bitstreamLSBF::fixData(){ + 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); + readBufferOffset += 8; + } + } +} diff --git a/lib/bitstream.h b/lib/bitstream.h new file mode 100644 index 00000000..d06d9406 --- /dev/null +++ b/lib/bitstream.h @@ -0,0 +1,56 @@ +#include + +namespace Utils{ + class bitstream{ + public: + bitstream(); + bitstream& operator<< (std::string input){ + append(input); + return *this; + }; + void append (char* input, size_t bytes); + void append (std::string input); + long long unsigned int size(); + void skip(size_t count); + long long unsigned int get(size_t count); + long long unsigned int peek(size_t count); + bool peekOffset(size_t peekOffset); + void flush(); + void clear(); + long long int getExpGolomb(); + long long unsigned int getUExpGolomb(); + long long int peekExpGolomb(); + long long unsigned int peekUExpGolomb(); + private: + bool checkBufferSize(unsigned int size); + long long unsigned int golombGetter(); + long long unsigned int golombPeeker(); + char* data; + size_t offset; + size_t dataSize; + size_t bufferSize; + }; + + class bitstreamLSBF{ + public: + bitstreamLSBF(); + bitstreamLSBF& operator<< (std::string input){ + append(input); + return *this; + }; + void append (char* input, size_t bytes); + void append (std::string input); + long long unsigned int size(); + void skip(size_t count); + long long unsigned int get(size_t count); + long long unsigned int peek(size_t count); + void clear(); + std::string data; + private: + long long unsigned int readBuffer; + int readBufferOffset; + void fixData(); + }; +} + + diff --git a/lib/ogg.cpp b/lib/ogg.cpp index 4668bbf7..bfffe720 100644 --- a/lib/ogg.cpp +++ b/lib/ogg.cpp @@ -177,7 +177,9 @@ namespace OGG{ } inline void Page::setPageSegments(char newVal){ - data[26] = newVal; + if(checkDataSize(26)){ + data[26] = newVal; + } } char* Page::getSegmentTable(){ @@ -432,7 +434,7 @@ namespace OGG{ return retVal; } - bool Page::checkDataSize(unsigned int size){ + inline bool Page::checkDataSize(unsigned int size){ if (size > datasize){ void* tmp = realloc(data,size); if (tmp){ diff --git a/lib/vorbis.cpp b/lib/vorbis.cpp index 4eead952..52327563 100644 --- a/lib/vorbis.cpp +++ b/lib/vorbis.cpp @@ -1,10 +1,27 @@ -#include"vorbis.h" -#include -#include -#include +#include "vorbis.h" +#include +#include +#include #include +#include "bitstream.h" +#include + +#include +#include 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 reverseByte32(long long unsigned int input){ + return ((input & 0xFF000000) >> 24)| ((input & 0xFF0000) >> 8) | ((input & 0xFF00) << 8) | ((input & 0xFF) << 24); + } + header::header(){ data = NULL; @@ -65,20 +82,21 @@ namespace vorbis{ } char header::getBlockSize0(){ - if (getHeaderType() == 1){ - return (data[28]>>4) & 0x0F; - }else{ - return 0; - } - } - - char header::getBlockSize1(){ if (getHeaderType() == 1){ return data[28] & 0x0F; }else{ return 0; } } + + char header::getBlockSize1(){ + if (getHeaderType() == 1){ + return (data[28]>>4) & 0x0F; + }else{ + return 0; + } + } + char header::getFramingFlag(){ if (getHeaderType() == 1){ @@ -140,9 +158,6 @@ namespace vorbis{ if (length < 7){ return false; } - /*if (! (newData[0] & 0x80)){ - return false; - }*/ if(memcmp(newData+1, "vorbis", 6)!=0){ return false; } @@ -154,8 +169,267 @@ namespace vorbis{ } return true; } + + std::deque header::readModeDeque(char audioChannels){ + Utils::bitstreamLSBF stream; + stream.append(data,datasize); + long long unsigned int beginsize = stream.size(); + stream.skip(28); //skipping common header part + stream.skip(28); //skipping common header part + char codebook_count = stream.get(8) + 1; + //std::cerr << "Codebook Count: " << (int)codebook_count << std::endl; + for (int i = 0; i < codebook_count; i++){ + //std::cerr << "codebook entry: " << i << std::endl; + long long unsigned int CMN = stream.get(24); + //std::cerr << " Codebook magic number: " << std::hex << CMN << std::dec << std::endl; + if (CMN != 0x564342){ + exit(1); + } + unsigned short codebook_dimensions = stream.get(16); + unsigned int codebook_entries = stream.get(24); + //std::cerr << " Codebook_dimensions, entries: "<< std::hex << codebook_dimensions << ", " < partition_class; + for (int o = 0; o < floorPartitions; o++){ + long long int temp = stream.get(4); + partition_class.push_back(temp); + //std::cerr << " partition_class: " << temp << std::endl; + if (temp>max) max = temp; + } + std::deque class_dimensions; + //std::cerr << " Max: " << max << std::endl; + for (int o = 0; o <= max; o++){ + class_dimensions.push_back(stream.get(3)+1);//class dimensions PUT IN ARRAY! + //std::cerr << " class dimension: " << class_dimensions.back() << std::endl; + 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); + //std::cerr << "ResidueType: " << residueType << std::endl; + 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 + //std::cerr<< " ResidueCLassification: " << residueClass << std::endl; + stream.skip(8);//residue classbook + for (int o = 0; o < residueClass; o++){ + char temp = stream.get(3);//low bits + bool bitFlag = stream.get(1); + //std::cerr << " bitFlag: " << bitFlag << std::endl; + if (bitFlag){ + temp += stream.get(5) << 3; + } + //std::cerr << " temp: " << (int)temp << std::endl; + residueCascade.push_back(temp); + } + for (int o = 0; o < residueClass; o++){ + //std::cerr << " "; + for (int p = 0; p < 7; p++){ + if (((residueCascade[o] >> p) & 1) == 1){ + //std::cerr << "1"; + stream.skip(8); + }else{ + //std::cerr << "0"; + } + } + //std::cerr << std::endl; + } + }else{ + exit(0); + } + } + //std::cerr << "bits in to Mappings: " << (beginsize-stream.size()) << ", " << stream.size() << std::endl; + //Mappings + long long unsigned int mappings = stream.get(6) + 1; + //std::cerr << "Mapping count: " << mappings << std::endl; + for(int i = 0; i < mappings; i++){ + long long unsigned int mapType = stream.get(16); + //std::cerr << "MapType: " << mapType << std::endl; + if (mapType == 0){ + char mappingSubmaps = 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; + //std::cerr << " coupling steps: " << coupling_steps << std::endl; + //std::cerr << " AudioChannels: " << (int)audioChannels << std::endl; + for (int o = 0; o0){ + stream.skip(temp);//mapping magnitude + stream.skip(temp);//mapping angle + } + } + } + char meh = stream.get(2); + if (meh != 0){ + std::cerr << " Sanity Check ==0 : " << (int)meh << std::endl; + exit(0); + } + //std::cerr << " Mapping Submaps: " << mappingSubmaps << std::endl; + if (mappingSubmaps > 1){ + for (int o = 0; o < audioChannels; o++){ + stream.skip(4); + } + } + 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{ + exit(0); + } + } + //Modes + //std::cerr << "bits in to Modes: " << (beginsize-stream.size()) << ", " << stream.size() << std::endl; + long long unsigned int modes = stream.get(6) + 1; + //std::cerr << "Mode count: " << modes << std::endl; + std::deque retVal; + for (int i = 0; i < modes; i++){ + mode temp; + temp.blockFlag = stream.get(1); + //std::cerr << " blockFlag: " << temp.blockFlag << std::endl; + temp.windowType = stream.get(16); + //std::cerr << " windowType: " << temp.windowType << std::endl; + temp.transformType = stream.get(16); + //std::cerr << " transformType: " << temp.transformType << std::endl; + temp.mapping = stream.get(8); + //std::cerr << " mapping: " << (int)temp.mapping << std::endl; + retVal.push_back(temp); + } + //std::cerr << "Ending Bitflag (!=0): " << stream.get(1) << std::endl; + stream.skip(1); + //std::cerr << "bits left: " << (beginsize-stream.size()) << ", " << stream.size() << std::endl; + return retVal; + } uint32_t header::getInt32(size_t index){ if (datasize >= (index + 3)){ @@ -180,8 +454,24 @@ namespace vorbis{ std::string header::toPrettyString(size_t indent){ std::stringstream r; - r << "Testing vorbis Pretty string" << 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 3ef5c57a..139ba3d2 100644 --- a/lib/vorbis.h +++ b/lib/vorbis.h @@ -1,9 +1,22 @@ #pragma once -#include -#include -#include +#include +#include +#include +#include +#include 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; + } + class header{ public: header(); @@ -19,14 +32,16 @@ namespace vorbis{ char getBlockSize1(); char getFramingFlag(); std::string toPrettyString(size_t indent = 0); + std::deque readModeDeque(char audioChannels); 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; unsigned int datasize; bool checkDataSize(unsigned int size); bool validate(); - }; + }; }