#include "bitfields.h" #include "defines.h" #include "encode.h" #include "flac.h" #include namespace FLAC{ /// Checks the first 4 bytes for the string "flaC". Implementing a basic FLAC header check, /// returning true if it is, false if not. bool is_header(const char *header){ if (header[0] != 'f') return false; if (header[1] != 'L') return false; if (header[2] != 'a') return false; if (header[3] != 'C') return false; return true; }// FLAC::is_header size_t utfBytes(char p){ if ((p & 0x80) == 0x00){return 1;} if ((p & 0xE0) == 0xC0){return 2;} if ((p & 0xF0) == 0xE0){return 3;} if ((p & 0xF8) == 0xF0){return 4;} if ((p & 0xFC) == 0xF8){return 5;} if ((p & 0xFE) == 0xFC){return 6;} if ((p & 0xFF) == 0xFE){return 7;} return 9; } uint32_t utfVal(char *p){ size_t bytes = utfBytes(*p); uint32_t ret = 0; if (bytes == 1){ ret = (uint32_t)*p; }else if (bytes == 2){ ret = (uint32_t)(*p & 0x1F) << 6; ret = ret | (*(p + 1) & 0x3f); }else if (bytes == 3){ ret = (uint32_t)(*p & 0x1F) << 6; ret = (ret | (*(p + 1) & 0x3f)) << 6; ret = ret | (*(p + 2) & 0x3f); }else if (bytes == 4){ ret = (uint32_t)(*p & 0x1F) << 6; ret = (ret | (*(p + 1) & 0x3f)) << 6; ret = (ret | (*(p + 2) & 0x3f)) << 6; ret = ret | (*(p + 3) & 0x3f); } return ret; } Frame::Frame(char *pkt){ data = pkt; if (data[0] != 0xFF || (data[1] & 0xFC) != 0xF8){ WARN_MSG("Sync code incorrect! Ignoring FLAC frame"); FAIL_MSG("%x %x", data[0], data[1]); data = 0; } } uint16_t Frame::samples(){ if (!data){return 0;} switch ((data[2] & 0xF0) >> 4){ case 0: return 0; // reserved case 1: return 192; case 2: return 576; case 3: return 1152; case 4: return 2304; case 5: return 4608; case 6: return 1; // 1b at end case 7: return 2; // 2b at end default: return 256 << (((data[2] & 0xf0) >> 4) - 8); } } uint32_t Frame::rate(){ if (!data){return 0;} switch (data[2] & 0x0F){ case 0: return 0; // get from STREAMINFO case 1: return 88200; case 2: return 176400; case 3: return 192000; case 4: return 8000; case 5: return 16000; case 6: return 22050; case 7: return 24000; case 8: return 32000; case 9: return 44100; case 10: return 48000; case 11: return 96000; case 12: return 1; // 1b at end, *1000 case 13: return 2; // 2b at end case 14: return 3; // 2b at end, *10 case 15: return 0; // invalid, get from STREAMINFO default: return 0; } } uint8_t Frame::channels(){ if (!data){return 0;} uint8_t ret = ((data[3] & 0xF0) >> 4) + 1; if (ret > 8 && ret < 12){return 2;}// special stereo return ret; } uint8_t Frame::size(){ if (!data){return 0;} switch (data[3] & 0x0E){ case 0: return 0; // get from STREAMINFO case 1: return 8; case 2: return 12; case 3: return 0; // reserved case 4: return 16; case 5: return 20; case 6: return 24; case 7: return 0; // reserved default: return 0; } } uint32_t Frame::utfVal(){ return ::FLAC::utfVal(data + 4); } std::string Frame::toPrettyString(){ if (!data){return "Invalid frame";} std::stringstream r; r << "FLAC frame, " << ((data[1] & 0x1) ? "variable" : "fixed") << " block size, " << samples() << " samples, " << rate() << " Hz, " << (int)channels() << " Ch, " << (int)size() << "-bit" << std::endl; return r.str(); } MetaBlock::MetaBlock() : ptr(0), len(0){} MetaBlock::MetaBlock(const char *_ptr, size_t _len) : ptr(_ptr), len(_len){} std::string MetaBlock::getType(){ if (!ptr || !len){return "";} switch (ptr[0] & 0x7F){ case 0: return "STREAMINFO"; case 1: return "PADDING"; case 2: return "APPLICATION"; case 3: return "SEEKTABLE"; case 4: return "VORBIS_COMMENT"; case 5: return "CUESHEET"; case 6: return "PICTURE"; case 127: return "INVALID"; default: return "UNKNOWN"; } } size_t MetaBlock::getSize(){ if (!ptr || len < 4){return 0;} return Bit::btoh24(ptr + 1); } bool MetaBlock::getLast(){ if (!ptr || !len){return false;} return ptr[0] & 0x80; } void MetaBlock::toPrettyString(std::ostream &out){ if (len < 4){return;} out << getType() << " metadata block (" << getSize() << "b, " << (getLast() ? "last" : "non-last") << ")" << std::endl; } /// Helper function that calls the other toPrettyString function and returns the output as a string std::string MetaBlock::toPrettyString(){ std::stringstream str; toPrettyString(str); return str.str(); } uint16_t StreamInfo::getMinBlockSize(){ return Bit::btohs(ptr + 4); } uint16_t StreamInfo::getMaxBlockSize(){ return Bit::btohs(ptr + 6); } uint32_t StreamInfo::getMinFrameSize(){ return Bit::btoh24(ptr + 8); } uint32_t StreamInfo::getMaxFrameSize(){ return Bit::btoh24(ptr + 11); } uint32_t StreamInfo::getSampleRate(){ return ((uint64_t)ptr[14] << 12) + ((uint64_t)ptr[15] << 4) + ((ptr[16] & 0xf0) >> 4); } uint8_t StreamInfo::getChannels(){ return ((ptr[16] & 0x0e) >> 1) + 1; } uint8_t StreamInfo::getBits(){ return ((ptr[17] & 0xf0) >> 4) + (ptr[16] & 1) * 16 + 1; } uint64_t StreamInfo::getSamples(){ return ((uint64_t)(ptr[17] & 0x0f) << 32) + ((uint64_t)ptr[18] << 24) + ((uint64_t)ptr[19] << 16) + ((uint64_t)ptr[20] << 8) + ptr[21]; } std::string StreamInfo::getMD5(){ return Encodings::Hex::encode(std::string(ptr + 19, 16)); } void StreamInfo::toPrettyString(std::ostream &out){ if (len < 4){return;} out << getType() << " metadata block (" << getSize() << "b, " << (getLast() ? "last" : "non-last") << "):" << std::endl; out << " Min block size: " << getMinBlockSize() << std::endl; out << " Max block size: " << getMaxBlockSize() << std::endl; out << " Min frame size: " << getMinFrameSize() << std::endl; out << " Max frame size: " << getMaxFrameSize() << std::endl; out << " Sample rate: " << getSampleRate() << std::endl; out << " Channels: " << (size_t)getChannels() << std::endl; out << " Bits: " << (size_t)getBits() << std::endl; out << " Samples: " << getSamples() << std::endl; out << " Checksum: " << getMD5() << std::endl; } std::string Picture::getPicType(){ uint32_t t = Bit::btohl(ptr + 4); switch (t){ case 0: return "Other"; case 1: return "File icon"; case 2: return "Other file icon"; case 3: return "Cover (front)"; case 4: return "Cover (back)"; case 5: return "Leaflet"; case 6: return "Media"; case 7: return "Lead artist"; case 8: return "Artist"; case 9: return "Conductor"; case 10: return "Band"; case 11: return "Composer"; case 12: return "Text writer"; case 13: return "Recording location"; case 14: return "During recording"; case 15: return "During performance"; case 16: return "Movie capture"; case 17: return "A bright coloured fish"; case 18: return "Illustration"; case 19: return "Band logo"; case 20: return "Publisher logo"; } return "Unknown"; } std::string Picture::getMime(){ return std::string(ptr + 12, getMimeLen()); } uint32_t Picture::getMimeLen(){ return Bit::btohl(ptr + 8); } std::string Picture::getDesc(){ return std::string(ptr + 16 + getMimeLen(), getDescLen()); } uint32_t Picture::getDescLen(){ return Bit::btohl(ptr + 12 + getMimeLen()); } uint32_t Picture::getWidth(){ return Bit::btohl(ptr + 16 + getMimeLen() + getDescLen()); } uint32_t Picture::getHeight(){ return Bit::btohl(ptr + 20 + getMimeLen() + getDescLen()); } uint32_t Picture::getDepth(){ return Bit::btohl(ptr + 24 + getMimeLen() + getDescLen()); } uint32_t Picture::getColors(){ return Bit::btohl(ptr + 28 + getMimeLen() + getDescLen()); } uint32_t Picture::getDataLen(){ return Bit::btohl(ptr + 32 + getMimeLen() + getDescLen()); } const char *Picture::getData(){ return ptr + 36 + getMimeLen() + getDescLen(); } void Picture::toPrettyString(std::ostream &out){ if (len < 4){return;} out << getType() << " metadata block (" << getSize() << "b, " << (getLast() ? "last" : "non-last") << "):" << std::endl; out << " Picture type: " << getPicType() << std::endl; out << " Mime type: " << getMime() << std::endl; out << " Description: " << getDesc() << std::endl; out << " Dimensions: " << getWidth() << "x" << getHeight() << std::endl; out << " Color depth: " << getDepth() << std::endl; out << " Color count: " << getColors() << std::endl; out << " Picture data size: " << getDataLen() << "b" << std::endl; } uint32_t VorbisComment::getVendorSize(){ return Bit::btohl_le(ptr + 4); } std::string VorbisComment::getVendor(){ return std::string(ptr + 8, getVendorSize()); } std::string VorbisComment::getComment(uint32_t _num){ size_t offset = 12 + getVendorSize(); size_t i = 0; while (offset < getSize() - 4){ size_t len = Bit::btohl_le(ptr + offset); if (i == _num){return std::string(ptr + offset + 4, len);} offset += 4 + len; ++i; } return ""; } uint32_t VorbisComment::getCommentCount(){ return Bit::btohl_le(ptr + 8 + getVendorSize()); } void VorbisComment::toPrettyString(std::ostream &out){ if (len < 4){return;} out << getType() << " metadata block (" << getSize() << "b, " << (getLast() ? "last" : "non-last") << "):" << std::endl; out << " Vendor: " << getVendor() << std::endl; out << " Comment count: " << getCommentCount() << std::endl; size_t offset = 12 + getVendorSize(); while (offset < getSize() - 4){ size_t len = Bit::btohl_le(ptr + offset); out << " " << std::string(ptr + offset + 4, len) << std::endl; offset += 4 + len; } } }; // Namespace FLAC