Improvements to FLAC library and analyser
This commit is contained in:
parent
a7183aedc5
commit
dc0ec77f26
4 changed files with 442 additions and 180 deletions
444
lib/flac.cpp
444
lib/flac.cpp
|
@ -1,128 +1,344 @@
|
||||||
|
#include "bitfields.h"
|
||||||
|
#include "defines.h"
|
||||||
|
#include "encode.h"
|
||||||
#include "flac.h"
|
#include "flac.h"
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
/// Checks the first 4 bytes for the string "flaC". Implementing a basic FLAC header check,
|
namespace FLAC{
|
||||||
/// returning true if it is, false if not.
|
|
||||||
bool FLAC::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 FLAC::utfBytes(char p){
|
/// Checks the first 4 bytes for the string "flaC". Implementing a basic FLAC header check,
|
||||||
if ((p & 0x80) == 0x00){return 1;}
|
/// returning true if it is, false if not.
|
||||||
if ((p & 0xE0) == 0xC0){return 2;}
|
bool is_header(const char *header){
|
||||||
if ((p & 0xF0) == 0xE0){return 3;}
|
if (header[0] != 'f') return false;
|
||||||
if ((p & 0xF8) == 0xF0){return 4;}
|
if (header[1] != 'L') return false;
|
||||||
if ((p & 0xFC) == 0xF8){return 5;}
|
if (header[2] != 'a') return false;
|
||||||
if ((p & 0xFE) == 0xFC){return 6;}
|
if (header[3] != 'C') return false;
|
||||||
if ((p & 0xFF) == 0xFE){return 7;}
|
return true;
|
||||||
return 9;
|
}// FLAC::is_header
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t FLAC::utfVal(char *p){
|
size_t utfBytes(char p){
|
||||||
size_t bytes = utfBytes(*p);
|
if ((p & 0x80) == 0x00){return 1;}
|
||||||
uint32_t ret = 0;
|
if ((p & 0xE0) == 0xC0){return 2;}
|
||||||
|
if ((p & 0xF0) == 0xE0){return 3;}
|
||||||
if (bytes == 1){
|
if ((p & 0xF8) == 0xF0){return 4;}
|
||||||
ret = (uint32_t)*p;
|
if ((p & 0xFC) == 0xF8){return 5;}
|
||||||
}else if (bytes == 2){
|
if ((p & 0xFE) == 0xFC){return 6;}
|
||||||
ret = (uint32_t)(*p & 0x1F) << 6;
|
if ((p & 0xFF) == 0xFE){return 7;}
|
||||||
ret = ret | (*(p + 1) & 0x3f);
|
return 9;
|
||||||
}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;
|
uint32_t utfVal(char *p){
|
||||||
}
|
size_t bytes = utfBytes(*p);
|
||||||
|
uint32_t ret = 0;
|
||||||
|
|
||||||
FLAC::Frame::Frame(char *pkt){
|
if (bytes == 1){
|
||||||
data = pkt;
|
ret = (uint32_t)*p;
|
||||||
if (data[0] != 0xFF || (data[1] & 0xFC) != 0xF8){
|
}else if (bytes == 2){
|
||||||
WARN_MSG("Sync code incorrect! Ignoring FLAC frame");
|
ret = (uint32_t)(*p & 0x1F) << 6;
|
||||||
FAIL_MSG("%x %x", data[0], data[1]);
|
ret = ret | (*(p + 1) & 0x3f);
|
||||||
data = 0;
|
}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;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
uint16_t FLAC::Frame::samples(){
|
Frame::Frame(char *pkt){
|
||||||
if (!data){return 0;}
|
data = pkt;
|
||||||
switch ((data[2] & 0xF0) >> 4){
|
if (data[0] != 0xFF || (data[1] & 0xFC) != 0xF8){
|
||||||
case 0: return 0; // reserved
|
WARN_MSG("Sync code incorrect! Ignoring FLAC frame");
|
||||||
case 1: return 192;
|
FAIL_MSG("%x %x", data[0], data[1]);
|
||||||
case 2: return 576;
|
data = 0;
|
||||||
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 FLAC::Frame::rate(){
|
uint16_t Frame::samples(){
|
||||||
if (!data){return 0;}
|
if (!data){return 0;}
|
||||||
switch (data[2] & 0x0F){
|
switch ((data[2] & 0xF0) >> 4){
|
||||||
case 0: return 0; // get from STREAMINFO
|
case 0: return 0; // reserved
|
||||||
case 1: return 88200;
|
case 1: return 192;
|
||||||
case 2: return 176400;
|
case 2: return 576;
|
||||||
case 3: return 192000;
|
case 3: return 1152;
|
||||||
case 4: return 8000;
|
case 4: return 2304;
|
||||||
case 5: return 16000;
|
case 5: return 4608;
|
||||||
case 6: return 22050;
|
case 6: return 1; // 1b at end
|
||||||
case 7: return 24000;
|
case 7: return 2; // 2b at end
|
||||||
case 8: return 32000;
|
default: return 256 << (((data[2] & 0xf0) >> 4) - 8);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
}
|
uint32_t Frame::rate(){
|
||||||
|
if (!data){return 0;}
|
||||||
uint8_t FLAC::Frame::channels(){
|
switch (data[2] & 0x0F){
|
||||||
if (!data){return 0;}
|
case 0: return 0; // get from STREAMINFO
|
||||||
uint8_t ret = ((data[3] & 0xF0) >> 4) + 1;
|
case 1: return 88200;
|
||||||
if (ret > 8 && ret < 12){return 2;}// special stereo
|
case 2: return 176400;
|
||||||
return ret;
|
case 3: return 192000;
|
||||||
}
|
case 4: return 8000;
|
||||||
uint8_t FLAC::Frame::size(){
|
case 5: return 16000;
|
||||||
if (!data){return 0;}
|
case 6: return 22050;
|
||||||
switch (data[3] & 0x0E){
|
case 7: return 24000;
|
||||||
case 0: return 0; // get from STREAMINFO
|
case 8: return 32000;
|
||||||
case 1: return 8;
|
case 9: return 44100;
|
||||||
case 2: return 12;
|
case 10: return 48000;
|
||||||
case 3: return 0; // reserved
|
case 11: return 96000;
|
||||||
case 4: return 16;
|
case 12: return 1; // 1b at end, *1000
|
||||||
case 5: return 20;
|
case 13: return 2; // 2b at end
|
||||||
case 6: return 24;
|
case 14: return 3; // 2b at end, *10
|
||||||
case 7: return 0; // reserved
|
case 15: return 0; // invalid, get from STREAMINFO
|
||||||
default: return 0;
|
default: return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t FLAC::Frame::utfVal(){
|
uint8_t Frame::channels(){
|
||||||
return FLAC::utfVal(data + 4);
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
std::string FLAC::Frame::toPrettyString(){
|
uint32_t Frame::utfVal(){
|
||||||
if (!data){return "Invalid frame";}
|
return ::FLAC::utfVal(data + 4);
|
||||||
std::stringstream r;
|
}
|
||||||
r << "FLAC frame" << std::endl;
|
|
||||||
r << " Block size: " << ((data[1] & 0x1) ? "variable" : "fixed") << std::endl;
|
std::string Frame::toPrettyString(){
|
||||||
r << " Samples: " << samples() << std::endl;
|
if (!data){return "Invalid frame";}
|
||||||
r << " Rate: " << rate() << "Hz" << std::endl;
|
std::stringstream r;
|
||||||
r << " Channels: " << (int)channels() << std::endl;
|
r << "FLAC frame, " << ((data[1] & 0x1) ? "variable" : "fixed") << " block size, " << samples() << " samples, "
|
||||||
r << " Size: " << (int)size() << "-bit" << std::endl;
|
<< rate() << " Hz, " << (int)channels() << " Ch, " << (int)size() << "-bit" << std::endl;
|
||||||
return r.str();
|
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
|
||||||
|
|
64
lib/flac.h
64
lib/flac.h
|
@ -1,5 +1,4 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <mist/defines.h>
|
|
||||||
#include <ostream>
|
#include <ostream>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
@ -11,9 +10,6 @@ namespace FLAC{
|
||||||
size_t utfBytes(char p); // UTF encoding byte size
|
size_t utfBytes(char p); // UTF encoding byte size
|
||||||
uint32_t utfVal(char *p); // UTF encoding value
|
uint32_t utfVal(char *p); // UTF encoding value
|
||||||
|
|
||||||
size_t rate();
|
|
||||||
uint8_t channels();
|
|
||||||
|
|
||||||
class Frame{
|
class Frame{
|
||||||
public:
|
public:
|
||||||
Frame(char *pkt);
|
Frame(char *pkt);
|
||||||
|
@ -29,4 +25,64 @@ namespace FLAC{
|
||||||
char *data;
|
char *data;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class MetaBlock{
|
||||||
|
public:
|
||||||
|
MetaBlock();
|
||||||
|
MetaBlock(const char *_ptr, size_t _len);
|
||||||
|
std::string getType();
|
||||||
|
size_t getSize();
|
||||||
|
bool getLast();
|
||||||
|
std::string toPrettyString();
|
||||||
|
virtual void toPrettyString(std::ostream &out);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
const char *ptr;
|
||||||
|
size_t len;
|
||||||
|
};
|
||||||
|
|
||||||
|
class StreamInfo : public MetaBlock{
|
||||||
|
public:
|
||||||
|
StreamInfo() : MetaBlock(){};
|
||||||
|
StreamInfo(const char *_ptr, size_t _len) : MetaBlock(_ptr, _len){};
|
||||||
|
uint16_t getMinBlockSize();
|
||||||
|
uint16_t getMaxBlockSize();
|
||||||
|
uint32_t getMinFrameSize();
|
||||||
|
uint32_t getMaxFrameSize();
|
||||||
|
uint32_t getSampleRate();
|
||||||
|
uint8_t getChannels();
|
||||||
|
uint8_t getBits();
|
||||||
|
uint64_t getSamples();
|
||||||
|
std::string getMD5();
|
||||||
|
void toPrettyString(std::ostream &out);
|
||||||
|
};
|
||||||
|
|
||||||
|
class Picture : public MetaBlock{
|
||||||
|
public:
|
||||||
|
Picture() : MetaBlock(){};
|
||||||
|
Picture(const char *_ptr, size_t _len) : MetaBlock(_ptr, _len){};
|
||||||
|
std::string getPicType();
|
||||||
|
std::string getMime();
|
||||||
|
uint32_t getMimeLen();
|
||||||
|
std::string getDesc();
|
||||||
|
uint32_t getDescLen();
|
||||||
|
uint32_t getWidth();
|
||||||
|
uint32_t getHeight();
|
||||||
|
uint32_t getDepth();
|
||||||
|
uint32_t getColors();
|
||||||
|
uint32_t getDataLen();
|
||||||
|
const char *getData();
|
||||||
|
void toPrettyString(std::ostream &out);
|
||||||
|
};
|
||||||
|
|
||||||
|
class VorbisComment : public MetaBlock{
|
||||||
|
public:
|
||||||
|
VorbisComment() : MetaBlock(){};
|
||||||
|
VorbisComment(const char *_ptr, size_t _len) : MetaBlock(_ptr, _len){};
|
||||||
|
uint32_t getVendorSize();
|
||||||
|
std::string getVendor();
|
||||||
|
std::string getComment(uint32_t _num);
|
||||||
|
uint32_t getCommentCount();
|
||||||
|
void toPrettyString(std::ostream &out);
|
||||||
|
};
|
||||||
|
|
||||||
}// namespace FLAC
|
}// namespace FLAC
|
||||||
|
|
|
@ -10,7 +10,6 @@
|
||||||
#include <mist/flac.h>
|
#include <mist/flac.h>
|
||||||
|
|
||||||
AnalyserFLAC::AnalyserFLAC(Util::Config &conf) : Analyser(conf){
|
AnalyserFLAC::AnalyserFLAC(Util::Config &conf) : Analyser(conf){
|
||||||
a = conf.getInteger("filter");
|
|
||||||
headerParsed = false;
|
headerParsed = false;
|
||||||
curPos = 0;
|
curPos = 0;
|
||||||
bufferSize = 0;
|
bufferSize = 0;
|
||||||
|
@ -19,89 +18,76 @@ AnalyserFLAC::AnalyserFLAC(Util::Config &conf) : Analyser(conf){
|
||||||
prev_header_size = 0;
|
prev_header_size = 0;
|
||||||
pos = NULL;
|
pos = NULL;
|
||||||
forceFill = false;
|
forceFill = false;
|
||||||
|
sampleNo = 0;
|
||||||
|
sampleRate = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AnalyserFLAC::readMagicPacket(){
|
bool AnalyserFLAC::readMagicPacket(){
|
||||||
char magic[4];
|
char magic[4];
|
||||||
if (fread(magic, 4, 1, stdin) != 1){
|
if (fread(magic, 4, 1, stdin) != 1){
|
||||||
std::cout << "Could not read magic word - aborting!" << std::endl;
|
FAIL_MSG("Could not read magic word - aborting!");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (FLAC::is_header(magic)){
|
if (!FLAC::is_header(magic)){
|
||||||
std::cout << "Found magic packet" << std::endl;
|
FAIL_MSG("Not a FLAC file - aborting!");
|
||||||
curPos = 4;
|
return false;
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
std::cout << "Not a FLAC file - aborting!" << std::endl;
|
curPos = 4;
|
||||||
return false;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AnalyserFLAC::init(Util::Config &conf){
|
void AnalyserFLAC::init(Util::Config &conf){
|
||||||
Analyser::init(conf);
|
Analyser::init(conf);
|
||||||
JSON::Value opt;
|
|
||||||
opt["long"] = "filter";
|
|
||||||
opt["short"] = "F";
|
|
||||||
opt["arg"] = "num";
|
|
||||||
opt["default"] = "0";
|
|
||||||
opt["help"] =
|
|
||||||
"Only print information about this tag type (8 = audio, 9 = video, 18 = meta, 0 = all)";
|
|
||||||
conf.addOption("filter", opt);
|
|
||||||
opt.null();
|
|
||||||
|
|
||||||
if (feof(stdin)){
|
|
||||||
WARN_MSG("cannot open stdin");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AnalyserFLAC::readMeta(){
|
bool AnalyserFLAC::readMeta(){
|
||||||
if (!readMagicPacket()){return false;}
|
if (!readMagicPacket()){return false;}
|
||||||
|
|
||||||
bool lastMeta = false;
|
bool lastMeta = false;
|
||||||
char metahead[4];
|
Util::ResizeablePointer flacmeta;
|
||||||
|
flacmeta.allocate(4);
|
||||||
while (!feof(stdin) && !lastMeta){
|
while (!feof(stdin) && !lastMeta){
|
||||||
if (fread(metahead, 4, 1, stdin) != 1){
|
flacmeta.truncate(0);
|
||||||
std::cout << "Could not read metadata block header - aborting!" << std::endl;
|
if (fread(flacmeta, 4, 1, stdin) != 1){
|
||||||
|
FAIL_MSG("Could not read metadata block header - aborting!");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
flacmeta.append(0, 4);
|
||||||
curPos += 4;
|
curPos += 4;
|
||||||
|
|
||||||
lastMeta = (metahead[0] & 0x80); // check for last metadata block flag
|
lastMeta = FLAC::MetaBlock(flacmeta, 4).getLast(); // check for last metadata block flag
|
||||||
std::string mType;
|
std::string mType = FLAC::MetaBlock(flacmeta, 4).getType();
|
||||||
switch (metahead[0] & 0x7F){
|
flacmeta.allocate(FLAC::MetaBlock(flacmeta, 4).getSize() + 4);
|
||||||
case 0: mType = "STREAMINFO"; break;
|
|
||||||
case 1: mType = "PADDING"; break;
|
// This variable is not created earlier because flacmeta.allocate updates the pointer and would invalidate it
|
||||||
case 2: mType = "APPLICATION"; break;
|
FLAC::MetaBlock mb(flacmeta, 4);
|
||||||
case 3: mType = "SEEKTABLE"; break;
|
|
||||||
case 4: mType = "VORBIS_COMMENT"; break;
|
if (fread(((char *)flacmeta) + 4, mb.getSize(), 1, stdin) != 1){
|
||||||
case 5: mType = "CUESHEET"; break;
|
FAIL_MSG("Could not read metadata block contents: %s", strerror(errno));
|
||||||
case 6: mType = "PICTURE"; break;
|
return false;
|
||||||
case 127: mType = "INVALID"; break;
|
}
|
||||||
default: mType = "UNKNOWN"; break;
|
flacmeta.append(0, mb.getSize());
|
||||||
|
curPos += mb.getSize();
|
||||||
|
|
||||||
|
if (mType == "STREAMINFO"){
|
||||||
|
FLAC::StreamInfo si(flacmeta, flacmeta.size());
|
||||||
|
sampleRate = si.getSampleRate();
|
||||||
|
si.toPrettyString(std::cout);
|
||||||
|
}else if (mType == "VORBIS_COMMENT"){
|
||||||
|
FLAC::VorbisComment(flacmeta, flacmeta.size()).toPrettyString(std::cout);
|
||||||
|
}else if (mType == "PICTURE"){
|
||||||
|
FLAC::Picture(flacmeta, flacmeta.size()).toPrettyString(std::cout);
|
||||||
|
}else{
|
||||||
|
mb.toPrettyString(std::cout);
|
||||||
}
|
}
|
||||||
unsigned int bytes = Bit::btoh24(metahead + 1);
|
|
||||||
curPos += bytes;
|
|
||||||
fseek(stdin, bytes, SEEK_CUR);
|
|
||||||
std::cout << "Found metadata block of type " << mType << ", skipping " << bytes << " bytes" << std::endl;
|
|
||||||
if (mType == "STREAMINFO"){FAIL_MSG("streaminfo");}
|
|
||||||
}
|
}
|
||||||
INFO_MSG("last metadata");
|
|
||||||
headerParsed = true;
|
headerParsed = true;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AnalyserFLAC::parsePacket(){
|
bool AnalyserFLAC::parsePacket(){
|
||||||
if (feof(stdin) && flacBuffer.size() < 100){
|
if (feof(stdin) && flacBuffer.size() < 100){return false;}
|
||||||
stop();
|
if (!headerParsed && !readMeta()){return false;}
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!headerParsed){
|
|
||||||
if (!readMeta()){
|
|
||||||
stop();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
uint64_t needed = 40000;
|
uint64_t needed = 40000;
|
||||||
|
|
||||||
// fill up buffer as we go
|
// fill up buffer as we go
|
||||||
|
@ -114,7 +100,7 @@ bool AnalyserFLAC::parsePacket(){
|
||||||
flacBuffer += tmp;
|
flacBuffer += tmp;
|
||||||
|
|
||||||
if (!std::cin.good()){
|
if (!std::cin.good()){
|
||||||
WARN_MSG("End, process remaining buffer data: %zu bytes", flacBuffer.size());
|
INFO_MSG("End, process remaining buffer data: %zu bytes", flacBuffer.size());
|
||||||
|
|
||||||
if (flacBuffer.size() < 1){
|
if (flacBuffer.size() < 1){
|
||||||
FAIL_MSG("eof");
|
FAIL_MSG("eof");
|
||||||
|
@ -141,11 +127,11 @@ bool AnalyserFLAC::parsePacket(){
|
||||||
int utfv = FLAC::utfVal(start + 4); // read framenumber
|
int utfv = FLAC::utfVal(start + 4); // read framenumber
|
||||||
|
|
||||||
if (utfv + 1 != FLAC::utfVal(a + 4)){
|
if (utfv + 1 != FLAC::utfVal(a + 4)){
|
||||||
FAIL_MSG("framenr: %d, end framenr: %d, size: %zu curPos: %" PRIu64, FLAC::utfVal(start + 4),
|
HIGH_MSG("framenr: %d, end framenr: %d, size: %zu curPos: %" PRIu64,
|
||||||
FLAC::utfVal(a + 4), (size_t)(pos - start), curPos);
|
FLAC::utfVal(start + 4), FLAC::utfVal(a + 4), (size_t)(pos - start), curPos);
|
||||||
}else{
|
}else{
|
||||||
INFO_MSG("framenr: %d, end framenr: %d, size: %zu curPos: %" PRIu64, FLAC::utfVal(start + 4),
|
DONTEVEN_MSG("framenr: %d, end framenr: %d, size: %zu curPos: %" PRIu64,
|
||||||
FLAC::utfVal(a + 4), (size_t)(pos - start), curPos);
|
FLAC::utfVal(start + 4), FLAC::utfVal(a + 4), (size_t)(pos - start), curPos);
|
||||||
}
|
}
|
||||||
|
|
||||||
int skip = FLAC::utfBytes(u);
|
int skip = FLAC::utfBytes(u);
|
||||||
|
@ -154,7 +140,7 @@ bool AnalyserFLAC::parsePacket(){
|
||||||
if (checksum::crc8(0, pos, prev_header_size) == *(a + prev_header_size)){
|
if (checksum::crc8(0, pos, prev_header_size) == *(a + prev_header_size)){
|
||||||
// checksum pass, valid startframe found
|
// checksum pass, valid startframe found
|
||||||
if (((utfv + 1 != FLAC::utfVal(a + 4))) && (utfv != 0)){
|
if (((utfv + 1 != FLAC::utfVal(a + 4))) && (utfv != 0)){
|
||||||
WARN_MSG("error frame, found: %d, expected: %d, ignore.. ", FLAC::utfVal(a + 4), utfv + 1);
|
HIGH_MSG("error frame, found: %d, expected: %d, ignore.. ", FLAC::utfVal(a + 4), utfv + 1);
|
||||||
}else{
|
}else{
|
||||||
|
|
||||||
FLAC::Frame f(start);
|
FLAC::Frame f(start);
|
||||||
|
@ -164,10 +150,13 @@ bool AnalyserFLAC::parsePacket(){
|
||||||
start = &flacBuffer[0];
|
start = &flacBuffer[0];
|
||||||
end = &flacBuffer[flacBuffer.size()];
|
end = &flacBuffer[flacBuffer.size()];
|
||||||
pos = start + 2;
|
pos = start + 2;
|
||||||
|
std::cout << f.toPrettyString();
|
||||||
|
sampleNo += f.samples();
|
||||||
|
mediaTime = sampleNo / (sampleRate / 10);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
WARN_MSG("Checksum mismatch! %x - %x, curPos: %" PRIu64, *(a + prev_header_size),
|
HIGH_MSG("Checksum mismatch! %x - %x, curPos: %" PRIu64, *(a + prev_header_size),
|
||||||
checksum::crc8(0, pos, prev_header_size), curPos + (pos - start));
|
checksum::crc8(0, pos, prev_header_size), curPos + (pos - start));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,6 @@ public:
|
||||||
bool readMeta();
|
bool readMeta();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int64_t a;
|
|
||||||
uint64_t neededBytes();
|
uint64_t neededBytes();
|
||||||
void newFrame(char *data);
|
void newFrame(char *data);
|
||||||
bool headerParsed;
|
bool headerParsed;
|
||||||
|
@ -24,6 +23,8 @@ private:
|
||||||
bool forceFill;
|
bool forceFill;
|
||||||
|
|
||||||
char *ptr;
|
char *ptr;
|
||||||
|
uint64_t sampleNo;
|
||||||
|
uint64_t sampleRate;
|
||||||
bool stopProcessing;
|
bool stopProcessing;
|
||||||
|
|
||||||
char *start; // = &flacBuffer[0];
|
char *start; // = &flacBuffer[0];
|
||||||
|
|
Loading…
Add table
Reference in a new issue