#include "theora.h" #include #include #include #include namespace theora { bool header::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; } } 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)) { 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)) { 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; } header::header(char * newData, unsigned int length) { data = NULL; datasize = 0; read(newData, length); } 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 ((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) { 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() { 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); } char header::getLFLIMS(size_t index) { if (getHeaderType() != 2) { return 0; } if (index >= 64) { return 0; } char NBITS = (data[0] >> 5) & 0x07; return NBITS; } 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++) { 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 (long unsigned int i = 0; i < getNComments(); i++) { result << std::string(indent + 4, ' ') << "[" << i << "] " << getUserComment(i) << std::endl; } break; case 2: result << std::string(indent + 2, ' ') << "NBITS: " << (int)getLFLIMS(0) << std::endl; } 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; } } 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) { 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(); } }