Clementine-audio-player-Mac.../3rdparty/taglib/mpeg/mpegheader.cpp

280 lines
7.1 KiB
C++

/***************************************************************************
copyright : (C) 2002 - 2008 by Scott Wheeler
email : wheeler@kde.org
***************************************************************************/
/***************************************************************************
* This library is free software; you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License version *
* 2.1 as published by the Free Software Foundation. *
* *
* This library is distributed in the hope that it will be useful, but *
* WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
* Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public *
* License along with this library; if not, write to the Free Software *
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
* 02110-1301 USA *
* *
* Alternatively, this file is available under the Mozilla Public *
* License Version 1.1. You may obtain a copy of the License at *
* http://www.mozilla.org/MPL/ *
***************************************************************************/
#include <bitset>
#include <tbytevector.h>
#include <tstring.h>
#include <tdebug.h>
#include "trefcounter.h"
#include "mpegheader.h"
using namespace TagLib;
class MPEG::Header::HeaderPrivate : public RefCounter
{
public:
HeaderPrivate() :
isValid(false),
version(Version1),
layer(0),
protectionEnabled(false),
sampleRate(0),
isPadded(false),
channelMode(Stereo),
isCopyrighted(false),
isOriginal(false),
frameLength(0),
samplesPerFrame(0) {}
bool isValid;
Version version;
int layer;
bool protectionEnabled;
int bitrate;
int sampleRate;
bool isPadded;
ChannelMode channelMode;
bool isCopyrighted;
bool isOriginal;
int frameLength;
int samplesPerFrame;
};
////////////////////////////////////////////////////////////////////////////////
// public members
////////////////////////////////////////////////////////////////////////////////
MPEG::Header::Header(const ByteVector &data)
{
d = new HeaderPrivate;
parse(data);
}
MPEG::Header::Header(const Header &h) : d(h.d)
{
d->ref();
}
MPEG::Header::~Header()
{
if (d->deref())
delete d;
}
bool MPEG::Header::isValid() const
{
return d->isValid;
}
MPEG::Header::Version MPEG::Header::version() const
{
return d->version;
}
int MPEG::Header::layer() const
{
return d->layer;
}
bool MPEG::Header::protectionEnabled() const
{
return d->protectionEnabled;
}
int MPEG::Header::bitrate() const
{
return d->bitrate;
}
int MPEG::Header::sampleRate() const
{
return d->sampleRate;
}
bool MPEG::Header::isPadded() const
{
return d->isPadded;
}
MPEG::Header::ChannelMode MPEG::Header::channelMode() const
{
return d->channelMode;
}
bool MPEG::Header::isCopyrighted() const
{
return d->isCopyrighted;
}
bool MPEG::Header::isOriginal() const
{
return d->isOriginal;
}
int MPEG::Header::frameLength() const
{
return d->frameLength;
}
int MPEG::Header::samplesPerFrame() const
{
return d->samplesPerFrame;
}
MPEG::Header &MPEG::Header::operator=(const Header &h)
{
if(&h == this)
return *this;
if(d->deref())
delete d;
d = h.d;
d->ref();
return *this;
}
////////////////////////////////////////////////////////////////////////////////
// private members
////////////////////////////////////////////////////////////////////////////////
void MPEG::Header::parse(const ByteVector &data)
{
if(data.size() < 4 || uchar(data[0]) != 0xff) {
debug("MPEG::Header::parse() -- First byte did not match MPEG synch.");
return;
}
std::bitset<32> flags(TAGLIB_CONSTRUCT_BITSET(data.toUInt()));
// Check for the second byte's part of the MPEG synch
if(!flags[23] || !flags[22] || !flags[21]) {
debug("MPEG::Header::parse() -- Second byte did not match MPEG synch.");
return;
}
// Set the MPEG version
if(!flags[20] && !flags[19])
d->version = Version2_5;
else if(flags[20] && !flags[19])
d->version = Version2;
else if(flags[20] && flags[19])
d->version = Version1;
// Set the MPEG layer
if(!flags[18] && flags[17])
d->layer = 3;
else if(flags[18] && !flags[17])
d->layer = 2;
else if(flags[18] && flags[17])
d->layer = 1;
d->protectionEnabled = !flags[16];
// Set the bitrate
static const int bitrates[2][3][16] = {
{ // Version 1
{ 0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448, 0 }, // layer 1
{ 0, 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384, 0 }, // layer 2
{ 0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 0 } // layer 3
},
{ // Version 2 or 2.5
{ 0, 32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256, 0 }, // layer 1
{ 0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, 0 }, // layer 2
{ 0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, 0 } // layer 3
}
};
const int versionIndex = (d->version == Version1) ? 0 : 1;
const int layerIndex = (d->layer > 0) ? d->layer - 1 : 0;
// The bitrate index is encoded as the first 4 bits of the 3rd byte,
// i.e. 1111xxxx
int i = uchar(data[2]) >> 4;
d->bitrate = bitrates[versionIndex][layerIndex][i];
// Set the sample rate
static const int sampleRates[3][4] = {
{ 44100, 48000, 32000, 0 }, // Version 1
{ 22050, 24000, 16000, 0 }, // Version 2
{ 11025, 12000, 8000, 0 } // Version 2.5
};
// The sample rate index is encoded as two bits in the 3nd byte, i.e. xxxx11xx
i = uchar(data[2]) >> 2 & 0x03;
d->sampleRate = sampleRates[d->version][i];
if(d->sampleRate == 0) {
debug("MPEG::Header::parse() -- Invalid sample rate.");
return;
}
// The channel mode is encoded as a 2 bit value at the end of the 3nd byte,
// i.e. xxxxxx11
d->channelMode = ChannelMode((uchar(data[3]) & 0xC0) >> 6);
// TODO: Add mode extension for completeness
d->isOriginal = flags[2];
d->isCopyrighted = flags[3];
d->isPadded = flags[9];
// Samples per frame
static const int samplesPerFrame[3][2] = {
// MPEG1, 2/2.5
{ 384, 384 }, // Layer I
{ 1152, 1152 }, // Layer II
{ 1152, 576 } // Layer III
};
d->samplesPerFrame = samplesPerFrame[layerIndex][versionIndex];
// Calculate the frame length
static const int paddingSize[3] = { 4, 1, 1 };
d->frameLength = d->samplesPerFrame * d->bitrate * 125 / d->sampleRate;
if(d->isPadded)
d->frameLength += paddingSize[layerIndex];
// Now that we're done parsing, set this to be a valid frame.
d->isValid = true;
}