Merge "Parse mp3 encoder padding/delay"
This commit is contained in:
committed by
Android (Google) Code Review
commit
54fa725483
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 &);
|
||||
|
||||
@@ -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];
|
||||
|
||||
Reference in New Issue
Block a user