Skip to content

Commit b8e651a

Browse files
committed
Properly identify how much metadata we need to cache in order to instantiate
the extractor without blocking (and therefore be able to abort). Change-Id: Id2acdde897e02baaeabadae70b7c95b66c9041b3 related-to-bug: 5666532
1 parent f57c138 commit b8e651a

File tree

3 files changed

+136
-41
lines changed

3 files changed

+136
-41
lines changed

media/libstagefright/AwesomePlayer.cpp

Lines changed: 40 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1949,6 +1949,8 @@ status_t AwesomePlayer::finishSetDataSource_l() {
19491949
mUri = newURI;
19501950
}
19511951

1952+
AString sniffedMIME;
1953+
19521954
if (!strncasecmp("http://", mUri.string(), 7)
19531955
|| !strncasecmp("https://", mUri.string(), 8)
19541956
|| isWidevineStreaming) {
@@ -1998,7 +2000,6 @@ status_t AwesomePlayer::finishSetDataSource_l() {
19982000

19992001
mConnectingDataSource.clear();
20002002

2001-
20022003
String8 contentType = dataSource->getMIMEType();
20032004

20042005
if (strncasecmp(contentType.string(), "audio/", 6)) {
@@ -2020,16 +2021,51 @@ status_t AwesomePlayer::finishSetDataSource_l() {
20202021

20212022
mLock.unlock();
20222023

2024+
// Initially make sure we have at least 128 bytes for the sniff
2025+
// to complete without blocking.
2026+
static const size_t kMinBytesForSniffing = 128;
2027+
2028+
off64_t metaDataSize = -1ll;
20232029
for (;;) {
20242030
status_t finalStatus;
20252031
size_t cachedDataRemaining =
20262032
mCachedSource->approxDataRemaining(&finalStatus);
20272033

2028-
if (finalStatus != OK || cachedDataRemaining >= kHighWaterMarkBytes
2034+
if (finalStatus != OK
2035+
|| (metaDataSize >= 0
2036+
&& cachedDataRemaining >= metaDataSize)
20292037
|| (mFlags & PREPARE_CANCELLED)) {
20302038
break;
20312039
}
20322040

2041+
LOGV("now cached %d bytes of data", cachedDataRemaining);
2042+
2043+
if (metaDataSize < 0
2044+
&& cachedDataRemaining >= kMinBytesForSniffing) {
2045+
String8 tmp;
2046+
float confidence;
2047+
sp<AMessage> meta;
2048+
if (!dataSource->sniff(&tmp, &confidence, &meta)) {
2049+
mLock.lock();
2050+
return UNKNOWN_ERROR;
2051+
}
2052+
2053+
// We successfully identified the file's extractor to
2054+
// be, remember this mime type so we don't have to
2055+
// sniff it again when we call MediaExtractor::Create()
2056+
// below.
2057+
sniffedMIME = tmp.string();
2058+
2059+
if (meta == NULL
2060+
|| !meta->findInt64(
2061+
"meta-data-size", &metaDataSize)) {
2062+
metaDataSize = kHighWaterMarkBytes;
2063+
}
2064+
2065+
CHECK_GE(metaDataSize, 0ll);
2066+
LOGV("metaDataSize = %lld bytes", metaDataSize);
2067+
}
2068+
20332069
usleep(200000);
20342070
}
20352071

@@ -2067,7 +2103,8 @@ status_t AwesomePlayer::finishSetDataSource_l() {
20672103
mWVMExtractor->setAdaptiveStreamingMode(true);
20682104
extractor = mWVMExtractor;
20692105
} else {
2070-
extractor = MediaExtractor::Create(dataSource);
2106+
extractor = MediaExtractor::Create(
2107+
dataSource, sniffedMIME.empty() ? NULL : sniffedMIME.c_str());
20712108

20722109
if (extractor == NULL) {
20732110
return UNKNOWN_ERROR;

media/libstagefright/MPEG4Extractor.cpp

Lines changed: 94 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
#include <string.h>
3131

3232
#include <media/stagefright/foundation/ADebug.h>
33+
#include <media/stagefright/foundation/AMessage.h>
3334
#include <media/stagefright/DataSource.h>
3435
#include <media/stagefright/MediaBuffer.h>
3536
#include <media/stagefright/MediaBufferGroup.h>
@@ -2301,51 +2302,121 @@ static bool isCompatibleBrand(uint32_t fourcc) {
23012302

23022303
// Attempt to actually parse the 'ftyp' atom and determine if a suitable
23032304
// compatible brand is present.
2305+
// Also try to identify where this file's metadata ends
2306+
// (end of the 'moov' atom) and report it to the caller as part of
2307+
// the metadata.
23042308
static bool BetterSniffMPEG4(
2305-
const sp<DataSource> &source, String8 *mimeType, float *confidence) {
2306-
uint8_t header[12];
2307-
if (source->readAt(0, header, 12) != 12
2308-
|| memcmp("ftyp", &header[4], 4)) {
2309-
return false;
2310-
}
2309+
const sp<DataSource> &source, String8 *mimeType, float *confidence,
2310+
sp<AMessage> *meta) {
2311+
// We scan up to 128 bytes to identify this file as an MP4.
2312+
static const off64_t kMaxScanOffset = 128ll;
23112313

2312-
size_t atomSize = U32_AT(&header[0]);
2313-
if (atomSize < 16 || (atomSize % 4) != 0) {
2314-
return false;
2315-
}
2314+
off64_t offset = 0ll;
2315+
bool foundGoodFileType = false;
2316+
off64_t moovAtomEndOffset = -1ll;
2317+
bool done = false;
23162318

2317-
bool success = false;
2318-
if (isCompatibleBrand(U32_AT(&header[8]))) {
2319-
success = true;
2320-
} else {
2321-
size_t numCompatibleBrands = (atomSize - 16) / 4;
2322-
for (size_t i = 0; i < numCompatibleBrands; ++i) {
2323-
uint8_t tmp[4];
2324-
if (source->readAt(16 + i * 4, tmp, 4) != 4) {
2319+
while (!done && offset < kMaxScanOffset) {
2320+
uint32_t hdr[2];
2321+
if (source->readAt(offset, hdr, 8) < 8) {
2322+
return false;
2323+
}
2324+
2325+
uint64_t chunkSize = ntohl(hdr[0]);
2326+
uint32_t chunkType = ntohl(hdr[1]);
2327+
off64_t chunkDataOffset = offset + 8;
2328+
2329+
if (chunkSize == 1) {
2330+
if (source->readAt(offset + 8, &chunkSize, 8) < 8) {
23252331
return false;
23262332
}
23272333

2328-
if (isCompatibleBrand(U32_AT(&tmp[0]))) {
2329-
success = true;
2334+
chunkSize = ntoh64(chunkSize);
2335+
chunkDataOffset += 8;
2336+
2337+
if (chunkSize < 16) {
2338+
// The smallest valid chunk is 16 bytes long in this case.
2339+
return false;
2340+
}
2341+
} else if (chunkSize < 8) {
2342+
// The smallest valid chunk is 8 bytes long.
2343+
return false;
2344+
}
2345+
2346+
off64_t chunkDataSize = offset + chunkSize - chunkDataOffset;
2347+
2348+
switch (chunkType) {
2349+
case FOURCC('f', 't', 'y', 'p'):
2350+
{
2351+
if (chunkDataSize < 8) {
2352+
return false;
2353+
}
2354+
2355+
uint32_t numCompatibleBrands = (chunkDataSize - 8) / 4;
2356+
for (size_t i = 0; i < numCompatibleBrands + 2; ++i) {
2357+
if (i == 1) {
2358+
// Skip this index, it refers to the minorVersion,
2359+
// not a brand.
2360+
continue;
2361+
}
2362+
2363+
uint32_t brand;
2364+
if (source->readAt(
2365+
chunkDataOffset + 4 * i, &brand, 4) < 4) {
2366+
return false;
2367+
}
2368+
2369+
brand = ntohl(brand);
2370+
2371+
if (isCompatibleBrand(brand)) {
2372+
foundGoodFileType = true;
2373+
break;
2374+
}
2375+
}
2376+
2377+
if (!foundGoodFileType) {
2378+
return false;
2379+
}
2380+
23302381
break;
23312382
}
2383+
2384+
case FOURCC('m', 'o', 'o', 'v'):
2385+
{
2386+
moovAtomEndOffset = offset + chunkSize;
2387+
2388+
done = true;
2389+
break;
2390+
}
2391+
2392+
default:
2393+
break;
23322394
}
2395+
2396+
offset += chunkSize;
23332397
}
23342398

2335-
if (!success) {
2399+
if (!foundGoodFileType) {
23362400
return false;
23372401
}
23382402

23392403
*mimeType = MEDIA_MIMETYPE_CONTAINER_MPEG4;
23402404
*confidence = 0.4f;
23412405

2406+
if (moovAtomEndOffset >= 0) {
2407+
*meta = new AMessage;
2408+
(*meta)->setInt64("meta-data-size", moovAtomEndOffset);
2409+
2410+
LOGV("found metadata size: %lld", moovAtomEndOffset);
2411+
}
2412+
23422413
return true;
23432414
}
23442415

23452416
bool SniffMPEG4(
23462417
const sp<DataSource> &source, String8 *mimeType, float *confidence,
2347-
sp<AMessage> *) {
2348-
if (BetterSniffMPEG4(source, mimeType, confidence)) {
2418+
sp<AMessage> *meta) {
2419+
if (BetterSniffMPEG4(source, mimeType, confidence, meta)) {
23492420
return true;
23502421
}
23512422

media/libstagefright/SampleTable.cpp

Lines changed: 2 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -631,14 +631,7 @@ status_t SampleTable::findSyncSampleNear(
631631
--left;
632632
}
633633

634-
uint32_t x;
635-
if (mDataSource->readAt(
636-
mSyncSampleOffset + 8 + left * 4, &x, 4) != 4) {
637-
return ERROR_IO;
638-
}
639-
640-
x = ntohl(x);
641-
--x;
634+
uint32_t x = mSyncSamples[left];
642635

643636
if (left + 1 < mNumSyncSamples) {
644637
uint32_t y = mSyncSamples[left + 1];
@@ -679,13 +672,7 @@ status_t SampleTable::findSyncSampleNear(
679672
if (x > start_sample_index) {
680673
CHECK(left > 0);
681674

682-
if (mDataSource->readAt(
683-
mSyncSampleOffset + 8 + (left - 1) * 4, &x, 4) != 4) {
684-
return ERROR_IO;
685-
}
686-
687-
x = ntohl(x);
688-
--x;
675+
x = mSyncSamples[left - 1];
689676

690677
CHECK(x <= start_sample_index);
691678
}

0 commit comments

Comments
 (0)