Merge "omx: prevent crash at MuxOMX::freeNode for already freed nodes" into nyc-mr1-dev
diff --git a/camera/camera2/CaptureRequest.cpp b/camera/camera2/CaptureRequest.cpp
index fb43708..0d689a6 100644
--- a/camera/camera2/CaptureRequest.cpp
+++ b/camera/camera2/CaptureRequest.cpp
@@ -37,7 +37,7 @@
mMetadata.clear();
mSurfaceList.clear();
- status_t err;
+ status_t err = OK;
if ((err = mMetadata.readFromParcel(parcel)) != OK) {
ALOGE("%s: Failed to read metadata from parcel", __FUNCTION__);
@@ -65,19 +65,16 @@
}
// Surface.writeToParcel
- const char16_t* name = parcel->readString16Inplace(&len);
- ALOGV("%s: Read surface name = %s", __FUNCTION__,
- name != NULL ? String8(name).string() : "<null>");
- sp<IBinder> binder(parcel->readStrongBinder());
- ALOGV("%s: Read surface binder = %p",
- __FUNCTION__, binder.get());
+ view::Surface surfaceShim;
+ if ((err = surfaceShim.readFromParcel(parcel)) != OK) {
+ ALOGE("%s: Failed to read output target Surface %d from parcel: %s (%d)",
+ __FUNCTION__, i, strerror(-err), err);
+ return err;
+ }
sp<Surface> surface;
-
- if (binder != NULL) {
- sp<IGraphicBufferProducer> gbp =
- interface_cast<IGraphicBufferProducer>(binder);
- surface = new Surface(gbp);
+ if (surfaceShim.graphicBufferProducer != NULL) {
+ surface = new Surface(surfaceShim.graphicBufferProducer);
}
mSurfaceList.push_back(surface);
@@ -99,7 +96,7 @@
return BAD_VALUE;
}
- status_t err;
+ status_t err = OK;
if ((err = mMetadata.writeToParcel(parcel)) != OK) {
return err;
@@ -111,20 +108,18 @@
parcel->writeInt32(size);
for (int32_t i = 0; i < size; ++i) {
- sp<Surface> surface = mSurfaceList[i];
-
- sp<IBinder> binder;
- if (surface != 0) {
- binder = IInterface::asBinder(surface->getIGraphicBufferProducer());
- }
-
// not sure if readParcelableArray does this, hard to tell from source
parcel->writeString16(String16("android.view.Surface"));
// Surface.writeToParcel
- parcel->writeString16(String16("unknown_name"));
- // Surface.nativeWriteToParcel
- parcel->writeStrongBinder(binder);
+ view::Surface surfaceShim;
+ surfaceShim.name = String16("unknown_name");
+ surfaceShim.graphicBufferProducer = mSurfaceList[i]->getIGraphicBufferProducer();
+ if ((err = surfaceShim.writeToParcel(parcel)) != OK) {
+ ALOGE("%s: Failed to write output target Surface %d to parcel: %s (%d)",
+ __FUNCTION__, i, strerror(-err), err);
+ return err;
+ }
}
parcel->writeInt32(mIsReprocess ? 1 : 0);
diff --git a/drm/mediadrm/plugins/clearkey/DrmFactory.cpp b/drm/mediadrm/plugins/clearkey/DrmFactory.cpp
index 40275cf..d27956c 100644
--- a/drm/mediadrm/plugins/clearkey/DrmFactory.cpp
+++ b/drm/mediadrm/plugins/clearkey/DrmFactory.cpp
@@ -24,6 +24,7 @@
#include "DrmPlugin.h"
#include "ClearKeyUUID.h"
+#include "MimeType.h"
#include "SessionLibrary.h"
namespace clearkeydrm {
@@ -32,10 +33,14 @@
return isClearKeyUUID(uuid);
}
-bool DrmFactory::isContentTypeSupported(const android::String8 &initDataType) {
+bool DrmFactory::isContentTypeSupported(const android::String8 &type) {
// This should match the types handed by InitDataParser.
- return initDataType == "cenc" ||
- initDataType == "webm";
+ return type == kIsoBmffVideoMimeType ||
+ type == kIsoBmffAudioMimeType ||
+ type == kCencInitDataFormat ||
+ type == kWebmVideoMimeType ||
+ type == kWebmAudioMimeType ||
+ type == kWebmInitDataFormat;
}
android::status_t DrmFactory::createDrmPlugin(
diff --git a/drm/mediadrm/plugins/clearkey/DrmFactory.h b/drm/mediadrm/plugins/clearkey/DrmFactory.h
index 164d3d0..87db982 100644
--- a/drm/mediadrm/plugins/clearkey/DrmFactory.h
+++ b/drm/mediadrm/plugins/clearkey/DrmFactory.h
@@ -32,7 +32,7 @@
virtual bool isCryptoSchemeSupported(const uint8_t uuid[16]);
- virtual bool isContentTypeSupported(const android::String8 &initDataType);
+ virtual bool isContentTypeSupported(const android::String8 &mimeType);
virtual android::status_t createDrmPlugin(
const uint8_t uuid[16], android::DrmPlugin** plugin);
diff --git a/drm/mediadrm/plugins/clearkey/DrmPlugin.cpp b/drm/mediadrm/plugins/clearkey/DrmPlugin.cpp
index e5ee403..86bf047 100644
--- a/drm/mediadrm/plugins/clearkey/DrmPlugin.cpp
+++ b/drm/mediadrm/plugins/clearkey/DrmPlugin.cpp
@@ -46,7 +46,7 @@
status_t DrmPlugin::getKeyRequest(
const Vector<uint8_t>& scope,
const Vector<uint8_t>& initData,
- const String8& initDataType,
+ const String8& mimeType,
KeyType keyType,
const KeyedVector<String8, String8>& optionalParameters,
Vector<uint8_t>& request,
@@ -62,7 +62,7 @@
if (!session.get()) {
return android::ERROR_DRM_SESSION_NOT_OPENED;
}
- return session->getKeyRequest(initData, initDataType, &request);
+ return session->getKeyRequest(initData, mimeType, &request);
}
status_t DrmPlugin::provideKeyResponse(
diff --git a/drm/mediadrm/plugins/clearkey/DrmPlugin.h b/drm/mediadrm/plugins/clearkey/DrmPlugin.h
index 9095045..efb9f8b 100644
--- a/drm/mediadrm/plugins/clearkey/DrmPlugin.h
+++ b/drm/mediadrm/plugins/clearkey/DrmPlugin.h
@@ -49,7 +49,7 @@
virtual status_t getKeyRequest(
const Vector<uint8_t>& scope,
- const Vector<uint8_t>& initData,
+ const Vector<uint8_t>& mimeType,
const String8& initDataType,
KeyType keyType,
const KeyedVector<String8, String8>& optionalParameters,
diff --git a/drm/mediadrm/plugins/clearkey/InitDataParser.cpp b/drm/mediadrm/plugins/clearkey/InitDataParser.cpp
index c22d73a..0216b8d 100644
--- a/drm/mediadrm/plugins/clearkey/InitDataParser.cpp
+++ b/drm/mediadrm/plugins/clearkey/InitDataParser.cpp
@@ -27,6 +27,7 @@
#include "InitDataParser.h"
#include "ClearKeyUUID.h"
+#include "MimeType.h"
#include "Utils.h"
namespace clearkeydrm {
@@ -41,16 +42,20 @@
}
android::status_t InitDataParser::parse(const Vector<uint8_t>& initData,
- const String8& initDataType,
+ const String8& type,
Vector<uint8_t>* licenseRequest) {
// Build a list of the key IDs
Vector<const uint8_t*> keyIds;
- if (initDataType == "cenc") {
+ if (type == kIsoBmffVideoMimeType ||
+ type == kIsoBmffAudioMimeType ||
+ type == kCencInitDataFormat) {
android::status_t res = parsePssh(initData, &keyIds);
if (res != android::OK) {
return res;
}
- } else if (initDataType == "webm") {
+ } else if (type == kWebmVideoMimeType ||
+ type == kWebmAudioMimeType ||
+ type == kWebmInitDataFormat) {
// WebM "init data" is just a single key ID
if (initData.size() != kKeyIdSize) {
return android::ERROR_DRM_CANNOT_HANDLE;
diff --git a/drm/mediadrm/plugins/clearkey/InitDataParser.h b/drm/mediadrm/plugins/clearkey/InitDataParser.h
index 9505d2a..a9707bf 100644
--- a/drm/mediadrm/plugins/clearkey/InitDataParser.h
+++ b/drm/mediadrm/plugins/clearkey/InitDataParser.h
@@ -29,7 +29,7 @@
InitDataParser() {}
android::status_t parse(const android::Vector<uint8_t>& initData,
- const android::String8& initDataType,
+ const android::String8& type,
android::Vector<uint8_t>* licenseRequest);
private:
diff --git a/drm/mediadrm/plugins/clearkey/MimeType.h b/drm/mediadrm/plugins/clearkey/MimeType.h
new file mode 100644
index 0000000..085f17a
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/MimeType.h
@@ -0,0 +1,15 @@
+#ifndef CLEARKEY_MIMETYPE_H_
+#define CLEARKEY_MIMETYPE_H_
+
+#include <utils/String8.h>
+
+namespace {
+ const android::String8 kCencInitDataFormat("cenc");
+ const android::String8 kIsoBmffAudioMimeType("audio/mp4");
+ const android::String8 kIsoBmffVideoMimeType("video/mp4");
+ const android::String8 kWebmInitDataFormat("webm");
+ const android::String8 kWebmAudioMimeType("audio/webm");
+ const android::String8 kWebmVideoMimeType("video/webm");
+}
+
+#endif // CLEARKEY_MIMETYPE_H_
diff --git a/drm/mediadrm/plugins/clearkey/Session.cpp b/drm/mediadrm/plugins/clearkey/Session.cpp
index 95016f5..d210f5e 100644
--- a/drm/mediadrm/plugins/clearkey/Session.cpp
+++ b/drm/mediadrm/plugins/clearkey/Session.cpp
@@ -36,10 +36,10 @@
status_t Session::getKeyRequest(
const Vector<uint8_t>& initData,
- const String8& initDataType,
+ const String8& mimeType,
Vector<uint8_t>* keyRequest) const {
InitDataParser parser;
- return parser.parse(initData, initDataType, keyRequest);
+ return parser.parse(initData, mimeType, keyRequest);
}
status_t Session::provideKeyResponse(const Vector<uint8_t>& response) {
diff --git a/drm/mediadrm/plugins/clearkey/Session.h b/drm/mediadrm/plugins/clearkey/Session.h
index cab0dc3..0933506 100644
--- a/drm/mediadrm/plugins/clearkey/Session.h
+++ b/drm/mediadrm/plugins/clearkey/Session.h
@@ -38,7 +38,7 @@
const android::Vector<uint8_t>& sessionId() const { return mSessionId; }
android::status_t getKeyRequest(
- const android::Vector<uint8_t>& initData,
+ const android::Vector<uint8_t>& mimeType,
const android::String8& initDataType,
android::Vector<uint8_t>* keyRequest) const;
diff --git a/drm/mediadrm/plugins/clearkey/tests/InitDataParserUnittest.cpp b/drm/mediadrm/plugins/clearkey/tests/InitDataParserUnittest.cpp
index 4ba65ed..e275108 100644
--- a/drm/mediadrm/plugins/clearkey/tests/InitDataParserUnittest.cpp
+++ b/drm/mediadrm/plugins/clearkey/tests/InitDataParserUnittest.cpp
@@ -30,27 +30,27 @@
namespace {
const size_t kKeyIdSize = 16;
- const String8 kCencType("cenc");
- const String8 kWebMType("webm");
+ const String8 kCencMimeType("video/mp4");
+ const String8 kWebmMimeType("video/webm");
const String8 kBase64Padding("=");
}
class InitDataParserTest : public ::testing::Test {
protected:
status_t attemptParse(const Vector<uint8_t>& initData,
- const String8& initDataType,
+ const String8& mimeType,
Vector<uint8_t>* licenseRequest) {
InitDataParser parser;
- return parser.parse(initData, initDataType, licenseRequest);
+ return parser.parse(initData, mimeType, licenseRequest);
}
void attemptParseExpectingSuccess(const Vector<uint8_t>& initData,
- const String8& initDataType,
+ const String8& mimeType,
const Vector<String8>& expectedKeys) {
const String8 kRequestPrefix("{\"kids\":[");
const String8 kRequestSuffix("],\"type\":\"temporary\"}");
Vector<uint8_t> request;
- ASSERT_EQ(android::OK, attemptParse(initData, initDataType, &request));
+ ASSERT_EQ(android::OK, attemptParse(initData, mimeType, &request));
String8 requestString(reinterpret_cast<const char*>(request.array()),
request.size());
@@ -68,9 +68,9 @@
}
void attemptParseExpectingFailure(const Vector<uint8_t>& initData,
- const String8& initDataType) {
+ const String8& mimeType) {
Vector<uint8_t> request;
- ASSERT_NE(android::OK, attemptParse(initData, initDataType, &request));
+ ASSERT_NE(android::OK, attemptParse(initData, mimeType, &request));
EXPECT_EQ(0, request.size());
}
};
@@ -93,7 +93,7 @@
Vector<String8> expectedKeys;
expectedKeys.push(String8("01234567890ABCDE"));
- attemptParseExpectingSuccess(initData, kCencType, expectedKeys);
+ attemptParseExpectingSuccess(initData, kCencMimeType, expectedKeys);
}
TEST_F(InitDataParserTest, ParsesMultipleKeyPssh) {
@@ -120,7 +120,7 @@
expectedKeys.push(String8("ClearKeyClearKey"));
expectedKeys.push(String8(" GOOGLE GOOGLE "));
- attemptParseExpectingSuccess(initData, kCencType, expectedKeys);
+ attemptParseExpectingSuccess(initData, kCencMimeType, expectedKeys);
}
TEST_F(InitDataParserTest, ParsesWebM) {
@@ -134,7 +134,7 @@
Vector<String8> expectedKeys;
expectedKeys.push(String8("01234567890ABCDE"));
- attemptParseExpectingSuccess(initData, kWebMType, expectedKeys);
+ attemptParseExpectingSuccess(initData, kWebmMimeType, expectedKeys);
}
TEST_F(InitDataParserTest, FailsForPsshTooSmall) {
@@ -147,7 +147,7 @@
Vector<uint8_t> initData;
initData.appendArray(pssh, 16);
- attemptParseExpectingFailure(initData, kCencType);
+ attemptParseExpectingFailure(initData, kCencMimeType);
}
TEST_F(InitDataParserTest, FailsForWebMTooSmall) {
@@ -157,7 +157,7 @@
Vector<uint8_t> initData;
initData.appendArray(initDataRaw, 8);
- attemptParseExpectingFailure(initData, kWebMType);
+ attemptParseExpectingFailure(initData, kWebmMimeType);
}
TEST_F(InitDataParserTest, FailsForPsshBadSystemId) {
@@ -175,7 +175,7 @@
Vector<uint8_t> initData;
initData.appendArray(pssh, 52);
- attemptParseExpectingFailure(initData, kCencType);
+ attemptParseExpectingFailure(initData, kCencMimeType);
}
TEST_F(InitDataParserTest, FailsForPsshBadSize) {
@@ -193,7 +193,7 @@
Vector<uint8_t> initData;
initData.appendArray(pssh, 52);
- attemptParseExpectingFailure(initData, kCencType);
+ attemptParseExpectingFailure(initData, kCencMimeType);
}
TEST_F(InitDataParserTest, FailsForPsshWrongVersion) {
@@ -211,7 +211,7 @@
Vector<uint8_t> initData;
initData.appendArray(pssh, 52);
- attemptParseExpectingFailure(initData, kCencType);
+ attemptParseExpectingFailure(initData, kCencMimeType);
}
TEST_F(InitDataParserTest, FailsForPsshBadKeyCount) {
@@ -229,7 +229,7 @@
Vector<uint8_t> initData;
initData.appendArray(pssh, 52);
- attemptParseExpectingFailure(initData, kCencType);
+ attemptParseExpectingFailure(initData, kCencMimeType);
}
} // namespace clearkeydrm
diff --git a/include/media/IOMX.h b/include/media/IOMX.h
index 15d691f..1c39b9c 100644
--- a/include/media/IOMX.h
+++ b/include/media/IOMX.h
@@ -192,6 +192,7 @@
INTERNAL_OPTION_START_TIME, // data is an int64_t
INTERNAL_OPTION_TIME_LAPSE, // data is an int64_t[2]
INTERNAL_OPTION_COLOR_ASPECTS, // data is ColorAspects
+ INTERNAL_OPTION_TIME_OFFSET, // data is an int64_t
};
virtual status_t setInternalOption(
node_id node,
diff --git a/include/media/ToneGenerator.h b/include/media/ToneGenerator.h
index 75515ac..a419e17 100644
--- a/include/media/ToneGenerator.h
+++ b/include/media/ToneGenerator.h
@@ -313,7 +313,7 @@
short mA1_Q14; // Q14 coefficient
// delay line of full amplitude generator
- short mS1, mS2; // delay line S2 oldest
+ long mS1, mS2; // delay line S2 oldest
short mS2_0; // saved value for reinitialisation
short mAmplitude_Q15; // Q15 amplitude
};
diff --git a/include/media/Visualizer.h b/include/media/Visualizer.h
index ec0dad5..7bb9e8b 100644
--- a/include/media/Visualizer.h
+++ b/include/media/Visualizer.h
@@ -95,8 +95,7 @@
// install a callback to receive periodic captures. The capture rate is specified in milliHertz
// and the capture format is according to flags (see callback_flags).
- status_t setCaptureCallBack(capture_cbk_t cbk, void* user, uint32_t flags, uint32_t rate,
- bool force = false);
+ status_t setCaptureCallBack(capture_cbk_t cbk, void* user, uint32_t flags, uint32_t rate);
// set the capture size capture size must be a power of two in the range
// [VISUALIZER_CAPTURE_SIZE_MAX. VISUALIZER_CAPTURE_SIZE_MIN]
diff --git a/include/media/stagefright/MediaBuffer.h b/include/media/stagefright/MediaBuffer.h
index 55b1f58..a61ddaa 100644
--- a/include/media/stagefright/MediaBuffer.h
+++ b/include/media/stagefright/MediaBuffer.h
@@ -68,11 +68,16 @@
mMemory = mem;
}
- // Decrements the reference count and returns the buffer to its
- // associated MediaBufferGroup if the reference count drops to 0.
+ // If MediaBufferGroup is set, decrement the local reference count;
+ // if the local reference count drops to 0, return the buffer to the
+ // associated MediaBufferGroup.
+ //
+ // If no MediaBufferGroup is set, the local reference count must be zero
+ // when called, whereupon the MediaBuffer is deleted.
virtual void release();
- // Increments the reference count.
+ // Increments the local reference count.
+ // Use only when MediaBufferGroup is set.
virtual void add_ref();
void *data() const;
@@ -97,7 +102,28 @@
// MetaData.
MediaBuffer *clone();
- int refcount() const;
+ // sum of localRefcount() and remoteRefcount()
+ int refcount() const {
+ return localRefcount() + remoteRefcount();
+ }
+
+ int localRefcount() const {
+ return mRefCount;
+ }
+
+ int remoteRefcount() const {
+ if (mMemory.get() == nullptr || mMemory->pointer() == nullptr) return 0;
+ int32_t remoteRefcount =
+ reinterpret_cast<SharedControl *>(mMemory->pointer())->getRemoteRefcount();
+ // Sanity check so that remoteRefCount() is non-negative.
+ return remoteRefcount >= 0 ? remoteRefcount : 0; // do not allow corrupted data.
+ }
+
+ // returns old value
+ int addRemoteRefcount(int32_t value) {
+ if (mMemory.get() == nullptr || mMemory->pointer() == nullptr) return 0;
+ return reinterpret_cast<SharedControl *>(mMemory->pointer())->addRemoteRefcount(value);
+ }
bool isDeadObject() const {
return isDeadObject(mMemory);
@@ -108,26 +134,15 @@
return reinterpret_cast<SharedControl *>(memory->pointer())->isDeadObject();
}
+ // Sticky on enabling of shared memory MediaBuffers. By default we don't use
+ // shared memory for MediaBuffers, but we enable this for those processes
+ // that export MediaBuffers.
+ static void useSharedMemory() {
+ std::atomic_store_explicit(
+ &mUseSharedMemory, (int_least32_t)1, std::memory_order_seq_cst);
+ }
+
protected:
- // MediaBuffer remote releases are handled through a
- // pending release count variable stored in a SharedControl block
- // at the start of the IMemory.
-
- // Returns old value of pending release count.
- inline int32_t addPendingRelease(int32_t value) {
- return getSharedControl()->addPendingRelease(value);
- }
-
- // Issues all pending releases (works in parallel).
- // Assumes there is a MediaBufferObserver.
- inline void resolvePendingRelease() {
- if (mMemory.get() == nullptr) return;
- while (addPendingRelease(-1) > 0) {
- release();
- }
- addPendingRelease(1);
- }
-
// true if MediaBuffer is observed (part of a MediaBufferGroup).
inline bool isObserved() const {
return mObserver != nullptr;
@@ -161,6 +176,8 @@
MediaBuffer *mOriginal;
+ static std::atomic_int_least32_t mUseSharedMemory;
+
MediaBuffer(const MediaBuffer &);
MediaBuffer &operator=(const MediaBuffer &);
@@ -171,18 +188,18 @@
};
// returns old value
- inline int32_t addPendingRelease(int32_t value) {
+ inline int32_t addRemoteRefcount(int32_t value) {
return std::atomic_fetch_add_explicit(
- &mPendingRelease, (int_least32_t)value, std::memory_order_seq_cst);
+ &mRemoteRefcount, (int_least32_t)value, std::memory_order_seq_cst);
}
- inline int32_t getPendingRelease() const {
- return std::atomic_load_explicit(&mPendingRelease, std::memory_order_seq_cst);
+ inline int32_t getRemoteRefcount() const {
+ return std::atomic_load_explicit(&mRemoteRefcount, std::memory_order_seq_cst);
}
- inline void setPendingRelease(int32_t value) {
+ inline void setRemoteRefcount(int32_t value) {
std::atomic_store_explicit(
- &mPendingRelease, (int_least32_t)value, std::memory_order_seq_cst);
+ &mRemoteRefcount, (int_least32_t)value, std::memory_order_seq_cst);
}
inline bool isDeadObject() const {
@@ -199,13 +216,13 @@
std::atomic_store_explicit(
&mFlags, (int_least32_t)0, std::memory_order_seq_cst);
std::atomic_store_explicit(
- &mPendingRelease, (int_least32_t)0, std::memory_order_seq_cst);
+ &mRemoteRefcount, (int_least32_t)0, std::memory_order_seq_cst);
}
private:
// Caution: atomic_int_fast32_t is 64 bits on LP64.
std::atomic_int_least32_t mFlags;
- std::atomic_int_least32_t mPendingRelease;
+ std::atomic_int_least32_t mRemoteRefcount;
int32_t unused[6]; // additional buffer space
};
diff --git a/include/media/stagefright/MediaBufferGroup.h b/include/media/stagefright/MediaBufferGroup.h
index dfa31b2..3051406 100644
--- a/include/media/stagefright/MediaBufferGroup.h
+++ b/include/media/stagefright/MediaBufferGroup.h
@@ -53,10 +53,7 @@
size_t buffers() const { return mBuffers.size(); }
- // freeBuffers is the number of free buffers allowed to remain.
- void gc(size_t freeBuffers = 0);
-
-protected:
+ // If buffer is nullptr, have acquire_buffer() check for remote release.
virtual void signalBufferReturned(MediaBuffer *buffer);
private:
diff --git a/include/media/stagefright/MediaCodecSource.h b/include/media/stagefright/MediaCodecSource.h
index cc62786..18b1955 100644
--- a/include/media/stagefright/MediaCodecSource.h
+++ b/include/media/stagefright/MediaCodecSource.h
@@ -49,7 +49,8 @@
bool isVideo() const { return mIsVideo; }
sp<IGraphicBufferProducer> getGraphicBufferProducer();
- void setInputBufferTimeOffset(int64_t timeOffsetUs);
+ status_t setInputBufferTimeOffset(int64_t timeOffsetUs);
+ int64_t getFirstSampleSystemTimeUs();
// MediaSource
virtual status_t start(MetaData *params = NULL);
@@ -79,6 +80,7 @@
kWhatStop,
kWhatPause,
kWhatSetInputBufferTimeOffset,
+ kWhatGetFirstSampleSystemTimeUs,
kWhatStopStalled,
};
@@ -90,6 +92,7 @@
uint32_t flags = 0);
status_t onStart(MetaData *params);
+ void onPause();
status_t init();
status_t initEncoder();
void releaseEncoder();
@@ -123,6 +126,8 @@
List<size_t> mAvailEncoderInputIndices;
List<int64_t> mDecodingTimeQueue; // decoding time (us) for video
int64_t mInputBufferTimeOffsetUs;
+ int64_t mFirstSampleSystemTimeUs;
+ bool mPausePending;
// audio drift time
int64_t mFirstSampleTimeUs;
diff --git a/include/private/media/AudioTrackShared.h b/include/private/media/AudioTrackShared.h
index ffdb9b5..7becf57 100644
--- a/include/private/media/AudioTrackShared.h
+++ b/include/private/media/AudioTrackShared.h
@@ -522,6 +522,12 @@
mTimestampMutator.push(timestamp);
}
+ // Flushes the shared ring buffer if the client had requested it using mStreaming.mFlush.
+ // If flush occurs then:
+ // cblk->u.mStreaming.mFront, ServerProxy::mFlush and ServerProxy::mFlushed will be modified
+ // client will be notified via Futex
+ virtual void flushBufferIfNeeded();
+
// Total count of the number of flushed frames since creation (never reset).
virtual int64_t framesFlushed() const { return mFlushed; }
diff --git a/include/radio/Radio.h b/include/radio/Radio.h
index 302bf16..a4dfdd1 100644
--- a/include/radio/Radio.h
+++ b/include/radio/Radio.h
@@ -75,7 +75,7 @@
private:
Radio(radio_handle_t handle,
const sp<RadioCallback>&);
- static const sp<IRadioService>& getRadioService();
+ static const sp<IRadioService> getRadioService();
Mutex mLock;
sp<IRadio> mIRadio;
diff --git a/include/soundtrigger/SoundTrigger.h b/include/soundtrigger/SoundTrigger.h
index bf5e1de..9a05cac 100644
--- a/include/soundtrigger/SoundTrigger.h
+++ b/include/soundtrigger/SoundTrigger.h
@@ -68,7 +68,7 @@
private:
SoundTrigger(sound_trigger_module_handle_t module,
const sp<SoundTriggerCallback>&);
- static const sp<ISoundTriggerHwService>& getSoundTriggerHwService();
+ static const sp<ISoundTriggerHwService> getSoundTriggerHwService();
Mutex mLock;
sp<ISoundTrigger> mISoundTrigger;
diff --git a/media/libmedia/AudioRecord.cpp b/media/libmedia/AudioRecord.cpp
index b172747..ff5903d 100644
--- a/media/libmedia/AudioRecord.cpp
+++ b/media/libmedia/AudioRecord.cpp
@@ -924,7 +924,7 @@
int32_t tryCounter = kMaxTries;
uint32_t pollUs = 10000;
do {
- int policy = sched_getscheduler(0);
+ int policy = sched_getscheduler(0) & ~SCHED_RESET_ON_FORK;
if (policy == SCHED_FIFO || policy == SCHED_RR) {
break;
}
diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp
index 68a47a3..7663fef 100644
--- a/media/libmedia/AudioTrack.cpp
+++ b/media/libmedia/AudioTrack.cpp
@@ -1777,7 +1777,7 @@
int32_t tryCounter = kMaxTries;
uint32_t pollUs = 10000;
do {
- int policy = sched_getscheduler(0);
+ int policy = sched_getscheduler(0) & ~SCHED_RESET_ON_FORK;
if (policy == SCHED_FIFO || policy == SCHED_RR) {
break;
}
diff --git a/media/libmedia/AudioTrackShared.cpp b/media/libmedia/AudioTrackShared.cpp
index 7119517..846f8b8 100644
--- a/media/libmedia/AudioTrackShared.cpp
+++ b/media/libmedia/AudioTrackShared.cpp
@@ -622,6 +622,56 @@
}
__attribute__((no_sanitize("integer")))
+void ServerProxy::flushBufferIfNeeded()
+{
+ audio_track_cblk_t* cblk = mCblk;
+ // The acquire_load is not really required. But since the write is a release_store in the
+ // client, using acquire_load here makes it easier for people to maintain the code,
+ // and the logic for communicating ipc variables seems somewhat standard,
+ // and there really isn't much penalty for 4 or 8 byte atomics.
+ int32_t flush = android_atomic_acquire_load(&cblk->u.mStreaming.mFlush);
+ if (flush != mFlush) {
+ ALOGV("ServerProxy::flushBufferIfNeeded() mStreaming.mFlush = 0x%x, mFlush = 0x%0x",
+ flush, mFlush);
+ int32_t rear = android_atomic_acquire_load(&cblk->u.mStreaming.mRear);
+ int32_t front = cblk->u.mStreaming.mFront;
+
+ // effectively obtain then release whatever is in the buffer
+ const size_t overflowBit = mFrameCountP2 << 1;
+ const size_t mask = overflowBit - 1;
+ int32_t newFront = (front & ~mask) | (flush & mask);
+ ssize_t filled = rear - newFront;
+ if (filled >= (ssize_t)overflowBit) {
+ // front and rear offsets span the overflow bit of the p2 mask
+ // so rebasing newFront on the front offset is off by the overflow bit.
+ // adjust newFront to match rear offset.
+ ALOGV("flush wrap: filled %zx >= overflowBit %zx", filled, overflowBit);
+ newFront += overflowBit;
+ filled -= overflowBit;
+ }
+ // Rather than shutting down on a corrupt flush, just treat it as a full flush
+ if (!(0 <= filled && (size_t) filled <= mFrameCount)) {
+ ALOGE("mFlush %#x -> %#x, front %#x, rear %#x, mask %#x, newFront %#x, "
+ "filled %zd=%#x",
+ mFlush, flush, front, rear,
+ (unsigned)mask, newFront, filled, (unsigned)filled);
+ newFront = rear;
+ }
+ mFlush = flush;
+ android_atomic_release_store(newFront, &cblk->u.mStreaming.mFront);
+ // There is no danger from a false positive, so err on the side of caution
+ if (true /*front != newFront*/) {
+ int32_t old = android_atomic_or(CBLK_FUTEX_WAKE, &cblk->mFutex);
+ if (!(old & CBLK_FUTEX_WAKE)) {
+ (void) syscall(__NR_futex, &cblk->mFutex,
+ mClientInServer ? FUTEX_WAKE_PRIVATE : FUTEX_WAKE, 1);
+ }
+ }
+ mFlushed += (newFront - front) & mask;
+ }
+}
+
+__attribute__((no_sanitize("integer")))
status_t ServerProxy::obtainBuffer(Buffer* buffer, bool ackFlush)
{
LOG_ALWAYS_FATAL_IF(buffer == NULL || buffer->mFrameCount == 0);
@@ -636,44 +686,9 @@
int32_t rear;
// See notes on barriers at ClientProxy::obtainBuffer()
if (mIsOut) {
- int32_t flush = cblk->u.mStreaming.mFlush;
+ flushBufferIfNeeded(); // might modify mFront
rear = android_atomic_acquire_load(&cblk->u.mStreaming.mRear);
front = cblk->u.mStreaming.mFront;
- if (flush != mFlush) {
- // effectively obtain then release whatever is in the buffer
- const size_t overflowBit = mFrameCountP2 << 1;
- const size_t mask = overflowBit - 1;
- int32_t newFront = (front & ~mask) | (flush & mask);
- ssize_t filled = rear - newFront;
- if (filled >= (ssize_t)overflowBit) {
- // front and rear offsets span the overflow bit of the p2 mask
- // so rebasing newFront on the front offset is off by the overflow bit.
- // adjust newFront to match rear offset.
- ALOGV("flush wrap: filled %zx >= overflowBit %zx", filled, overflowBit);
- newFront += overflowBit;
- filled -= overflowBit;
- }
- // Rather than shutting down on a corrupt flush, just treat it as a full flush
- if (!(0 <= filled && (size_t) filled <= mFrameCount)) {
- ALOGE("mFlush %#x -> %#x, front %#x, rear %#x, mask %#x, newFront %#x, "
- "filled %zd=%#x",
- mFlush, flush, front, rear,
- (unsigned)mask, newFront, filled, (unsigned)filled);
- newFront = rear;
- }
- mFlush = flush;
- android_atomic_release_store(newFront, &cblk->u.mStreaming.mFront);
- // There is no danger from a false positive, so err on the side of caution
- if (true /*front != newFront*/) {
- int32_t old = android_atomic_or(CBLK_FUTEX_WAKE, &cblk->mFutex);
- if (!(old & CBLK_FUTEX_WAKE)) {
- (void) syscall(__NR_futex, &cblk->mFutex,
- mClientInServer ? FUTEX_WAKE_PRIVATE : FUTEX_WAKE, 1);
- }
- }
- mFlushed += (newFront - front) & mask;
- front = newFront;
- }
} else {
front = android_atomic_acquire_load(&cblk->u.mStreaming.mFront);
rear = cblk->u.mStreaming.mRear;
diff --git a/media/libmedia/IDrm.cpp b/media/libmedia/IDrm.cpp
index 7f131f4..51a1130 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/libmedia/IMediaExtractorService.cpp b/media/libmedia/IMediaExtractorService.cpp
index dcbbde2..d170c22 100644
--- a/media/libmedia/IMediaExtractorService.cpp
+++ b/media/libmedia/IMediaExtractorService.cpp
@@ -71,6 +71,9 @@
ALOGE("Error reading source from parcel");
return ret;
}
+ // If we make an extractor through Binder, enabled shared memory
+ // for MediaBuffers for this process.
+ MediaBuffer::useSharedMemory();
sp<IDataSource> source = interface_cast<IDataSource>(b);
const char *mime = data.readCString();
sp<IMediaExtractor> ex = makeExtractor(source, mime);
diff --git a/media/libmedia/IMediaSource.cpp b/media/libmedia/IMediaSource.cpp
index dd94ccf..5289c5f 100644
--- a/media/libmedia/IMediaSource.cpp
+++ b/media/libmedia/IMediaSource.cpp
@@ -58,9 +58,9 @@
protected:
virtual ~RemoteMediaBufferWrapper() {
- // Indicate to MediaBufferGroup to release.
- int32_t old = addPendingRelease(1);
- ALOGV("RemoteMediaBufferWrapper: releasing %p, old %d", this, old);
+ // Release our interest in the MediaBuffer's shared memory.
+ int32_t old = addRemoteRefcount(-1);
+ ALOGV("RemoteMediaBufferWrapper: releasing %p, refcount %d", this, old - 1);
mMemory.clear(); // don't set the dead object flag.
}
};
@@ -296,8 +296,8 @@
case STOP: {
ALOGV("stop");
CHECK_INTERFACE(IMediaSource, data, reply);
+ mGroup->signalBufferReturned(nullptr);
status_t status = stop();
- mGroup->gc();
mIndexCache.reset();
mBuffersSinceStop = 0;
return status;
@@ -305,6 +305,7 @@
case PAUSE: {
ALOGV("pause");
CHECK_INTERFACE(IMediaSource, data, reply);
+ mGroup->signalBufferReturned(nullptr);
return pause();
}
case GETFORMAT: {
@@ -336,7 +337,7 @@
&& len == sizeof(opts)
&& data.read((void *)&opts, len) == NO_ERROR;
- mGroup->gc(kBinderMediaBuffers /* freeBuffers */);
+ mGroup->signalBufferReturned(nullptr);
mIndexCache.gc();
size_t inlineTransferSize = 0;
status_t ret = NO_ERROR;
@@ -411,10 +412,11 @@
reply->writeInt32(offset);
reply->writeInt32(length);
buf->meta_data()->writeToParcel(*reply);
- if (transferBuf != buf) {
- buf->release();
- } else if (!supportNonblockingRead()) {
- maxNumBuffers = 0; // stop readMultiple with one shared buffer.
+ if (transferBuf == buf) {
+ buf->addRemoteRefcount(1);
+ if (!supportNonblockingRead()) {
+ maxNumBuffers = 0; // stop readMultiple with one shared buffer.
+ }
}
} else {
ALOGV_IF(buf->mMemory != nullptr,
@@ -423,12 +425,12 @@
reply->writeInt32(INLINE_BUFFER);
reply->writeByteArray(length, (uint8_t*)buf->data() + offset);
buf->meta_data()->writeToParcel(*reply);
- buf->release();
inlineTransferSize += length;
if (inlineTransferSize > kInlineMaxTransfer) {
maxNumBuffers = 0; // stop readMultiple if inline transfer is too large.
}
}
+ buf->release();
}
reply->writeInt32(NULL_BUFFER); // Indicate no more MediaBuffers.
reply->writeInt32(ret);
diff --git a/media/libmedia/ToneGenerator.cpp b/media/libmedia/ToneGenerator.cpp
index 2f53637..9a087ff 100644
--- a/media/libmedia/ToneGenerator.cpp
+++ b/media/libmedia/ToneGenerator.cpp
@@ -1612,8 +1612,8 @@
lS1 = (long)0;
lS2 = (long)mS2_0;
} else {
- lS1 = (long)mS1;
- lS2 = (long)mS2;
+ lS1 = mS1;
+ lS2 = mS2;
}
lA1 = (long)mA1_Q14;
lAmplitude = (long)mAmplitude_Q15;
@@ -1649,8 +1649,8 @@
}
// save status
- mS1 = (short)lS1;
- mS2 = (short)lS2;
+ mS1 = lS1;
+ mS2 = lS2;
}
} // end namespace android
diff --git a/media/libmedia/Visualizer.cpp b/media/libmedia/Visualizer.cpp
index 31e310b..37bf0bd 100644
--- a/media/libmedia/Visualizer.cpp
+++ b/media/libmedia/Visualizer.cpp
@@ -55,7 +55,7 @@
{
ALOGV("Visualizer::~Visualizer()");
setEnabled(false);
- setCaptureCallBack(NULL, NULL, 0, 0, true);
+ setCaptureCallBack(NULL, NULL, 0, 0);
}
status_t Visualizer::setEnabled(bool enabled)
@@ -77,13 +77,11 @@
status_t status = AudioEffect::setEnabled(enabled);
- if (status == NO_ERROR) {
- if (t != 0) {
- if (enabled) {
- t->run("Visualizer");
- } else {
- t->requestExit();
- }
+ if (t != 0) {
+ if (enabled && status == NO_ERROR) {
+ t->run("Visualizer");
+ } else {
+ t->requestExit();
}
}
@@ -95,14 +93,14 @@
}
status_t Visualizer::setCaptureCallBack(capture_cbk_t cbk, void* user, uint32_t flags,
- uint32_t rate, bool force)
+ uint32_t rate)
{
if (rate > CAPTURE_RATE_MAX) {
return BAD_VALUE;
}
Mutex::Autolock _l(mCaptureLock);
- if (force || mEnabled) {
+ if (mEnabled) {
return INVALID_OPERATION;
}
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index 3cfed5e..bd16e91 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 4643f20..7a41d9c 100644
--- a/media/libmediaplayerservice/MediaPlayerService.h
+++ b/media/libmediaplayerservice/MediaPlayerService.h
@@ -227,6 +227,7 @@
virtual status_t dump(int fd, const Vector<String16>& args);
void removeClient(wp<Client> client);
+ bool hasClient(wp<Client> client);
enum {
MEDIASERVER_PROCESS_DEATH = 0,
diff --git a/media/libmediaplayerservice/StagefrightRecorder.cpp b/media/libmediaplayerservice/StagefrightRecorder.cpp
index 24ca582..bd1fd7c 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.cpp
+++ b/media/libmediaplayerservice/StagefrightRecorder.cpp
@@ -1807,19 +1807,38 @@
return OK;
}
- // 30 ms buffer to avoid timestamp overlap
- mTotalPausedDurationUs += (systemTime() / 1000) - mPauseStartTimeUs - 30000;
+ int64_t bufferStartTimeUs = 0;
+ bool allSourcesStarted = true;
+ for (const auto &source : { mAudioEncoderSource, mVideoEncoderSource }) {
+ if (source == nullptr) {
+ continue;
+ }
+ int64_t timeUs = source->getFirstSampleSystemTimeUs();
+ if (timeUs < 0) {
+ allSourcesStarted = false;
+ }
+ if (bufferStartTimeUs < timeUs) {
+ bufferStartTimeUs = timeUs;
+ }
+ }
+
+ if (allSourcesStarted) {
+ if (mPauseStartTimeUs < bufferStartTimeUs) {
+ mPauseStartTimeUs = bufferStartTimeUs;
+ }
+ // 30 ms buffer to avoid timestamp overlap
+ mTotalPausedDurationUs += (systemTime() / 1000) - mPauseStartTimeUs - 30000;
+ }
double timeOffset = -mTotalPausedDurationUs;
if (mCaptureFpsEnable) {
timeOffset *= mCaptureFps / mFrameRate;
}
- if (mAudioEncoderSource != NULL) {
- mAudioEncoderSource->setInputBufferTimeOffset((int64_t)timeOffset);
- mAudioEncoderSource->start();
- }
- if (mVideoEncoderSource != NULL) {
- mVideoEncoderSource->setInputBufferTimeOffset((int64_t)timeOffset);
- mVideoEncoderSource->start();
+ for (const auto &source : { mAudioEncoderSource, mVideoEncoderSource }) {
+ if (source == nullptr) {
+ continue;
+ }
+ source->setInputBufferTimeOffset((int64_t)timeOffset);
+ source->start();
}
mPauseStartTimeUs = 0;
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
index b47a4f1..b742762 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
@@ -141,6 +141,17 @@
mAudioSink->flush();
mAudioSink->close();
}
+
+ // Try to avoid racing condition in case callback is still on.
+ Mutex::Autolock autoLock(mLock);
+ mUseAudioCallback = false;
+ flushQueue(&mAudioQueue);
+ flushQueue(&mVideoQueue);
+ mWakeLock.clear();
+ mMediaClock.clear();
+ mVideoScheduler.clear();
+ mNotify.clear();
+ mAudioSink.clear();
}
void NuPlayer::Renderer::queueBuffer(
@@ -744,7 +755,7 @@
case MediaPlayerBase::AudioSink::CB_EVENT_STREAM_END:
{
ALOGV("AudioSink::CB_EVENT_STREAM_END");
- me->notifyEOS(true /* audio */, ERROR_END_OF_STREAM);
+ me->notifyEOSCallback();
break;
}
@@ -759,6 +770,16 @@
return 0;
}
+void NuPlayer::Renderer::notifyEOSCallback() {
+ Mutex::Autolock autoLock(mLock);
+
+ if (!mUseAudioCallback) {
+ return;
+ }
+
+ notifyEOS(true /* audio */, ERROR_END_OF_STREAM);
+}
+
size_t NuPlayer::Renderer::fillAudioBuffer(void *buffer, size_t size) {
Mutex::Autolock autoLock(mLock);
@@ -1190,8 +1211,10 @@
msg->setWhat(kWhatPostDrainVideoQueue);
msg->post(postDelayUs);
mVideoScheduler->restart();
- ALOGI("possible video time jump of %dms or uninitialized media clock, retrying in %dms",
- (int)(delayUs / 1000), (int)(postDelayUs / 1000));
+ ALOGI("possible video time jump of %dms (%lld : %lld) or uninitialized media clock,"
+ " retrying in %dms",
+ (int)(delayUs / 1000), (long long)mediaTimeUs,
+ (long long)mAudioFirstAnchorTimeMediaUs, (int)(postDelayUs / 1000));
mDrainVideoQueuePending = true;
return;
}
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h
index 004e21c..fe7f8fa 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h
@@ -212,6 +212,7 @@
status_t getCurrentPositionFromAnchor(
int64_t *mediaUs, int64_t nowUs, bool allowPastQueuedVideo = false);
+ void notifyEOSCallback();
size_t fillAudioBuffer(void *buffer, size_t size);
bool onDrainAudioQueue();
diff --git a/media/libmediaplayerservice/nuplayer/RTSPSource.cpp b/media/libmediaplayerservice/nuplayer/RTSPSource.cpp
index 8a305de..c4e5df7 100644
--- a/media/libmediaplayerservice/nuplayer/RTSPSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/RTSPSource.cpp
@@ -58,6 +58,7 @@
mDisconnectReplyID(0),
mBuffering(false),
mInPreparationPhase(true),
+ mEOSPending(false),
mSeekGeneration(0),
mEOSTimeoutAudio(0),
mEOSTimeoutVideo(0) {
@@ -200,34 +201,28 @@
status_t finalResult;
if (!source->hasBufferAvailable(&finalResult)) {
if (finalResult == OK) {
- int64_t mediaDurationUs = 0;
- getDuration(&mediaDurationUs);
- sp<AnotherPacketSource> otherSource = getSource(!audio);
- status_t otherFinalResult;
- // If other source already signaled EOS, this source should also signal EOS
- if (otherSource != NULL &&
- !otherSource->hasBufferAvailable(&otherFinalResult) &&
- otherFinalResult == ERROR_END_OF_STREAM) {
- source->signalEOS(ERROR_END_OF_STREAM);
+ // If other source already signaled EOS, this source should also return EOS
+ if (sourceReachedEOS(!audio)) {
return ERROR_END_OF_STREAM;
}
// If this source has detected near end, give it some time to retrieve more
- // data before signaling EOS
+ // data before returning EOS
+ int64_t mediaDurationUs = 0;
+ getDuration(&mediaDurationUs);
if (source->isFinished(mediaDurationUs)) {
int64_t eosTimeout = audio ? mEOSTimeoutAudio : mEOSTimeoutVideo;
if (eosTimeout == 0) {
setEOSTimeout(audio, ALooper::GetNowUs());
} else if ((ALooper::GetNowUs() - eosTimeout) > kNearEOSTimeoutUs) {
setEOSTimeout(audio, 0);
- source->signalEOS(ERROR_END_OF_STREAM);
return ERROR_END_OF_STREAM;
}
return -EWOULDBLOCK;
}
- if (!(otherSource != NULL && otherSource->isFinished(mediaDurationUs))) {
+ if (!sourceNearEOS(!audio)) {
// We should not enter buffering mode
// if any of the sources already have detected EOS.
startBufferingIfNecessary();
@@ -306,6 +301,7 @@
mState = SEEKING;
mHandler->seek(seekTimeUs);
+ mEOSPending = false;
}
void NuPlayer::RTSPSource::schedulePollBuffering() {
@@ -314,10 +310,10 @@
}
void NuPlayer::RTSPSource::checkBuffering(
- bool *prepared, bool *underflow, bool *overflow, bool *startServer) {
+ bool *prepared, bool *underflow, bool *overflow, bool *startServer, bool *finished) {
size_t numTracks = mTracks.size();
- size_t preparedCount, underflowCount, overflowCount, startCount;
- preparedCount = underflowCount = overflowCount = startCount = 0;
+ size_t preparedCount, underflowCount, overflowCount, startCount, finishedCount;
+ preparedCount = underflowCount = overflowCount = startCount = finishedCount = 0;
size_t count = numTracks;
for (size_t i = 0; i < count; ++i) {
@@ -337,6 +333,7 @@
if (src->isFinished(/* duration */ 0)) {
++overflowCount;
+ ++finishedCount;
} else {
if (bufferedDurationUs < kUnderflowMarkUs) {
++underflowCount;
@@ -354,11 +351,12 @@
*underflow = (underflowCount > 0);
*overflow = (overflowCount == numTracks);
*startServer = (startCount > 0);
+ *finished = (finishedCount > 0);
}
void NuPlayer::RTSPSource::onPollBuffering() {
- bool prepared, underflow, overflow, startServer;
- checkBuffering(&prepared, &underflow, &overflow, &startServer);
+ bool prepared, underflow, overflow, startServer, finished;
+ checkBuffering(&prepared, &underflow, &overflow, &startServer, &finished);
if (prepared && mInPreparationPhase) {
mInPreparationPhase = false;
@@ -369,8 +367,11 @@
startBufferingIfNecessary();
}
- if (overflow && mHandler != NULL) {
+ if (haveSufficientDataOnAllTracks()) {
stopBufferingIfNecessary();
+ }
+
+ if (overflow && mHandler != NULL) {
mHandler->pause();
}
@@ -378,9 +379,72 @@
mHandler->resume();
}
+ if (finished && mHandler != NULL) {
+ mHandler->cancelAccessUnitTimeoutCheck();
+ }
+
schedulePollBuffering();
}
+void NuPlayer::RTSPSource::signalSourceEOS(status_t result) {
+ const bool audio = true;
+ const bool video = false;
+
+ sp<AnotherPacketSource> source = getSource(audio);
+ if (source != NULL) {
+ source->signalEOS(result);
+ }
+
+ source = getSource(video);
+ if (source != NULL) {
+ source->signalEOS(result);
+ }
+}
+
+bool NuPlayer::RTSPSource::sourceReachedEOS(bool audio) {
+ sp<AnotherPacketSource> source = getSource(audio);
+ status_t finalResult;
+ return (source != NULL &&
+ !source->hasBufferAvailable(&finalResult) &&
+ finalResult == ERROR_END_OF_STREAM);
+}
+
+bool NuPlayer::RTSPSource::sourceNearEOS(bool audio) {
+ sp<AnotherPacketSource> source = getSource(audio);
+ int64_t mediaDurationUs = 0;
+ getDuration(&mediaDurationUs);
+ return (source != NULL && source->isFinished(mediaDurationUs));
+}
+
+void NuPlayer::RTSPSource::onSignalEOS(const sp<AMessage> &msg) {
+ int32_t generation;
+ CHECK(msg->findInt32("generation", &generation));
+
+ if (generation != mSeekGeneration) {
+ return;
+ }
+
+ if (mEOSPending) {
+ signalSourceEOS(ERROR_END_OF_STREAM);
+ mEOSPending = false;
+ }
+}
+
+void NuPlayer::RTSPSource::postSourceEOSIfNecessary() {
+ const bool audio = true;
+ const bool video = false;
+ // If a source has detected near end, give it some time to retrieve more
+ // data before signaling EOS
+ if (sourceNearEOS(audio) || sourceNearEOS(video)) {
+ if (!mEOSPending) {
+ sp<AMessage> msg = new AMessage(kWhatSignalEOS, this);
+ msg->setInt32("generation", mSeekGeneration);
+ msg->post(kNearEOSTimeoutUs);
+ mEOSPending = true;
+ }
+ }
+}
+
void NuPlayer::RTSPSource::onMessageReceived(const sp<AMessage> &msg) {
if (msg->what() == kWhatDisconnect) {
sp<AReplyToken> replyID;
@@ -408,6 +472,9 @@
} else if (msg->what() == kWhatPollBuffering) {
onPollBuffering();
return;
+ } else if (msg->what() == kWhatSignalEOS) {
+ onSignalEOS(msg);
+ return;
}
CHECK_EQ(msg->what(), (int)kWhatNotify);
@@ -517,16 +584,10 @@
}
if (err != OK) {
- sp<AnotherPacketSource> source = getSource(false /* audio */);
- if (source != NULL) {
- source->signalEOS(err);
- }
-
- source = getSource(true /* audio */);
- if (source != NULL) {
- source->signalEOS(err);
- }
+ signalSourceEOS(err);
}
+
+ postSourceEOSIfNecessary();
break;
}
@@ -554,6 +615,7 @@
source->queueAccessUnit(accessUnit);
}
+ postSourceEOSIfNecessary();
break;
}
@@ -564,17 +626,7 @@
CHECK_NE(finalResult, (status_t)OK);
if (mTSParser != NULL) {
- sp<AnotherPacketSource> source = getSource(false /* audio */);
- if (source != NULL) {
- source->signalEOS(finalResult);
- }
-
- source = getSource(true /* audio */);
- if (source != NULL) {
- source->signalEOS(finalResult);
- }
-
- return;
+ signalSourceEOS(finalResult);
}
size_t trackIndex;
diff --git a/media/libmediaplayerservice/nuplayer/RTSPSource.h b/media/libmediaplayerservice/nuplayer/RTSPSource.h
index a6a7644..c7834ef 100644
--- a/media/libmediaplayerservice/nuplayer/RTSPSource.h
+++ b/media/libmediaplayerservice/nuplayer/RTSPSource.h
@@ -64,6 +64,7 @@
kWhatDisconnect = 'disc',
kWhatPerformSeek = 'seek',
kWhatPollBuffering = 'poll',
+ kWhatSignalEOS = 'eos ',
};
enum State {
@@ -106,6 +107,7 @@
Mutex mBufferingLock;
bool mBuffering;
bool mInPreparationPhase;
+ bool mEOSPending;
sp<ALooper> mLooper;
sp<MyHandler> mHandler;
@@ -133,7 +135,12 @@
void performSeek(int64_t seekTimeUs);
void schedulePollBuffering();
- void checkBuffering(bool *prepared, bool *underflow, bool *overflow, bool *startServer);
+ void checkBuffering(
+ bool *prepared,
+ bool *underflow,
+ bool *overflow,
+ bool *startServer,
+ bool *finished);
void onPollBuffering();
bool haveSufficientDataOnAllTracks();
@@ -144,6 +151,13 @@
bool stopBufferingIfNecessary();
void finishSeek(status_t err);
+ void postSourceEOSIfNecessary();
+ void signalSourceEOS(status_t result);
+ void onSignalEOS(const sp<AMessage> &msg);
+
+ bool sourceNearEOS(bool audio);
+ bool sourceReachedEOS(bool audio);
+
DISALLOW_EVIL_CONSTRUCTORS(RTSPSource);
};
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index cfdc341..37fd5a5 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -7473,6 +7473,23 @@
}
}
+ int64_t timeOffsetUs;
+ if (params->findInt64("time-offset-us", &timeOffsetUs)) {
+ status_t err = mOMX->setInternalOption(
+ mNode,
+ kPortIndexInput,
+ IOMX::INTERNAL_OPTION_TIME_OFFSET,
+ &timeOffsetUs,
+ sizeof(timeOffsetUs));
+
+ if (err != OK) {
+ ALOGE("[%s] Unable to set input buffer time offset (err %d)",
+ mComponentName.c_str(),
+ err);
+ return err;
+ }
+ }
+
int64_t skipFramesBeforeUs;
if (params->findInt64("skip-frames-before", &skipFramesBeforeUs)) {
status_t err =
diff --git a/media/libstagefright/CameraSource.cpp b/media/libstagefright/CameraSource.cpp
index e087249..893da89 100644
--- a/media/libstagefright/CameraSource.cpp
+++ b/media/libstagefright/CameraSource.cpp
@@ -1117,6 +1117,9 @@
int64_t token = IPCThreadState::self()->clearCallingIdentity();
mCamera->releaseRecordingFrameHandle(handle);
IPCThreadState::self()->restoreCallingIdentity(token);
+ } else {
+ native_handle_close(handle);
+ native_handle_delete(handle);
}
}
diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp
index 21a5faa..7cb568d 100644
--- a/media/libstagefright/MPEG4Extractor.cpp
+++ b/media/libstagefright/MPEG4Extractor.cpp
@@ -1732,8 +1732,9 @@
// Worst case the location string length would be 18,
// for instance +90.0000-180.0000, without the trailing "/" and
- // the string length + language code.
- char buffer[18];
+ // the string length + language code, and some devices include
+ // an additional 8 bytes of altitude, e.g. +007.186
+ char buffer[18 + 8];
// Substracting 5 from the data size is because the text string length +
// language code takes 4 bytes, and the trailing slash "/" takes 1 byte.
@@ -4109,11 +4110,13 @@
if (!mDataSource->getUInt32(offset, &flags)) {
return ERROR_MALFORMED;
}
- ALOGV("fragment run flags: %08x", flags);
-
- if (flags & 0xff000000) {
- return -EINVAL;
- }
+ // |version| only affects SampleCompositionTimeOffset field.
+ // If version == 0, SampleCompositionTimeOffset is uint32_t;
+ // Otherwise, SampleCompositionTimeOffset is int32_t.
+ // Sample.compositionOffset is defined as int32_t.
+ uint8_t version = flags >> 24;
+ flags &= 0xffffff;
+ ALOGV("fragment run version: 0x%02x, flags: 0x%06x", version, flags);
if ((flags & kFirstSampleFlagsPresent) && (flags & kSampleFlagsPresent)) {
// These two shall not be used together.
diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp
index 4681abd..f84f484 100644
--- a/media/libstagefright/MPEG4Writer.cpp
+++ b/media/libstagefright/MPEG4Writer.cpp
@@ -272,6 +272,7 @@
bool mIsHevc;
bool mIsAudio;
bool mIsMPEG4;
+ bool mIsMalformed;
int32_t mTrackId;
int64_t mTrackDurationUs;
int64_t mMaxChunkDurationUs;
@@ -1536,6 +1537,7 @@
mPaused(false),
mResumed(false),
mStarted(false),
+ mIsMalformed(false),
mTrackId(trackId),
mTrackDurationUs(0),
mEstimatedTrackSizeBytes(0),
@@ -2505,13 +2507,15 @@
int64_t durExcludingEarlierPausesUs = timestampUs - previousPausedDurationUs;
if (WARN_UNLESS(durExcludingEarlierPausesUs >= 0ll, "for %s track", trackName)) {
copy->release();
- return ERROR_MALFORMED;
+ mIsMalformed = true;
+ break;
}
int64_t pausedDurationUs = durExcludingEarlierPausesUs - mTrackDurationUs;
if (WARN_UNLESS(pausedDurationUs >= lastDurationUs, "for %s track", trackName)) {
copy->release();
- return ERROR_MALFORMED;
+ mIsMalformed = true;
+ break;
}
previousPausedDurationUs += pausedDurationUs - lastDurationUs;
@@ -2521,7 +2525,8 @@
timestampUs -= previousPausedDurationUs;
if (WARN_UNLESS(timestampUs >= 0ll, "for %s track", trackName)) {
copy->release();
- return ERROR_MALFORMED;
+ mIsMalformed = true;
+ break;
}
if (!mIsAudio) {
@@ -2548,7 +2553,8 @@
timestampUs + kMaxCttsOffsetTimeUs - decodingTimeUs;
if (WARN_UNLESS(cttsOffsetTimeUs >= 0ll, "for %s track", trackName)) {
copy->release();
- return ERROR_MALFORMED;
+ mIsMalformed = true;
+ break;
}
timestampUs = decodingTimeUs;
@@ -2560,7 +2566,8 @@
(cttsOffsetTimeUs * mTimeScale + 500000LL) / 1000000LL;
if (WARN_UNLESS(currCttsOffsetTimeTicks <= 0x0FFFFFFFFLL, "for %s track", trackName)) {
copy->release();
- return ERROR_MALFORMED;
+ mIsMalformed = true;
+ break;
}
if (mStszTableEntries->count() == 0) {
@@ -2602,7 +2609,8 @@
if (WARN_UNLESS(timestampUs >= 0ll, "for %s track", trackName)) {
copy->release();
- return ERROR_MALFORMED;
+ mIsMalformed = true;
+ break;
}
ALOGV("%s media time stamp: %" PRId64 " and previous paused duration %" PRId64,
@@ -2624,7 +2632,8 @@
(long long)timestampUs, (long long)lastTimestampUs, trackName);
copy->release();
mSource->stop();
- return UNKNOWN_ERROR;
+ mIsMalformed = true;
+ break;
}
// if the duration is different for this sample, see if it is close enough to the previous
@@ -2780,6 +2789,10 @@
}
bool MPEG4Writer::Track::isTrackMalFormed() const {
+ if (mIsMalformed) {
+ return true;
+ }
+
if (mStszTableEntries->count() == 0) { // no samples written
ALOGE("The number of recorded samples is 0");
return true;
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index ff5c4d4..e476424 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -2160,14 +2160,19 @@
CHECK(msg->findPointer("buffers", (void **)&dstBuffers));
dstBuffers->clear();
- const Vector<BufferInfo> &srcBuffers = mPortBuffers[portIndex];
+ // If we're using input surface (either non-persistent created by
+ // createInputSurface(), or persistent set by setInputSurface()),
+ // give the client an empty input buffers array.
+ if (portIndex != kPortIndexInput || !mHaveInputSurface) {
+ const Vector<BufferInfo> &srcBuffers = mPortBuffers[portIndex];
- for (size_t i = 0; i < srcBuffers.size(); ++i) {
- const BufferInfo &info = srcBuffers.itemAt(i);
+ for (size_t i = 0; i < srcBuffers.size(); ++i) {
+ const BufferInfo &info = srcBuffers.itemAt(i);
- dstBuffers->push_back(
- (portIndex == kPortIndexInput && mCrypto != NULL)
- ? info.mEncryptedData : info.mData);
+ dstBuffers->push_back(
+ (portIndex == kPortIndexInput && mCrypto != NULL)
+ ? info.mEncryptedData : info.mData);
+ }
}
(new AMessage)->postReply(replyID);
diff --git a/media/libstagefright/MediaCodecSource.cpp b/media/libstagefright/MediaCodecSource.cpp
index 5039922..33d624e 100644
--- a/media/libstagefright/MediaCodecSource.cpp
+++ b/media/libstagefright/MediaCodecSource.cpp
@@ -336,10 +336,21 @@
return NULL;
}
-void MediaCodecSource::setInputBufferTimeOffset(int64_t timeOffsetUs) {
+status_t MediaCodecSource::setInputBufferTimeOffset(int64_t timeOffsetUs) {
sp<AMessage> msg = new AMessage(kWhatSetInputBufferTimeOffset, mReflector);
msg->setInt64("time-offset-us", timeOffsetUs);
- postSynchronouslyAndReturnError(msg);
+ return postSynchronouslyAndReturnError(msg);
+}
+
+int64_t MediaCodecSource::getFirstSampleSystemTimeUs() {
+ sp<AMessage> msg = new AMessage(kWhatGetFirstSampleSystemTimeUs, mReflector);
+ sp<AMessage> response;
+ msg->postAndAwaitResponse(&response);
+ int64_t timeUs;
+ if (!response->findInt64("time-us", &timeUs)) {
+ timeUs = -1ll;
+ }
+ return timeUs;
}
status_t MediaCodecSource::start(MetaData* params) {
@@ -408,6 +419,8 @@
mEncoderDataSpace(0),
mGraphicBufferConsumer(consumer),
mInputBufferTimeOffsetUs(0),
+ mFirstSampleSystemTimeUs(-1ll),
+ mPausePending(false),
mFirstSampleTimeUs(-1ll),
mGeneration(0) {
CHECK(mLooper != NULL);
@@ -646,17 +659,19 @@
if (mbuf != NULL) {
CHECK(mbuf->meta_data()->findInt64(kKeyTime, &timeUs));
- timeUs += mInputBufferTimeOffsetUs;
-
- // Due to the extra delay adjustment at the beginning of start/resume,
- // the adjusted timeUs may be negative if MediaCodecSource goes into pause
- // state before feeding any buffers to the encoder. Drop the buffer in this
- // case.
- if (timeUs < 0) {
- mbuf->release();
- return OK;
+ if (mFirstSampleSystemTimeUs < 0ll) {
+ mFirstSampleSystemTimeUs = systemTime() / 1000;
+ if (mPausePending) {
+ mPausePending = false;
+ onPause();
+ mbuf->release();
+ mAvailEncoderInputIndices.push_back(bufferIndex);
+ return OK;
+ }
}
+ timeUs += mInputBufferTimeOffsetUs;
+
// push decoding time for video, or drift time for audio
if (mIsVideo) {
mDecodingTimeQueue.push_back(timeUs);
@@ -665,7 +680,6 @@
if (mFirstSampleTimeUs < 0ll) {
mFirstSampleTimeUs = timeUs;
}
-
int64_t driftTimeUs = 0;
if (mbuf->meta_data()->findInt64(kKeyDriftTime, &driftTimeUs)
&& driftTimeUs) {
@@ -717,6 +731,10 @@
if (mStarted) {
ALOGI("MediaCodecSource (%s) resuming", mIsVideo ? "video" : "audio");
+ if (mPausePending) {
+ mPausePending = false;
+ return OK;
+ }
if (mIsVideo) {
mEncoder->requestIDRFrame();
}
@@ -763,6 +781,15 @@
return OK;
}
+void MediaCodecSource::onPause() {
+ if (mFlags & FLAG_USE_SURFACE_INPUT) {
+ suspend();
+ } else {
+ CHECK(mPuller != NULL);
+ mPuller->pause();
+ }
+}
+
void MediaCodecSource::onMessageReceived(const sp<AMessage> &msg) {
switch (msg->what()) {
case kWhatPullerNotify:
@@ -832,25 +859,25 @@
}
MediaBuffer *mbuf = new MediaBuffer(outbuf->size());
- memcpy(mbuf->data(), outbuf->data(), outbuf->size());
+ mbuf->add_ref();
if (!(flags & MediaCodec::BUFFER_FLAG_CODECCONFIG)) {
if (mIsVideo) {
int64_t decodingTimeUs;
if (mFlags & FLAG_USE_SURFACE_INPUT) {
- // Time offset is not applied at
- // feedEncoderInputBuffer() in surface input case.
- timeUs += mInputBufferTimeOffsetUs;
-
- // Due to the extra delay adjustment at the beginning of
- // start/resume, the adjusted timeUs may be negative if
- // MediaCodecSource goes into pause state before feeding
- // any buffers to the encoder. Drop the buffer in this case.
- if (timeUs < 0) {
- mEncoder->releaseOutputBuffer(index);
- break;
+ if (mFirstSampleSystemTimeUs < 0ll) {
+ mFirstSampleSystemTimeUs = systemTime() / 1000;
+ if (mPausePending) {
+ mPausePending = false;
+ onPause();
+ mbuf->release();
+ break;
+ }
}
-
+ // Timestamp offset is already adjusted in GraphicBufferSource.
+ // GraphicBufferSource is supposed to discard samples
+ // queued before start, and offset timeUs by start time
+ CHECK_GE(timeUs, 0ll);
// TODO:
// Decoding time for surface source is unavailable,
// use presentation time for now. May need to move
@@ -883,8 +910,8 @@
if (flags & MediaCodec::BUFFER_FLAG_SYNCFRAME) {
mbuf->meta_data()->setInt32(kKeyIsSyncFrame, true);
}
+ memcpy(mbuf->data(), outbuf->data(), outbuf->size());
mbuf->setObserver(this);
- mbuf->add_ref();
{
Mutexed<Output>::Locked output(mOutput);
@@ -975,11 +1002,10 @@
case kWhatPause:
{
- if (mFlags & FLAG_USE_SURFACE_INPUT) {
- suspend();
+ if (mFirstSampleSystemTimeUs < 0) {
+ mPausePending = true;
} else {
- CHECK(mPuller != NULL);
- mPuller->pause();
+ onPause();
}
break;
}
@@ -987,10 +1013,28 @@
{
sp<AReplyToken> replyID;
CHECK(msg->senderAwaitsResponse(&replyID));
-
+ status_t err = OK;
CHECK(msg->findInt64("time-offset-us", &mInputBufferTimeOffsetUs));
+ // Propagate the timestamp offset to GraphicBufferSource.
+ if (mIsVideo) {
+ sp<AMessage> params = new AMessage;
+ params->setInt64("time-offset-us", mInputBufferTimeOffsetUs);
+ err = mEncoder->setParameters(params);
+ }
+
sp<AMessage> response = new AMessage;
+ response->setInt32("err", err);
+ response->postReply(replyID);
+ break;
+ }
+ case kWhatGetFirstSampleSystemTimeUs:
+ {
+ sp<AReplyToken> replyID;
+ CHECK(msg->senderAwaitsResponse(&replyID));
+
+ sp<AMessage> response = new AMessage;
+ response->setInt64("time-us", mFirstSampleSystemTimeUs);
response->postReply(replyID);
break;
}
diff --git a/media/libstagefright/NuMediaExtractor.cpp b/media/libstagefright/NuMediaExtractor.cpp
index a669dca..276d731 100644
--- a/media/libstagefright/NuMediaExtractor.cpp
+++ b/media/libstagefright/NuMediaExtractor.cpp
@@ -305,7 +305,10 @@
sp<IMediaSource> source = mImpl->getTrack(index);
- CHECK_EQ((status_t)OK, source->start());
+ status_t ret = source->start();
+ if (ret != OK) {
+ return ret;
+ }
mSelectedTracks.push();
TrackInfo *info = &mSelectedTracks.editItemAt(mSelectedTracks.size() - 1);
diff --git a/media/libstagefright/StagefrightMetadataRetriever.cpp b/media/libstagefright/StagefrightMetadataRetriever.cpp
index d2ba02e..be5067d 100644
--- a/media/libstagefright/StagefrightMetadataRetriever.cpp
+++ b/media/libstagefright/StagefrightMetadataRetriever.cpp
@@ -158,11 +158,14 @@
// TODO: Use Flexible color instead
videoFormat->setInt32("color-format", OMX_COLOR_FormatYUV420Planar);
- // For the thumbnail extraction case, try to allocate single buffer
- // in both input and output ports. NOTE: This request may fail if
- // component requires more than that for decoding.
- videoFormat->setInt32("android._num-input-buffers", 1);
- videoFormat->setInt32("android._num-output-buffers", 1);
+ // For the thumbnail extraction case, try to allocate single buffer in both
+ // input and output ports, if seeking to a sync frame. NOTE: This request may
+ // fail if component requires more than that for decoding.
+ bool isSeekingClosest = (seekMode == MediaSource::ReadOptions::SEEK_CLOSEST);
+ if (!isSeekingClosest) {
+ videoFormat->setInt32("android._num-input-buffers", 1);
+ videoFormat->setInt32("android._num-output-buffers", 1);
+ }
status_t err;
sp<ALooper> looper = new ALooper;
@@ -254,6 +257,9 @@
bool isAvcOrHevc = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC)
|| !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_HEVC);
+ bool firstSample = true;
+ int64_t targetTimeUs = -1ll;
+
do {
size_t inputIndex = -1;
int64_t ptsUs = 0ll;
@@ -280,6 +286,11 @@
haveMoreInputs = false;
break;
}
+ if (firstSample && isSeekingClosest) {
+ mediaBuffer->meta_data()->findInt64(kKeyTargetTime, &targetTimeUs);
+ ALOGV("Seeking closest: targetTimeUs=%lld", (long long)targetTimeUs);
+ }
+ firstSample = false;
if (mediaBuffer->range_length() > codecBuffer->capacity()) {
ALOGE("buffer size (%zu) too large for codec input size (%zu)",
@@ -292,8 +303,9 @@
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.
+ if (isAvcOrHevc && IsIDR(codecBuffer) && !isSeekingClosest) {
+ // Only need to decode one IDR frame, unless we're seeking with CLOSEST
+ // option, in which case we need to actually decode to targetTimeUs.
haveMoreInputs = false;
flags |= MediaCodec::BUFFER_FLAG_EOS;
}
@@ -340,8 +352,13 @@
ALOGV("Timed-out waiting for output.. retries left = %zu", retriesLeft);
err = OK;
} else if (err == OK) {
- ALOGV("Received an output buffer");
- done = true;
+ // If we're seeking with CLOSEST option and obtained a valid targetTimeUs
+ // from the extractor, decode to the specified frame. Otherwise we're done.
+ done = (targetTimeUs < 0ll) || (timeUs >= targetTimeUs);
+ ALOGV("Received an output buffer, timeUs=%lld", (long long)timeUs);
+ if (!done) {
+ err = decoder->releaseOutputBuffer(index);
+ }
} else {
ALOGW("Received error %d (%s) instead of output", err, asString(err));
done = true;
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 8802fad..f496b0c 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/foundation/ColorUtils.cpp b/media/libstagefright/foundation/ColorUtils.cpp
index e329766..d7439b2 100644
--- a/media/libstagefright/foundation/ColorUtils.cpp
+++ b/media/libstagefright/foundation/ColorUtils.cpp
@@ -286,6 +286,7 @@
{ 15, ColorAspects::TransferSMPTE170M },
{ 16, ColorAspects::TransferST2084 },
{ 17, ColorAspects::TransferST428 },
+ { 18, ColorAspects::TransferHLG },
}
};
diff --git a/media/libstagefright/foundation/MediaBuffer.cpp b/media/libstagefright/foundation/MediaBuffer.cpp
index 15d557d..16000ef 100644
--- a/media/libstagefright/foundation/MediaBuffer.cpp
+++ b/media/libstagefright/foundation/MediaBuffer.cpp
@@ -30,6 +30,9 @@
namespace android {
+/* static */
+std::atomic_int_least32_t MediaBuffer::mUseSharedMemory(0);
+
MediaBuffer::MediaBuffer(void *data, size_t size)
: mObserver(NULL),
mRefCount(0),
@@ -52,7 +55,8 @@
mOwnsData(true),
mMetaData(new MetaData),
mOriginal(NULL) {
- if (size < kSharedMemThreshold) {
+ if (size < kSharedMemThreshold
+ || std::atomic_load_explicit(&mUseSharedMemory, std::memory_order_seq_cst) == 0) {
mData = malloc(size);
} else {
ALOGV("creating memoryDealer");
@@ -101,14 +105,7 @@
void MediaBuffer::release() {
if (mObserver == NULL) {
- if (mMemory.get() != nullptr) {
- // See if there is a pending release and there are no observers.
- // Ideally this never happens.
- while (addPendingRelease(-1) > 0) {
- __sync_fetch_and_sub(&mRefCount, 1);
- }
- addPendingRelease(1);
- }
+ // Legacy contract for MediaBuffer without a MediaBufferGroup.
CHECK_EQ(mRefCount, 0);
delete this;
return;
@@ -201,10 +198,6 @@
mObserver = observer;
}
-int MediaBuffer::refcount() const {
- return mRefCount;
-}
-
MediaBuffer *MediaBuffer::clone() {
CHECK(mGraphicBuffer == NULL);
diff --git a/media/libstagefright/foundation/MediaBufferGroup.cpp b/media/libstagefright/foundation/MediaBufferGroup.cpp
index cb78879..54f768a 100644
--- a/media/libstagefright/foundation/MediaBufferGroup.cpp
+++ b/media/libstagefright/foundation/MediaBufferGroup.cpp
@@ -51,7 +51,7 @@
for (size_t i = 0; i < buffers; ++i) {
sp<IMemory> mem = memoryDealer->allocate(augmented_size);
- if (mem.get() == nullptr) {
+ if (mem.get() == nullptr || mem->pointer() == nullptr) {
ALOGW("Only allocated %zu shared buffers of size %zu", i, buffer_size);
break;
}
@@ -76,11 +76,24 @@
MediaBufferGroup::~MediaBufferGroup() {
for (MediaBuffer *buffer : mBuffers) {
- buffer->resolvePendingRelease();
- // If we don't release it, perhaps noone will release it.
- LOG_ALWAYS_FATAL_IF(buffer->refcount() != 0,
- "buffer refcount %p = %d != 0", buffer, buffer->refcount());
- // actually delete it.
+ if (buffer->refcount() != 0) {
+ const int localRefcount = buffer->localRefcount();
+ const int remoteRefcount = buffer->remoteRefcount();
+
+ // Fatal if we have a local refcount.
+ LOG_ALWAYS_FATAL_IF(localRefcount != 0,
+ "buffer(%p) localRefcount %d != 0, remoteRefcount %d",
+ buffer, localRefcount, remoteRefcount);
+
+ // Log an error if we have a remaining remote refcount,
+ // as the remote process may have died or may have inappropriate behavior.
+ // The shared memory associated with the MediaBuffer will
+ // automatically be reclaimed when there are no remaining fds
+ // associated with it.
+ ALOGE("buffer(%p) has residual remoteRefcount %d",
+ buffer, remoteRefcount);
+ }
+ // gracefully delete.
buffer->setObserver(nullptr);
buffer->release();
}
@@ -94,32 +107,11 @@
// optionally: mGrowthLimit = max(mGrowthLimit, mBuffers.size());
}
-void MediaBufferGroup::gc(size_t freeBuffers) {
- Mutex::Autolock autoLock(mLock);
-
- size_t freeCount = 0;
- for (auto it = mBuffers.begin(); it != mBuffers.end(); ) {
- (*it)->resolvePendingRelease();
- if ((*it)->isDeadObject()) {
- // The MediaBuffer has been deleted, why is it in the MediaBufferGroup?
- LOG_ALWAYS_FATAL("buffer(%p) has dead object with refcount %d",
- (*it), (*it)->refcount());
- } else if ((*it)->refcount() == 0 && ++freeCount > freeBuffers) {
- (*it)->setObserver(nullptr);
- (*it)->release();
- it = mBuffers.erase(it);
- } else {
- ++it;
- }
- }
-}
-
bool MediaBufferGroup::has_buffers() {
if (mBuffers.size() < mGrowthLimit) {
return true; // We can add more buffers internally.
}
for (MediaBuffer *buffer : mBuffers) {
- buffer->resolvePendingRelease();
if (buffer->refcount() == 0) {
return true;
}
@@ -135,7 +127,6 @@
MediaBuffer *buffer = nullptr;
auto free = mBuffers.end();
for (auto it = mBuffers.begin(); it != mBuffers.end(); ++it) {
- (*it)->resolvePendingRelease();
if ((*it)->refcount() == 0) {
const size_t size = (*it)->size();
if (size >= requestedSize) {
diff --git a/media/libstagefright/foundation/MetaData.cpp b/media/libstagefright/foundation/MetaData.cpp
index b4abc60..a8965f0 100644
--- a/media/libstagefright/foundation/MetaData.cpp
+++ b/media/libstagefright/foundation/MetaData.cpp
@@ -392,8 +392,12 @@
}
status_t MetaData::writeToParcel(Parcel &parcel) {
+ status_t ret;
size_t numItems = mItems.size();
- parcel.writeUint32(uint32_t(numItems));
+ ret = parcel.writeUint32(uint32_t(numItems));
+ if (ret) {
+ return ret;
+ }
for (size_t i = 0; i < numItems; i++) {
int32_t key = mItems.keyAt(i);
const typed_data &item = mItems.valueAt(i);
@@ -401,9 +405,32 @@
const void *data;
size_t size;
item.getData(&type, &data, &size);
- parcel.writeInt32(key);
- parcel.writeUint32(type);
- parcel.writeByteArray(size, (uint8_t*)data);
+ ret = parcel.writeInt32(key);
+ if (ret) {
+ return ret;
+ }
+ ret = parcel.writeUint32(type);
+ if (ret) {
+ return ret;
+ }
+ if (type == TYPE_NONE) {
+ android::Parcel::WritableBlob blob;
+ ret = parcel.writeUint32(static_cast<uint32_t>(size));
+ if (ret) {
+ return ret;
+ }
+ ret = parcel.writeBlob(size, false, &blob);
+ if (ret) {
+ return ret;
+ }
+ memcpy(blob.data(), data, size);
+ blob.release();
+ } else {
+ ret = parcel.writeByteArray(size, (uint8_t*)data);
+ if (ret) {
+ return ret;
+ }
+ }
}
return OK;
}
@@ -422,8 +449,20 @@
if (ret != OK) {
break;
}
- // copy data directly from Parcel storage, then advance position
- setData(key, type, parcel.readInplace(size), size);
+ // copy data from Blob, which may be inline in Parcel storage,
+ // then advance position
+ if (type == TYPE_NONE) {
+ android::Parcel::ReadableBlob blob;
+ ret = parcel.readBlob(size, &blob);
+ if (ret != OK) {
+ break;
+ }
+ setData(key, type, blob.data(), size);
+ blob.release();
+ } else {
+ // copy data directly from Parcel storage, then advance position
+ setData(key, type, parcel.readInplace(size), size);
+ }
}
return OK;
diff --git a/media/libstagefright/http/MediaHTTP.cpp b/media/libstagefright/http/MediaHTTP.cpp
index 76ec625..5b18814 100644
--- a/media/libstagefright/http/MediaHTTP.cpp
+++ b/media/libstagefright/http/MediaHTTP.cpp
@@ -58,15 +58,19 @@
extHeaders.add(String8("User-Agent"), String8(MakeUserAgent().c_str()));
}
- bool success = mHTTPConnection->connect(uri, &extHeaders);
+ mLastURI = uri;
+ // reconnect() calls with uri == old mLastURI.c_str(), which gets zapped
+ // as part of the above assignment. Ensure no accidental later use.
+ uri = NULL;
+
+ bool success = mHTTPConnection->connect(mLastURI.c_str(), &extHeaders);
mLastHeaders = extHeaders;
- mLastURI = uri;
mCachedSizeValid = false;
if (success) {
- AString sanitized = uriDebugString(uri);
+ AString sanitized = uriDebugString(mLastURI);
mName = String8::format("MediaHTTP(%s)", sanitized.c_str());
}
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/OMXNodeInstance.h b/media/libstagefright/include/OMXNodeInstance.h
index 56ab3f6..94cf15a 100644
--- a/media/libstagefright/include/OMXNodeInstance.h
+++ b/media/libstagefright/include/OMXNodeInstance.h
@@ -21,6 +21,7 @@
#include "OMX.h"
#include <utils/RefBase.h>
+#include <utils/SortedVector.h>
#include <utils/threads.h>
namespace android {
@@ -151,6 +152,9 @@
OMX_HANDLETYPE mHandle;
sp<IOMXObserver> mObserver;
bool mDying;
+ bool mSailed; // configuration is set (no more meta-mode changes)
+ bool mQueriedProhibitedExtensions;
+ SortedVector<OMX_INDEXTYPE> mProhibitedExtensions;
bool mIsSecure;
// Lock only covers mGraphicBufferSource. We can't always use mLock
@@ -204,6 +208,8 @@
OMX::buffer_id findBufferID(OMX_BUFFERHEADERTYPE *bufferHeader);
void invalidateBufferID(OMX::buffer_id buffer);
+ bool isProhibitedIndex_l(OMX_INDEXTYPE index);
+
status_t useGraphicBuffer2_l(
OMX_U32 portIndex, const sp<GraphicBuffer> &graphicBuffer,
OMX::buffer_id *buffer);
diff --git a/media/libstagefright/omx/GraphicBufferSource.cpp b/media/libstagefright/omx/GraphicBufferSource.cpp
index 0c8fd67..93d6584 100644
--- a/media/libstagefright/omx/GraphicBufferSource.cpp
+++ b/media/libstagefright/omx/GraphicBufferSource.cpp
@@ -139,13 +139,13 @@
mRepeatLastFrameTimestamp(-1ll),
mLatestBufferId(-1),
mLatestBufferFrameNum(0),
- mLatestBufferUseCount(0),
mLatestBufferFence(Fence::NO_FENCE),
mRepeatBufferDeferred(false),
mTimePerCaptureUs(-1ll),
mTimePerFrameUs(-1ll),
mPrevCaptureUs(-1ll),
- mPrevFrameUs(-1ll) {
+ mPrevFrameUs(-1ll),
+ mInputBufferTimeOffsetUs(0ll) {
ALOGV("GraphicBufferSource w=%u h=%u c=%u",
bufferWidth, bufferHeight, bufferCount);
@@ -397,12 +397,16 @@
sp<Fence> fence = new Fence(fenceFd);
if (mBufferSlot[id] != NULL &&
mBufferSlot[id]->handle == codecBuffer.mGraphicBuffer->handle) {
- ALOGV("cbi %d matches bq slot %d, handle=%p",
- cbi, id, mBufferSlot[id]->handle);
+ mBufferUseCount[id]--;
- if (id == mLatestBufferId) {
- CHECK_GT(mLatestBufferUseCount--, 0);
- } else {
+ ALOGV("codecBufferEmptied: slot=%d, cbi=%d, useCount=%d, handle=%p",
+ id, cbi, mBufferUseCount[id], mBufferSlot[id]->handle);
+
+ if (mBufferUseCount[id] < 0) {
+ ALOGW("mBufferUseCount for bq slot %d < 0 (=%d)", id, mBufferUseCount[id]);
+ mBufferUseCount[id] = 0;
+ }
+ if (id != mLatestBufferId && mBufferUseCount[id] == 0) {
releaseBuffer(id, codecBuffer.mFrameNumber, mBufferSlot[id], fence);
}
} else {
@@ -613,6 +617,7 @@
if (item.mGraphicBuffer != NULL) {
ALOGV("fillCodecBuffer_l: setting mBufferSlot %d", item.mSlot);
mBufferSlot[item.mSlot] = item.mGraphicBuffer;
+ mBufferUseCount[item.mSlot] = 0;
}
if (item.mDataSpace != mLastDataSpace) {
@@ -698,7 +703,7 @@
return false;
}
- ++mLatestBufferUseCount;
+ ++mBufferUseCount[item.mSlot];
/* repeat last frame up to kRepeatLastFrameCount times.
* in case of static scene, a single repeat might not get rid of encoder
@@ -719,10 +724,8 @@
void GraphicBufferSource::setLatestBuffer_l(
const BufferItem &item, bool dropped) {
- ALOGV("setLatestBuffer_l");
-
if (mLatestBufferId >= 0) {
- if (mLatestBufferUseCount == 0) {
+ if (mBufferUseCount[mLatestBufferId] == 0) {
releaseBuffer(mLatestBufferId, mLatestBufferFrameNum,
mBufferSlot[mLatestBufferId], mLatestBufferFence);
// mLatestBufferFence will be set to new fence just below
@@ -733,7 +736,13 @@
mLatestBufferFrameNum = item.mFrameNumber;
mRepeatLastFrameTimestamp = item.mTimestamp + mRepeatAfterUs * 1000;
- mLatestBufferUseCount = dropped ? 0 : 1;
+ if (!dropped) {
+ ++mBufferUseCount[item.mSlot];
+ }
+
+ ALOGV("setLatestBuffer_l: slot=%d, useCount=%d",
+ item.mSlot, mBufferUseCount[item.mSlot]);
+
mRepeatBufferDeferred = false;
mRepeatLastFrameCount = kRepeatLastFrameCount;
mLatestBufferFence = item.mFence;
@@ -774,6 +783,7 @@
int64_t GraphicBufferSource::getTimestamp(const BufferItem &item) {
int64_t timeUs = item.mTimestamp / 1000;
+ timeUs += mInputBufferTimeOffsetUs;
if (mTimePerCaptureUs > 0ll
&& (mTimePerCaptureUs > 2 * mTimePerFrameUs
@@ -802,42 +812,45 @@
static_cast<long long>(mPrevFrameUs));
return mPrevFrameUs;
- } else if (mMaxTimestampGapUs > 0ll) {
- //TODO: Fix the case when mMaxTimestampGapUs and mTimePerCaptureUs are both set.
-
- /* Cap timestamp gap between adjacent frames to specified max
- *
- * In the scenario of cast mirroring, encoding could be suspended for
- * prolonged periods. Limiting the pts gap to workaround the problem
- * where encoder's rate control logic produces huge frames after a
- * long period of suspension.
- */
-
+ } else {
int64_t originalTimeUs = timeUs;
- if (mPrevOriginalTimeUs >= 0ll) {
- if (originalTimeUs < mPrevOriginalTimeUs) {
+ if (originalTimeUs <= mPrevOriginalTimeUs) {
// Drop the frame if it's going backward in time. Bad timestamp
// could disrupt encoder's rate control completely.
- ALOGW("Dropping frame that's going backward in time");
- return -1;
- }
- int64_t timestampGapUs = originalTimeUs - mPrevOriginalTimeUs;
- timeUs = (timestampGapUs < mMaxTimestampGapUs ?
- timestampGapUs : mMaxTimestampGapUs) + mPrevModifiedTimeUs;
+ ALOGW("Dropping frame that's going backward in time");
+ return -1;
}
+
+ if (mMaxTimestampGapUs > 0ll) {
+ //TODO: Fix the case when mMaxTimestampGapUs and mTimePerCaptureUs are both set.
+
+ /* Cap timestamp gap between adjacent frames to specified max
+ *
+ * In the scenario of cast mirroring, encoding could be suspended for
+ * prolonged periods. Limiting the pts gap to workaround the problem
+ * where encoder's rate control logic produces huge frames after a
+ * long period of suspension.
+ */
+ if (mPrevOriginalTimeUs >= 0ll) {
+ int64_t timestampGapUs = originalTimeUs - mPrevOriginalTimeUs;
+ timeUs = (timestampGapUs < mMaxTimestampGapUs ?
+ timestampGapUs : mMaxTimestampGapUs) + mPrevModifiedTimeUs;
+ }
+ mOriginalTimeUs.add(timeUs, originalTimeUs);
+ ALOGV("IN timestamp: %lld -> %lld",
+ static_cast<long long>(originalTimeUs),
+ static_cast<long long>(timeUs));
+ }
+
mPrevOriginalTimeUs = originalTimeUs;
mPrevModifiedTimeUs = timeUs;
- mOriginalTimeUs.add(timeUs, originalTimeUs);
- ALOGV("IN timestamp: %lld -> %lld",
- static_cast<long long>(originalTimeUs),
- static_cast<long long>(timeUs));
}
return timeUs;
}
status_t GraphicBufferSource::submitBuffer_l(const BufferItem &item, int cbi) {
- ALOGV("submitBuffer_l cbi=%d", cbi);
+ ALOGV("submitBuffer_l: slot=%d, cbi=%d", item.mSlot, cbi);
int64_t timeUs = getTimestamp(item);
if (timeUs < 0ll) {
@@ -930,6 +943,7 @@
void GraphicBufferSource::releaseBuffer(
int &id, uint64_t frameNum,
const sp<GraphicBuffer> buffer, const sp<Fence> &fence) {
+ ALOGV("releaseBuffer: slot=%d", id);
if (mIsPersistent) {
mConsumer->detachBuffer(id);
mBufferSlot[id] = NULL;
@@ -973,6 +987,7 @@
if (item.mGraphicBuffer != NULL) {
ALOGV("onFrameAvailable: setting mBufferSlot %d", item.mSlot);
mBufferSlot[item.mSlot] = item.mGraphicBuffer;
+ mBufferUseCount[item.mSlot] = 0;
}
releaseBuffer(item.mSlot, item.mFrameNumber,
@@ -1006,6 +1021,7 @@
for (int i = 0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) {
if ((slotMask & 0x01) != 0) {
mBufferSlot[i] = NULL;
+ mBufferUseCount[i] = 0;
}
slotMask >>= 1;
}
@@ -1048,6 +1064,18 @@
return OK;
}
+status_t GraphicBufferSource::setInputBufferTimeOffset(int64_t timeOffsetUs) {
+ Mutex::Autolock autoLock(mMutex);
+
+ // timeOffsetUs must be negative for adjustment.
+ if (timeOffsetUs >= 0ll) {
+ return INVALID_OPERATION;
+ }
+
+ mInputBufferTimeOffsetUs = timeOffsetUs;
+ return OK;
+}
+
status_t GraphicBufferSource::setMaxFps(float maxFps) {
Mutex::Autolock autoLock(mMutex);
diff --git a/media/libstagefright/omx/GraphicBufferSource.h b/media/libstagefright/omx/GraphicBufferSource.h
index c8b0e62..aa4ceb3 100644
--- a/media/libstagefright/omx/GraphicBufferSource.h
+++ b/media/libstagefright/omx/GraphicBufferSource.h
@@ -131,6 +131,10 @@
// of suspension on input.
status_t setMaxTimestampGapUs(int64_t maxGapUs);
+ // Sets the input buffer timestamp offset.
+ // When set, the sample's timestamp will be adjusted with the timeOffsetUs.
+ status_t setInputBufferTimeOffset(int64_t timeOffsetUs);
+
// When set, the max frame rate fed to the encoder will be capped at maxFps.
status_t setMaxFps(float maxFps);
@@ -291,6 +295,7 @@
// is done processing a GraphicBuffer, we can use this to map back
// to a slot number.
sp<GraphicBuffer> mBufferSlot[BufferQueue::NUM_BUFFER_SLOTS];
+ int32_t mBufferUseCount[BufferQueue::NUM_BUFFER_SLOTS];
// Tracks codec buffers.
Vector<CodecBuffer> mCodecBuffers;
@@ -323,7 +328,6 @@
int mLatestBufferId;
uint64_t mLatestBufferFrameNum;
- int32_t mLatestBufferUseCount;
sp<Fence> mLatestBufferFence;
// The previous buffer should've been repeated but
@@ -336,6 +340,8 @@
int64_t mPrevCaptureUs;
int64_t mPrevFrameUs;
+ int64_t mInputBufferTimeOffsetUs;
+
MetadataBufferType mMetadataBufferType;
ColorAspects mColorAspects;
diff --git a/media/libstagefright/omx/OMXNodeInstance.cpp b/media/libstagefright/omx/OMXNodeInstance.cpp
index 4f1a952..e9ed570 100644
--- a/media/libstagefright/omx/OMXNodeInstance.cpp
+++ b/media/libstagefright/omx/OMXNodeInstance.cpp
@@ -93,26 +93,34 @@
namespace android {
struct BufferMeta {
- BufferMeta(const sp<IMemory> &mem, OMX_U32 portIndex, bool is_backup = false)
+ BufferMeta(
+ const sp<IMemory> &mem, OMX_U32 portIndex, bool copyToOmx,
+ bool copyFromOmx, OMX_U8 *backup)
: mMem(mem),
- mIsBackup(is_backup),
- mPortIndex(portIndex) {
+ mCopyFromOmx(copyFromOmx),
+ mCopyToOmx(copyToOmx),
+ mPortIndex(portIndex),
+ mBackup(backup) {
}
BufferMeta(size_t size, OMX_U32 portIndex)
: mSize(size),
- mIsBackup(false),
- mPortIndex(portIndex) {
+ mCopyFromOmx(false),
+ mCopyToOmx(false),
+ mPortIndex(portIndex),
+ mBackup(NULL) {
}
BufferMeta(const sp<GraphicBuffer> &graphicBuffer, OMX_U32 portIndex)
: mGraphicBuffer(graphicBuffer),
- mIsBackup(false),
- mPortIndex(portIndex) {
+ mCopyFromOmx(false),
+ mCopyToOmx(false),
+ mPortIndex(portIndex),
+ mBackup(NULL) {
}
void CopyFromOMX(const OMX_BUFFERHEADERTYPE *header) {
- if (!mIsBackup) {
+ if (!mCopyFromOmx) {
return;
}
@@ -123,7 +131,7 @@
}
void CopyToOMX(const OMX_BUFFERHEADERTYPE *header) {
- if (!mIsBackup) {
+ if (!mCopyToOmx) {
return;
}
@@ -163,13 +171,19 @@
return mPortIndex;
}
+ ~BufferMeta() {
+ delete[] mBackup;
+ }
+
private:
sp<GraphicBuffer> mGraphicBuffer;
sp<NativeHandle> mNativeHandle;
sp<IMemory> mMem;
size_t mSize;
- bool mIsBackup;
+ bool mCopyFromOmx;
+ bool mCopyToOmx;
OMX_U32 mPortIndex;
+ OMX_U8 *mBackup;
BufferMeta(const BufferMeta &);
BufferMeta &operator=(const BufferMeta &);
@@ -196,6 +210,8 @@
mHandle(NULL),
mObserver(observer),
mDying(false),
+ mSailed(false),
+ mQueriedProhibitedExtensions(false),
mBufferIDCount(0)
{
mName = ADebug::GetDebugName(name);
@@ -355,7 +371,11 @@
status_t OMXNodeInstance::sendCommand(
OMX_COMMANDTYPE cmd, OMX_S32 param) {
- const sp<GraphicBufferSource>& bufferSource(getGraphicBufferSource());
+ if (cmd == OMX_CommandStateSet) {
+ // There are no configurations past first StateSet command.
+ mSailed = true;
+ }
+ const sp<GraphicBufferSource> bufferSource(getGraphicBufferSource());
if (bufferSource != NULL && cmd == OMX_CommandStateSet) {
if (param == OMX_StateIdle) {
// Initiating transition from Executing -> Idle
@@ -388,10 +408,57 @@
return StatusFromOMXError(err);
}
+bool OMXNodeInstance::isProhibitedIndex_l(OMX_INDEXTYPE index) {
+ // these extensions can only be used from OMXNodeInstance, not by clients directly.
+ static const char *restricted_extensions[] = {
+ "OMX.google.android.index.storeMetaDataInBuffers",
+ "OMX.google.android.index.storeANWBufferInMetadata",
+ "OMX.google.android.index.prepareForAdaptivePlayback",
+ "OMX.google.android.index.configureVideoTunnelMode",
+ "OMX.google.android.index.useAndroidNativeBuffer2",
+ "OMX.google.android.index.useAndroidNativeBuffer",
+ "OMX.google.android.index.enableAndroidNativeBuffers",
+ "OMX.google.android.index.allocateNativeHandle",
+ "OMX.google.android.index.getAndroidNativeBufferUsage",
+ };
+
+ if ((index > OMX_IndexComponentStartUnused && index <= OMX_IndexParamStandardComponentRole)
+ || (index > OMX_IndexPortStartUnused && index <= OMX_IndexParamCompBufferSupplier)
+ || (index > OMX_IndexAudioStartUnused && index <= OMX_IndexConfigAudioChannelVolume)
+ || (index > OMX_IndexVideoStartUnused && index <= OMX_IndexConfigVideoNalSize)
+ || (index > OMX_IndexCommonStartUnused
+ && index <= OMX_IndexConfigCommonTransitionEffect)
+ || (index > (OMX_INDEXTYPE)OMX_IndexExtAudioStartUnused
+ && index <= (OMX_INDEXTYPE)OMX_IndexParamAudioProfileQuerySupported)
+ || (index > (OMX_INDEXTYPE)OMX_IndexExtVideoStartUnused
+ && index <= (OMX_INDEXTYPE)OMX_IndexConfigAndroidVideoTemporalLayering)
+ || (index > (OMX_INDEXTYPE)OMX_IndexExtOtherStartUnused
+ && index <= (OMX_INDEXTYPE)OMX_IndexParamConsumerUsageBits)) {
+ return false;
+ }
+
+ if (!mQueriedProhibitedExtensions) {
+ for (size_t i = 0; i < NELEM(restricted_extensions); ++i) {
+ OMX_INDEXTYPE ext;
+ if (OMX_GetExtensionIndex(mHandle, (OMX_STRING)restricted_extensions[i], &ext) == OMX_ErrorNone) {
+ mProhibitedExtensions.add(ext);
+ }
+ }
+ mQueriedProhibitedExtensions = true;
+ }
+
+ return mProhibitedExtensions.indexOf(index) >= 0;
+}
+
status_t OMXNodeInstance::getParameter(
OMX_INDEXTYPE index, void *params, size_t /* size */) {
Mutex::Autolock autoLock(mLock);
+ if (isProhibitedIndex_l(index)) {
+ android_errorWriteLog(0x534e4554, "29422020");
+ return BAD_INDEX;
+ }
+
OMX_ERRORTYPE err = OMX_GetParameter(mHandle, index, params);
OMX_INDEXEXTTYPE extIndex = (OMX_INDEXEXTTYPE)index;
// some errors are expected for getParameter
@@ -407,6 +474,11 @@
OMX_INDEXEXTTYPE extIndex = (OMX_INDEXEXTTYPE)index;
CLOG_CONFIG(setParameter, "%s(%#x), %zu@%p)", asString(extIndex), index, size, params);
+ if (isProhibitedIndex_l(index)) {
+ android_errorWriteLog(0x534e4554, "29422020");
+ return BAD_INDEX;
+ }
+
OMX_ERRORTYPE err = OMX_SetParameter(
mHandle, index, const_cast<void *>(params));
CLOG_IF_ERROR(setParameter, err, "%s(%#x)", asString(extIndex), index);
@@ -417,6 +489,11 @@
OMX_INDEXTYPE index, void *params, size_t /* size */) {
Mutex::Autolock autoLock(mLock);
+ if (isProhibitedIndex_l(index)) {
+ android_errorWriteLog(0x534e4554, "29422020");
+ return BAD_INDEX;
+ }
+
OMX_ERRORTYPE err = OMX_GetConfig(mHandle, index, params);
OMX_INDEXEXTTYPE extIndex = (OMX_INDEXEXTTYPE)index;
// some errors are expected for getConfig
@@ -432,6 +509,11 @@
OMX_INDEXEXTTYPE extIndex = (OMX_INDEXEXTTYPE)index;
CLOG_CONFIG(setConfig, "%s(%#x), %zu@%p)", asString(extIndex), index, size, params);
+ if (isProhibitedIndex_l(index)) {
+ android_errorWriteLog(0x534e4554, "29422020");
+ return BAD_INDEX;
+ }
+
OMX_ERRORTYPE err = OMX_SetConfig(
mHandle, index, const_cast<void *>(params));
CLOG_IF_ERROR(setConfig, err, "%s(%#x)", asString(extIndex), index);
@@ -448,6 +530,12 @@
status_t OMXNodeInstance::enableNativeBuffers(
OMX_U32 portIndex, OMX_BOOL graphic, OMX_BOOL enable) {
+ if (portIndex >= NELEM(mSecureBufferType)) {
+ ALOGE("b/31385713, portIndex(%u)", portIndex);
+ android_errorWriteLog(0x534e4554, "31385713");
+ return BAD_VALUE;
+ }
+
Mutex::Autolock autoLock(mLock);
CLOG_CONFIG(enableNativeBuffers, "%s:%u%s, %d", portString(portIndex), portIndex,
graphic ? ", graphic" : "", enable);
@@ -534,6 +622,10 @@
status_t OMXNodeInstance::storeMetaDataInBuffers_l(
OMX_U32 portIndex, OMX_BOOL enable, MetadataBufferType *type) {
+ if (mSailed) {
+ android_errorWriteLog(0x534e4554, "29422020");
+ return INVALID_OPERATION;
+ }
if (portIndex != kPortIndexInput && portIndex != kPortIndexOutput) {
android_errorWriteLog(0x534e4554, "26324358");
if (type != NULL) {
@@ -611,6 +703,10 @@
OMX_U32 portIndex, OMX_BOOL enable, OMX_U32 maxFrameWidth,
OMX_U32 maxFrameHeight) {
Mutex::Autolock autolock(mLock);
+ if (mSailed) {
+ android_errorWriteLog(0x534e4554, "29422020");
+ return INVALID_OPERATION;
+ }
CLOG_CONFIG(prepareForAdaptivePlayback, "%s:%u en=%d max=%ux%u",
portString(portIndex), portIndex, enable, maxFrameWidth, maxFrameHeight);
@@ -641,6 +737,10 @@
OMX_U32 portIndex, OMX_BOOL tunneled, OMX_U32 audioHwSync,
native_handle_t **sidebandHandle) {
Mutex::Autolock autolock(mLock);
+ if (mSailed) {
+ android_errorWriteLog(0x534e4554, "29422020");
+ return INVALID_OPERATION;
+ }
CLOG_CONFIG(configureVideoTunnelMode, "%s:%u tun=%d sync=%u",
portString(portIndex), portIndex, tunneled, audioHwSync);
@@ -688,21 +788,46 @@
}
Mutex::Autolock autoLock(mLock);
- if (allottedSize > params->size()) {
+ if (allottedSize > params->size() || portIndex >= NELEM(mNumPortBuffers)) {
return BAD_VALUE;
}
- BufferMeta *buffer_meta = new BufferMeta(params, portIndex);
+ // metadata buffers are not connected cross process
+ // use a backup buffer instead of the actual buffer
+ BufferMeta *buffer_meta;
+ bool useBackup = mMetadataType[portIndex] != kMetadataBufferTypeInvalid;
+ OMX_U8 *data = static_cast<OMX_U8 *>(params->pointer());
+ // allocate backup buffer
+ if (useBackup) {
+ data = new (std::nothrow) OMX_U8[allottedSize];
+ if (data == NULL) {
+ return NO_MEMORY;
+ }
+ memset(data, 0, allottedSize);
+
+ // if we are not connecting the buffers, the sizes must match
+ if (allottedSize != params->size()) {
+ CLOG_ERROR(useBuffer, BAD_VALUE, SIMPLE_BUFFER(portIndex, (size_t)allottedSize, data));
+ delete[] data;
+ return BAD_VALUE;
+ }
+
+ buffer_meta = new BufferMeta(
+ params, portIndex, false /* copyToOmx */, false /* copyFromOmx */, data);
+ } else {
+ buffer_meta = new BufferMeta(
+ params, portIndex, false /* copyToOmx */, false /* copyFromOmx */, NULL);
+ }
OMX_BUFFERHEADERTYPE *header;
OMX_ERRORTYPE err = OMX_UseBuffer(
mHandle, &header, portIndex, buffer_meta,
- allottedSize, static_cast<OMX_U8 *>(params->pointer()));
+ allottedSize, data);
if (err != OMX_ErrorNone) {
CLOG_ERROR(useBuffer, err, SIMPLE_BUFFER(
- portIndex, (size_t)allottedSize, params->pointer()));
+ portIndex, (size_t)allottedSize, data));
delete buffer_meta;
buffer_meta = NULL;
@@ -901,7 +1026,7 @@
// update backup buffer for input, codec buffer for output
return updateGraphicBufferInMeta_l(
portIndex, graphicBuffer, buffer, header,
- portIndex == kPortIndexOutput /* updateCodecBuffer */);
+ true /* updateCodecBuffer */);
}
status_t OMXNodeInstance::updateNativeHandleInMeta(
@@ -919,9 +1044,9 @@
}
BufferMeta *bufferMeta = (BufferMeta *)(header->pAppPrivate);
- // update backup buffer for input, codec buffer for output
+ // update backup buffer
sp<ABuffer> data = bufferMeta->getBuffer(
- header, portIndex == kPortIndexInput /* backup */, false /* limit */);
+ header, false /* backup */, false /* limit */);
bufferMeta->setNativeHandle(nativeHandle);
if (mMetadataType[portIndex] == kMetadataBufferTypeNativeHandleSource
&& data->capacity() >= sizeof(VideoNativeHandleMetadata)) {
@@ -945,7 +1070,16 @@
OMX_U32 portIndex, sp<IGraphicBufferConsumer> bufferConsumer, MetadataBufferType *type) {
status_t err;
- const sp<GraphicBufferSource>& surfaceCheck = getGraphicBufferSource();
+ // only allow graphic source on input port, when there are no allocated buffers yet
+ if (portIndex != kPortIndexInput) {
+ android_errorWriteLog(0x534e4554, "29422020");
+ return BAD_VALUE;
+ } else if (mNumPortBuffers[portIndex] > 0) {
+ android_errorWriteLog(0x534e4554, "29422020");
+ return INVALID_OPERATION;
+ }
+
+ const sp<GraphicBufferSource> surfaceCheck = getGraphicBufferSource();
if (surfaceCheck != NULL) {
if (portIndex < NELEM(mMetadataType) && type != NULL) {
*type = mMetadataType[portIndex];
@@ -1088,6 +1222,12 @@
return BAD_VALUE;
}
+ if (portIndex >= NELEM(mSecureBufferType)) {
+ ALOGE("b/31385713, portIndex(%u)", portIndex);
+ android_errorWriteLog(0x534e4554, "31385713");
+ return BAD_VALUE;
+ }
+
Mutex::Autolock autoLock(mLock);
BufferMeta *buffer_meta = new BufferMeta(size, portIndex);
@@ -1141,11 +1281,18 @@
}
Mutex::Autolock autoLock(mLock);
- if (allottedSize > params->size()) {
+ if (allottedSize > params->size() || portIndex >= NELEM(mNumPortBuffers)) {
return BAD_VALUE;
}
- BufferMeta *buffer_meta = new BufferMeta(params, portIndex, true);
+ // metadata buffers are not connected cross process; only copy if not meta
+ bool copy = mMetadataType[portIndex] == kMetadataBufferTypeInvalid;
+
+ BufferMeta *buffer_meta = new BufferMeta(
+ params, portIndex,
+ (portIndex == kPortIndexInput) && copy /* copyToOmx */,
+ (portIndex == kPortIndexOutput) && copy /* copyFromOmx */,
+ NULL /* data */);
OMX_BUFFERHEADERTYPE *header;
@@ -1163,6 +1310,7 @@
}
CHECK_EQ(header->pAppPrivate, buffer_meta);
+ memset(header->pBuffer, 0, header->nAllocLen);
*buffer = makeBufferID(header);
@@ -1243,6 +1391,12 @@
OMX_U32 flags, OMX_TICKS timestamp, int fenceFd) {
Mutex::Autolock autoLock(mLock);
+ // no emptybuffer if using input surface
+ if (getGraphicBufferSource() != NULL) {
+ android_errorWriteLog(0x534e4554, "29422020");
+ return INVALID_OPERATION;
+ }
+
OMX_BUFFERHEADERTYPE *header = findBufferHeader(buffer, kPortIndexInput);
if (header == NULL) {
ALOGE("b/25884056");
@@ -1250,23 +1404,11 @@
}
BufferMeta *buffer_meta =
static_cast<BufferMeta *>(header->pAppPrivate);
- sp<ABuffer> backup = buffer_meta->getBuffer(header, true /* backup */, false /* limit */);
- sp<ABuffer> codec = buffer_meta->getBuffer(header, false /* backup */, false /* limit */);
- // convert incoming ANW meta buffers if component is configured for gralloc metadata mode
- // ignore rangeOffset in this case
- if (mMetadataType[kPortIndexInput] == kMetadataBufferTypeGrallocSource
- && backup->capacity() >= sizeof(VideoNativeMetadata)
- && codec->capacity() >= sizeof(VideoGrallocMetadata)
- && ((VideoNativeMetadata *)backup->base())->eType
- == kMetadataBufferTypeANWBuffer) {
- VideoNativeMetadata &backupMeta = *(VideoNativeMetadata *)backup->base();
- VideoGrallocMetadata &codecMeta = *(VideoGrallocMetadata *)codec->base();
- CLOG_BUFFER(emptyBuffer, "converting ANWB %p to handle %p",
- backupMeta.pBuffer, backupMeta.pBuffer->handle);
- codecMeta.pHandle = backupMeta.pBuffer != NULL ? backupMeta.pBuffer->handle : NULL;
- codecMeta.eType = kMetadataBufferTypeGrallocSource;
- header->nFilledLen = rangeLength ? sizeof(codecMeta) : 0;
+ // set up proper filled length if component is configured for gralloc metadata mode
+ // ignore rangeOffset in this case (as client may be assuming ANW meta buffers).
+ if (mMetadataType[kPortIndexInput] == kMetadataBufferTypeGrallocSource) {
+ header->nFilledLen = rangeLength ? sizeof(VideoGrallocMetadata) : 0;
header->nOffset = 0;
} else {
// rangeLength and rangeOffset must be a subset of the allocated data in the buffer.
@@ -1445,6 +1587,7 @@
case IOMX::INTERNAL_OPTION_MAX_FPS: return "MAX_FPS";
case IOMX::INTERNAL_OPTION_START_TIME: return "START_TIME";
case IOMX::INTERNAL_OPTION_TIME_LAPSE: return "TIME_LAPSE";
+ case IOMX::INTERNAL_OPTION_TIME_OFFSET: return "TIME_OFFSET";
default: return def;
}
}
@@ -1473,6 +1616,7 @@
case IOMX::INTERNAL_OPTION_MAX_FPS:
case IOMX::INTERNAL_OPTION_START_TIME:
case IOMX::INTERNAL_OPTION_TIME_LAPSE:
+ case IOMX::INTERNAL_OPTION_TIME_OFFSET:
case IOMX::INTERNAL_OPTION_COLOR_ASPECTS:
{
const sp<GraphicBufferSource> &bufferSource =
@@ -1499,6 +1643,13 @@
CLOG_CONFIG(setInternalOption, "delayUs=%lld", (long long)delayUs);
return bufferSource->setRepeatPreviousFrameDelayUs(delayUs);
+ } else if (type == IOMX::INTERNAL_OPTION_TIME_OFFSET) {
+ int64_t timeOffsetUs;
+ if (!getInternalOption(data, size, &timeOffsetUs)) {
+ return INVALID_OPERATION;
+ }
+ CLOG_CONFIG(setInternalOption, "bufferOffsetUs=%lld", (long long)timeOffsetUs);
+ return bufferSource->setInputBufferTimeOffset(timeOffsetUs);
} else if (type == IOMX::INTERNAL_OPTION_MAX_TIMESTAMP_GAP) {
int64_t maxGapUs;
if (!getInternalOption(data, size, &maxGapUs)) {
@@ -1692,6 +1843,13 @@
&& arg2 == OMX_StateExecuting) {
bufferSource->omxExecuting();
}
+
+ // allow configuration if we return to the loaded state
+ if (event == OMX_EventCmdComplete
+ && arg1 == OMX_CommandStateSet
+ && arg2 == OMX_StateLoaded) {
+ mSailed = false;
+ }
}
// static
diff --git a/media/libstagefright/rtsp/MyHandler.h b/media/libstagefright/rtsp/MyHandler.h
index 42a1182..76e2e6e 100644
--- a/media/libstagefright/rtsp/MyHandler.h
+++ b/media/libstagefright/rtsp/MyHandler.h
@@ -1408,6 +1408,11 @@
msg->post((mKeepAliveTimeoutUs * 9) / 10);
}
+ void cancelAccessUnitTimeoutCheck() {
+ ALOGV("cancelAccessUnitTimeoutCheck");
+ ++mCheckGeneration;
+ }
+
void postAccessUnitTimeoutCheck() {
if (mCheckPending) {
return;
@@ -1792,14 +1797,8 @@
// Time is now established, lets start timestamping immediately
for (size_t i = 0; i < mTracks.size(); ++i) {
- TrackInfo *trackInfo = &mTracks.editItemAt(i);
- while (!trackInfo->mPackets.empty()) {
- sp<ABuffer> accessUnit = *trackInfo->mPackets.begin();
- trackInfo->mPackets.erase(trackInfo->mPackets.begin());
-
- if (addMediaTimestamp(i, trackInfo, accessUnit)) {
- postQueueAccessUnit(i, accessUnit);
- }
+ if (OK != processAccessUnitQueue(i)) {
+ return;
}
}
for (size_t i = 0; i < mTracks.size(); ++i) {
@@ -1812,26 +1811,8 @@
}
}
- void onAccessUnitComplete(
- int32_t trackIndex, const sp<ABuffer> &accessUnit) {
- ALOGV("onAccessUnitComplete track %d", trackIndex);
-
+ status_t processAccessUnitQueue(int32_t trackIndex) {
TrackInfo *track = &mTracks.editItemAt(trackIndex);
- if(!mPlayResponseParsed){
- uint32_t seqNum = (uint32_t)accessUnit->int32Data();
- ALOGI("play response is not parsed, storing accessunit %u", seqNum);
- track->mPackets.push_back(accessUnit);
- return;
- }
-
- handleFirstAccessUnit();
-
- if (!mAllTracksHaveTime) {
- ALOGV("storing accessUnit, no time established yet");
- track->mPackets.push_back(accessUnit);
- return;
- }
-
while (!track->mPackets.empty()) {
sp<ABuffer> accessUnit = *track->mPackets.begin();
track->mPackets.erase(track->mPackets.begin());
@@ -1842,27 +1823,29 @@
// by ARTPSource. Only the low 16 bits of seq in RTP-Info of reply of
// RTSP "PLAY" command should be used to detect the first RTP packet
// after seeking.
- if (track->mAllowedStaleAccessUnits > 0) {
- uint32_t seqNum16 = seqNum & 0xffff;
- uint32_t firstSeqNumInSegment16 = track->mFirstSeqNumInSegment & 0xffff;
- if (seqNum16 > firstSeqNumInSegment16 + kMaxAllowedStaleAccessUnits
- || seqNum16 < firstSeqNumInSegment16) {
- // Not the first rtp packet of the stream after seeking, discarding.
- track->mAllowedStaleAccessUnits--;
- ALOGV("discarding stale access unit (0x%x : 0x%x)",
- seqNum, track->mFirstSeqNumInSegment);
- continue;
+ if (mSeekable) {
+ if (track->mAllowedStaleAccessUnits > 0) {
+ uint32_t seqNum16 = seqNum & 0xffff;
+ uint32_t firstSeqNumInSegment16 = track->mFirstSeqNumInSegment & 0xffff;
+ if (seqNum16 > firstSeqNumInSegment16 + kMaxAllowedStaleAccessUnits
+ || seqNum16 < firstSeqNumInSegment16) {
+ // Not the first rtp packet of the stream after seeking, discarding.
+ track->mAllowedStaleAccessUnits--;
+ ALOGV("discarding stale access unit (0x%x : 0x%x)",
+ seqNum, track->mFirstSeqNumInSegment);
+ continue;
+ }
+ ALOGW_IF(seqNum16 != firstSeqNumInSegment16,
+ "Missing the first packet(%u), now take packet(%u) as first one",
+ track->mFirstSeqNumInSegment, seqNum);
+ } else { // track->mAllowedStaleAccessUnits <= 0
+ mNumAccessUnitsReceived = 0;
+ ALOGW_IF(track->mAllowedStaleAccessUnits == 0,
+ "Still no first rtp packet after %d stale ones",
+ kMaxAllowedStaleAccessUnits);
+ track->mAllowedStaleAccessUnits = -1;
+ return UNKNOWN_ERROR;
}
- ALOGW_IF(seqNum16 != firstSeqNumInSegment16,
- "Missing the first packet(%u), now take packet(%u) as first one",
- track->mFirstSeqNumInSegment, seqNum);
- } else { // track->mAllowedStaleAccessUnits <= 0
- mNumAccessUnitsReceived = 0;
- ALOGW_IF(track->mAllowedStaleAccessUnits == 0,
- "Still no first rtp packet after %d stale ones",
- kMaxAllowedStaleAccessUnits);
- track->mAllowedStaleAccessUnits = -1;
- return;
}
// Now found the first rtp packet of the stream after seeking.
@@ -1876,14 +1859,35 @@
continue;
}
-
if (addMediaTimestamp(trackIndex, track, accessUnit)) {
postQueueAccessUnit(trackIndex, accessUnit);
}
}
+ return OK;
+ }
- if (addMediaTimestamp(trackIndex, track, accessUnit)) {
- postQueueAccessUnit(trackIndex, accessUnit);
+ void onAccessUnitComplete(
+ int32_t trackIndex, const sp<ABuffer> &accessUnit) {
+ TrackInfo *track = &mTracks.editItemAt(trackIndex);
+ track->mPackets.push_back(accessUnit);
+
+ uint32_t seqNum = (uint32_t)accessUnit->int32Data();
+ ALOGV("onAccessUnitComplete track %d storing accessunit %u", trackIndex, seqNum);
+
+ if(!mPlayResponseParsed){
+ ALOGV("play response is not parsed");
+ return;
+ }
+
+ handleFirstAccessUnit();
+
+ if (!mAllTracksHaveTime) {
+ ALOGV("storing accessUnit, no time established yet");
+ return;
+ }
+
+ if (OK != processAccessUnitQueue(trackIndex)) {
+ return;
}
if (track->mEOSReceived) {
diff --git a/media/ndk/NdkMediaExtractor.cpp b/media/ndk/NdkMediaExtractor.cpp
index 1118959..89f2d9c 100644
--- a/media/ndk/NdkMediaExtractor.cpp
+++ b/media/ndk/NdkMediaExtractor.cpp
@@ -148,7 +148,14 @@
EXPORT
bool AMediaExtractor_advance(AMediaExtractor *mData) {
//ALOGV("advance");
- return mData->mImpl->advance();
+ status_t err = mData->mImpl->advance();
+ if (err == ERROR_END_OF_STREAM) {
+ return false;
+ } else if (err != OK) {
+ ALOGE("sf error code: %d", err);
+ return false;
+ }
+ return true;
}
EXPORT
@@ -343,9 +350,9 @@
const void *key;
size_t keysize;
- if (meta->findData(kKeyCryptoIV, &type, &key, &keysize)) {
+ if (meta->findData(kKeyCryptoKey, &type, &key, &keysize)) {
if (keysize != 16) {
- // IVs must be 16 bytes in length.
+ // Keys must be 16 bytes in length.
return NULL;
}
}
diff --git a/radio/Radio.cpp b/radio/Radio.cpp
index e3554c2..3c04fb0 100644
--- a/radio/Radio.cpp
+++ b/radio/Radio.cpp
@@ -55,7 +55,7 @@
sp<DeathNotifier> gDeathNotifier;
}; // namespace anonymous
-const sp<IRadioService>& Radio::getRadioService()
+const sp<IRadioService> Radio::getRadioService()
{
Mutex::Autolock _l(gLock);
if (gRadioService.get() == 0) {
@@ -84,7 +84,7 @@
uint32_t *numModules)
{
ALOGV("listModules()");
- const sp<IRadioService>& service = getRadioService();
+ const sp<IRadioService> service = getRadioService();
if (service == 0) {
return NO_INIT;
}
@@ -98,7 +98,7 @@
{
ALOGV("attach()");
sp<Radio> radio;
- const sp<IRadioService>& service = getRadioService();
+ const sp<IRadioService> service = getRadioService();
if (service == 0) {
return radio;
}
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 79f4a66..1785a03 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -1104,14 +1104,20 @@
// AUDIO_IO_HANDLE_NONE means the parameters are global to the audio hardware interface
if (ioHandle == AUDIO_IO_HANDLE_NONE) {
Mutex::Autolock _l(mLock);
- status_t final_result = NO_ERROR;
+ // result will remain NO_INIT if no audio device is present
+ status_t final_result = NO_INIT;
{
AutoMutex lock(mHardwareLock);
mHardwareStatus = AUDIO_HW_SET_PARAMETER;
for (size_t i = 0; i < mAudioHwDevs.size(); i++) {
audio_hw_device_t *dev = mAudioHwDevs.valueAt(i)->hwDevice();
status_t result = dev->set_parameters(dev, keyValuePairs.string());
- final_result = result ?: final_result;
+ // return success if at least one audio device accepts the parameters as not all
+ // HALs are requested to support all parameters. If no audio device supports the
+ // requested parameters, the last error is reported.
+ if (final_result != NO_ERROR) {
+ final_result = result;
+ }
}
mHardwareStatus = AUDIO_HW_IDLE;
}
diff --git a/services/audioflinger/BufferProviders.cpp b/services/audioflinger/BufferProviders.cpp
index 2ca2cac..7b6dfcb 100644
--- a/services/audioflinger/BufferProviders.cpp
+++ b/services/audioflinger/BufferProviders.cpp
@@ -474,18 +474,18 @@
ALOGV("processFrames(%zu %zu) remaining(%zu)", *dstFrames, *srcFrames, mRemaining);
// Note dstFrames is the required number of frames.
- // Ensure consumption from src is as expected.
- //TODO: add logic to track "very accurate" consumption related to speed, original sampling
- //rate, actual frames processed.
- const size_t targetSrc = *dstFrames * mPlaybackRate.mSpeed;
- if (*srcFrames < targetSrc) { // limit dst frames to that possible
- *dstFrames = *srcFrames / mPlaybackRate.mSpeed;
- } else if (*srcFrames > targetSrc + 1) {
- *srcFrames = targetSrc + 1;
- }
-
if (!mAudioPlaybackRateValid) {
//fallback mode
+ // Ensure consumption from src is as expected.
+ // TODO: add logic to track "very accurate" consumption related to speed, original sampling
+ // rate, actual frames processed.
+
+ const size_t targetSrc = *dstFrames * mPlaybackRate.mSpeed;
+ if (*srcFrames < targetSrc) { // limit dst frames to that possible
+ *dstFrames = *srcFrames / mPlaybackRate.mSpeed;
+ } else if (*srcFrames > targetSrc + 1) {
+ *srcFrames = targetSrc + 1;
+ }
if (*dstFrames > 0) {
switch(mPlaybackRate.mFallbackMode) {
case AUDIO_TIMESTRETCH_FALLBACK_CUT_REPEAT:
diff --git a/services/audioflinger/Effects.cpp b/services/audioflinger/Effects.cpp
index e3e518c..aedde69 100644
--- a/services/audioflinger/Effects.cpp
+++ b/services/audioflinger/Effects.cpp
@@ -279,12 +279,29 @@
mConfig.inputCfg.buffer.s32,
mConfig.inputCfg.buffer.frameCount/2);
}
+ int ret;
+ if (isProcessImplemented()) {
+ // do the actual processing in the effect engine
+ ret = (*mEffectInterface)->process(mEffectInterface,
+ &mConfig.inputCfg.buffer,
+ &mConfig.outputCfg.buffer);
+ } else {
+ if (mConfig.inputCfg.buffer.raw != mConfig.outputCfg.buffer.raw) {
+ size_t frameCnt = mConfig.inputCfg.buffer.frameCount * FCC_2; //always stereo here
+ int16_t *in = mConfig.inputCfg.buffer.s16;
+ int16_t *out = mConfig.outputCfg.buffer.s16;
- // do the actual processing in the effect engine
- int ret = (*mEffectInterface)->process(mEffectInterface,
- &mConfig.inputCfg.buffer,
- &mConfig.outputCfg.buffer);
-
+ if (mConfig.outputCfg.accessMode == EFFECT_BUFFER_ACCESS_ACCUMULATE) {
+ for (size_t i = 0; i < frameCnt; i++) {
+ out[i] = clamp16((int32_t)out[i] + (int32_t)in[i]);
+ }
+ } else {
+ memcpy(mConfig.outputCfg.buffer.raw, mConfig.inputCfg.buffer.raw,
+ frameCnt * sizeof(int16_t));
+ }
+ }
+ ret = -ENODATA;
+ }
// force transition to IDLE state when engine is ready
if (mState == STOPPED && ret == -ENODATA) {
mDisableWaitCnt = 1;
@@ -301,7 +318,7 @@
// accumulate input onto output
sp<EffectChain> chain = mChain.promote();
if (chain != 0 && chain->activeTrackCnt() != 0) {
- size_t frameCnt = mConfig.inputCfg.buffer.frameCount * 2; //always stereo here
+ size_t frameCnt = mConfig.inputCfg.buffer.frameCount * FCC_2; //always stereo here
int16_t *in = mConfig.inputCfg.buffer.s16;
int16_t *out = mConfig.outputCfg.buffer.s16;
for (size_t i = 0; i < frameCnt; i++) {
@@ -555,6 +572,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,
@@ -576,6 +600,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/Effects.h b/services/audioflinger/Effects.h
index 322c06a..da0f3c5 100644
--- a/services/audioflinger/Effects.h
+++ b/services/audioflinger/Effects.h
@@ -119,6 +119,8 @@
{ return (mDescriptor.flags & EFFECT_FLAG_OFFLOAD_SUPPORTED) != 0; }
bool isImplementationSoftware() const
{ return (mDescriptor.flags & EFFECT_FLAG_HW_ACC_MASK) == 0; }
+ bool isProcessImplemented() const
+ { return (mDescriptor.flags & EFFECT_FLAG_NO_PROCESS) == 0; }
status_t setOffloaded(bool offloaded, audio_io_handle_t io);
bool isOffloaded() const;
void addEffectToHal_l();
diff --git a/services/audioflinger/FastThread.cpp b/services/audioflinger/FastThread.cpp
index 8da54b0..dca7bf9 100644
--- a/services/audioflinger/FastThread.cpp
+++ b/services/audioflinger/FastThread.cpp
@@ -167,7 +167,7 @@
if (old <= 0) {
syscall(__NR_futex, coldFutexAddr, FUTEX_WAIT_PRIVATE, old - 1, NULL);
}
- int policy = sched_getscheduler(0);
+ int policy = sched_getscheduler(0) & ~SCHED_RESET_ON_FORK;
if (!(policy == SCHED_FIFO || policy == SCHED_RR)) {
ALOGE("did not receive expected priority boost");
}
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index aa2561e..a91fc26 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -1272,6 +1272,12 @@
desc->name, mThreadName);
return BAD_VALUE;
}
+
+ // always allow effects without processing load or latency
+ if ((desc->flags & EFFECT_FLAG_NO_PROCESS_MASK) == EFFECT_FLAG_NO_PROCESS) {
+ return NO_ERROR;
+ }
+
audio_input_flags_t flags = mInput->flags;
if (hasFastCapture() || (flags & AUDIO_INPUT_FLAG_FAST)) {
if (flags & AUDIO_INPUT_FLAG_RAW) {
@@ -1328,6 +1334,11 @@
break;
}
}
+
+ // always allow effects without processing load or latency
+ if ((desc->flags & EFFECT_FLAG_NO_PROCESS_MASK) == EFFECT_FLAG_NO_PROCESS) {
+ break;
+ }
if (flags & AUDIO_OUTPUT_FLAG_RAW) {
ALOGW("checkEffectCompatibility_l(): effect %s on playback thread in raw mode",
desc->name);
@@ -3106,9 +3117,9 @@
if (!keepWakeLock()) {
releaseWakeLock_l();
released = true;
+ mWakeLockUids.clear();
+ mActiveTracksGeneration++;
}
- mWakeLockUids.clear();
- mActiveTracksGeneration++;
ALOGV("wait async completion");
mWaitWorkCV.wait(mLock);
ALOGV("async completion/wake");
@@ -3447,10 +3458,15 @@
status_t AudioFlinger::MixerThread::createAudioPatch_l(const struct audio_patch *patch,
audio_patch_handle_t *handle)
{
- AutoPark<FastMixer> park(mFastMixer);
-
- status_t status = PlaybackThread::createAudioPatch_l(patch, handle);
-
+ status_t status;
+ if (property_get_bool("af.patch_park", false /* default_value */)) {
+ // Park FastMixer to avoid potential DOS issues with writing to the HAL
+ // or if HAL does not properly lock against access.
+ AutoPark<FastMixer> park(mFastMixer);
+ status = PlaybackThread::createAudioPatch_l(patch, handle);
+ } else {
+ status = PlaybackThread::createAudioPatch_l(patch, handle);
+ }
return status;
}
@@ -3532,10 +3548,15 @@
status_t AudioFlinger::MixerThread::releaseAudioPatch_l(const audio_patch_handle_t handle)
{
- AutoPark<FastMixer> park(mFastMixer);
-
- status_t status = PlaybackThread::releaseAudioPatch_l(handle);
-
+ status_t status;
+ if (property_get_bool("af.patch_park", false /* default_value */)) {
+ // Park FastMixer to avoid potential DOS issues with writing to the HAL
+ // or if HAL does not properly lock against access.
+ AutoPark<FastMixer> park(mFastMixer);
+ status = PlaybackThread::releaseAudioPatch_l(handle);
+ } else {
+ status = PlaybackThread::releaseAudioPatch_l(handle);
+ }
return status;
}
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index b387af3..3cca054 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -777,6 +777,13 @@
Mutex::Autolock _l(thread->mLock);
PlaybackThread *playbackThread = (PlaybackThread *)thread.get();
+ // Flush the ring buffer now if the track is not active in the PlaybackThread.
+ // Otherwise the flush would not be done until the track is resumed.
+ // Requires FastTrack removal be BLOCK_UNTIL_ACKED
+ if (playbackThread->mActiveTracks.indexOf(this) < 0) {
+ (void)mServerProxy->flushBufferIfNeeded();
+ }
+
if (isOffloaded()) {
// If offloaded we allow flush during any state except terminated
// and keep the track active to avoid problems if user is seeking
@@ -828,6 +835,10 @@
if (!isOffloaded() && !isDirect())
return;
+ // Clear the client ring buffer so that the app can prime the buffer while paused.
+ // Otherwise it might not get cleared until playback is resumed and obtainBuffer() is called.
+ mServerProxy->flushBufferIfNeeded();
+
mFlushHwPending = false;
}
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index b752541..9095cde 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -1321,9 +1321,11 @@
desc->isActive() &&
outputDesc->sharesHwModuleWith(desc) &&
(newDevice != desc->device())) {
+ audio_devices_t newDevice2 = getNewOutputDevice(desc, false /*fromCache*/);
+ bool force = desc->device() != newDevice2;
setOutputDevice(desc,
- getNewOutputDevice(desc, false /*fromCache*/),
- true,
+ newDevice2,
+ force,
outputDesc->latency()*2);
}
}
@@ -4937,6 +4939,18 @@
audio_devices_t device)
{
float volumeDB = mVolumeCurves->volIndexToDb(stream, Volume::getDeviceCategory(device), index);
+
+ // handle the case of accessibility active while a ringtone is playing: if the ringtone is much
+ // louder than the accessibility prompt, the prompt cannot be heard, thus masking the touch
+ // exploration of the dialer UI. In this situation, bring the accessibility volume closer to
+ // the ringtone volume
+ if ((stream == AUDIO_STREAM_ACCESSIBILITY)
+ && (AUDIO_MODE_RINGTONE == mEngine->getPhoneState())
+ && isStreamActive(AUDIO_STREAM_RING, 0)) {
+ const float ringVolumeDB = computeVolume(AUDIO_STREAM_RING, index, device);
+ return ringVolumeDB - 4 > volumeDB ? ringVolumeDB - 4 : volumeDB;
+ }
+
// if a headset is connected, apply the following rules to ring tones and notifications
// to avoid sound level bursts in user's ears:
// - always attenuate notifications volume by 6dB
diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp
index 5703934..48a2a99 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
@@ -42,6 +42,7 @@
#include <utils/Log.h>
#include <utils/Trace.h>
#include <utils/Timers.h>
+#include <cutils/properties.h>
#include <android/hardware/camera2/ICameraDeviceUser.h>
@@ -169,6 +170,9 @@
return res;
}
+ /** Register in-flight map to the status tracker */
+ mInFlightStatusId = mStatusTracker->addComponent();
+
/** Create buffer manager */
mBufferManager = new Camera3BufferManager();
@@ -2037,15 +2041,20 @@
// across configure_streams() calls
mRequestThread->configurationComplete(mIsConstrainedHighSpeedConfiguration);
- // Boost priority of request thread to SCHED_FIFO.
- pid_t requestThreadTid = mRequestThread->getTid();
- res = requestPriority(getpid(), requestThreadTid,
- kRequestThreadPriority, /*asynchronous*/ false);
- if (res != OK) {
- ALOGW("Can't set realtime priority for request processing thread: %s (%d)",
- strerror(-res), res);
- } else {
- ALOGD("Set real time priority for request queue thread (tid %d)", requestThreadTid);
+ char value[PROPERTY_VALUE_MAX];
+ property_get("camera.fifo.disable", value, "0");
+ int32_t disableFifo = atoi(value);
+ if (disableFifo != 1) {
+ // Boost priority of request thread to SCHED_FIFO.
+ pid_t requestThreadTid = mRequestThread->getTid();
+ res = requestPriority(getpid(), requestThreadTid,
+ kRequestThreadPriority, /*asynchronous*/ false);
+ if (res != OK) {
+ ALOGW("Can't set realtime priority for request processing thread: %s (%d)",
+ strerror(-res), res);
+ } else {
+ ALOGD("Set real time priority for request queue thread (tid %d)", requestThreadTid);
+ }
}
// Update device state
@@ -2190,6 +2199,10 @@
aeTriggerCancelOverride));
if (res < 0) return res;
+ if (mInFlightMap.size() == 1) {
+ mStatusTracker->markComponentActive(mInFlightStatusId);
+ }
+
return OK;
}
@@ -2246,6 +2259,11 @@
mInFlightMap.removeItemsAt(idx, 1);
+ // Indicate idle inFlightMap to the status tracker
+ if (mInFlightMap.size() == 0) {
+ mStatusTracker->markComponentIdle(mInFlightStatusId, Fence::NO_FENCE);
+ }
+
ALOGVV("%s: removed frame %d from InFlightMap", __FUNCTION__, frameNumber);
}
diff --git a/services/camera/libcameraservice/device3/Camera3Device.h b/services/camera/libcameraservice/device3/Camera3Device.h
index 3244258..17893a9 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.h
+++ b/services/camera/libcameraservice/device3/Camera3Device.h
@@ -725,6 +725,7 @@
Mutex mInFlightLock; // Protects mInFlightMap
InFlightMap mInFlightMap;
+ int mInFlightStatusId;
status_t registerInFlight(uint32_t frameNumber,
int32_t numBuffers, CaptureResultExtras resultExtras, bool hasInput,
diff --git a/services/soundtrigger/SoundTriggerHwService.cpp b/services/soundtrigger/SoundTriggerHwService.cpp
index bb2416a..eebc487 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;
diff --git a/soundtrigger/SoundTrigger.cpp b/soundtrigger/SoundTrigger.cpp
index 2138cb7..e959b83 100644
--- a/soundtrigger/SoundTrigger.cpp
+++ b/soundtrigger/SoundTrigger.cpp
@@ -55,7 +55,7 @@
sp<DeathNotifier> gDeathNotifier;
}; // namespace anonymous
-const sp<ISoundTriggerHwService>& SoundTrigger::getSoundTriggerHwService()
+const sp<ISoundTriggerHwService> SoundTrigger::getSoundTriggerHwService()
{
Mutex::Autolock _l(gLock);
if (gSoundTriggerHwService.get() == 0) {
@@ -84,7 +84,7 @@
uint32_t *numModules)
{
ALOGV("listModules()");
- const sp<ISoundTriggerHwService>& service = getSoundTriggerHwService();
+ const sp<ISoundTriggerHwService> service = getSoundTriggerHwService();
if (service == 0) {
return NO_INIT;
}
@@ -96,7 +96,7 @@
{
ALOGV("attach()");
sp<SoundTrigger> soundTrigger;
- const sp<ISoundTriggerHwService>& service = getSoundTriggerHwService();
+ const sp<ISoundTriggerHwService> service = getSoundTriggerHwService();
if (service == 0) {
return soundTrigger;
}
@@ -116,7 +116,7 @@
status_t SoundTrigger::setCaptureState(bool active)
{
ALOGV("setCaptureState(%d)", active);
- const sp<ISoundTriggerHwService>& service = getSoundTriggerHwService();
+ const sp<ISoundTriggerHwService> service = getSoundTriggerHwService();
if (service == 0) {
return NO_INIT;
}