Merge "Fix google-explicit-constructor warnings in camera." am: f9ee5183c8
am: beff1fb18b
Change-Id: I0f337390c99af8b300b28f8dfe60635290fc20b0
diff --git a/include/media/IDataSource.h b/include/media/IDataSource.h
index 838e29f..655f337 100644
--- a/include/media/IDataSource.h
+++ b/include/media/IDataSource.h
@@ -25,6 +25,7 @@
namespace android {
class IMemory;
+class DecryptHandle;
// A binder interface for implementing a stagefright DataSource remotely.
class IDataSource : public IInterface {
@@ -47,6 +48,8 @@
virtual uint32_t getFlags() = 0;
// get a description of the source, e.g. the url or filename it is based on
virtual String8 toString() = 0;
+ // Initialize DRM and return a DecryptHandle.
+ virtual sp<DecryptHandle> DrmInitialization(const char *mime) = 0;
private:
DISALLOW_EVIL_CONSTRUCTORS(IDataSource);
diff --git a/include/media/stagefright/ACodec.h b/include/media/stagefright/ACodec.h
index c41d0f0..d658ff7 100644
--- a/include/media/stagefright/ACodec.h
+++ b/include/media/stagefright/ACodec.h
@@ -315,11 +315,12 @@
status_t handleSetSurface(const sp<Surface> &surface);
status_t setupNativeWindowSizeFormatAndUsage(
- ANativeWindow *nativeWindow /* nonnull */, int *finalUsage /* nonnull */);
+ ANativeWindow *nativeWindow /* nonnull */, int *finalUsage /* nonnull */,
+ bool reconnect);
status_t configureOutputBuffersFromNativeWindow(
OMX_U32 *nBufferCount, OMX_U32 *nBufferSize,
- OMX_U32 *nMinUndequeuedBuffers);
+ OMX_U32 *nMinUndequeuedBuffers, bool preregister);
status_t allocateOutputMetadataBuffers();
status_t submitOutputMetadataBuffer();
void signalSubmitOutputMetadataBufferIfEOS_workaround();
diff --git a/include/media/stagefright/SurfaceUtils.h b/include/media/stagefright/SurfaceUtils.h
index c1a9c0a..13d580c 100644
--- a/include/media/stagefright/SurfaceUtils.h
+++ b/include/media/stagefright/SurfaceUtils.h
@@ -24,9 +24,14 @@
namespace android {
+/**
+ * Configures |nativeWindow| for given |width|x|height|, pixel |format|, |rotation| and |usage|.
+ * If |reconnect| is true, reconnects to the native window before hand.
+ * @return first error encountered, or NO_ERROR on success.
+ */
status_t setNativeWindowSizeFormatAndUsage(
ANativeWindow *nativeWindow /* nonnull */,
- int width, int height, int format, int rotation, int usage);
+ int width, int height, int format, int rotation, int usage, bool reconnect);
status_t pushBlankBuffersToNativeWindow(ANativeWindow *nativeWindow /* nonnull */);
} // namespace android
diff --git a/media/libmedia/IDataSource.cpp b/media/libmedia/IDataSource.cpp
index 9da1a70..7df3b65 100644
--- a/media/libmedia/IDataSource.cpp
+++ b/media/libmedia/IDataSource.cpp
@@ -23,6 +23,7 @@
#include <binder/IMemory.h>
#include <binder/Parcel.h>
+#include <drm/drm_framework_common.h>
#include <media/stagefright/foundation/ADebug.h>
namespace android {
@@ -34,6 +35,7 @@
CLOSE,
GET_FLAGS,
TO_STRING,
+ DRM_INITIALIZATION,
};
struct BpDataSource : public BpInterface<IDataSource> {
@@ -85,6 +87,47 @@
remote()->transact(TO_STRING, data, &reply);
return reply.readString8();
}
+
+ virtual sp<DecryptHandle> DrmInitialization(const char *mime) {
+ Parcel data, reply;
+ data.writeInterfaceToken(IDataSource::getInterfaceDescriptor());
+ if (mime == NULL) {
+ data.writeInt32(0);
+ } else {
+ data.writeInt32(1);
+ data.writeCString(mime);
+ }
+ remote()->transact(DRM_INITIALIZATION, data, &reply);
+ sp<DecryptHandle> handle;
+ if (reply.dataAvail() != 0) {
+ handle = new DecryptHandle();
+ handle->decryptId = reply.readInt32();
+ handle->mimeType = reply.readString8();
+ handle->decryptApiType = reply.readInt32();
+ handle->status = reply.readInt32();
+
+ const int bufferLength = data.readInt32();
+ if (bufferLength != -1) {
+ handle->decryptInfo = new DecryptInfo();
+ handle->decryptInfo->decryptBufferLength = bufferLength;
+ }
+
+ size_t size = data.readInt32();
+ for (size_t i = 0; i < size; ++i) {
+ DrmCopyControl key = (DrmCopyControl)data.readInt32();
+ int value = data.readInt32();
+ handle->copyControlVector.add(key, value);
+ }
+
+ size = data.readInt32();
+ for (size_t i = 0; i < size; ++i) {
+ String8 key = data.readString8();
+ String8 value = data.readString8();
+ handle->extendedData.add(key, value);
+ }
+ }
+ return handle;
+ }
};
IMPLEMENT_META_INTERFACE(DataSource, "android.media.IDataSource");
@@ -127,6 +170,42 @@
reply->writeString8(toString());
return NO_ERROR;
} break;
+ case DRM_INITIALIZATION: {
+ CHECK_INTERFACE(IDataSource, data, reply);
+ const char *mime = NULL;
+ const int32_t flag = data.readInt32();
+ if (flag != 0) {
+ mime = data.readCString();
+ }
+ sp<DecryptHandle> handle = DrmInitialization(mime);
+ if (handle != NULL) {
+ reply->writeInt32(handle->decryptId);
+ reply->writeString8(handle->mimeType);
+ reply->writeInt32(handle->decryptApiType);
+ reply->writeInt32(handle->status);
+
+ if (handle->decryptInfo != NULL) {
+ reply->writeInt32(handle->decryptInfo->decryptBufferLength);
+ } else {
+ reply->writeInt32(-1);
+ }
+
+ size_t size = handle->copyControlVector.size();
+ reply->writeInt32(size);
+ for (size_t i = 0; i < size; ++i) {
+ reply->writeInt32(handle->copyControlVector.keyAt(i));
+ reply->writeInt32(handle->copyControlVector.valueAt(i));
+ }
+
+ size = handle->extendedData.size();
+ reply->writeInt32(size);
+ for (size_t i = 0; i < size; ++i) {
+ reply->writeString8(handle->extendedData.keyAt(i));
+ reply->writeString8(handle->extendedData.valueAt(i));
+ }
+ }
+ return NO_ERROR;
+ } break;
default:
return BBinder::onTransact(code, data, reply, flags);
diff --git a/media/libmedia/IDrm.cpp b/media/libmedia/IDrm.cpp
index d2b3aae..c4558c6 100644
--- a/media/libmedia/IDrm.cpp
+++ b/media/libmedia/IDrm.cpp
@@ -891,7 +891,7 @@
readVector(data, keyId);
readVector(data, message);
readVector(data, signature);
- bool match;
+ bool match = false;
uint32_t result = verify(sessionId, keyId, message, signature, match);
reply->writeInt32(match);
reply->writeInt32(result);
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index d3c6c5d..12ad6d1 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -558,6 +558,12 @@
mClients.remove(client);
}
+bool MediaPlayerService::hasClient(wp<Client> client)
+{
+ Mutex::Autolock lock(mLock);
+ return mClients.indexOf(client) != NAME_NOT_FOUND;
+}
+
MediaPlayerService::Client::Client(
const sp<MediaPlayerService>& service, pid_t pid,
int32_t connId, const sp<IMediaPlayerClient>& client,
@@ -1086,6 +1092,10 @@
ALOGV("setNextPlayer");
Mutex::Autolock l(mLock);
sp<Client> c = static_cast<Client*>(player.get());
+ if (c != NULL && !mService->hasClient(c)) {
+ return BAD_VALUE;
+ }
+
mNextClient = c;
if (c != NULL) {
diff --git a/media/libmediaplayerservice/MediaPlayerService.h b/media/libmediaplayerservice/MediaPlayerService.h
index 817d10f..4ff1371 100644
--- a/media/libmediaplayerservice/MediaPlayerService.h
+++ b/media/libmediaplayerservice/MediaPlayerService.h
@@ -226,6 +226,7 @@
virtual status_t dump(int fd, const Vector<String16>& args);
void removeClient(const wp<Client>& client);
+ bool hasClient(wp<Client> client);
enum {
MEDIASERVER_PROCESS_DEATH = 0,
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index 07f5960..f801365 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -675,7 +675,10 @@
}
int usageBits = 0;
- status_t err = setupNativeWindowSizeFormatAndUsage(nativeWindow, &usageBits);
+ // no need to reconnect as we will not dequeue all buffers
+ status_t err = setupNativeWindowSizeFormatAndUsage(
+ nativeWindow, &usageBits,
+ !storingMetadataInDecodedBuffers() || mLegacyAdaptiveExperiment /* reconnect */);
if (err != OK) {
return err;
}
@@ -949,7 +952,8 @@
}
status_t ACodec::setupNativeWindowSizeFormatAndUsage(
- ANativeWindow *nativeWindow /* nonnull */, int *finalUsage /* nonnull */) {
+ ANativeWindow *nativeWindow /* nonnull */, int *finalUsage /* nonnull */,
+ bool reconnect) {
OMX_PARAM_PORTDEFINITIONTYPE def;
InitOMXParams(&def);
def.nPortIndex = kPortIndexOutput;
@@ -987,12 +991,14 @@
def.format.video.nFrameHeight,
def.format.video.eColorFormat,
mRotationDegrees,
- usage);
+ usage,
+ reconnect);
}
status_t ACodec::configureOutputBuffersFromNativeWindow(
OMX_U32 *bufferCount, OMX_U32 *bufferSize,
- OMX_U32 *minUndequeuedBuffers) {
+ OMX_U32 *minUndequeuedBuffers, bool preregister) {
+
OMX_PARAM_PORTDEFINITIONTYPE def;
InitOMXParams(&def);
def.nPortIndex = kPortIndexOutput;
@@ -1001,7 +1007,8 @@
mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
if (err == OK) {
- err = setupNativeWindowSizeFormatAndUsage(mNativeWindow.get(), &mNativeWindowUsageBits);
+ err = setupNativeWindowSizeFormatAndUsage(
+ mNativeWindow.get(), &mNativeWindowUsageBits, preregister /* reconnect */);
}
if (err != OK) {
mNativeWindowUsageBits = 0;
@@ -1083,7 +1090,7 @@
status_t ACodec::allocateOutputBuffersFromNativeWindow() {
OMX_U32 bufferCount, bufferSize, minUndequeuedBuffers;
status_t err = configureOutputBuffersFromNativeWindow(
- &bufferCount, &bufferSize, &minUndequeuedBuffers);
+ &bufferCount, &bufferSize, &minUndequeuedBuffers, true /* preregister */);
if (err != 0)
return err;
mNumUndequeuedBuffers = minUndequeuedBuffers;
@@ -1169,7 +1176,8 @@
status_t ACodec::allocateOutputMetadataBuffers() {
OMX_U32 bufferCount, bufferSize, minUndequeuedBuffers;
status_t err = configureOutputBuffersFromNativeWindow(
- &bufferCount, &bufferSize, &minUndequeuedBuffers);
+ &bufferCount, &bufferSize, &minUndequeuedBuffers,
+ mLegacyAdaptiveExperiment /* preregister */);
if (err != 0)
return err;
mNumUndequeuedBuffers = minUndequeuedBuffers;
diff --git a/media/libstagefright/AMRExtractor.cpp b/media/libstagefright/AMRExtractor.cpp
index 1458802..0e98db8 100644
--- a/media/libstagefright/AMRExtractor.cpp
+++ b/media/libstagefright/AMRExtractor.cpp
@@ -100,7 +100,10 @@
static status_t getFrameSizeByOffset(const sp<DataSource> &source,
off64_t offset, bool isWide, size_t *frameSize) {
uint8_t header;
- if (source->readAt(offset, &header, 1) < 1) {
+ ssize_t count = source->readAt(offset, &header, 1);
+ if (count == 0) {
+ return ERROR_END_OF_STREAM;
+ } else if (count < 0) {
return ERROR_IO;
}
@@ -140,7 +143,10 @@
if (mDataSource->getSize(&streamSize) == OK) {
while (offset < streamSize) {
- if (getFrameSizeByOffset(source, offset, mIsWide, &frameSize) != OK) {
+ status_t status = getFrameSizeByOffset(source, offset, mIsWide, &frameSize);
+ if (status == ERROR_END_OF_STREAM) {
+ break;
+ } else if (status != OK) {
return;
}
diff --git a/media/libstagefright/CallbackDataSource.cpp b/media/libstagefright/CallbackDataSource.cpp
index f14d34d..0df7da4 100644
--- a/media/libstagefright/CallbackDataSource.cpp
+++ b/media/libstagefright/CallbackDataSource.cpp
@@ -109,6 +109,10 @@
}
}
+sp<DecryptHandle> CallbackDataSource::DrmInitialization(const char *mime) {
+ return mIDataSource->DrmInitialization(mime);
+}
+
TinyCacheSource::TinyCacheSource(const sp<DataSource>& source)
: mSource(source), mCachedOffset(0), mCachedSize(0) {
mName = String8::format("TinyCacheSource(%s)", mSource->toString().string());
@@ -146,12 +150,19 @@
}
}
+
// Fill the cache and copy to the caller.
const ssize_t numRead = mSource->readAt(offset, mCache, kCacheSize);
if (numRead <= 0) {
+ // Flush cache on error
+ mCachedSize = 0;
+ mCachedOffset = 0;
return numRead;
}
if ((size_t)numRead > kCacheSize) {
+ // Flush cache on error
+ mCachedSize = 0;
+ mCachedOffset = 0;
return ERROR_OUT_OF_RANGE;
}
@@ -172,4 +183,11 @@
return mSource->flags();
}
+sp<DecryptHandle> TinyCacheSource::DrmInitialization(const char *mime) {
+ // flush cache when DrmInitialization occurs since decrypted
+ // data may differ from what is in cache.
+ mCachedOffset = 0;
+ mCachedSize = 0;
+ return mSource->DrmInitialization(mime);
+}
} // namespace android
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index b51853e..a4f7042 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -1791,9 +1791,8 @@
err = BAD_VALUE;
} else {
err = connectToSurface(surface);
- if (err == BAD_VALUE) {
- // assuming reconnecting to same surface
- // TODO: check if it is the same surface
+ if (err == ALREADY_EXISTS) {
+ // reconnecting to same surface
err = OK;
} else {
if (err == OK) {
@@ -2683,11 +2682,17 @@
status_t MediaCodec::connectToSurface(const sp<Surface> &surface) {
status_t err = OK;
if (surface != NULL) {
+ uint64_t oldId, newId;
+ if (mSurface != NULL
+ && surface->getUniqueId(&newId) == NO_ERROR
+ && mSurface->getUniqueId(&oldId) == NO_ERROR
+ && newId == oldId) {
+ ALOGI("[%s] connecting to the same surface. Nothing to do.", mComponentName.c_str());
+ return ALREADY_EXISTS;
+ }
+
err = native_window_api_connect(surface.get(), NATIVE_WINDOW_API_MEDIA);
- if (err == BAD_VALUE) {
- ALOGI("native window already connected. Assuming no change of surface");
- return err;
- } else if (err == OK) {
+ if (err == OK) {
// Require a fresh set of buffers after each connect by using a unique generation
// number. Rely on the fact that max supported process id by Linux is 2^22.
// PID is never 0 so we don't have to worry that we use the default generation of 0.
@@ -2709,7 +2714,8 @@
ALOGE("native_window_api_connect returned an error: %s (%d)", strerror(-err), err);
}
}
- return err;
+ // do not return ALREADY_EXISTS unless surfaces are the same
+ return err == ALREADY_EXISTS ? BAD_VALUE : err;
}
status_t MediaCodec::disconnectFromSurface() {
diff --git a/media/libstagefright/MediaExtractor.cpp b/media/libstagefright/MediaExtractor.cpp
index 1c6c882..92ce88c 100644
--- a/media/libstagefright/MediaExtractor.cpp
+++ b/media/libstagefright/MediaExtractor.cpp
@@ -88,6 +88,7 @@
virtual void close();
virtual uint32_t getFlags();
virtual String8 toString();
+ virtual sp<DecryptHandle> DrmInitialization(const char *mime);
private:
sp<IMemory> mMemory;
@@ -134,6 +135,10 @@
return mName;
}
+sp<DecryptHandle> RemoteDataSource::DrmInitialization(const char *mime) {
+ return mSource->DrmInitialization(mime);
+}
+
// static
sp<IMediaExtractor> MediaExtractor::Create(
const sp<DataSource> &source, const char *mime) {
@@ -146,10 +151,6 @@
ALOGW("creating media extractor in calling process");
return CreateFromService(source, mime);
} else {
- // remote extractor
- ALOGV("get service manager");
- sp<IBinder> binder = defaultServiceManager()->getService(String16("media.extractor"));
-
// Check if it's WVM, since WVMExtractor needs to be created in the media server process,
// not the extractor process.
String8 mime8;
@@ -160,6 +161,21 @@
return new WVMExtractor(source);
}
+ // Check if it's es-based DRM, since DRMExtractor needs to be created in the media server
+ // process, not the extractor process.
+ if (SniffDRM(source, &mime8, &confidence, &meta)) {
+ const char *drmMime = mime8.string();
+ ALOGV("Detected media content as '%s' with confidence %.2f", drmMime, confidence);
+ if (!strncmp(drmMime, "drm+es_based+", 13)) {
+ // DRMExtractor sets container metadata kKeyIsDRM to 1
+ return new DRMExtractor(source, drmMime + 14);
+ }
+ }
+
+ // remote extractor
+ ALOGV("get service manager");
+ sp<IBinder> binder = defaultServiceManager()->getService(String16("media.extractor"));
+
if (binder != 0) {
sp<IMediaExtractorService> mediaExService(interface_cast<IMediaExtractorService>(binder));
sp<IMediaExtractor> ex = mediaExService->makeExtractor(RemoteDataSource::wrap(source), mime);
diff --git a/media/libstagefright/SampleTable.cpp b/media/libstagefright/SampleTable.cpp
index 5df2e2e..47d360c 100644
--- a/media/libstagefright/SampleTable.cpp
+++ b/media/libstagefright/SampleTable.cpp
@@ -18,6 +18,8 @@
//#define LOG_NDEBUG 0
#include <utils/Log.h>
+#include <limits>
+
#include "include/SampleTable.h"
#include "include/SampleIterator.h"
@@ -45,6 +47,8 @@
////////////////////////////////////////////////////////////////////////////////
+const off64_t kMaxOffset = std::numeric_limits<off64_t>::max();
+
struct SampleTable::CompositionDeltaLookup {
CompositionDeltaLookup();
@@ -123,7 +127,7 @@
mNumSampleSizes(0),
mHasTimeToSample(false),
mTimeToSampleCount(0),
- mTimeToSample(),
+ mTimeToSample(NULL),
mSampleTimeEntries(NULL),
mCompositionTimeDeltaEntries(NULL),
mNumCompositionTimeDeltaEntries(0),
@@ -132,7 +136,8 @@
mNumSyncSamples(0),
mSyncSamples(NULL),
mLastSyncSampleIndex(0),
- mSampleToChunkEntries(NULL) {
+ mSampleToChunkEntries(NULL),
+ mTotalSize(0) {
mSampleIterator = new SampleIterator(this);
}
@@ -143,6 +148,9 @@
delete[] mSyncSamples;
mSyncSamples = NULL;
+ delete[] mTimeToSample;
+ mTimeToSample = NULL;
+
delete mCompositionDeltaLookup;
mCompositionDeltaLookup = NULL;
@@ -234,27 +242,55 @@
mNumSampleToChunkOffsets = U32_AT(&header[4]);
- if ((data_size - 8) / 12 < mNumSampleToChunkOffsets) {
+ if ((data_size - 8) / sizeof(SampleToChunkEntry) < mNumSampleToChunkOffsets) {
return ERROR_MALFORMED;
}
- if (SIZE_MAX / sizeof(SampleToChunkEntry) <= (size_t)mNumSampleToChunkOffsets)
+ if ((uint64_t)kMaxTotalSize / sizeof(SampleToChunkEntry) <=
+ (uint64_t)mNumSampleToChunkOffsets) {
+ ALOGE("Sample-to-chunk table size too large.");
return ERROR_OUT_OF_RANGE;
+ }
+
+ mTotalSize += (uint64_t)mNumSampleToChunkOffsets *
+ sizeof(SampleToChunkEntry);
+ if (mTotalSize > kMaxTotalSize) {
+ ALOGE("Sample-to-chunk table size would make sample table too large.\n"
+ " Requested sample-to-chunk table size = %llu\n"
+ " Eventual sample table size >= %llu\n"
+ " Allowed sample table size = %llu\n",
+ (unsigned long long)mNumSampleToChunkOffsets *
+ sizeof(SampleToChunkEntry),
+ (unsigned long long)mTotalSize,
+ (unsigned long long)kMaxTotalSize);
+ return ERROR_OUT_OF_RANGE;
+ }
mSampleToChunkEntries =
new (std::nothrow) SampleToChunkEntry[mNumSampleToChunkOffsets];
- if (!mSampleToChunkEntries)
+ if (!mSampleToChunkEntries) {
+ ALOGE("Cannot allocate sample-to-chunk table with %llu entries.",
+ (unsigned long long)mNumSampleToChunkOffsets);
return ERROR_OUT_OF_RANGE;
+ }
+
+ if (mNumSampleToChunkOffsets == 0) {
+ return OK;
+ }
+
+ if ((off64_t)(kMaxOffset - 8 -
+ ((mNumSampleToChunkOffsets - 1) * sizeof(SampleToChunkEntry)))
+ < mSampleToChunkOffset) {
+ return ERROR_MALFORMED;
+ }
for (uint32_t i = 0; i < mNumSampleToChunkOffsets; ++i) {
- uint8_t buffer[12];
-
- if ((SIZE_MAX - 8 - (i * 12)) < (size_t)mSampleToChunkOffset) {
- return ERROR_MALFORMED;
- }
+ uint8_t buffer[sizeof(SampleToChunkEntry)];
if (mDataSource->readAt(
- mSampleToChunkOffset + 8 + i * 12, buffer, sizeof(buffer))
+ mSampleToChunkOffset + 8 + i * sizeof(SampleToChunkEntry),
+ buffer,
+ sizeof(buffer))
!= (ssize_t)sizeof(buffer)) {
return ERROR_IO;
}
@@ -355,28 +391,48 @@
}
mTimeToSampleCount = U32_AT(&header[4]);
- if ((uint64_t)mTimeToSampleCount >
- (uint64_t)UINT32_MAX / (2 * sizeof(uint32_t))) {
+ if (mTimeToSampleCount > UINT32_MAX / (2 * sizeof(uint32_t))) {
// Choose this bound because
// 1) 2 * sizeof(uint32_t) is the amount of memory needed for one
// time-to-sample entry in the time-to-sample table.
// 2) mTimeToSampleCount is the number of entries of the time-to-sample
// table.
// 3) We hope that the table size does not exceed UINT32_MAX.
- ALOGE(" Error: Time-to-sample table size too large.");
+ ALOGE("Time-to-sample table size too large.");
return ERROR_OUT_OF_RANGE;
}
// Note: At this point, we know that mTimeToSampleCount * 2 will not
// overflow because of the above condition.
- if (!mDataSource->getVector(data_offset + 8, &mTimeToSample,
- mTimeToSampleCount * 2)) {
- ALOGE(" Error: Incomplete data read for time-to-sample table.");
+
+ uint64_t allocSize = (uint64_t)mTimeToSampleCount * 2 * sizeof(uint32_t);
+ mTotalSize += allocSize;
+ if (mTotalSize > kMaxTotalSize) {
+ ALOGE("Time-to-sample table size would make sample table too large.\n"
+ " Requested time-to-sample table size = %llu\n"
+ " Eventual sample table size >= %llu\n"
+ " Allowed sample table size = %llu\n",
+ (unsigned long long)allocSize,
+ (unsigned long long)mTotalSize,
+ (unsigned long long)kMaxTotalSize);
+ return ERROR_OUT_OF_RANGE;
+ }
+
+ mTimeToSample = new (std::nothrow) uint32_t[mTimeToSampleCount * 2];
+ if (!mTimeToSample) {
+ ALOGE("Cannot allocate time-to-sample table with %llu entries.",
+ (unsigned long long)mTimeToSampleCount);
+ return ERROR_OUT_OF_RANGE;
+ }
+
+ if (mDataSource->readAt(data_offset + 8, mTimeToSample,
+ (size_t)allocSize) < (ssize_t)allocSize) {
+ ALOGE("Incomplete data read for time-to-sample table.");
return ERROR_IO;
}
- for (size_t i = 0; i < mTimeToSample.size(); ++i) {
- mTimeToSample.editItemAt(i) = ntohl(mTimeToSample[i]);
+ for (size_t i = 0; i < mTimeToSampleCount * 2; ++i) {
+ mTimeToSample[i] = ntohl(mTimeToSample[i]);
}
mHasTimeToSample = true;
@@ -418,18 +474,33 @@
}
mNumCompositionTimeDeltaEntries = numEntries;
- uint64_t allocSize = (uint64_t)numEntries * 2 * sizeof(uint32_t);
- if (allocSize > UINT32_MAX) {
+ uint64_t allocSize = (uint64_t)numEntries * 2 * sizeof(int32_t);
+ if (allocSize > kMaxTotalSize) {
+ ALOGE("Composition-time-to-sample table size too large.");
+ return ERROR_OUT_OF_RANGE;
+ }
+
+ mTotalSize += allocSize;
+ if (mTotalSize > kMaxTotalSize) {
+ ALOGE("Composition-time-to-sample table would make sample table too large.\n"
+ " Requested composition-time-to-sample table size = %llu\n"
+ " Eventual sample table size >= %llu\n"
+ " Allowed sample table size = %llu\n",
+ (unsigned long long)allocSize,
+ (unsigned long long)mTotalSize,
+ (unsigned long long)kMaxTotalSize);
return ERROR_OUT_OF_RANGE;
}
mCompositionTimeDeltaEntries = new (std::nothrow) int32_t[2 * numEntries];
- if (!mCompositionTimeDeltaEntries)
+ if (!mCompositionTimeDeltaEntries) {
+ ALOGE("Cannot allocate composition-time-to-sample table with %llu "
+ "entries.", (unsigned long long)numEntries);
return ERROR_OUT_OF_RANGE;
+ }
- if (mDataSource->readAt(
- data_offset + 8, mCompositionTimeDeltaEntries, numEntries * 8)
- < (ssize_t)numEntries * 8) {
+ if (mDataSource->readAt(data_offset + 8, mCompositionTimeDeltaEntries,
+ (size_t)allocSize) < (ssize_t)allocSize) {
delete[] mCompositionTimeDeltaEntries;
mCompositionTimeDeltaEntries = NULL;
@@ -470,18 +541,33 @@
ALOGV("Table of sync samples is empty or has only a single entry!");
}
- uint64_t allocSize = mNumSyncSamples * (uint64_t)sizeof(uint32_t);
- if (allocSize > SIZE_MAX) {
+ uint64_t allocSize = (uint64_t)mNumSyncSamples * sizeof(uint32_t);
+ if (allocSize > kMaxTotalSize) {
+ ALOGE("Sync sample table size too large.");
+ return ERROR_OUT_OF_RANGE;
+ }
+
+ mTotalSize += allocSize;
+ if (mTotalSize > kMaxTotalSize) {
+ ALOGE("Sync sample table size would make sample table too large.\n"
+ " Requested sync sample table size = %llu\n"
+ " Eventual sample table size >= %llu\n"
+ " Allowed sample table size = %llu\n",
+ (unsigned long long)allocSize,
+ (unsigned long long)mTotalSize,
+ (unsigned long long)kMaxTotalSize);
return ERROR_OUT_OF_RANGE;
}
mSyncSamples = new (std::nothrow) uint32_t[mNumSyncSamples];
- if (!mSyncSamples)
+ if (!mSyncSamples) {
+ ALOGE("Cannot allocate sync sample table with %llu entries.",
+ (unsigned long long)mNumSyncSamples);
return ERROR_OUT_OF_RANGE;
+ }
- size_t size = mNumSyncSamples * sizeof(uint32_t);
- if (mDataSource->readAt(mSyncSampleOffset + 8, mSyncSamples, size)
- != (ssize_t)size) {
+ if (mDataSource->readAt(mSyncSampleOffset + 8, mSyncSamples,
+ (size_t)allocSize) != (ssize_t)allocSize) {
return ERROR_IO;
}
@@ -549,9 +635,24 @@
return;
}
- mSampleTimeEntries = new (std::nothrow) SampleTimeEntry[mNumSampleSizes];
- if (!mSampleTimeEntries)
+ mTotalSize += (uint64_t)mNumSampleSizes * sizeof(SampleTimeEntry);
+ if (mTotalSize > kMaxTotalSize) {
+ ALOGE("Sample entry table size would make sample table too large.\n"
+ " Requested sample entry table size = %llu\n"
+ " Eventual sample table size >= %llu\n"
+ " Allowed sample table size = %llu\n",
+ (unsigned long long)mNumSampleSizes * sizeof(SampleTimeEntry),
+ (unsigned long long)mTotalSize,
+ (unsigned long long)kMaxTotalSize);
return;
+ }
+
+ mSampleTimeEntries = new (std::nothrow) SampleTimeEntry[mNumSampleSizes];
+ if (!mSampleTimeEntries) {
+ ALOGE("Cannot allocate sample entry table with %llu entries.",
+ (unsigned long long)mNumSampleSizes);
+ return;
+ }
uint32_t sampleIndex = 0;
uint32_t sampleTime = 0;
diff --git a/media/libstagefright/StagefrightMetadataRetriever.cpp b/media/libstagefright/StagefrightMetadataRetriever.cpp
index a62e1a2..377f5fd 100644
--- a/media/libstagefright/StagefrightMetadataRetriever.cpp
+++ b/media/libstagefright/StagefrightMetadataRetriever.cpp
@@ -22,6 +22,7 @@
#include <utils/Log.h>
#include <gui/Surface.h>
+#include "include/avc_utils.h"
#include "include/StagefrightMetadataRetriever.h"
#include <media/ICrypto.h>
@@ -237,6 +238,15 @@
int64_t timeUs;
size_t retriesLeft = kRetryCount;
bool done = false;
+ const char *mime;
+ bool success = format->findCString(kKeyMIMEType, &mime);
+ if (!success) {
+ ALOGE("Could not find mime type");
+ return NULL;
+ }
+
+ bool isAvcOrHevc = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC)
+ || !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_HEVC);
do {
size_t inputIndex = -1;
@@ -276,6 +286,11 @@
memcpy(codecBuffer->data(),
(const uint8_t*)mediaBuffer->data() + mediaBuffer->range_offset(),
mediaBuffer->range_length());
+ if (isAvcOrHevc && IsIDR(codecBuffer)) {
+ // Only need to decode one IDR frame.
+ haveMoreInputs = false;
+ flags |= MediaCodec::BUFFER_FLAG_EOS;
+ }
}
mediaBuffer->release();
diff --git a/media/libstagefright/SurfaceUtils.cpp b/media/libstagefright/SurfaceUtils.cpp
index 9940822..568837a 100644
--- a/media/libstagefright/SurfaceUtils.cpp
+++ b/media/libstagefright/SurfaceUtils.cpp
@@ -26,8 +26,25 @@
status_t setNativeWindowSizeFormatAndUsage(
ANativeWindow *nativeWindow /* nonnull */,
- int width, int height, int format, int rotation, int usage) {
- status_t err = native_window_set_buffers_dimensions(nativeWindow, width, height);
+ int width, int height, int format, int rotation, int usage, bool reconnect) {
+ status_t err = NO_ERROR;
+
+ // In some cases we need to reconnect so that we can dequeue all buffers
+ if (reconnect) {
+ err = native_window_api_disconnect(nativeWindow, NATIVE_WINDOW_API_MEDIA);
+ if (err != NO_ERROR) {
+ ALOGE("native_window_api_disconnect failed: %s (%d)", strerror(-err), -err);
+ return err;
+ }
+
+ err = native_window_api_connect(nativeWindow, NATIVE_WINDOW_API_MEDIA);
+ if (err != NO_ERROR) {
+ ALOGE("native_window_api_connect failed: %s (%d)", strerror(-err), -err);
+ return err;
+ }
+ }
+
+ err = native_window_set_buffers_dimensions(nativeWindow, width, height);
if (err != NO_ERROR) {
ALOGE("native_window_set_buffers_dimensions failed: %s (%d)", strerror(-err), -err);
return err;
@@ -124,7 +141,8 @@
}
err = setNativeWindowSizeFormatAndUsage(
- nativeWindow, 1, 1, HAL_PIXEL_FORMAT_RGBX_8888, 0, GRALLOC_USAGE_SW_WRITE_OFTEN);
+ nativeWindow, 1, 1, HAL_PIXEL_FORMAT_RGBX_8888, 0, GRALLOC_USAGE_SW_WRITE_OFTEN,
+ false /* reconnect */);
if (err != NO_ERROR) {
goto error;
}
diff --git a/media/libstagefright/Utils.cpp b/media/libstagefright/Utils.cpp
index 2b3fd7b..fc587f3 100644
--- a/media/libstagefright/Utils.cpp
+++ b/media/libstagefright/Utils.cpp
@@ -22,6 +22,7 @@
#include <sys/stat.h>
#include <utility>
+#include <vector>
#include "include/ESDS.h"
#include "include/HevcUtils.h"
@@ -1377,24 +1378,24 @@
// reassemble the csd data into its original form
sp<ABuffer> csd0, csd1, csd2;
if (msg->findBuffer("csd-0", &csd0)) {
+ int csd0size = csd0->size();
if (mime == MEDIA_MIMETYPE_VIDEO_AVC) {
sp<ABuffer> csd1;
if (msg->findBuffer("csd-1", &csd1)) {
- char avcc[1024]; // that oughta be enough, right?
- size_t outsize = reassembleAVCC(csd0, csd1, avcc);
- meta->setData(kKeyAVCC, kKeyAVCC, avcc, outsize);
+ std::vector<char> avcc(csd0size + csd1->size() + 1024);
+ size_t outsize = reassembleAVCC(csd0, csd1, avcc.data());
+ meta->setData(kKeyAVCC, kKeyAVCC, avcc.data(), outsize);
}
} else if (mime == MEDIA_MIMETYPE_AUDIO_AAC || mime == MEDIA_MIMETYPE_VIDEO_MPEG4) {
- int csd0size = csd0->size();
- char esds[csd0size + 31];
+ std::vector<char> esds(csd0size + 31);
// The written ESDS is actually for an audio stream, but it's enough
// for transporting the CSD to muxers.
- reassembleESDS(csd0, esds);
- meta->setData(kKeyESDS, kKeyESDS, esds, sizeof(esds));
+ reassembleESDS(csd0, esds.data());
+ meta->setData(kKeyESDS, kKeyESDS, esds.data(), esds.size());
} else if (mime == MEDIA_MIMETYPE_VIDEO_HEVC) {
- uint8_t hvcc[1024]; // that oughta be enough, right?
- size_t outsize = reassembleHVCC(csd0, hvcc, 1024, 4);
- meta->setData(kKeyHVCC, kKeyHVCC, hvcc, outsize);
+ std::vector<uint8_t> hvcc(csd0size + 1024);
+ size_t outsize = reassembleHVCC(csd0, hvcc.data(), hvcc.size(), 4);
+ meta->setData(kKeyHVCC, kKeyHVCC, hvcc.data(), outsize);
} else if (mime == MEDIA_MIMETYPE_VIDEO_VP9) {
meta->setData(kKeyVp9CodecPrivate, 0, csd0->data(), csd0->size());
} else if (mime == MEDIA_MIMETYPE_AUDIO_OPUS) {
diff --git a/media/libstagefright/codecs/m4v_h263/dec/SoftMPEG4.cpp b/media/libstagefright/codecs/m4v_h263/dec/SoftMPEG4.cpp
index bb59ae4..1dd631a 100644
--- a/media/libstagefright/codecs/m4v_h263/dec/SoftMPEG4.cpp
+++ b/media/libstagefright/codecs/m4v_h263/dec/SoftMPEG4.cpp
@@ -210,8 +210,17 @@
PortInfo *port = editPortInfo(1);
OMX_BUFFERHEADERTYPE *outHeader = port->mBuffers.editItemAt(1).mHeader;
+ OMX_U32 yFrameSize = sizeof(uint8) * mHandle->size;
+ if ((outHeader->nAllocLen < yFrameSize) ||
+ (outHeader->nAllocLen - yFrameSize < yFrameSize / 2)) {
+ ALOGE("Too small output buffer for reference frame: %lu bytes",
+ (unsigned long)outHeader->nAllocLen);
+ android_errorWriteLog(0x534e4554, "30033990");
+ notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
+ mSignalledError = true;
+ return;
+ }
PVSetReferenceYUV(mHandle, outHeader->pBuffer);
-
mFramesConfigured = true;
}
@@ -229,7 +238,16 @@
int32_t bufferSize = inHeader->nFilledLen;
int32_t tmp = bufferSize;
- OMX_U32 frameSize = (mWidth * mHeight * 3) / 2;
+ OMX_U32 frameSize;
+ OMX_U64 yFrameSize = (OMX_U64)mWidth * (OMX_U64)mHeight;
+ if (yFrameSize > ((OMX_U64)UINT32_MAX / 3) * 2) {
+ ALOGE("Frame size too large");
+ notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
+ mSignalledError = true;
+ return;
+ }
+ frameSize = (OMX_U32)(yFrameSize + (yFrameSize / 2));
+
if (outHeader->nAllocLen < frameSize) {
android_errorWriteLog(0x534e4554, "27833616");
ALOGE("Insufficient output buffer size");
diff --git a/media/libstagefright/codecs/m4v_h263/enc/SoftMPEG4Encoder.cpp b/media/libstagefright/codecs/m4v_h263/enc/SoftMPEG4Encoder.cpp
index 7638bb7..2eb51c9 100644
--- a/media/libstagefright/codecs/m4v_h263/enc/SoftMPEG4Encoder.cpp
+++ b/media/libstagefright/codecs/m4v_h263/enc/SoftMPEG4Encoder.cpp
@@ -116,6 +116,10 @@
ALOGE("Failed to get default encoding parameters");
return OMX_ErrorUndefined;
}
+ if (mFramerate == 0) {
+ ALOGE("Framerate should not be 0");
+ return OMX_ErrorUndefined;
+ }
mEncParams->encMode = mEncodeMode;
mEncParams->encWidth[0] = mWidth;
mEncParams->encHeight[0] = mHeight;
diff --git a/media/libstagefright/codecs/mp3dec/SoftMP3.cpp b/media/libstagefright/codecs/mp3dec/SoftMP3.cpp
index 4cde54e..0822c34 100644
--- a/media/libstagefright/codecs/mp3dec/SoftMP3.cpp
+++ b/media/libstagefright/codecs/mp3dec/SoftMP3.cpp
@@ -120,6 +120,17 @@
mIsFirst = true;
}
+void *SoftMP3::memsetSafe(OMX_BUFFERHEADERTYPE *outHeader, int c, size_t len) {
+ if (len > outHeader->nAllocLen) {
+ ALOGE("memset buffer too small: got %u, expected %zu", outHeader->nAllocLen, len);
+ android_errorWriteLog(0x534e4554, "29422022");
+ notify(OMX_EventError, OMX_ErrorUndefined, OUTPUT_BUFFER_TOO_SMALL, NULL);
+ mSignalledError = true;
+ return NULL;
+ }
+ return memset(outHeader->pBuffer, c, len);
+}
+
OMX_ERRORTYPE SoftMP3::internalGetParameter(
OMX_INDEXTYPE index, OMX_PTR params) {
switch (index) {
@@ -300,7 +311,10 @@
outHeader->nOffset = 0;
outHeader->nFilledLen = kPVMP3DecoderDelay * mNumChannels * sizeof(int16_t);
- memset(outHeader->pBuffer, 0, outHeader->nFilledLen);
+ if (!memsetSafe(outHeader, 0, outHeader->nFilledLen)) {
+ return;
+ }
+
}
outHeader->nFlags = OMX_BUFFERFLAG_EOS;
mSignalledOutputEos = true;
@@ -312,9 +326,9 @@
// if mIsFirst is true as we may not have a valid
// mConfig->samplingRate and mConfig->num_channels?
ALOGV_IF(mIsFirst, "insufficient data for first frame, sending silence");
- memset(outHeader->pBuffer,
- 0,
- mConfig->outputFrameSize * sizeof(int16_t));
+ if (!memsetSafe(outHeader, 0, mConfig->outputFrameSize * sizeof(int16_t))) {
+ return;
+ }
if (inHeader) {
mConfig->inputBufferUsedLength = inHeader->nFilledLen;
diff --git a/media/libstagefright/codecs/mp3dec/SoftMP3.h b/media/libstagefright/codecs/mp3dec/SoftMP3.h
index f9e7b53..3bfa6c7 100644
--- a/media/libstagefright/codecs/mp3dec/SoftMP3.h
+++ b/media/libstagefright/codecs/mp3dec/SoftMP3.h
@@ -72,6 +72,7 @@
void initPorts();
void initDecoder();
+ void *memsetSafe(OMX_BUFFERHEADERTYPE *outHeader, int c, size_t len);
DISALLOW_EVIL_CONSTRUCTORS(SoftMP3);
};
diff --git a/media/libstagefright/codecs/on2/dec/SoftVPX.cpp b/media/libstagefright/codecs/on2/dec/SoftVPX.cpp
index 8022467..3490008 100644
--- a/media/libstagefright/codecs/on2/dec/SoftVPX.cpp
+++ b/media/libstagefright/codecs/on2/dec/SoftVPX.cpp
@@ -156,7 +156,7 @@
outHeader->nFlags = 0;
outHeader->nFilledLen = (outputBufferWidth() * outputBufferHeight() * 3) / 2;
outHeader->nTimeStamp = *(OMX_TICKS *)mImg->user_priv;
- if (outHeader->nAllocLen >= outHeader->nFilledLen) {
+ if (outputBufferSafe(outHeader)) {
uint8_t *dst = outHeader->pBuffer;
const uint8_t *srcY = (const uint8_t *)mImg->planes[VPX_PLANE_Y];
const uint8_t *srcU = (const uint8_t *)mImg->planes[VPX_PLANE_U];
@@ -166,8 +166,6 @@
size_t srcVStride = mImg->stride[VPX_PLANE_V];
copyYV12FrameToOutputBuffer(dst, srcY, srcU, srcV, srcYStride, srcUStride, srcVStride);
} else {
- ALOGE("b/27597103, buffer too small");
- android_errorWriteLog(0x534e4554, "27597103");
outHeader->nFilledLen = 0;
}
@@ -197,6 +195,25 @@
return true;
}
+bool SoftVPX::outputBufferSafe(OMX_BUFFERHEADERTYPE *outHeader) {
+ uint32_t width = outputBufferWidth();
+ uint32_t height = outputBufferHeight();
+ uint64_t nFilledLen = width;
+ nFilledLen *= height;
+ if (nFilledLen > UINT32_MAX / 3) {
+ ALOGE("b/29421675, nFilledLen overflow %llu w %u h %u",
+ (unsigned long long)nFilledLen, width, height);
+ android_errorWriteLog(0x534e4554, "29421675");
+ return false;
+ } else if (outHeader->nAllocLen < outHeader->nFilledLen) {
+ ALOGE("b/27597103, buffer too small");
+ android_errorWriteLog(0x534e4554, "27597103");
+ return false;
+ }
+
+ return true;
+}
+
void SoftVPX::onQueueFilled(OMX_U32 /* portIndex */) {
if (mOutputPortSettingsChange != NONE || mEOSStatus == OUTPUT_FRAMES_FLUSHED) {
return;
diff --git a/media/libstagefright/codecs/on2/dec/SoftVPX.h b/media/libstagefright/codecs/on2/dec/SoftVPX.h
index 8ccbae2..84cf79c 100644
--- a/media/libstagefright/codecs/on2/dec/SoftVPX.h
+++ b/media/libstagefright/codecs/on2/dec/SoftVPX.h
@@ -66,6 +66,7 @@
status_t initDecoder();
status_t destroyDecoder();
bool outputBuffers(bool flushDecoder, bool display, bool eos, bool *portWillReset);
+ bool outputBufferSafe(OMX_BUFFERHEADERTYPE *outHeader);
DISALLOW_EVIL_CONSTRUCTORS(SoftVPX);
};
diff --git a/media/libstagefright/id3/ID3.cpp b/media/libstagefright/id3/ID3.cpp
index 35691b9..3942158 100644
--- a/media/libstagefright/id3/ID3.cpp
+++ b/media/libstagefright/id3/ID3.cpp
@@ -77,7 +77,10 @@
mFirstFrameOffset(0),
mVersion(ID3_UNKNOWN),
mRawSize(0) {
- sp<MemorySource> source = new MemorySource(data, size);
+ sp<MemorySource> source = new (std::nothrow) MemorySource(data, size);
+
+ if (source == NULL)
+ return;
mIsValid = parseV2(source, 0);
@@ -542,6 +545,10 @@
n -= skipped;
}
+ if (n <= 0) {
+ return;
+ }
+
if (encoding == 0x00) {
// supposedly ISO 8859-1
id->setTo((const char*)frameData + 1, n);
@@ -555,11 +562,16 @@
const char16_t *framedata = (const char16_t *) (frameData + 1);
char16_t *framedatacopy = NULL;
#if BYTE_ORDER == LITTLE_ENDIAN
- framedatacopy = new char16_t[len];
- for (int i = 0; i < len; i++) {
- framedatacopy[i] = bswap_16(framedata[i]);
+ if (len > 0) {
+ framedatacopy = new (std::nothrow) char16_t[len];
+ if (framedatacopy == NULL) {
+ return;
+ }
+ for (int i = 0; i < len; i++) {
+ framedatacopy[i] = bswap_16(framedata[i]);
+ }
+ framedata = framedatacopy;
}
- framedata = framedatacopy;
#endif
id->setTo(framedata, len);
if (framedatacopy != NULL) {
@@ -572,15 +584,26 @@
const char16_t *framedata = (const char16_t *) (frameData + 1);
char16_t *framedatacopy = NULL;
if (*framedata == 0xfffe) {
- // endianness marker doesn't match host endianness, convert
- framedatacopy = new char16_t[len];
+ // endianness marker != host endianness, convert & skip
+ if (len <= 1) {
+ return; // nothing after the marker
+ }
+ framedatacopy = new (std::nothrow) char16_t[len];
+ if (framedatacopy == NULL) {
+ return;
+ }
for (int i = 0; i < len; i++) {
framedatacopy[i] = bswap_16(framedata[i]);
}
framedata = framedatacopy;
- }
- // If the string starts with an endianness marker, skip it
- if (*framedata == 0xfeff) {
+ // and skip over the marker
+ framedata++;
+ len--;
+ } else if (*framedata == 0xfeff) {
+ // endianness marker == host endianness, skip it
+ if (len <= 1) {
+ return; // nothing after the marker
+ }
framedata++;
len--;
}
@@ -595,12 +618,16 @@
}
if (eightBit) {
// collapse to 8 bit, then let the media scanner client figure out the real encoding
- char *frame8 = new char[len];
- for (int i = 0; i < len; i++) {
- frame8[i] = framedata[i];
+ char *frame8 = new (std::nothrow) char[len];
+ if (frame8 != NULL) {
+ for (int i = 0; i < len; i++) {
+ frame8[i] = framedata[i];
+ }
+ id->setTo(frame8, len);
+ delete [] frame8;
+ } else {
+ id->setTo(framedata, len);
}
- id->setTo(frame8, len);
- delete [] frame8;
} else {
id->setTo(framedata, len);
}
diff --git a/media/libstagefright/include/CallbackDataSource.h b/media/libstagefright/include/CallbackDataSource.h
index f582c53..80cd1f7 100644
--- a/media/libstagefright/include/CallbackDataSource.h
+++ b/media/libstagefright/include/CallbackDataSource.h
@@ -41,6 +41,7 @@
virtual String8 toString() {
return mName;
}
+ virtual sp<DecryptHandle> DrmInitialization(const char *mime = NULL);
private:
sp<IDataSource> mIDataSource;
@@ -68,6 +69,7 @@
virtual String8 toString() {
return mName;
}
+ virtual sp<DecryptHandle> DrmInitialization(const char *mime = NULL);
private:
// 2kb comes from experimenting with the time-to-first-frame from a MediaPlayer
diff --git a/media/libstagefright/include/SampleTable.h b/media/libstagefright/include/SampleTable.h
index 0b42229..eb1a674 100644
--- a/media/libstagefright/include/SampleTable.h
+++ b/media/libstagefright/include/SampleTable.h
@@ -24,7 +24,6 @@
#include <media/stagefright/MediaErrors.h>
#include <utils/RefBase.h>
#include <utils/threads.h>
-#include <utils/Vector.h>
namespace android {
@@ -96,6 +95,9 @@
static const uint32_t kSampleSizeType32;
static const uint32_t kSampleSizeTypeCompact;
+ // Limit the total size of all internal tables to 200MiB.
+ static const size_t kMaxTotalSize = 200 * (1 << 20);
+
sp<DataSource> mDataSource;
Mutex mLock;
@@ -113,7 +115,7 @@
bool mHasTimeToSample;
uint32_t mTimeToSampleCount;
- Vector<uint32_t> mTimeToSample;
+ uint32_t* mTimeToSample;
struct SampleTimeEntry {
uint32_t mSampleIndex;
@@ -139,6 +141,9 @@
};
SampleToChunkEntry *mSampleToChunkEntries;
+ // Approximate size of all tables combined.
+ uint64_t mTotalSize;
+
friend struct SampleIterator;
// normally we don't round
diff --git a/media/libstagefright/omx/SimpleSoftOMXComponent.cpp b/media/libstagefright/omx/SimpleSoftOMXComponent.cpp
index 60c1e2e..13afd45 100644
--- a/media/libstagefright/omx/SimpleSoftOMXComponent.cpp
+++ b/media/libstagefright/omx/SimpleSoftOMXComponent.cpp
@@ -469,6 +469,13 @@
CHECK_EQ((int)port->mTransition, (int)PortInfo::NONE);
CHECK(port->mDef.bEnabled == !enable);
+ if (port->mDef.eDir != OMX_DirOutput) {
+ ALOGE("Port enable/disable allowed only on output ports.");
+ notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
+ android_errorWriteLog(0x534e4554, "29421804");
+ return;
+ }
+
if (!enable) {
port->mDef.bEnabled = OMX_FALSE;
port->mTransition = PortInfo::DISABLING;
diff --git a/media/libstagefright/rtsp/ASessionDescription.cpp b/media/libstagefright/rtsp/ASessionDescription.cpp
index 98498e9..47573c3 100644
--- a/media/libstagefright/rtsp/ASessionDescription.cpp
+++ b/media/libstagefright/rtsp/ASessionDescription.cpp
@@ -17,6 +17,7 @@
//#define LOG_NDEBUG 0
#define LOG_TAG "ASessionDescription"
#include <utils/Log.h>
+#include <cutils/log.h>
#include "ASessionDescription.h"
@@ -211,12 +212,12 @@
*PT = x;
- char key[20];
- sprintf(key, "a=rtpmap:%lu", x);
+ char key[32];
+ snprintf(key, sizeof(key), "a=rtpmap:%lu", x);
CHECK(findAttribute(index, key, desc));
- sprintf(key, "a=fmtp:%lu", x);
+ snprintf(key, sizeof(key), "a=fmtp:%lu", x);
if (!findAttribute(index, key, params)) {
params->clear();
}
@@ -228,8 +229,11 @@
*width = 0;
*height = 0;
- char key[20];
- sprintf(key, "a=framesize:%lu", PT);
+ char key[33];
+ snprintf(key, sizeof(key), "a=framesize:%lu", PT);
+ if (PT > 9999999) {
+ android_errorWriteLog(0x534e4554, "25747670");
+ }
AString value;
if (!findAttribute(index, key, &value)) {
return false;
diff --git a/services/audioflinger/Effects.cpp b/services/audioflinger/Effects.cpp
index 3e644df..c5b56ad 100644
--- a/services/audioflinger/Effects.cpp
+++ b/services/audioflinger/Effects.cpp
@@ -543,6 +543,13 @@
return NO_ERROR;
}
+// round up delta valid if value and divisor are positive.
+template <typename T>
+static T roundUpDelta(const T &value, const T &divisor) {
+ T remainder = value % divisor;
+ return remainder == 0 ? 0 : divisor - remainder;
+}
+
status_t AudioFlinger::EffectModule::command(uint32_t cmdCode,
uint32_t cmdSize,
void *pCmdData,
@@ -564,6 +571,22 @@
android_errorWriteLog(0x534e4554, "29251553");
return -EINVAL;
}
+ if ((cmdCode == EFFECT_CMD_SET_PARAM
+ || cmdCode == EFFECT_CMD_SET_PARAM_DEFERRED) && // DEFERRED not generally used
+ (sizeof(effect_param_t) > cmdSize
+ || ((effect_param_t *)pCmdData)->psize > cmdSize
+ - sizeof(effect_param_t)
+ || ((effect_param_t *)pCmdData)->vsize > cmdSize
+ - sizeof(effect_param_t)
+ - ((effect_param_t *)pCmdData)->psize
+ || roundUpDelta(((effect_param_t *)pCmdData)->psize, (uint32_t)sizeof(int)) >
+ cmdSize
+ - sizeof(effect_param_t)
+ - ((effect_param_t *)pCmdData)->psize
+ - ((effect_param_t *)pCmdData)->vsize)) {
+ android_errorWriteLog(0x534e4554, "30204301");
+ return -EINVAL;
+ }
status_t status = (*mEffectInterface)->command(mEffectInterface,
cmdCode,
cmdSize,
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 764b13e..1a330ef 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -1573,6 +1573,7 @@
mEffectBufferValid(false),
mSuspended(0), mBytesWritten(0),
mFramesWritten(0),
+ mSuspendedFrames(0),
mActiveTracksGeneration(0),
// mStreamTypes[] initialized in constructor body
mOutput(output),
@@ -2915,7 +2916,8 @@
// copy over kernel info
mTimestamp.mPosition[ExtendedTimestamp::LOCATION_KERNEL] =
- timestamp.mPosition[ExtendedTimestamp::LOCATION_KERNEL];
+ timestamp.mPosition[ExtendedTimestamp::LOCATION_KERNEL]
+ + mSuspendedFrames; // add frames discarded when suspended
mTimestamp.mTimeNs[ExtendedTimestamp::LOCATION_KERNEL] =
timestamp.mTimeNs[ExtendedTimestamp::LOCATION_KERNEL];
}
@@ -3079,10 +3081,12 @@
mBytesRemaining = mCurrentWriteLength;
if (isSuspended()) {
- mSleepTimeUs = suspendSleepTimeUs();
- // simulate write to HAL when suspended
- mBytesWritten += mSinkBufferSize;
- mFramesWritten += mSinkBufferSize / mFrameSize;
+ // Simulate write to HAL when suspended (e.g. BT SCO phone call).
+ mSleepTimeUs = suspendSleepTimeUs(); // assumes full buffer.
+ const size_t framesRemaining = mBytesRemaining / mFrameSize;
+ mBytesWritten += mBytesRemaining;
+ mFramesWritten += framesRemaining;
+ mSuspendedFrames += framesRemaining; // to adjust kernel HAL position
mBytesRemaining = 0;
}
@@ -5180,7 +5184,8 @@
AudioFlinger::OffloadThread::OffloadThread(const sp<AudioFlinger>& audioFlinger,
AudioStreamOut* output, audio_io_handle_t id, uint32_t device, bool systemReady)
: DirectOutputThread(audioFlinger, output, id, device, OFFLOAD, systemReady),
- mPausedWriteLength(0), mPausedBytesRemaining(0), mKeepWakeLock(true)
+ mPausedWriteLength(0), mPausedBytesRemaining(0), mKeepWakeLock(true),
+ mOffloadUnderrunPosition(~0LL)
{
//FIXME: mStandby should be set to true by ThreadBase constructor
mStandby = true;
@@ -5386,12 +5391,30 @@
// No buffers for this track. Give it a few chances to
// fill a buffer, then remove it from active list.
if (--(track->mRetryCount) <= 0) {
- ALOGV("OffloadThread: BUFFER TIMEOUT: remove(%d) from active list",
- track->name());
- tracksToRemove->add(track);
- // indicate to client process that the track was disabled because of underrun;
- // it will then automatically call start() when data is available
- track->disable();
+ bool running = false;
+ if (mOutput->stream->get_presentation_position != nullptr) {
+ uint64_t position = 0;
+ struct timespec unused;
+ // The running check restarts the retry counter at least once.
+ int ret = mOutput->stream->get_presentation_position(
+ mOutput->stream, &position, &unused);
+ if (ret == NO_ERROR && position != mOffloadUnderrunPosition) {
+ running = true;
+ mOffloadUnderrunPosition = position;
+ }
+ ALOGVV("underrun counter, running(%d): %lld vs %lld", running,
+ (long long)position, (long long)mOffloadUnderrunPosition);
+ }
+ if (running) { // still running, give us more time.
+ track->mRetryCount = kMaxTrackRetriesOffload;
+ } else {
+ ALOGV("OffloadThread: BUFFER TIMEOUT: remove(%d) from active list",
+ track->name());
+ tracksToRemove->add(track);
+ // indicate to client process that the track was disabled because of underrun;
+ // it will then automatically call start() when data is available
+ track->disable();
+ }
} else if (last){
mixerStatus = MIXER_TRACKS_ENABLED;
}
@@ -5448,6 +5471,7 @@
mPausedBytesRemaining = 0;
// reset bytes written count to reflect that DSP buffers are empty after flush.
mBytesWritten = 0;
+ mOffloadUnderrunPosition = ~0LL;
if (mUseAsyncWrite) {
// discard any pending drain or write ack by incrementing sequence
diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
index 0578118..5dfbf08 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -703,6 +703,7 @@
int64_t mBytesWritten;
int64_t mFramesWritten; // not reset on standby
+ int64_t mSuspendedFrames; // not reset on standby
private:
// mMasterMute is in both PlaybackThread and in AudioFlinger. When a
// PlaybackThread needs to find out if master-muted, it checks it's local
@@ -1008,6 +1009,10 @@
size_t mPausedWriteLength; // length in bytes of write interrupted by pause
size_t mPausedBytesRemaining; // bytes still waiting in mixbuffer after resume
bool mKeepWakeLock; // keep wake lock while waiting for write callback
+ uint64_t mOffloadUnderrunPosition; // Current frame position for offloaded playback
+ // used and valid only during underrun. ~0 if
+ // no underrun has occurred during playback and
+ // is not reset on standby.
};
class AsyncCallbackThread : public Thread {
diff --git a/services/camera/libcameraservice/device3/Camera3IOStreamBase.cpp b/services/camera/libcameraservice/device3/Camera3IOStreamBase.cpp
index 4824974..cb39244 100644
--- a/services/camera/libcameraservice/device3/Camera3IOStreamBase.cpp
+++ b/services/camera/libcameraservice/device3/Camera3IOStreamBase.cpp
@@ -124,6 +124,7 @@
switch (mState) {
case STATE_IN_RECONFIG:
case STATE_CONFIGURED:
+ case STATE_ABANDONED:
// OK
break;
default:
diff --git a/services/camera/libcameraservice/device3/Camera3OutputStream.cpp b/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
index dff5a49..3f69b46 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
@@ -611,9 +611,9 @@
*buffer = 0;
ALOGW("%s: the released buffer has already been freed by the buffer queue!", __FUNCTION__);
} else if (res != OK) {
- // Other errors are fatal.
+ // Treat other errors as abandonment
ALOGE("%s: detach next buffer failed: %s (%d).", __FUNCTION__, strerror(-res), res);
- mState = STATE_ERROR;
+ mState = STATE_ABANDONED;
return res;
}
diff --git a/services/soundtrigger/SoundTriggerHwService.cpp b/services/soundtrigger/SoundTriggerHwService.cpp
index ac379bd..6a52b9c 100644
--- a/services/soundtrigger/SoundTriggerHwService.cpp
+++ b/services/soundtrigger/SoundTriggerHwService.cpp
@@ -542,6 +542,22 @@
struct sound_trigger_sound_model *sound_model =
(struct sound_trigger_sound_model *)modelMemory->pointer();
+ size_t structSize;
+ if (sound_model->type == SOUND_MODEL_TYPE_KEYPHRASE) {
+ structSize = sizeof(struct sound_trigger_phrase_sound_model);
+ } else {
+ structSize = sizeof(struct sound_trigger_sound_model);
+ }
+
+ if (sound_model->data_offset < structSize ||
+ sound_model->data_size > (UINT_MAX - sound_model->data_offset) ||
+ modelMemory->size() < sound_model->data_offset ||
+ sound_model->data_size > (modelMemory->size() - sound_model->data_offset)) {
+ android_errorWriteLog(0x534e4554, "30148546");
+ ALOGE("loadSoundModel() data_size is too big");
+ return BAD_VALUE;
+ }
+
AutoMutex lock(mLock);
if (mModels.size() >= mDescriptor.properties.max_sound_models) {
@@ -607,11 +623,23 @@
return PERMISSION_DENIED;
}
- if (dataMemory != 0 && dataMemory->pointer() == NULL) {
- ALOGE("startRecognition() dataMemory is non-0 but has NULL pointer()");
+ if (dataMemory == 0 || dataMemory->pointer() == NULL) {
+ ALOGE("startRecognition() dataMemory is 0 or has NULL pointer()");
return BAD_VALUE;
}
+
+ struct sound_trigger_recognition_config *config =
+ (struct sound_trigger_recognition_config *)dataMemory->pointer();
+
+ if (config->data_offset < sizeof(struct sound_trigger_recognition_config) ||
+ config->data_size > (UINT_MAX - config->data_offset) ||
+ dataMemory->size() < config->data_offset ||
+ config->data_size > (dataMemory->size() - config->data_offset)) {
+ ALOGE("startRecognition() data_size is too big");
+ return BAD_VALUE;
+ }
+
AutoMutex lock(mLock);
if (mServiceState == SOUND_TRIGGER_STATE_DISABLED) {
return INVALID_OPERATION;
@@ -620,17 +648,11 @@
if (model == 0) {
return BAD_VALUE;
}
- if ((dataMemory == 0) ||
- (dataMemory->size() < sizeof(struct sound_trigger_recognition_config))) {
- return BAD_VALUE;
- }
if (model->mState == Model::STATE_ACTIVE) {
return INVALID_OPERATION;
}
- struct sound_trigger_recognition_config *config =
- (struct sound_trigger_recognition_config *)dataMemory->pointer();
//TODO: get capture handle and device from audio policy service
config->capture_handle = model->mCaptureIOHandle;