Merge "Parse mp3 encoder padding/delay"

This commit is contained in:
Marco Nelissen
2012-03-20 09:15:05 -07:00
committed by Android (Google) Code Review
6 changed files with 111 additions and 17 deletions

View File

@@ -70,6 +70,8 @@ enum {
kKeyThumbnailTime = 'thbT', // int64_t (usecs)
kKeyTrackID = 'trID',
kKeyIsDRM = 'idrm', // int32_t (bool)
kKeyEncoderDelay = 'encd', // int32_t (frames)
kKeyEncoderPadding = 'encp', // int32_t (frames)
kKeyAlbum = 'albu', // cstring
kKeyArtist = 'arti', // cstring

View File

@@ -311,10 +311,18 @@ MP3Extractor::MP3Extractor(
mMeta->setInt32(kKeyBitRate, bitrate * 1000);
mMeta->setInt32(kKeyChannelCount, num_channels);
mSeeker = XINGSeeker::CreateFromSource(mDataSource, mFirstFramePos);
sp<XINGSeeker> seeker = XINGSeeker::CreateFromSource(mDataSource, mFirstFramePos);
if (mSeeker == NULL) {
if (seeker == NULL) {
mSeeker = VBRISeeker::CreateFromSource(mDataSource, post_id3_pos);
} else {
mSeeker = seeker;
int encd = seeker->getEncoderDelay();
int encp = seeker->getEncoderPadding();
if (encd != 0 || encp != 0) {
mMeta->setInt32(kKeyEncoderDelay, encd);
mMeta->setInt32(kKeyEncoderPadding, encp);
}
}
if (mSeeker != NULL) {
@@ -547,6 +555,33 @@ sp<MetaData> MP3Extractor::getMetaData() {
return meta;
}
ID3::Iterator *com = new ID3::Iterator(id3, "COM");
if (com->done()) {
delete com;
com = new ID3::Iterator(id3, "COMM");
}
while(!com->done()) {
String8 commentdesc;
String8 commentvalue;
com->getString(&commentdesc, &commentvalue);
const char * desc = commentdesc.string();
const char * value = commentvalue.string();
// first 3 characters are the language, which we don't care about
if(strlen(desc) > 3 && strcmp(desc + 3, "iTunSMPB") == 0) {
int32_t delay, padding;
if (sscanf(value, " %*x %x %x %*x", &delay, &padding) == 2) {
mMeta->setInt32(kKeyEncoderDelay, delay);
mMeta->setInt32(kKeyEncoderPadding, padding);
}
break;
}
com->next();
}
delete com;
com = NULL;
struct Map {
int key;
const char *tag1;

View File

@@ -14,6 +14,9 @@
* limitations under the License.
*/
#define LOG_TAG "XINGSEEKER"
#include <utils/Log.h>
#include "include/XINGSeeker.h"
#include "include/avc_utils.h"
@@ -24,7 +27,9 @@ namespace android {
XINGSeeker::XINGSeeker()
: mDurationUs(-1),
mSizeBytes(0) {
mSizeBytes(0),
mEncoderDelay(0),
mEncoderPadding(0) {
}
bool XINGSeeker::getDuration(int64_t *durationUs) {
@@ -76,8 +81,6 @@ sp<XINGSeeker> XINGSeeker::CreateFromSource(
seeker->mFirstFramePos = first_frame_pos;
ALOGI("xingseeker first frame pos: %lld", first_frame_pos);
seeker->mSizeBytes = 0;
seeker->mTOCValid = false;
seeker->mDurationUs = 0;
@@ -111,6 +114,8 @@ sp<XINGSeeker> XINGSeeker::CreateFromSource(
else offset += 9;
}
int xingbase = offset;
if (source->readAt(offset, &buffer, 4) < 4) { // XING header ID
return NULL;
}
@@ -161,10 +166,31 @@ sp<XINGSeeker> XINGSeeker::CreateFromSource(
// do something with the quality indicator
offset += 4;
}
if (source->readAt(xingbase + 0xaf - 0x24, &buffer, 1) < 1) { // encoding flags
return false;
}
ALOGV("nogap preceding: %s, nogap continued in next: %s",
(buffer[0] & 0x80) ? "true" : "false",
(buffer[0] & 0x40) ? "true" : "false");
#endif
if (source->readAt(xingbase + 0xb1 - 0x24, &buffer, 3) == 3) {
seeker->mEncoderDelay = (buffer[0] << 4) + (buffer[1] >> 4);
seeker->mEncoderPadding = ((buffer[1] & 0xf) << 8) + buffer[2];
}
return seeker;
}
int32_t XINGSeeker::getEncoderDelay() {
return mEncoderDelay;
}
int32_t XINGSeeker::getEncoderPadding() {
return mEncoderPadding;
}
} // namespace android

View File

@@ -463,40 +463,65 @@ static void convertISO8859ToString8(
tmp = NULL;
}
void ID3::Iterator::getString(String8 *id) const {
// the 2nd argument is used to get the data following the \0 in a comment field
void ID3::Iterator::getString(String8 *id, String8 *comment) const {
getstring(id, false);
if (comment != NULL) {
getstring(comment, true);
}
}
// comment fields (COM/COMM) contain an initial short descriptor, followed by \0,
// followed by more data. The data following the \0 can be retrieved by setting
// "otherdata" to true.
void ID3::Iterator::getstring(String8 *id, bool otherdata) const {
id->setTo("");
if (mFrameData == NULL) {
const uint8_t *frameData = mFrameData;
if (frameData == NULL) {
return;
}
uint8_t encoding = *frameData;
if (mParent.mVersion == ID3_V1 || mParent.mVersion == ID3_V1_1) {
if (mOffset == 126 || mOffset == 127) {
// Special treatment for the track number and genre.
char tmp[16];
sprintf(tmp, "%d", (int)*mFrameData);
sprintf(tmp, "%d", (int)*frameData);
id->setTo(tmp);
return;
}
convertISO8859ToString8(mFrameData, mFrameSize, id);
convertISO8859ToString8(frameData, mFrameSize, id);
return;
}
size_t n = mFrameSize - getHeaderLength() - 1;
if (otherdata) {
// skip past the encoding, language, and the 0 separator
frameData += 4;
int32_t i = n - 4;
while(--i >= 0 && *++frameData != 0) ;
int skipped = (frameData - mFrameData);
if (skipped >= n) {
return;
}
n -= skipped;
}
if (*mFrameData == 0x00) {
if (encoding == 0x00) {
// ISO 8859-1
convertISO8859ToString8(mFrameData + 1, n, id);
} else if (*mFrameData == 0x03) {
convertISO8859ToString8(frameData + 1, n, id);
} else if (encoding == 0x03) {
// UTF-8
id->setTo((const char *)(mFrameData + 1), n);
} else if (*mFrameData == 0x02) {
id->setTo((const char *)(frameData + 1), n);
} else if (encoding == 0x02) {
// UTF-16 BE, no byte order mark.
// API wants number of characters, not number of bytes...
int len = n / 2;
const char16_t *framedata = (const char16_t *) (mFrameData + 1);
const char16_t *framedata = (const char16_t *) (frameData + 1);
char16_t *framedatacopy = NULL;
#if BYTE_ORDER == LITTLE_ENDIAN
framedatacopy = new char16_t[len];
@@ -513,7 +538,7 @@ void ID3::Iterator::getString(String8 *id) const {
// UCS-2
// API wants number of characters, not number of bytes...
int len = n / 2;
const char16_t *framedata = (const char16_t *) (mFrameData + 1);
const char16_t *framedata = (const char16_t *) (frameData + 1);
char16_t *framedatacopy = NULL;
if (*framedata == 0xfffe) {
// endianness marker doesn't match host endianness, convert

View File

@@ -50,7 +50,7 @@ struct ID3 {
bool done() const;
void getID(String8 *id) const;
void getString(String8 *s) const;
void getString(String8 *s, String8 *ss = NULL) const;
const uint8_t *getData(size_t *length) const;
void next();
@@ -65,6 +65,7 @@ struct ID3 {
void findFrame();
size_t getHeaderLength() const;
void getstring(String8 *s, bool secondhalf) const;
Iterator(const Iterator &);
Iterator &operator=(const Iterator &);

View File

@@ -31,10 +31,15 @@ struct XINGSeeker : public MP3Seeker {
virtual bool getDuration(int64_t *durationUs);
virtual bool getOffsetForTime(int64_t *timeUs, off64_t *pos);
virtual int32_t getEncoderDelay();
virtual int32_t getEncoderPadding();
private:
int64_t mFirstFramePos;
int64_t mDurationUs;
int32_t mSizeBytes;
int32_t mEncoderDelay;
int32_t mEncoderPadding;
// TOC entries in XING header. Skip the first one since it's always 0.
unsigned char mTOC[99];