From a2f088ad80153e71f7a87a823136997220b5992e Mon Sep 17 00:00:00 2001 From: Erik Zandvliet Date: Mon, 24 Jun 2013 09:36:27 +0200 Subject: [PATCH] Theora headers 1 and 2 working in analyser --- lib/ogg.cpp | 48 +++++-- lib/ogg.h | 8 +- lib/theora.cpp | 336 ++++++++++++++++++++++++++++++++++++------------- lib/theora.h | 39 +++++- 4 files changed, 324 insertions(+), 107 deletions(-) diff --git a/lib/ogg.cpp b/lib/ogg.cpp index e0d4d5b0..20a26c26 100644 --- a/lib/ogg.cpp +++ b/lib/ogg.cpp @@ -251,13 +251,17 @@ namespace OGG{ } return false; } + + void Page::setInternalCodec(std::string myCodec){ + codec = myCodec; + } - std::string Page::toPrettyString(){ + std::string Page::toPrettyString(size_t indent){ std::stringstream r; - r << "Size(" << getPageSize() << ")(" << dataSum << ")" << std::endl; - r << "Magic_Number: " << std::string(data, 4) << std::endl; - r << "Version: " << (int)getVersion() << std::endl; - r << "Header_type: " << std::hex << (int)getHeaderType() << std::dec; + r << std::string(indent,' ') << "OGG Page (" << getPageSize() << ")" << std::endl; + r << std::string(indent + 2,' ') << "Magic Number: " << std::string(data, 4) << std::endl; + r << std::string(indent + 2,' ') << "Version: " << (int)getVersion() << std::endl; + r << std::string(indent + 2,' ') << "Headertype: " << std::hex << (int)getHeaderType() << std::dec; if (typeContinue()){ r << " continued"; } @@ -268,19 +272,33 @@ namespace OGG{ r << " eos"; } r << std::endl; - r << "Granule_position: " < temp = getSegmentTableDeque(); for (std::deque::iterator i = temp.begin(); i != temp.end(); i++){ - r << (*i) << " "; + r << std::string(indent + 4,' ') << (*i) << std::endl; + } + r << std::string(indent + 2,' ') << "Payloadsize: " << dataSum << std::endl; + if (codec == "theora"){ + int offset = 0; + for (int i = 0; i < getSegmentTableDeque().size(); i++){ + theora::header tmpHeader; + int len = getSegmentTableDeque()[i]; + if (tmpHeader.read(getFullPayload()+offset,len)){ + r << tmpHeader.toPrettyString(indent + 4); + } + theora::frame tmpFrame; + if (tmpFrame.read(getFullPayload()+offset,len)){ + r << tmpFrame.toPrettyString(indent + 4); + } + offset += len; + } } - r << std::endl; return r.str(); } @@ -384,4 +402,8 @@ namespace OGG{ return true; } } + + int Page::getPayloadSize(){ + return dataSum; + } } diff --git a/lib/ogg.h b/lib/ogg.h index e9a363d8..8af19687 100644 --- a/lib/ogg.h +++ b/lib/ogg.h @@ -1,7 +1,9 @@ +#pragma once #include #include #include #include"dtsc.h" +#include "theora.h" namespace OGG{ class Page{ @@ -30,17 +32,19 @@ namespace OGG{ void setSegmentTable(char* newVal, unsigned int length); unsigned long int getPageSize(); char* getFullPayload(); - char* getSegment(long unsigned int); + int getPayloadSize(); bool typeBOS(); bool typeEOS(); bool typeContinue(); bool typeNone(); - std::string toPrettyString(); + std::string toPrettyString(size_t indent = 0); + void setInternalCodec(std::string myCodec); private: long unsigned int calcChecksum(); char* data; unsigned int datasize; unsigned int dataSum; bool checkDataSize(unsigned int size); + std::string codec; }; } diff --git a/lib/theora.cpp b/lib/theora.cpp index 0399f0ee..72160062 100644 --- a/lib/theora.cpp +++ b/lib/theora.cpp @@ -2,6 +2,7 @@ #include #include #include +#include namespace theora{ bool header::checkDataSize(unsigned int size){ @@ -19,73 +20,261 @@ namespace theora{ } } - /// Gets the 32 bits integer at the given index. - /// Attempts to resize the data pointer if the index is out of range. - /// Returns zero if resizing failed. uint32_t header::getInt32(size_t index){ - /*if (index + 3 >= datasize){ - if ( !reserve(index, 0, 4)){ - return 0; - } - setInt32(0, index); - }*/ - uint32_t result; - memcpy((char*) &result, data + index, 4); - return ntohl(result); + 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 (index + 3 >= datasize){ - if ( !reserve(index, 0, 4)){ - return 0; - } - setInt32(0, index); - }*/ - uint32_t result = 0; - //memcpy(((char*) &result)+1, data + index, 3); - result += data[index] << 16; - result += data[index+1] << 8; - result += data[index+2]; - return result; + 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 (index + 3 >= datasize){ - if ( !reserve(index, 0, 4)){ - return 0; - } - setInt32(0, index); - }*/ - uint16_t result; - memcpy((char*) &result, data + index, 2); - return ntohs(result); + 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){ + return data[index] + (data[index + 1] << 8) + (data[index + 2] << 16) + (data[index + 3] << 24); + } + return 0; + } header::header(){ data = NULL; datasize = 0; } + + bool header::validateIdentificationHeader(){ + if (datasize != 42){return false;} + if (getHeaderType() != 0){return false;} + if (getVMAJ() != 3){return false;} + if (getVMIN() != 2){return false;} + if (getFMBW() == 0){return false;} + if (getFMBH() == 0){return false;} + if (getPICW() > getFMBW() * 16){return false;} + if (getPICH() > getFMBH() * 16){return false;} + if (getPICX() > (getFMBW() * 16) - getPICW()){return false;} + if (getPICY() > (getFMBH() * 16) - getPICH()){return false;} + if (getFRN() == 0){return false;} + if (getFRD() == 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; } - switch(newData[0]){ - case 0x80: - //if (length != 42) return false; + if (checkDataSize(length)){ + memcpy(data, newData, length); + }else{ + return false; + } + switch(getHeaderType()){ + case 0: + return validateIdentificationHeader(); break; - case 0x81: + case 1: + ///\todo Read Comment header break; - case 0x82: + case 2: + ///\todo Read Setup Header break; - default: + } + return true; + } + + int header::getHeaderType(){ + return (data[0] & 0x7F); + } + + char header::getVMAJ(){ + if (getHeaderType() == 0){return data[7];} + return 0; + } + + char header::getVMIN(){ + if (getHeaderType() == 0){return data[8];} + return 0; + } + + char header::getVREV(){ + if (getHeaderType() == 0){return data[9];} + return 0; + } + + short header::getFMBW(){ + if (getHeaderType() == 0){return getInt16(10);} + return 0; + } + + short header::getFMBH(){ + if (getHeaderType() == 0){return getInt16(12);} + return 0; + } + + char header::getPICX(){ + if (getHeaderType() == 0){return data[20];} + return 0; + } + + char header::getPICY(){ + if (getHeaderType() == 0){return data[21];} + return 0; + } + + char header::getKFGShift(){ + if (getHeaderType() == 0){return (getInt16(40) >> 5) & 0x1F;} + return 0; + } + + long unsigned int header::getFRN(){ + if (getHeaderType() == 0){return getInt32(22);} + return 0; + } + + long unsigned int header::getPICH(){ + if (getHeaderType() == 0){return getInt24(17);} + return 0; + } + + long unsigned int header::getPICW(){ + if (getHeaderType() == 0){return getInt24(14);} + return 0; + } + + long unsigned int header::getFRD(){ + if (getHeaderType() == 0){return getInt32(26);} + return 0; + } + + long unsigned int header::getPARN(){ + if (getHeaderType() == 0){return getInt24(30);} + return 0; + } + + long unsigned int header::getPARD(){ + if (getHeaderType() == 0){return getInt24(33);} + return 0; + } + + char header::getCS(){ + if (getHeaderType() == 0){return data[36];} + return 0; + } + + long unsigned int header::getNOMBR(){ + if (getHeaderType() == 0){return getInt24(37);} + return 0; + } + + char header::getQUAL(){ + if (getHeaderType() == 0){return (data[40] >> 3) & 0x1F;} + return 0; + } + + char header::getPF(){ + if (getHeaderType() == 0){return (data[41] >> 3) & 0x03;} + return 0; + } + + std::string header::getVendor(){ + if (getHeaderType() != 1){return "";} + return std::string(data + 11, commentLen(7)); + } + + long unsigned int header::getNComments(){ + if (getHeaderType() != 1){return 0;} + int offset = 11 + commentLen(7); + return commentLen(offset); + } + + std::string header::getUserComment(size_t index){ + if (index >= getNComments()){return "";} + int len; + int offset = 11 + commentLen(7) + 4; + for (int i = 0; i < index; i++){ + offset += 4 + commentLen(offset); + } + return std::string(data + offset + 4,commentLen(offset)); + } + + std::string header::toPrettyString(size_t indent){ + std::stringstream result; + result << std::string(indent,' ') << "Theora header" << std::endl; + result << std::string(indent+2,' ') << "HeaderType: " << getHeaderType() << std::endl; + switch (getHeaderType()){ + case 0: + result << std::string(indent+2,' ') << "VMAJ: " << (int)getVMAJ() << std::endl; + result << std::string(indent+2,' ') << "VMIN: " << (int)getVMIN() << std::endl; + result << std::string(indent+2,' ') << "VREV: " << (int)getVREV() << std::endl; + result << std::string(indent+2,' ') << "FMBW: " << getFMBW() << std::endl; + result << std::string(indent+2,' ') << "FMBH: " << getFMBH() << std::endl; + result << std::string(indent+2,' ') << "PICH: " << getPICH() << std::endl; + result << std::string(indent+2,' ') << "PICW: " << getPICW() << std::endl; + result << std::string(indent+2,' ') << "PICX: " << (int)getPICX() << std::endl; + result << std::string(indent+2,' ') << "PICY: " << (int)getPICY() << std::endl; + result << std::string(indent+2,' ') << "FRN: " << getFRN() << std::endl; + result << std::string(indent+2,' ') << "FRD: " << getFRD() << std::endl; + result << std::string(indent+2,' ') << "PARN: " << getPARN() << std::endl; + result << std::string(indent+2,' ') << "PARD: " << getPARD() << std::endl; + result << std::string(indent+2,' ') << "CS: " << (int)getCS() << std::endl; + result << std::string(indent+2,' ') << "NOMBR: " << getNOMBR() << std::endl; + result << std::string(indent+2,' ') << "QUAL: " << (int)getQUAL() << std::endl; + result << std::string(indent+2,' ') << "KFGShift: " << (int)getKFGShift() << std::endl; + break; + case 1: + result << std::string(indent+2,' ') << "Vendor: " << getVendor() << std::endl; + result << std::string(indent+2,' ') << "User Comments (" << getNComments() << "):" << std::endl; + for (int i = 0; i < getNComments(); i++){ + result << std::string(indent+4,' ') << "[" << i << "] " << getUserComment(i) << std::endl; + } + break; + } + return result.str(); + } + + frame::frame(){ + data = NULL; + datasize = 0; + } + + 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; - break; - }; + } + }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{ @@ -93,57 +282,24 @@ namespace theora{ } return true; } - - int header::getHeaderType(){ - switch(data[0]){ - case 0x80: - return 0; - break; - case 0x81: - return 1; - break; - case 0x82: - return 2; - break; - default: - return -1; - break; - }; + + char frame::getFTYPE(){ + return (data[0] >> 6) & 0x01; } - - char header::getKFGShift(){ - if (getHeaderType() == 0){ - return (getInt16(40) >> 5) & 0x1F; - } - return 0; - } - - long unsigned int header::getFRN(){ - if (getHeaderType() == 0){ - return getInt32(22); - } - return 0; - } - - long unsigned int header::getPICH(){ - if (getHeaderType() == 0){ - return getInt24(17); - } - return 0; - } - - long unsigned int header::getPICW(){ - if (getHeaderType() == 0){ - return getInt24(14); - } - return 0; - } - - long unsigned int header::getFRD(){ - if (getHeaderType() == 0){ - return getInt32(26); - } + + char frame::getNQIS(){ return 0; } + char frame::getQIS(size_t index){ + if (index >= 3){return 0;} + return 0; + } + + 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 99a7b6cc..6bfdb64f 100644 --- a/lib/theora.h +++ b/lib/theora.h @@ -1,5 +1,7 @@ +#pragma once #include #include +#include namespace theora{ class header{ @@ -7,18 +9,51 @@ namespace theora{ header(); bool read(char* newData, unsigned int length); int getHeaderType(); - char getKFGShift(); - long unsigned int getPICH();//movie height + char getVMAJ(); + char getVMIN(); + char getVREV(); + short getFMBW(); + short getFMBH(); long unsigned int getPICW();//movie width + long unsigned int getPICH();//movie height + char getPICX(); + char getPICY(); long unsigned int getFRN();//frame rate numerator long unsigned int getFRD();//frame rate denominator + long unsigned int getPARN(); + long unsigned int getPARD(); + char getCS(); + long unsigned int getNOMBR(); + char getQUAL(); + char getPF(); + char getKFGShift(); + std::string getVendor(); + long unsigned int getNComments(); + std::string getUserComment(size_t index); + std::string toPrettyString(size_t indent = 0); protected: uint32_t getInt32(size_t index); uint32_t getInt24(size_t index); uint16_t getInt16(size_t index); + 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); }; }