#include <iostream>
#include <cstdint>
#include <cassert>
//----------[ generischer Kram ]----------
// extracts a sequence of bits from an unsigned char array
// at arbitrary bit positions (most significant bits first)
std::uint32_t get_bits_msbf(
const unsigned char data[],
unsigned bit_offset, unsigned nbits)
{
// TODO: Diese Implementierung kann man vielleicht noch vereinfachen.
assert(nbits <= 32);
if (nbits == 0) return 0u;
data += bit_offset / 8;
bit_offset &= 7;
unsigned tlen = 8 - bit_offset;
std::uint32_t temp = *data & (0xFFu >> bit_offset);
if (tlen >= nbits)
return temp >> (tlen-nbits);
while (tlen+8 <= nbits) {
++data;
temp = (temp << 8) | (*data & 0xFFu);
tlen += 8;
}
unsigned missing = nbits - tlen;
if (missing) {
++data;
temp = (temp << missing) | (*data >> (8-missing));
}
return temp;
}
template<unsigned BitOffset, unsigned BitLen, class MessageTag=void>
struct field
{
typedef MessageTag message_tag;
static const unsigned bit_offset = BitOffset;
static const unsigned bit_len = BitLen;
};
template<class MessageTag=void>
struct message_ptr
{
const unsigned char* data;
unsigned length;
explicit message_ptr(const unsigned char *ptr, unsigned len)
: data(ptr), length(len)
{}
template<unsigned BitOffset, unsigned BitLen>
std::uint32_t get(field<BitOffset,BitLen,MessageTag>) const
{
assert(BitOffset+BitLen <= 8*length);
return get_bits_msbf(data,BitOffset,BitLen);
}
};
//----------[ Anwendungsfall ]----------
namespace mp3_stuff {
struct frame_header_tag {};
const field<0,11,frame_header_tag> sync = {};
const field<11,2,frame_header_tag> mpegid = {};
const field<13,2,frame_header_tag> layer = {};
const field<15,1,frame_header_tag> protection_bit = {};
const field<16,4,frame_header_tag> bitrate_index = {};
const field<20,2,frame_header_tag> sampling_rate_index = {};
const field<22,1,frame_header_tag> padding_bit = {};
const field<23,1,frame_header_tag> private_bit = {};
const field<24,2,frame_header_tag> channel_mode = {};
const field<26,2,frame_header_tag> cm_extension = {};
const field<28,1,frame_header_tag> copyrighted_bit = {};
const field<29,1,frame_header_tag> original_bit = {};
const field<30,2,frame_header_tag> emphasis_mode = {};
static const char* const mpegid2str[] = {"MPEG 2.5", "reserved", "MPEG 2", "MPEG 1"};
static const char* const chanmodes[] = {"Stereo", "Joint Stereo", "Dual Channel", "Mono"};
static const long srate[] = {44100,48000,32000};
} // namespace mp3_stuff
void test()
{
using namespace std;
using namespace mp3_stuff;
unsigned char data[] = {0xFF, 0xFB, 0xA0, 0x64};
message_ptr<frame_header_tag> mptr (data,4);
if (mptr.get(sync) == 0x7FF) {
cout << "MPEG : " << mpegid2str[mptr.get(mpegid)] << endl;
cout << "Layer : " << 4-mptr.get(layer) << endl;
cout << "Bitrate index : " << mptr.get(bitrate_index) << endl;
const int srdivisor = 4-mptr.get(mpegid);
cout << "Sampling rate : " << srate[mptr.get(sampling_rate_index)]/srdivisor << endl;
cout << "Channel mode : " << chanmodes[mptr.get(channel_mode)] << endl;
} else {
cout << "Sync bits invalid\n";
}
}
int main()
{
test();
}
I2luY2x1ZGUgPGlvc3RyZWFtPgojaW5jbHVkZSA8Y3N0ZGludD4KI2luY2x1ZGUgPGNhc3NlcnQ+CiAKLy8tLS0tLS0tLS0tWyBnZW5lcmlzY2hlciBLcmFtIF0tLS0tLS0tLS0tCiAKLy8gZXh0cmFjdHMgYSBzZXF1ZW5jZSBvZiBiaXRzIGZyb20gYW4gdW5zaWduZWQgY2hhciBhcnJheQovLyBhdCBhcmJpdHJhcnkgYml0IHBvc2l0aW9ucyAobW9zdCBzaWduaWZpY2FudCBiaXRzIGZpcnN0KQpzdGQ6OnVpbnQzMl90IGdldF9iaXRzX21zYmYoCiAgICBjb25zdCB1bnNpZ25lZCBjaGFyIGRhdGFbXSwKICAgIHVuc2lnbmVkIGJpdF9vZmZzZXQsIHVuc2lnbmVkIG5iaXRzKQp7CiAgICAvLyBUT0RPOiBEaWVzZSBJbXBsZW1lbnRpZXJ1bmcga2FubiBtYW4gdmllbGxlaWNodCBub2NoIHZlcmVpbmZhY2hlbi4KICAgIGFzc2VydChuYml0cyA8PSAzMik7CiAgICBpZiAobmJpdHMgPT0gMCkgcmV0dXJuIDB1OwogICAgZGF0YSArPSBiaXRfb2Zmc2V0IC8gODsKICAgIGJpdF9vZmZzZXQgJj0gNzsKICAgIHVuc2lnbmVkIHRsZW4gPSA4IC0gYml0X29mZnNldDsKICAgIHN0ZDo6dWludDMyX3QgdGVtcCA9ICpkYXRhICYgKDB4RkZ1ID4+IGJpdF9vZmZzZXQpOwogICAgaWYgKHRsZW4gPj0gbmJpdHMpCiAgICAgICAgcmV0dXJuIHRlbXAgPj4gKHRsZW4tbmJpdHMpOwogICAgd2hpbGUgKHRsZW4rOCA8PSBuYml0cykgewogICAgICAgICsrZGF0YTsKICAgICAgICB0ZW1wID0gKHRlbXAgPDwgOCkgfCAoKmRhdGEgJiAweEZGdSk7CiAgICAgICAgdGxlbiArPSA4OwogICAgfQogICAgdW5zaWduZWQgbWlzc2luZyA9IG5iaXRzIC0gdGxlbjsKICAgIGlmIChtaXNzaW5nKSB7CiAgICAgICAgKytkYXRhOwogICAgICAgIHRlbXAgPSAodGVtcCA8PCBtaXNzaW5nKSB8ICgqZGF0YSA+PiAoOC1taXNzaW5nKSk7CiAgICB9CiAgICByZXR1cm4gdGVtcDsKfQogCnRlbXBsYXRlPHVuc2lnbmVkIEJpdE9mZnNldCwgdW5zaWduZWQgQml0TGVuLCBjbGFzcyBNZXNzYWdlVGFnPXZvaWQ+CnN0cnVjdCBmaWVsZAp7CiAgICB0eXBlZGVmIE1lc3NhZ2VUYWcgbWVzc2FnZV90YWc7CiAgICBzdGF0aWMgY29uc3QgdW5zaWduZWQgYml0X29mZnNldCA9IEJpdE9mZnNldDsKICAgIHN0YXRpYyBjb25zdCB1bnNpZ25lZCBiaXRfbGVuID0gQml0TGVuOwp9OwogCnRlbXBsYXRlPGNsYXNzIE1lc3NhZ2VUYWc9dm9pZD4Kc3RydWN0IG1lc3NhZ2VfcHRyCnsKICAgIGNvbnN0IHVuc2lnbmVkIGNoYXIqIGRhdGE7CiAgICB1bnNpZ25lZCBsZW5ndGg7CiAKICAgIGV4cGxpY2l0IG1lc3NhZ2VfcHRyKGNvbnN0IHVuc2lnbmVkIGNoYXIgKnB0ciwgdW5zaWduZWQgbGVuKQogICAgICAgIDogZGF0YShwdHIpLCBsZW5ndGgobGVuKQogICAge30KIAogICAgdGVtcGxhdGU8dW5zaWduZWQgQml0T2Zmc2V0LCB1bnNpZ25lZCBCaXRMZW4+CiAgICBzdGQ6OnVpbnQzMl90IGdldChmaWVsZDxCaXRPZmZzZXQsQml0TGVuLE1lc3NhZ2VUYWc+KSBjb25zdAogICAgewogICAgICAgIGFzc2VydChCaXRPZmZzZXQrQml0TGVuIDw9IDgqbGVuZ3RoKTsKICAgICAgICByZXR1cm4gZ2V0X2JpdHNfbXNiZihkYXRhLEJpdE9mZnNldCxCaXRMZW4pOwogICAgfQp9OwogCi8vLS0tLS0tLS0tLVsgQW53ZW5kdW5nc2ZhbGwgXS0tLS0tLS0tLS0KIApuYW1lc3BhY2UgbXAzX3N0dWZmIHsKIApzdHJ1Y3QgZnJhbWVfaGVhZGVyX3RhZyB7fTsKY29uc3QgZmllbGQ8MCwxMSxmcmFtZV9oZWFkZXJfdGFnPiBzeW5jID0ge307CmNvbnN0IGZpZWxkPDExLDIsZnJhbWVfaGVhZGVyX3RhZz4gbXBlZ2lkID0ge307CmNvbnN0IGZpZWxkPDEzLDIsZnJhbWVfaGVhZGVyX3RhZz4gbGF5ZXIgPSB7fTsKY29uc3QgZmllbGQ8MTUsMSxmcmFtZV9oZWFkZXJfdGFnPiBwcm90ZWN0aW9uX2JpdCA9IHt9Owpjb25zdCBmaWVsZDwxNiw0LGZyYW1lX2hlYWRlcl90YWc+IGJpdHJhdGVfaW5kZXggPSB7fTsKY29uc3QgZmllbGQ8MjAsMixmcmFtZV9oZWFkZXJfdGFnPiBzYW1wbGluZ19yYXRlX2luZGV4ID0ge307CmNvbnN0IGZpZWxkPDIyLDEsZnJhbWVfaGVhZGVyX3RhZz4gcGFkZGluZ19iaXQgPSB7fTsKY29uc3QgZmllbGQ8MjMsMSxmcmFtZV9oZWFkZXJfdGFnPiBwcml2YXRlX2JpdCA9IHt9Owpjb25zdCBmaWVsZDwyNCwyLGZyYW1lX2hlYWRlcl90YWc+IGNoYW5uZWxfbW9kZSA9IHt9Owpjb25zdCBmaWVsZDwyNiwyLGZyYW1lX2hlYWRlcl90YWc+IGNtX2V4dGVuc2lvbiA9IHt9Owpjb25zdCBmaWVsZDwyOCwxLGZyYW1lX2hlYWRlcl90YWc+IGNvcHlyaWdodGVkX2JpdCA9IHt9Owpjb25zdCBmaWVsZDwyOSwxLGZyYW1lX2hlYWRlcl90YWc+IG9yaWdpbmFsX2JpdCA9IHt9Owpjb25zdCBmaWVsZDwzMCwyLGZyYW1lX2hlYWRlcl90YWc+IGVtcGhhc2lzX21vZGUgPSB7fTsKIApzdGF0aWMgY29uc3QgY2hhciogY29uc3QgbXBlZ2lkMnN0cltdID0geyJNUEVHIDIuNSIsICJyZXNlcnZlZCIsICJNUEVHIDIiLCAiTVBFRyAxIn07CnN0YXRpYyBjb25zdCBjaGFyKiBjb25zdCBjaGFubW9kZXNbXSA9IHsiU3RlcmVvIiwgIkpvaW50IFN0ZXJlbyIsICJEdWFsIENoYW5uZWwiLCAiTW9ubyJ9OwpzdGF0aWMgY29uc3QgbG9uZyBzcmF0ZVtdID0gezQ0MTAwLDQ4MDAwLDMyMDAwfTsKIAp9IC8vIG5hbWVzcGFjZSBtcDNfc3R1ZmYKIAp2b2lkIHRlc3QoKQp7CiAgICB1c2luZyBuYW1lc3BhY2Ugc3RkOwogICAgdXNpbmcgbmFtZXNwYWNlIG1wM19zdHVmZjsKICAgIHVuc2lnbmVkIGNoYXIgZGF0YVtdID0gezB4RkYsIDB4RkIsIDB4QTAsIDB4NjR9OwogICAgbWVzc2FnZV9wdHI8ZnJhbWVfaGVhZGVyX3RhZz4gbXB0ciAoZGF0YSw0KTsKICAgIGlmIChtcHRyLmdldChzeW5jKSA9PSAweDdGRikgewogICAgICAgIGNvdXQgPDwgIk1QRUcgICAgICAgICAgOiAiIDw8IG1wZWdpZDJzdHJbbXB0ci5nZXQobXBlZ2lkKV0gPDwgZW5kbDsKICAgICAgICBjb3V0IDw8ICJMYXllciAgICAgICAgIDogIiA8PCA0LW1wdHIuZ2V0KGxheWVyKSA8PCBlbmRsOwogICAgICAgIGNvdXQgPDwgIkJpdHJhdGUgaW5kZXggOiAiIDw8IG1wdHIuZ2V0KGJpdHJhdGVfaW5kZXgpIDw8IGVuZGw7CiAgICAgICAgY29uc3QgaW50IHNyZGl2aXNvciA9IDQtbXB0ci5nZXQobXBlZ2lkKTsKICAgICAgICBjb3V0IDw8ICJTYW1wbGluZyByYXRlIDogIiA8PCBzcmF0ZVttcHRyLmdldChzYW1wbGluZ19yYXRlX2luZGV4KV0vc3JkaXZpc29yIDw8IGVuZGw7CiAgICAgICAgY291dCA8PCAiQ2hhbm5lbCBtb2RlICA6ICIgPDwgY2hhbm1vZGVzW21wdHIuZ2V0KGNoYW5uZWxfbW9kZSldIDw8IGVuZGw7CiAgICB9IGVsc2UgewogICAgICAgIGNvdXQgPDwgIlN5bmMgYml0cyBpbnZhbGlkXG4iOwogICAgfQp9CiAKaW50IG1haW4oKQp7CiAgICB0ZXN0KCk7Cn0=