Added RIFF analyser
This commit is contained in:
parent
945e6f2d1a
commit
b7d1d38fb4
6 changed files with 350 additions and 0 deletions
|
@ -169,6 +169,7 @@ set(libHeaders
|
||||||
${SOURCE_DIR}/lib/vorbis.h
|
${SOURCE_DIR}/lib/vorbis.h
|
||||||
${SOURCE_DIR}/lib/triggers.h
|
${SOURCE_DIR}/lib/triggers.h
|
||||||
${SOURCE_DIR}/lib/opus.h
|
${SOURCE_DIR}/lib/opus.h
|
||||||
|
${SOURCE_DIR}/lib/riff.h
|
||||||
)
|
)
|
||||||
|
|
||||||
########################################
|
########################################
|
||||||
|
@ -215,6 +216,7 @@ set(libSources
|
||||||
${SOURCE_DIR}/lib/vorbis.cpp
|
${SOURCE_DIR}/lib/vorbis.cpp
|
||||||
${SOURCE_DIR}/lib/triggers.cpp
|
${SOURCE_DIR}/lib/triggers.cpp
|
||||||
${SOURCE_DIR}/lib/opus.cpp
|
${SOURCE_DIR}/lib/opus.cpp
|
||||||
|
${SOURCE_DIR}/lib/riff.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
########################################
|
########################################
|
||||||
|
@ -282,6 +284,7 @@ makeAnalyser(TS ts) #LTS
|
||||||
makeAnalyser(MP4 mp4) #LTS
|
makeAnalyser(MP4 mp4) #LTS
|
||||||
makeAnalyser(H264 h264) #LTS
|
makeAnalyser(H264 h264) #LTS
|
||||||
makeAnalyser(HLS hls) #LTS
|
makeAnalyser(HLS hls) #LTS
|
||||||
|
makeAnalyser(RIFF riff) #LTS
|
||||||
|
|
||||||
#LTS_START
|
#LTS_START
|
||||||
########################################
|
########################################
|
||||||
|
|
|
@ -68,5 +68,58 @@ namespace Bit{
|
||||||
p[7] = val & 0xFF;
|
p[7] = val & 0xFF;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Retrieves a short in little endian from the pointer p.
|
||||||
|
inline unsigned short btohs_le(const char * p) {
|
||||||
|
return ((unsigned short)p[1] << 8) | p[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Stores a short value of val in little endian to the pointer p.
|
||||||
|
inline void htobs_le(char * p, unsigned short val) {
|
||||||
|
p[1] = (val >> 8) & 0xFF;
|
||||||
|
p[0] = val & 0xFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Retrieves a long in network order from the pointer p.
|
||||||
|
inline unsigned long btohl_le(const char * p) {
|
||||||
|
return ((unsigned long)p[3] << 24) | ((unsigned long)p[2] << 16) | ((unsigned long)p[1] << 8) | p[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Stores a long value of val in little endian to the pointer p.
|
||||||
|
inline void htobl_le(char * p, unsigned long val) {
|
||||||
|
p[3] = (val >> 24) & 0xFF;
|
||||||
|
p[2] = (val >> 16) & 0xFF;
|
||||||
|
p[1] = (val >> 8) & 0xFF;
|
||||||
|
p[0] = val & 0xFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Retrieves a long in little endian from the pointer p.
|
||||||
|
inline unsigned long btoh24_le(const char * p) {
|
||||||
|
return ((unsigned long)p[2] << 16) | ((unsigned long)p[1] << 8) | p[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Stores a long value of val in network order to the pointer p.
|
||||||
|
inline void htob24_le(char * p, unsigned long val) {
|
||||||
|
p[2] = (val >> 16) & 0xFF;
|
||||||
|
p[1] = (val >> 8) & 0xFF;
|
||||||
|
p[0] = val & 0xFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Retrieves a long long in little endian from the pointer p.
|
||||||
|
inline unsigned long long btohll_le(const char * p) {
|
||||||
|
return ((unsigned long long)p[7] << 56) | ((unsigned long long)p[6] << 48) | ((unsigned long long)p[5] << 40) | ((unsigned long long)p[4] << 32) | ((unsigned long)p[3] << 24) | ((unsigned long)p[2] << 16) | ((unsigned long)p[1] << 8) | p[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Stores a long value of val in little endian to the pointer p.
|
||||||
|
inline void htobll_le(char * p, unsigned long long val) {
|
||||||
|
p[7] = (val >> 56) & 0xFF;
|
||||||
|
p[6] = (val >> 48) & 0xFF;
|
||||||
|
p[5] = (val >> 40) & 0xFF;
|
||||||
|
p[4] = (val >> 32) & 0xFF;
|
||||||
|
p[3] = (val >> 24) & 0xFF;
|
||||||
|
p[2] = (val >> 16) & 0xFF;
|
||||||
|
p[1] = (val >> 8) & 0xFF;
|
||||||
|
p[0] = val & 0xFF;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
158
lib/riff.cpp
Normal file
158
lib/riff.cpp
Normal file
|
@ -0,0 +1,158 @@
|
||||||
|
#include "riff.h"
|
||||||
|
|
||||||
|
namespace RIFF{
|
||||||
|
|
||||||
|
Chunk::Chunk(const void *_p, uint32_t len){
|
||||||
|
p = (const char *)_p;
|
||||||
|
if (len && len < getPayloadSize() + 8){
|
||||||
|
FAIL_MSG("Chunk %s (%lub) does not fit in %lu bytes length!", getType().c_str(),
|
||||||
|
getPayloadSize() + 8, len);
|
||||||
|
p = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Chunk::Chunk(void *_p, const char * t, uint32_t len){
|
||||||
|
p = (const char *)_p;
|
||||||
|
memcpy((void*)p, t, 4);
|
||||||
|
Bit::htobl_le((char*)p+4, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Chunk::toPrettyString(std::ostream &o, size_t indent) const{
|
||||||
|
if (!p){
|
||||||
|
o << std::string(indent, ' ') << "INVALID CHUNK" << std::endl;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
switch (Bit::btohl(p)){
|
||||||
|
case 0x52494646lu: // RIFF
|
||||||
|
case 0x4C495354lu: // LIST
|
||||||
|
return ListChunk(p).toPrettyString(o, indent);
|
||||||
|
case 0x666D7420: // "fmt "
|
||||||
|
return fmt(p).toPrettyString(o, indent);
|
||||||
|
case 0x66616374: // fact
|
||||||
|
return fact(p).toPrettyString(o, indent);
|
||||||
|
case 0x49534654: // ISFT
|
||||||
|
return ISFT(p).toPrettyString(o, indent);
|
||||||
|
default:
|
||||||
|
o << std::string(indent, ' ') << "[" << getType() << "] UNIMPLEMENTED ("
|
||||||
|
<< (getPayloadSize() + 8) << "b)" << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ListChunk::toPrettyString(std::ostream &o, size_t indent) const{
|
||||||
|
o << std::string(indent, ' ') << "[" << getType() << "] " << getIdentifier() << " ("
|
||||||
|
<< (getPayloadSize() + 8) << "b):" << std::endl;
|
||||||
|
indent += 2;
|
||||||
|
uint32_t i = 12;
|
||||||
|
uint32_t len = getPayloadSize() + 8;
|
||||||
|
while (i + 8 <= len){
|
||||||
|
const Chunk C(p + i);
|
||||||
|
C.toPrettyString(o, indent);
|
||||||
|
i += C.getPayloadSize() + 8;
|
||||||
|
if (!C){return;}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t fmt::getFormat() const{
|
||||||
|
if (!p){return 0;}
|
||||||
|
return Bit::btohs_le(p + 8);
|
||||||
|
}
|
||||||
|
std::string fmt::getCodec() const{
|
||||||
|
switch (getFormat()){
|
||||||
|
case 0x1: return "PCM";
|
||||||
|
case 0x2: return "ADPCM";
|
||||||
|
case 0x3: return "FLOAT";
|
||||||
|
case 0x102:
|
||||||
|
case 0x172:
|
||||||
|
case 0x6: return "PCMA";
|
||||||
|
case 0x101:
|
||||||
|
case 0x171:
|
||||||
|
case 0x7: return "PCMU";
|
||||||
|
case 0x55: return "MP3";
|
||||||
|
case 0xFFFE: // Extended, not implemented
|
||||||
|
default: return "?";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
uint16_t fmt::getChannels() const{
|
||||||
|
if (!p){return 0;}
|
||||||
|
return Bit::btohs_le(p + 10);
|
||||||
|
}
|
||||||
|
uint32_t fmt::getHz() const{
|
||||||
|
if (!p){return 0;}
|
||||||
|
return Bit::btohl_le(p + 12);
|
||||||
|
}
|
||||||
|
uint32_t fmt::getBPS() const{
|
||||||
|
if (!p){return 0;}
|
||||||
|
return Bit::btohl_le(p + 16);
|
||||||
|
}
|
||||||
|
uint16_t fmt::getBlockSize() const{
|
||||||
|
if (!p){return 0;}
|
||||||
|
return Bit::btohs_le(p + 20);
|
||||||
|
}
|
||||||
|
uint16_t fmt::getSize() const{
|
||||||
|
if (!p){return 0;}
|
||||||
|
return Bit::btohs_le(p + 22);
|
||||||
|
}
|
||||||
|
uint16_t fmt::getExtLen() const{
|
||||||
|
if (getPayloadSize() < 18){return 0;}
|
||||||
|
return Bit::btohs_le(p + 24);
|
||||||
|
}
|
||||||
|
uint16_t fmt::getValidBits() const{
|
||||||
|
if (getPayloadSize() < 20 || getExtLen() < 2){return 0;}
|
||||||
|
return Bit::btohs_le(p + 26);
|
||||||
|
}
|
||||||
|
uint32_t fmt::getChannelMask() const{
|
||||||
|
if (getPayloadSize() < 24 || getExtLen() < 6){return 0;}
|
||||||
|
return Bit::btohl_le(p + 28);
|
||||||
|
}
|
||||||
|
std::string fmt::getGUID() const{
|
||||||
|
if (getPayloadSize() < 40 || getExtLen() < 22){return "";}
|
||||||
|
return std::string(p + 32, 16);
|
||||||
|
}
|
||||||
|
void fmt::toPrettyString(std::ostream &o, size_t indent) const{
|
||||||
|
o << std::string(indent, ' ') << "[" << getType() << "] (" << (getPayloadSize() + 8)
|
||||||
|
<< "b):" << std::endl;
|
||||||
|
indent += 1;
|
||||||
|
o << std::string(indent, ' ') << "Codec: " << getCodec() << " (" << getFormat() << ")"
|
||||||
|
<< std::endl;
|
||||||
|
o << std::string(indent, ' ') << "Channels: " << getChannels() << std::endl;
|
||||||
|
o << std::string(indent, ' ') << "Sample rate: " << getHz() << "Hz" << std::endl;
|
||||||
|
o << std::string(indent, ' ') << "Bytes/s: " << getBPS() << std::endl;
|
||||||
|
o << std::string(indent, ' ') << "Block size: " << getBlockSize() << " bytes" << std::endl;
|
||||||
|
o << std::string(indent, ' ') << "Sample size: " << getSize() << " bits" << std::endl;
|
||||||
|
if (getExtLen()){
|
||||||
|
o << std::string(indent, ' ') << "-- extended " << getExtLen() << "bytes --" << std::endl;
|
||||||
|
if (getExtLen() >= 2){
|
||||||
|
o << std::string(indent, ' ') << "Valid bits: " << getValidBits() << std::endl;
|
||||||
|
}
|
||||||
|
if (getExtLen() >= 6){
|
||||||
|
o << std::string(indent, ' ') << "Channel mask: " << getChannelMask() << std::endl;
|
||||||
|
}
|
||||||
|
if (getExtLen() >= 22){
|
||||||
|
o << std::string(indent, ' ') << "GUID: " << getGUID() << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t fact::getSamplesPerChannel() const{
|
||||||
|
if (!p){return 0;}
|
||||||
|
return Bit::btohl_le(p + 8);
|
||||||
|
}
|
||||||
|
void fact::toPrettyString(std::ostream &o, size_t indent) const{
|
||||||
|
o << std::string(indent, ' ') << "[" << getType() << "] (" << (getPayloadSize() + 8)
|
||||||
|
<< "b):" << std::endl;
|
||||||
|
indent += 1;
|
||||||
|
o << std::string(indent, ' ') << "Samples per channel: " << getSamplesPerChannel() << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string ISFT::getSoftware() const{
|
||||||
|
if (!p){return 0;}
|
||||||
|
return std::string(p+8, getPayloadSize());
|
||||||
|
}
|
||||||
|
void ISFT::toPrettyString(std::ostream &o, size_t indent) const{
|
||||||
|
o << std::string(indent, ' ') << "[" << getType() << "] (" << (getPayloadSize() + 8)
|
||||||
|
<< "b):" << std::endl;
|
||||||
|
indent += 1;
|
||||||
|
o << std::string(indent, ' ') << "Software: " << getSoftware() << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
77
lib/riff.h
Normal file
77
lib/riff.h
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
#pragma once
|
||||||
|
#include "bitfields.h"
|
||||||
|
#include "defines.h"
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace RIFF{
|
||||||
|
|
||||||
|
/// Basic RIFF chunk class - can only read type and size.
|
||||||
|
/// All RIFF chunks have this format.
|
||||||
|
class Chunk{
|
||||||
|
public:
|
||||||
|
Chunk(const void *_p = 0, uint32_t len = 0);
|
||||||
|
Chunk(void *_p, const char * t, uint32_t len);
|
||||||
|
inline operator bool() const{return p;}
|
||||||
|
inline std::string getType() const{
|
||||||
|
if (!p){return "";}
|
||||||
|
return std::string(p, 4);
|
||||||
|
}
|
||||||
|
inline uint32_t getPayloadSize() const{
|
||||||
|
if (!p){return 0;}
|
||||||
|
return Bit::btohl_le(p + 4);
|
||||||
|
}
|
||||||
|
virtual void toPrettyString(std::ostream &o, size_t indent = 0) const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
const char *p;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// List-type RIFF chunk. Can read list identifier.
|
||||||
|
/// "RIFF" and "LIST" type chunks follow this format.
|
||||||
|
class ListChunk : public Chunk{
|
||||||
|
public:
|
||||||
|
ListChunk(const void *_p = 0, uint32_t len = 0) : Chunk(_p, len){}
|
||||||
|
inline std::string getIdentifier() const{
|
||||||
|
if (!p){return "";}
|
||||||
|
return std::string(p + 8, 4);
|
||||||
|
}
|
||||||
|
virtual void toPrettyString(std::ostream &o, size_t indent = 0) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// WAVE "fmt " class.
|
||||||
|
class fmt : public Chunk{
|
||||||
|
public:
|
||||||
|
fmt(const void *_p = 0, uint32_t len = 0) : Chunk(_p, len){}
|
||||||
|
uint16_t getFormat() const;
|
||||||
|
std::string getCodec() const;
|
||||||
|
uint16_t getChannels() const;
|
||||||
|
uint32_t getHz() const;
|
||||||
|
uint32_t getBPS() const;
|
||||||
|
uint16_t getBlockSize() const;
|
||||||
|
uint16_t getSize() const;
|
||||||
|
uint16_t getExtLen() const;
|
||||||
|
uint16_t getValidBits() const;
|
||||||
|
uint32_t getChannelMask() const;
|
||||||
|
std::string getGUID() const;
|
||||||
|
virtual void toPrettyString(std::ostream &o, size_t indent = 0) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// WAVE fact class.
|
||||||
|
class fact : public Chunk {
|
||||||
|
public:
|
||||||
|
fact(const void *_p = 0, uint32_t len = 0) : Chunk(_p, len){}
|
||||||
|
uint32_t getSamplesPerChannel() const;
|
||||||
|
virtual void toPrettyString(std::ostream &o, size_t indent = 0) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// ISFT class. Contains software name.
|
||||||
|
class ISFT : public Chunk {
|
||||||
|
public:
|
||||||
|
ISFT(const void *_p = 0, uint32_t len = 0) : Chunk(_p, len){}
|
||||||
|
std::string getSoftware() const;
|
||||||
|
virtual void toPrettyString(std::ostream &o, size_t indent = 0) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
44
src/analysers/analyser_riff.cpp
Normal file
44
src/analysers/analyser_riff.cpp
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
#include "analyser_riff.h"
|
||||||
|
#include <iostream>
|
||||||
|
#include <mist/riff.h>
|
||||||
|
|
||||||
|
void AnalyserRIFF::init(Util::Config &conf){
|
||||||
|
Analyser::init(conf);
|
||||||
|
}
|
||||||
|
|
||||||
|
AnalyserRIFF::AnalyserRIFF(Util::Config &conf) : Analyser(conf){
|
||||||
|
curPos = prePos = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AnalyserRIFF::parsePacket(){
|
||||||
|
prePos = curPos;
|
||||||
|
// Read in smart bursts until we have enough data
|
||||||
|
while (isOpen() && dataBuffer.size() < neededBytes()){
|
||||||
|
uint64_t needed = neededBytes();
|
||||||
|
dataBuffer.reserve(needed);
|
||||||
|
for (uint64_t i = dataBuffer.size(); i < needed; ++i){
|
||||||
|
dataBuffer += std::cin.get();
|
||||||
|
++curPos;
|
||||||
|
if (!std::cin.good()){dataBuffer.erase(dataBuffer.size() - 1, 1);}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dataBuffer.size() < 8){return false;}
|
||||||
|
|
||||||
|
RIFF::Chunk C(dataBuffer.data(), dataBuffer.size());
|
||||||
|
INFO_MSG("Read a chunk at position %d", prePos);
|
||||||
|
if (detail >= 2){C.toPrettyString(std::cout);}
|
||||||
|
///\TODO update mediaTime with the current timestamp
|
||||||
|
if (C){
|
||||||
|
dataBuffer.erase(0, C.getPayloadSize()+8);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Calculates how many bytes we need to read a whole box.
|
||||||
|
uint64_t AnalyserRIFF::neededBytes(){
|
||||||
|
if (dataBuffer.size() < 8){return 8;}
|
||||||
|
return RIFF::Chunk(dataBuffer.data()).getPayloadSize()+8;
|
||||||
|
}
|
||||||
|
|
15
src/analysers/analyser_riff.h
Normal file
15
src/analysers/analyser_riff.h
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
#include "analyser.h"
|
||||||
|
|
||||||
|
class AnalyserRIFF : public Analyser{
|
||||||
|
public:
|
||||||
|
AnalyserRIFF(Util::Config &conf);
|
||||||
|
static void init(Util::Config &conf);
|
||||||
|
bool parsePacket();
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint64_t neededBytes();
|
||||||
|
std::string dataBuffer;
|
||||||
|
uint64_t curPos;
|
||||||
|
uint64_t prePos;
|
||||||
|
};
|
||||||
|
|
Loading…
Add table
Reference in a new issue