diff --git a/CMakeLists.txt b/CMakeLists.txt index aabd5449..d0a5a69f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -152,6 +152,7 @@ set(libHeaders ${SOURCE_DIR}/lib/mp4_generic.h ${SOURCE_DIR}/lib/mp4.h ${SOURCE_DIR}/lib/mp4_ms.h + ${SOURCE_DIR}/lib/mpeg.h ${SOURCE_DIR}/lib/nal.h ${SOURCE_DIR}/lib/ogg.h ${SOURCE_DIR}/lib/procs.h @@ -200,6 +201,7 @@ set(libSources ${SOURCE_DIR}/lib/mp4_encryption.cpp ${SOURCE_DIR}/lib/mp4_generic.cpp ${SOURCE_DIR}/lib/mp4_ms.cpp + ${SOURCE_DIR}/lib/mpeg.cpp ${SOURCE_DIR}/lib/nal.cpp ${SOURCE_DIR}/lib/ogg.cpp ${SOURCE_DIR}/lib/procs.cpp diff --git a/lib/mpeg.cpp b/lib/mpeg.cpp new file mode 100644 index 00000000..1c052eca --- /dev/null +++ b/lib/mpeg.cpp @@ -0,0 +1,63 @@ +#include "mpeg.h" + +namespace Mpeg{ + + MP2Info parseMP2Header(const std::string &hdr){return parseMP2Header(hdr.c_str());} + MP2Info parseMP2Header(const char *hdr){ + MP2Info res; + // mpeg version is on the bits 0x18 of header[1], but only 0x08 is important --> 0 is version 2, + // 1 is version 1 + // leads to 2 - value == version, -1 to get the right index for the array + int mpegVersion = 1 - ((hdr[1] >> 3) & 0x01); + // samplerate is encoded in bits 0x0C of header[2]; + res.sampleRate = sampleRates[mpegVersion][((hdr[2] >> 2) & 0x03)] * 1000; + res.channels = 2 - (hdr[3] >> 7); + return res; + } + + void MPEG2Info::clear(){ + width = 0; + height = 0; + fps = 0; + tempSeq = 0; + frameType = 0; + isHeader = false; + } + + MPEG2Info parseMPEG2Header(const std::string &hdr){return parseMPEG2Header(hdr.data());} + MPEG2Info parseMPEG2Header(const char *hdr){ + MPEG2Info res; + parseMPEG2Header(hdr, res); + return res; + } + bool parseMPEG2Header(const char *hdr, MPEG2Info &mpInfo){ + // Check for start code + if (hdr[0] != 0 || hdr[1] != 0 || hdr[2] != 1){return false;} + if (hdr[3] == 0xB3){// Sequence header + mpInfo.isHeader = true; + mpInfo.width = (hdr[4] << 4) | ((hdr[5] >> 4) & 0x0F); + mpInfo.height = ((hdr[5] & 0x0F) << 8) | hdr[6]; + mpInfo.fps = frameRate[hdr[7] & 0x0F]; + return true; + } + if (hdr[3] == 0x00){// Picture header + mpInfo.tempSeq = (((uint16_t)hdr[4]) << 2) || (hdr[5] >> 6); + mpInfo.frameType = (hdr[5] & 0x38) >> 3; + return true; + } + // Not parsed + return false; + } + void parseMPEG2Headers(const char *hdr, uint32_t len, MPEG2Info &mpInfo){ + mpInfo.clear(); + for (uint32_t i = 0; i < len-5; ++i){ + parseMPEG2Header(hdr+i, mpInfo); + } + } + MPEG2Info parseMPEG2Headers(const char *hdr, uint32_t len){ + MPEG2Info res; + parseMPEG2Headers(hdr, len, res); + return res; + } +} + diff --git a/lib/mpeg.h b/lib/mpeg.h new file mode 100644 index 00000000..8febeadd --- /dev/null +++ b/lib/mpeg.h @@ -0,0 +1,44 @@ +#include +#include + +namespace Mpeg{ + const static double sampleRates[2][3] ={{44.1, 48.0, 32.0},{22.05, 24.0, 16.0}}; + const static int sampleCounts[2][3] ={{374, 1152, 1152},{384, 1152, 576}}; + const static int bitRates[2][3][16] ={ + {{0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448, -1}, + {0, 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384, -1}, + {0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, -1}}, + {{0, 32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256, -1}, + {0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, -1}, + {0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, -1}}}; + + struct MP2Info{ + uint64_t sampleRate; + uint8_t channels; + }; + + MP2Info parseMP2Header(const std::string &hdr); + MP2Info parseMP2Header(const char *hdr); + + const static double frameRate[16] ={ + 0, 24000.0 / 1001, 24, 25, 30000.0 / 1001, 30, 50, 60000.0 / 1001, 60, 0, 0, 0, 0, 0, 0, 0}; + + class MPEG2Info{ + public: + MPEG2Info(){clear();} + void clear(); + uint64_t width; + uint64_t height; + double fps; + uint16_t tempSeq; + uint8_t frameType; + bool isHeader; + }; + + MPEG2Info parseMPEG2Header(const std::string &hdr); + MPEG2Info parseMPEG2Header(const char *hdr); + bool parseMPEG2Header(const char *hdr, MPEG2Info &mpInfo); + void parseMPEG2Headers(const char *hdr, uint32_t len, MPEG2Info &mpInfo); + MPEG2Info parseMPEG2Headers(const char *hdr, uint32_t len); +} + diff --git a/src/input/input_mp3.cpp b/src/input/input_mp3.cpp index c640fda5..e128f8f0 100644 --- a/src/input/input_mp3.cpp +++ b/src/input/input_mp3.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include "input_mp3.h" @@ -70,13 +71,9 @@ namespace Mist { fread(header, 4, 1, inFile); fseek(inFile, filePos, SEEK_SET); - //mpeg version is on the bits 0x18 of header[1], but only 0x08 is important --> 0 is version 2, 1 is version 1 - //leads to 2 - value == version, -1 to get the right index for the array - int mpegVersion = 1 - ((header[1] >> 3) & 0x01); - //samplerate is encoded in bits 0x0C of header[2]; - myMeta.tracks[1].rate = sampleRates[mpegVersion][((header[2] >> 2) & 0x03)] * 1000; - myMeta.tracks[1].channels = 2 - ( header[3] >> 7); - + Mpeg::MP2Info mp2Info = Mpeg::parseMP2Header(header); + myMeta.tracks[1].rate = mp2Info.sampleRate; + myMeta.tracks[1].channels = mp2Info.channels; getNext(); while (thisPacket){