diff options
author | Jef <jef@targetspot.com> | 2024-09-24 08:54:57 -0400 |
---|---|---|
committer | Jef <jef@targetspot.com> | 2024-09-24 08:54:57 -0400 |
commit | 20d28e80a5c861a9d5f449ea911ab75b4f37ad0d (patch) | |
tree | 12f17f78986871dd2cfb0a56e5e93b545c1ae0d0 /Src/external_dependencies/openmpt-trunk/soundlib/MPEGFrame.cpp | |
parent | 537bcbc86291b32fc04ae4133ce4d7cac8ebe9a7 (diff) | |
download | winamp-20d28e80a5c861a9d5f449ea911ab75b4f37ad0d.tar.gz |
Initial community commit
Diffstat (limited to 'Src/external_dependencies/openmpt-trunk/soundlib/MPEGFrame.cpp')
-rw-r--r-- | Src/external_dependencies/openmpt-trunk/soundlib/MPEGFrame.cpp | 113 |
1 files changed, 113 insertions, 0 deletions
diff --git a/Src/external_dependencies/openmpt-trunk/soundlib/MPEGFrame.cpp b/Src/external_dependencies/openmpt-trunk/soundlib/MPEGFrame.cpp new file mode 100644 index 00000000..16547539 --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/soundlib/MPEGFrame.cpp @@ -0,0 +1,113 @@ +/* + * MPEGFrame.cpp + * ------------- + * Purpose: Basic MPEG frame parsing functionality + * Notes : (currently none) + * Authors: OpenMPT Devs + * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. + */ + + +#include "stdafx.h" +#include "MPEGFrame.h" +#include "../common/FileReader.h" + +OPENMPT_NAMESPACE_BEGIN + +// Samples per frame - for each MPEG version and all three layers +static constexpr uint16 samplesPerFrame[2][3] = +{ + { 384, 1152, 1152 }, // MPEG 1 + { 384, 1152, 576 } // MPEG 2 / 2.5 +}; +// Bit rates for each MPEG version and all three layers +static constexpr uint16 bitRates[2][3][15] = +{ + // MPEG 1 + { + { 0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448 }, // Layer 1 + { 0, 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384 }, // Layer 2 + { 0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320 } // Layer 3 + }, + // MPEG 2 / 2.5 + { + { 0, 32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256 }, // Layer 1 + { 0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160 }, // Layer 2 + { 0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160 } // Layer 3 + } +}; +// Sampling rates for each MPEG version and all three layers +static constexpr uint16 samplingRates[4][3] = +{ + { 11025, 12000, 8000 }, // MPEG 2.5 + { 0, 0, 0 }, // Invalid + { 22050, 24000, 16000 }, // MPEG 2 + { 44100, 48000, 32000 } // MPEG 1 +}; +// Samples per Frame / 8 +static constexpr uint8 mpegCoefficients[2][3] = +{ + { 12, 144, 144 }, // MPEG 1 + { 12, 144, 72 } // MPEG 2 / 2.5 +}; +// Side info size = Offset in frame where Xing/Info magic starts +static constexpr uint8 sideInfoSize[2][2] = +{ + { 17, 32 }, // MPEG 1 + { 9, 17 } // MPEG 2 / 2.5 +}; + + +bool MPEGFrame::IsMPEGHeader(const uint8 (&header)[3]) +{ + return header[0] == 0xFF && (header[1] & 0xE0) == 0xE0 // Sync + && (header[1] & 0x18) != 0x08 // Invalid MPEG version + && (header[1] & 0x06) != 0x00 // Invalid MPEG layer + && (header[2] & 0x0C) != 0x0C // Invalid frequency + && (header[2] & 0xF0) != 0xF0; // Invalid bitrate +} + + +MPEGFrame::MPEGFrame(FileReader &file) + : frameSize(0) + , numSamples(0) + , isValid(false) + , isLAME(false) +{ + uint8 header[4]; + file.ReadArray(header); + + if(!IsMPEGHeader(reinterpret_cast<const uint8(&)[3]>(header))) + return; + + uint8 version = (header[1] & 0x18) >> 3; + uint8 mpeg1 = (version == 3) ? 0 : 1; + uint8 layer = 3 - ((header[1] & 0x06) >> 1); + uint8 bitRate = (header[2] & 0xF0) >> 4; + uint8 sampleRate = (header[2] & 0x0C) >> 2; + uint8 padding = (header[2] & 0x02) >> 1; + bool stereo = ((header[3] & 0xC0) >> 6) != 3; + + isValid = true; + frameSize = (((mpegCoefficients[mpeg1][layer] * (bitRates[mpeg1][layer][bitRate] * 1000) / samplingRates[version][sampleRate]) + padding)) * (layer == 0 ? 4 : 1); + numSamples = samplesPerFrame[mpeg1][layer]; + if(stereo) numSamples *= 2u; + + uint32 lameOffset = sideInfoSize[mpeg1][stereo ? 1 : 0]; + if(frameSize < lameOffset + 8) + return; + + uint8 frame[36]; + file.ReadStructPartial(frame, lameOffset + 4); + // Don't check first two bytes, might be CRC + for(uint32 i = 2; i < lameOffset; i++) + { + if(frame[i] != 0) + return; + } + + // This is all we really need to know for our purposes in the MO3 decoder. + isLAME = !memcmp(frame + lameOffset, "Info", 4) || !memcmp(frame + lameOffset, "Xing", 4); +} + +OPENMPT_NAMESPACE_END |