Skip to content

Commit 2ed7770

Browse files
committed
Parse mp3 encoder padding/delay
Get the mp3 encoder padding and delay from a XING frame or iTunSMPB tag. Change-Id: Icde598c8857d7e7c187a718f478ee9799d6a1b8a
1 parent 4fc769e commit 2ed7770

File tree

6 files changed

+111
-17
lines changed

6 files changed

+111
-17
lines changed

include/media/stagefright/MetaData.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,8 @@ enum {
7070
kKeyThumbnailTime = 'thbT', // int64_t (usecs)
7171
kKeyTrackID = 'trID',
7272
kKeyIsDRM = 'idrm', // int32_t (bool)
73+
kKeyEncoderDelay = 'encd', // int32_t (frames)
74+
kKeyEncoderPadding = 'encp', // int32_t (frames)
7375

7476
kKeyAlbum = 'albu', // cstring
7577
kKeyArtist = 'arti', // cstring

media/libstagefright/MP3Extractor.cpp

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -311,10 +311,18 @@ MP3Extractor::MP3Extractor(
311311
mMeta->setInt32(kKeyBitRate, bitrate * 1000);
312312
mMeta->setInt32(kKeyChannelCount, num_channels);
313313

314-
mSeeker = XINGSeeker::CreateFromSource(mDataSource, mFirstFramePos);
314+
sp<XINGSeeker> seeker = XINGSeeker::CreateFromSource(mDataSource, mFirstFramePos);
315315

316-
if (mSeeker == NULL) {
316+
if (seeker == NULL) {
317317
mSeeker = VBRISeeker::CreateFromSource(mDataSource, post_id3_pos);
318+
} else {
319+
mSeeker = seeker;
320+
int encd = seeker->getEncoderDelay();
321+
int encp = seeker->getEncoderPadding();
322+
if (encd != 0 || encp != 0) {
323+
mMeta->setInt32(kKeyEncoderDelay, encd);
324+
mMeta->setInt32(kKeyEncoderPadding, encp);
325+
}
318326
}
319327

320328
if (mSeeker != NULL) {
@@ -547,6 +555,33 @@ sp<MetaData> MP3Extractor::getMetaData() {
547555
return meta;
548556
}
549557

558+
ID3::Iterator *com = new ID3::Iterator(id3, "COM");
559+
if (com->done()) {
560+
delete com;
561+
com = new ID3::Iterator(id3, "COMM");
562+
}
563+
while(!com->done()) {
564+
String8 commentdesc;
565+
String8 commentvalue;
566+
com->getString(&commentdesc, &commentvalue);
567+
const char * desc = commentdesc.string();
568+
const char * value = commentvalue.string();
569+
570+
// first 3 characters are the language, which we don't care about
571+
if(strlen(desc) > 3 && strcmp(desc + 3, "iTunSMPB") == 0) {
572+
573+
int32_t delay, padding;
574+
if (sscanf(value, " %*x %x %x %*x", &delay, &padding) == 2) {
575+
mMeta->setInt32(kKeyEncoderDelay, delay);
576+
mMeta->setInt32(kKeyEncoderPadding, padding);
577+
}
578+
break;
579+
}
580+
com->next();
581+
}
582+
delete com;
583+
com = NULL;
584+
550585
struct Map {
551586
int key;
552587
const char *tag1;

media/libstagefright/XINGSeeker.cpp

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@
1414
* limitations under the License.
1515
*/
1616

17+
#define LOG_TAG "XINGSEEKER"
18+
#include <utils/Log.h>
19+
1720
#include "include/XINGSeeker.h"
1821
#include "include/avc_utils.h"
1922

@@ -24,7 +27,9 @@ namespace android {
2427

2528
XINGSeeker::XINGSeeker()
2629
: mDurationUs(-1),
27-
mSizeBytes(0) {
30+
mSizeBytes(0),
31+
mEncoderDelay(0),
32+
mEncoderPadding(0) {
2833
}
2934

3035
bool XINGSeeker::getDuration(int64_t *durationUs) {
@@ -76,8 +81,6 @@ sp<XINGSeeker> XINGSeeker::CreateFromSource(
7681

7782
seeker->mFirstFramePos = first_frame_pos;
7883

79-
ALOGI("xingseeker first frame pos: %lld", first_frame_pos);
80-
8184
seeker->mSizeBytes = 0;
8285
seeker->mTOCValid = false;
8386
seeker->mDurationUs = 0;
@@ -111,6 +114,8 @@ sp<XINGSeeker> XINGSeeker::CreateFromSource(
111114
else offset += 9;
112115
}
113116

117+
int xingbase = offset;
118+
114119
if (source->readAt(offset, &buffer, 4) < 4) { // XING header ID
115120
return NULL;
116121
}
@@ -161,10 +166,31 @@ sp<XINGSeeker> XINGSeeker::CreateFromSource(
161166
// do something with the quality indicator
162167
offset += 4;
163168
}
169+
170+
if (source->readAt(xingbase + 0xaf - 0x24, &buffer, 1) < 1) { // encoding flags
171+
return false;
172+
}
173+
174+
ALOGV("nogap preceding: %s, nogap continued in next: %s",
175+
(buffer[0] & 0x80) ? "true" : "false",
176+
(buffer[0] & 0x40) ? "true" : "false");
164177
#endif
165178

179+
if (source->readAt(xingbase + 0xb1 - 0x24, &buffer, 3) == 3) {
180+
seeker->mEncoderDelay = (buffer[0] << 4) + (buffer[1] >> 4);
181+
seeker->mEncoderPadding = ((buffer[1] & 0xf) << 8) + buffer[2];
182+
}
183+
166184
return seeker;
167185
}
168186

187+
int32_t XINGSeeker::getEncoderDelay() {
188+
return mEncoderDelay;
189+
}
190+
191+
int32_t XINGSeeker::getEncoderPadding() {
192+
return mEncoderPadding;
193+
}
194+
169195
} // namespace android
170196

media/libstagefright/id3/ID3.cpp

Lines changed: 36 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -463,40 +463,65 @@ static void convertISO8859ToString8(
463463
tmp = NULL;
464464
}
465465

466-
void ID3::Iterator::getString(String8 *id) const {
466+
// the 2nd argument is used to get the data following the \0 in a comment field
467+
void ID3::Iterator::getString(String8 *id, String8 *comment) const {
468+
getstring(id, false);
469+
if (comment != NULL) {
470+
getstring(comment, true);
471+
}
472+
}
473+
474+
// comment fields (COM/COMM) contain an initial short descriptor, followed by \0,
475+
// followed by more data. The data following the \0 can be retrieved by setting
476+
// "otherdata" to true.
477+
void ID3::Iterator::getstring(String8 *id, bool otherdata) const {
467478
id->setTo("");
468479

469-
if (mFrameData == NULL) {
480+
const uint8_t *frameData = mFrameData;
481+
if (frameData == NULL) {
470482
return;
471483
}
472484

485+
uint8_t encoding = *frameData;
486+
473487
if (mParent.mVersion == ID3_V1 || mParent.mVersion == ID3_V1_1) {
474488
if (mOffset == 126 || mOffset == 127) {
475489
// Special treatment for the track number and genre.
476490
char tmp[16];
477-
sprintf(tmp, "%d", (int)*mFrameData);
491+
sprintf(tmp, "%d", (int)*frameData);
478492

479493
id->setTo(tmp);
480494
return;
481495
}
482496

483-
convertISO8859ToString8(mFrameData, mFrameSize, id);
497+
convertISO8859ToString8(frameData, mFrameSize, id);
484498
return;
485499
}
486500

487501
size_t n = mFrameSize - getHeaderLength() - 1;
502+
if (otherdata) {
503+
// skip past the encoding, language, and the 0 separator
504+
frameData += 4;
505+
int32_t i = n - 4;
506+
while(--i >= 0 && *++frameData != 0) ;
507+
int skipped = (frameData - mFrameData);
508+
if (skipped >= n) {
509+
return;
510+
}
511+
n -= skipped;
512+
}
488513

489-
if (*mFrameData == 0x00) {
514+
if (encoding == 0x00) {
490515
// ISO 8859-1
491-
convertISO8859ToString8(mFrameData + 1, n, id);
492-
} else if (*mFrameData == 0x03) {
516+
convertISO8859ToString8(frameData + 1, n, id);
517+
} else if (encoding == 0x03) {
493518
// UTF-8
494-
id->setTo((const char *)(mFrameData + 1), n);
495-
} else if (*mFrameData == 0x02) {
519+
id->setTo((const char *)(frameData + 1), n);
520+
} else if (encoding == 0x02) {
496521
// UTF-16 BE, no byte order mark.
497522
// API wants number of characters, not number of bytes...
498523
int len = n / 2;
499-
const char16_t *framedata = (const char16_t *) (mFrameData + 1);
524+
const char16_t *framedata = (const char16_t *) (frameData + 1);
500525
char16_t *framedatacopy = NULL;
501526
#if BYTE_ORDER == LITTLE_ENDIAN
502527
framedatacopy = new char16_t[len];
@@ -513,7 +538,7 @@ void ID3::Iterator::getString(String8 *id) const {
513538
// UCS-2
514539
// API wants number of characters, not number of bytes...
515540
int len = n / 2;
516-
const char16_t *framedata = (const char16_t *) (mFrameData + 1);
541+
const char16_t *framedata = (const char16_t *) (frameData + 1);
517542
char16_t *framedatacopy = NULL;
518543
if (*framedata == 0xfffe) {
519544
// endianness marker doesn't match host endianness, convert

media/libstagefright/include/ID3.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ struct ID3 {
5050

5151
bool done() const;
5252
void getID(String8 *id) const;
53-
void getString(String8 *s) const;
53+
void getString(String8 *s, String8 *ss = NULL) const;
5454
const uint8_t *getData(size_t *length) const;
5555
void next();
5656

@@ -65,6 +65,7 @@ struct ID3 {
6565
void findFrame();
6666

6767
size_t getHeaderLength() const;
68+
void getstring(String8 *s, bool secondhalf) const;
6869

6970
Iterator(const Iterator &);
7071
Iterator &operator=(const Iterator &);

media/libstagefright/include/XINGSeeker.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,15 @@ struct XINGSeeker : public MP3Seeker {
3131
virtual bool getDuration(int64_t *durationUs);
3232
virtual bool getOffsetForTime(int64_t *timeUs, off64_t *pos);
3333

34+
virtual int32_t getEncoderDelay();
35+
virtual int32_t getEncoderPadding();
36+
3437
private:
3538
int64_t mFirstFramePos;
3639
int64_t mDurationUs;
3740
int32_t mSizeBytes;
41+
int32_t mEncoderDelay;
42+
int32_t mEncoderPadding;
3843

3944
// TOC entries in XING header. Skip the first one since it's always 0.
4045
unsigned char mTOC[99];

0 commit comments

Comments
 (0)