fork download
  1. #include <iostream>
  2. #include <cstdint>
  3. #include <cassert>
  4.  
  5. //----------[ generischer Kram ]----------
  6.  
  7. // extracts a sequence of bits from an unsigned char array
  8. // at arbitrary bit positions (most significant bits first)
  9. std::uint32_t get_bits_msbf(
  10. const unsigned char data[],
  11. unsigned bit_offset, unsigned nbits)
  12. {
  13. // TODO: Diese Implementierung kann man vielleicht noch vereinfachen.
  14. assert(nbits <= 32);
  15. if (nbits == 0) return 0u;
  16. data += bit_offset / 8;
  17. bit_offset &= 7;
  18. unsigned tlen = 8 - bit_offset;
  19. std::uint32_t temp = *data & (0xFFu >> bit_offset);
  20. if (tlen >= nbits)
  21. return temp >> (tlen-nbits);
  22. while (tlen+8 <= nbits) {
  23. ++data;
  24. temp = (temp << 8) | (*data & 0xFFu);
  25. tlen += 8;
  26. }
  27. unsigned missing = nbits - tlen;
  28. if (missing) {
  29. ++data;
  30. temp = (temp << missing) | (*data >> (8-missing));
  31. }
  32. return temp;
  33. }
  34.  
  35. template<unsigned BitOffset, unsigned BitLen, class MessageTag=void>
  36. struct field
  37. {
  38. typedef MessageTag message_tag;
  39. static const unsigned bit_offset = BitOffset;
  40. static const unsigned bit_len = BitLen;
  41. };
  42.  
  43. template<class MessageTag=void>
  44. struct message_ptr
  45. {
  46. const unsigned char* data;
  47. unsigned length;
  48.  
  49. explicit message_ptr(const unsigned char *ptr, unsigned len)
  50. : data(ptr), length(len)
  51. {}
  52.  
  53. template<unsigned BitOffset, unsigned BitLen>
  54. std::uint32_t get(field<BitOffset,BitLen,MessageTag>) const
  55. {
  56. assert(BitOffset+BitLen <= 8*length);
  57. return get_bits_msbf(data,BitOffset,BitLen);
  58. }
  59. };
  60.  
  61. //----------[ Anwendungsfall ]----------
  62.  
  63. namespace mp3_stuff {
  64.  
  65. struct frame_header_tag {};
  66. const field<0,11,frame_header_tag> sync = {};
  67. const field<11,2,frame_header_tag> mpegid = {};
  68. const field<13,2,frame_header_tag> layer = {};
  69. const field<15,1,frame_header_tag> protection_bit = {};
  70. const field<16,4,frame_header_tag> bitrate_index = {};
  71. const field<20,2,frame_header_tag> sampling_rate_index = {};
  72. const field<22,1,frame_header_tag> padding_bit = {};
  73. const field<23,1,frame_header_tag> private_bit = {};
  74. const field<24,2,frame_header_tag> channel_mode = {};
  75. const field<26,2,frame_header_tag> cm_extension = {};
  76. const field<28,1,frame_header_tag> copyrighted_bit = {};
  77. const field<29,1,frame_header_tag> original_bit = {};
  78. const field<30,2,frame_header_tag> emphasis_mode = {};
  79.  
  80. static const char* const mpegid2str[] = {"MPEG 2.5", "reserved", "MPEG 2", "MPEG 1"};
  81. static const char* const chanmodes[] = {"Stereo", "Joint Stereo", "Dual Channel", "Mono"};
  82. static const long srate[] = {44100,48000,32000};
  83.  
  84. } // namespace mp3_stuff
  85.  
  86. void test()
  87. {
  88. using namespace std;
  89. using namespace mp3_stuff;
  90. unsigned char data[] = {0xFF, 0xFB, 0xA0, 0x64};
  91. message_ptr<frame_header_tag> mptr (data,4);
  92. if (mptr.get(sync) == 0x7FF) {
  93. cout << "MPEG : " << mpegid2str[mptr.get(mpegid)] << endl;
  94. cout << "Layer : " << 4-mptr.get(layer) << endl;
  95. cout << "Bitrate index : " << mptr.get(bitrate_index) << endl;
  96. const int srdivisor = 4-mptr.get(mpegid);
  97. cout << "Sampling rate : " << srate[mptr.get(sampling_rate_index)]/srdivisor << endl;
  98. cout << "Channel mode : " << chanmodes[mptr.get(channel_mode)] << endl;
  99. } else {
  100. cout << "Sync bits invalid\n";
  101. }
  102. }
  103.  
  104. int main()
  105. {
  106. test();
  107. }
Success #stdin #stdout 0s 2856KB
stdin
Standard input is empty
stdout
MPEG          : MPEG 1
Layer         : 3
Bitrate index : 10
Sampling rate : 44100
Channel mode  : Joint Stereo