Merge "AudioFlinger: Add missing channel names for thread dump"
diff --git a/drm/libmediadrm/CryptoHal.cpp b/drm/libmediadrm/CryptoHal.cpp
index f229751..5d0f68e 100644
--- a/drm/libmediadrm/CryptoHal.cpp
+++ b/drm/libmediadrm/CryptoHal.cpp
@@ -223,10 +223,14 @@
Mutex::Autolock autoLock(mLock);
if (mInitCheck != OK) {
- return mInitCheck;
+ return false;
}
- return mPlugin->requiresSecureDecoderComponent(hidl_string(mime));
+ Return<bool> hResult = mPlugin->requiresSecureDecoderComponent(hidl_string(mime));
+ if (!hResult.isOk()) {
+ return false;
+ }
+ return hResult;
}
@@ -249,7 +253,7 @@
int32_t seqNum = mHeapSeqNum++;
sp<HidlMemory> hidlMemory = fromHeap(heap);
- mHeapBases.add(seqNum, mNextBufferId);
+ mHeapBases.add(seqNum, HeapBase(mNextBufferId, heap->getSize()));
Return<void> hResult = mPlugin->setSharedBufferBase(*hidlMemory, mNextBufferId++);
ALOGE_IF(!hResult.isOk(), "setSharedBufferBase(): remote call failed");
return seqNum;
@@ -274,10 +278,26 @@
return UNEXPECTED_NULL;
}
- // memory must be in the declared heap
- CHECK(mHeapBases.indexOfKey(seqNum) >= 0);
+ // memory must be in one of the heaps that have been set
+ if (mHeapBases.indexOfKey(seqNum) < 0) {
+ return UNKNOWN_ERROR;
+ }
- buffer->bufferId = mHeapBases.valueFor(seqNum);
+ // heap must be the same size as the one that was set in setHeapBase
+ if (mHeapBases.valueFor(seqNum).getSize() != heap->getSize()) {
+ android_errorWriteLog(0x534e4554, "76221123");
+ return UNKNOWN_ERROR;
+ }
+
+ // memory must be within the address space of the heap
+ if (memory->pointer() != static_cast<uint8_t *>(heap->getBase()) + memory->offset() ||
+ heap->getSize() < memory->offset() + memory->size() ||
+ SIZE_MAX - memory->offset() < memory->size()) {
+ android_errorWriteLog(0x534e4554, "76221123");
+ return UNKNOWN_ERROR;
+ }
+
+ buffer->bufferId = mHeapBases.valueFor(seqNum).getBufferId();
buffer->offset = offset >= 0 ? offset : 0;
buffer->size = size;
return OK;
diff --git a/drm/libmediadrm/DrmHal.cpp b/drm/libmediadrm/DrmHal.cpp
index 06e8487..cf08610 100644
--- a/drm/libmediadrm/DrmHal.cpp
+++ b/drm/libmediadrm/DrmHal.cpp
@@ -68,10 +68,12 @@
template<typename T>
std::string toBase64StringNoPad(const T* data, size_t size) {
- if (size == 0) {
+ // Note that the base 64 conversion only works with arrays of single-byte
+ // values. If the source is empty or is not an array of single-byte values,
+ // return empty string.
+ if (size == 0 || sizeof(data[0]) != 1) {
return "";
}
- CHECK(sizeof(data[0] == 1));
android::AString outputString;
encodeBase64(data, size, &outputString);
diff --git a/drm/libmediadrm/DrmMetrics.cpp b/drm/libmediadrm/DrmMetrics.cpp
index fce1717..4fed707 100644
--- a/drm/libmediadrm/DrmMetrics.cpp
+++ b/drm/libmediadrm/DrmMetrics.cpp
@@ -29,6 +29,7 @@
using ::android::String16;
using ::android::String8;
using ::android::drm_metrics::DrmFrameworkMetrics;
+using ::android::hardware::hidl_string;
using ::android::hardware::hidl_vec;
using ::android::hardware::drm::V1_0::EventType;
using ::android::hardware::drm::V1_0::KeyStatusType;
@@ -192,6 +193,13 @@
}
}
+inline String16 MakeIndexString(unsigned int index) {
+ std::string str("[");
+ str.append(std::to_string(index));
+ str.append("]");
+ return String16(str.c_str());
+}
+
} // namespace
namespace android {
@@ -370,9 +378,11 @@
}
int groupIndex = 0;
+ std::map<String16, int> indexMap;
for (const auto &hidlMetricGroup : hidlMetricGroups) {
PersistableBundle bundleMetricGroup;
for (const auto &hidlMetric : hidlMetricGroup.metrics) {
+ String16 metricName(hidlMetric.name.c_str());
PersistableBundle bundleMetric;
// Add metric component values.
for (const auto &value : hidlMetric.values) {
@@ -388,14 +398,22 @@
// Add attributes to the bundle metric.
bundleMetric.putPersistableBundle(String16("attributes"),
bundleMetricAttributes);
+ // Add one layer of indirection, allowing for repeated metric names.
+ PersistableBundle repeatedMetrics;
+ bundleMetricGroup.getPersistableBundle(metricName,
+ &repeatedMetrics);
+ int index = indexMap[metricName];
+ repeatedMetrics.putPersistableBundle(MakeIndexString(index),
+ bundleMetric);
+ indexMap[metricName] = ++index;
+
// Add the bundle metric to the group of metrics.
- bundleMetricGroup.putPersistableBundle(
- String16(hidlMetric.name.c_str()), bundleMetric);
+ bundleMetricGroup.putPersistableBundle(metricName,
+ repeatedMetrics);
}
// Add the bundle metric group to the collection of groups.
- bundleMetricGroups->putPersistableBundle(
- String16(std::to_string(groupIndex).c_str()), bundleMetricGroup);
- groupIndex++;
+ bundleMetricGroups->putPersistableBundle(MakeIndexString(groupIndex++),
+ bundleMetricGroup);
}
return OK;
diff --git a/drm/libmediadrm/tests/DrmMetrics_test.cpp b/drm/libmediadrm/tests/DrmMetrics_test.cpp
index 1a20342..64aa9d0 100644
--- a/drm/libmediadrm/tests/DrmMetrics_test.cpp
+++ b/drm/libmediadrm/tests/DrmMetrics_test.cpp
@@ -429,7 +429,8 @@
DrmMetricGroup hidlMetricGroup =
{ { {
"open_session_ok",
- { { "status", DrmMetricGroup::ValueType::INT64_TYPE, (int64_t) Status::OK, 0.0, "" } },
+ { { "status", DrmMetricGroup::ValueType::INT64_TYPE,
+ (int64_t) Status::OK, 0.0, "" } },
{ { "count", DrmMetricGroup::ValueType::INT64_TYPE, 3, 0.0, "" } }
},
{
@@ -444,25 +445,28 @@
&bundleMetricGroups));
ASSERT_EQ(1U, bundleMetricGroups.size());
PersistableBundle bundleMetricGroup;
- ASSERT_TRUE(bundleMetricGroups.getPersistableBundle(String16("0"), &bundleMetricGroup));
+ ASSERT_TRUE(bundleMetricGroups.getPersistableBundle(String16("[0]"), &bundleMetricGroup));
ASSERT_EQ(2U, bundleMetricGroup.size());
// Verify each metric.
PersistableBundle metric;
ASSERT_TRUE(bundleMetricGroup.getPersistableBundle(String16("open_session_ok"), &metric));
+ PersistableBundle metricInstance;
+ ASSERT_TRUE(metric.getPersistableBundle(String16("[0]"), &metricInstance));
int64_t value = 0;
- ASSERT_TRUE(metric.getLong(String16("count"), &value));
+ ASSERT_TRUE(metricInstance.getLong(String16("count"), &value));
ASSERT_EQ(3, value);
PersistableBundle attributeBundle;
- ASSERT_TRUE(metric.getPersistableBundle(String16("attributes"), &attributeBundle));
+ ASSERT_TRUE(metricInstance.getPersistableBundle(String16("attributes"), &attributeBundle));
ASSERT_TRUE(attributeBundle.getLong(String16("status"), &value));
ASSERT_EQ((int64_t) Status::OK, value);
ASSERT_TRUE(bundleMetricGroup.getPersistableBundle(String16("close_session_not_opened"),
&metric));
- ASSERT_TRUE(metric.getLong(String16("count"), &value));
+ ASSERT_TRUE(metric.getPersistableBundle(String16("[0]"), &metricInstance));
+ ASSERT_TRUE(metricInstance.getLong(String16("count"), &value));
ASSERT_EQ(7, value);
- ASSERT_TRUE(metric.getPersistableBundle(String16("attributes"), &attributeBundle));
+ ASSERT_TRUE(metricInstance.getPersistableBundle(String16("attributes"), &attributeBundle));
value = 0;
ASSERT_TRUE(attributeBundle.getLong(String16("status"), &value));
ASSERT_EQ((int64_t) Status::ERROR_DRM_SESSION_NOT_OPENED, value);
diff --git a/include/private/media/VideoFrame.h b/include/private/media/VideoFrame.h
index 8b8824f..712f118 100644
--- a/include/private/media/VideoFrame.h
+++ b/include/private/media/VideoFrame.h
@@ -37,9 +37,11 @@
// will calculate frame buffer size if |hasData| is set to true.
VideoFrame(uint32_t width, uint32_t height,
uint32_t displayWidth, uint32_t displayHeight,
+ uint32_t tileWidth, uint32_t tileHeight,
uint32_t angle, uint32_t bpp, bool hasData, size_t iccSize):
mWidth(width), mHeight(height),
mDisplayWidth(displayWidth), mDisplayHeight(displayHeight),
+ mTileWidth(tileWidth), mTileHeight(tileHeight),
mRotationAngle(angle), mBytesPerPixel(bpp), mRowBytes(bpp * width),
mSize(hasData ? (bpp * width * height) : 0),
mIccSize(iccSize), mReserved(0) {
@@ -74,6 +76,8 @@
uint32_t mHeight; // Decoded image height before rotation
uint32_t mDisplayWidth; // Display width before rotation
uint32_t mDisplayHeight; // Display height before rotation
+ uint32_t mTileWidth; // Tile width (0 if image doesn't have grid)
+ uint32_t mTileHeight; // Tile height (0 if image doesn't have grid)
int32_t mRotationAngle; // Rotation angle, clockwise, should be multiple of 90
uint32_t mBytesPerPixel; // Number of bytes per pixel
uint32_t mRowBytes; // Number of bytes per row before rotation
diff --git a/media/extractors/mp4/ItemTable.cpp b/media/extractors/mp4/ItemTable.cpp
index a1f6e9a..b6787af 100644
--- a/media/extractors/mp4/ItemTable.cpp
+++ b/media/extractors/mp4/ItemTable.cpp
@@ -1397,7 +1397,8 @@
ALOGV("adding %s: itemId %d", image.isGrid() ? "grid" : "image", info.itemId);
if (image.isGrid()) {
- if (size > 12) {
+ // ImageGrid struct is at least 8-byte, at most 12-byte (if flags&1)
+ if (size < 8 || size > 12) {
return ERROR_MALFORMED;
}
uint8_t buf[12];
diff --git a/media/libaudioclient/AudioTrack.cpp b/media/libaudioclient/AudioTrack.cpp
index 86791c2..ab9efe8 100644
--- a/media/libaudioclient/AudioTrack.cpp
+++ b/media/libaudioclient/AudioTrack.cpp
@@ -806,7 +806,7 @@
return;
}
AutoMutex lock(mLock);
- if (mState == STATE_ACTIVE || mState == STATE_FLUSHED) {
+ if (mState == STATE_ACTIVE) {
return;
}
flush_l();
diff --git a/media/libaudioclient/IAudioPolicyService.cpp b/media/libaudioclient/IAudioPolicyService.cpp
index abb502b..eca6fee 100644
--- a/media/libaudioclient/IAudioPolicyService.cpp
+++ b/media/libaudioclient/IAudioPolicyService.cpp
@@ -876,7 +876,8 @@
case SET_DEVICE_CONNECTION_STATE:
case HANDLE_DEVICE_CONFIG_CHANGE:
case SET_PHONE_STATE:
- case SET_FORCE_USE:
+//FIXME: Allow SET_FORCE_USE calls from system apps until a better use case routing API is available
+// case SET_FORCE_USE:
case INIT_STREAM_VOLUME:
case SET_STREAM_VOLUME:
case REGISTER_POLICY_MIXES:
@@ -895,20 +896,7 @@
break;
}
- // FIXME: extend timeout for SET_DEVICE_CONNECTION_STATE and HANDLE_DEVICE_CONFIG_CHANGE
- // while we investigate why BT A2DP device connection/disconnection can sometimes
- // take more than 5 seconds
- uint32_t timeoutMs = TimeCheck::kDefaultTimeOutMs;
- switch (code) {
- case SET_DEVICE_CONNECTION_STATE:
- case HANDLE_DEVICE_CONFIG_CHANGE:
- timeoutMs *= 2;
- break;
- default:
- break;
- }
-
- TimeCheck check("IAudioPolicyService", timeoutMs);
+ TimeCheck check("IAudioPolicyService");
switch (code) {
case SET_DEVICE_CONNECTION_STATE: {
diff --git a/media/libaudioprocessing/AudioMixer.cpp b/media/libaudioprocessing/AudioMixer.cpp
index 93ed5f2..045c2c3 100644
--- a/media/libaudioprocessing/AudioMixer.cpp
+++ b/media/libaudioprocessing/AudioMixer.cpp
@@ -204,15 +204,14 @@
// channel masks have changed, does this track need a downmixer?
// update to try using our desired format (if we aren't already using it)
- const audio_format_t prevDownmixerFormat = track->mDownmixRequiresFormat;
const status_t status = track->prepareForDownmix();
ALOGE_IF(status != OK,
"prepareForDownmix error %d, track channel mask %#x, mixer channel mask %#x",
status, track->channelMask, track->mMixerChannelMask);
- if (prevDownmixerFormat != track->mDownmixRequiresFormat) {
- track->prepareForReformat(); // because of downmixer, track format may change!
- }
+ // always do reformat since channel mask changed,
+ // do it after downmix since track format may change!
+ track->prepareForReformat();
if (track->mResampler.get() != nullptr && mixerChannelCountChanged) {
// resampler channels may have changed.
diff --git a/media/libheif/HeifDecoderImpl.cpp b/media/libheif/HeifDecoderImpl.cpp
index 8dae251..01f014f 100644
--- a/media/libheif/HeifDecoderImpl.cpp
+++ b/media/libheif/HeifDecoderImpl.cpp
@@ -271,17 +271,43 @@
/////////////////////////////////////////////////////////////////////////
+struct HeifDecoderImpl::DecodeThread : public Thread {
+ explicit DecodeThread(HeifDecoderImpl *decoder) : mDecoder(decoder) {}
+
+private:
+ HeifDecoderImpl* mDecoder;
+
+ bool threadLoop();
+
+ DISALLOW_EVIL_CONSTRUCTORS(DecodeThread);
+};
+
+bool HeifDecoderImpl::DecodeThread::threadLoop() {
+ return mDecoder->decodeAsync();
+}
+
+/////////////////////////////////////////////////////////////////////////
+
HeifDecoderImpl::HeifDecoderImpl() :
// output color format should always be set via setOutputColor(), in case
// it's not, default to HAL_PIXEL_FORMAT_RGB_565.
mOutputColor(HAL_PIXEL_FORMAT_RGB_565),
mCurScanline(0),
+ mWidth(0),
+ mHeight(0),
mFrameDecoded(false),
mHasImage(false),
- mHasVideo(false) {
+ mHasVideo(false),
+ mAvailableLines(0),
+ mNumSlices(1),
+ mSliceHeight(0),
+ mAsyncDecodeDone(false) {
}
HeifDecoderImpl::~HeifDecoderImpl() {
+ if (mThread != nullptr) {
+ mThread->join();
+ }
}
bool HeifDecoderImpl::init(HeifStream* stream, HeifFrameInfo* frameInfo) {
@@ -310,22 +336,23 @@
mHasImage = hasImage && !strcasecmp(hasImage, "yes");
mHasVideo = hasVideo && !strcasecmp(hasVideo, "yes");
+ sp<IMemory> sharedMem;
if (mHasImage) {
// image index < 0 to retrieve primary image
- mFrameMemory = mRetriever->getImageAtIndex(
+ sharedMem = mRetriever->getImageAtIndex(
-1, mOutputColor, true /*metaOnly*/);
} else if (mHasVideo) {
- mFrameMemory = mRetriever->getFrameAtTime(0,
+ sharedMem = mRetriever->getFrameAtTime(0,
MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC,
mOutputColor, true /*metaOnly*/);
}
- if (mFrameMemory == nullptr || mFrameMemory->pointer() == nullptr) {
+ if (sharedMem == nullptr || sharedMem->pointer() == nullptr) {
ALOGE("getFrameAtTime: videoFrame is a nullptr");
return false;
}
- VideoFrame* videoFrame = static_cast<VideoFrame*>(mFrameMemory->pointer());
+ VideoFrame* videoFrame = static_cast<VideoFrame*>(sharedMem->pointer());
ALOGV("Meta dimension %dx%d, display %dx%d, angle %d, iccSize %d",
videoFrame->mWidth,
@@ -344,6 +371,14 @@
videoFrame->mIccSize,
videoFrame->getFlattenedIccData());
}
+ mWidth = videoFrame->mWidth;
+ mHeight = videoFrame->mHeight;
+ if (mHasImage && videoFrame->mTileHeight >= 512 && mWidth >= 3000 && mHeight >= 2000 ) {
+ // Try decoding in slices only if the image has tiles and is big enough.
+ mSliceHeight = videoFrame->mTileHeight;
+ mNumSlices = (videoFrame->mHeight + mSliceHeight - 1) / mSliceHeight;
+ ALOGV("mSliceHeight %u, mNumSlices %zu", mSliceHeight, mNumSlices);
+ }
return true;
}
@@ -376,6 +411,36 @@
return false;
}
+bool HeifDecoderImpl::decodeAsync() {
+ for (size_t i = 1; i < mNumSlices; i++) {
+ ALOGV("decodeAsync(): decoding slice %zu", i);
+ size_t top = i * mSliceHeight;
+ size_t bottom = (i + 1) * mSliceHeight;
+ if (bottom > mHeight) {
+ bottom = mHeight;
+ }
+ sp<IMemory> frameMemory = mRetriever->getImageRectAtIndex(
+ -1, mOutputColor, 0, top, mWidth, bottom);
+ {
+ Mutex::Autolock autolock(mLock);
+
+ if (frameMemory == nullptr || frameMemory->pointer() == nullptr) {
+ mAsyncDecodeDone = true;
+ mScanlineReady.signal();
+ break;
+ }
+ mFrameMemory = frameMemory;
+ mAvailableLines = bottom;
+ ALOGV("decodeAsync(): available lines %zu", mAvailableLines);
+ mScanlineReady.signal();
+ }
+ }
+ // Aggressive clear to avoid holding on to resources
+ mRetriever.clear();
+ mDataSource.clear();
+ return false;
+}
+
bool HeifDecoderImpl::decode(HeifFrameInfo* frameInfo) {
// reset scanline pointer
mCurScanline = 0;
@@ -384,6 +449,47 @@
return true;
}
+ // See if we want to decode in slices to allow client to start
+ // scanline processing in parallel with decode. If this fails
+ // we fallback to decoding the full frame.
+ if (mHasImage && mNumSlices > 1) {
+ // get first slice and metadata
+ sp<IMemory> frameMemory = mRetriever->getImageRectAtIndex(
+ -1, mOutputColor, 0, 0, mWidth, mSliceHeight);
+
+ if (frameMemory == nullptr || frameMemory->pointer() == nullptr) {
+ ALOGE("decode: metadata is a nullptr");
+ return false;
+ }
+
+ VideoFrame* videoFrame = static_cast<VideoFrame*>(frameMemory->pointer());
+
+ if (frameInfo != nullptr) {
+ frameInfo->set(
+ videoFrame->mWidth,
+ videoFrame->mHeight,
+ videoFrame->mRotationAngle,
+ videoFrame->mBytesPerPixel,
+ videoFrame->mIccSize,
+ videoFrame->getFlattenedIccData());
+ }
+
+ mFrameMemory = frameMemory;
+ mAvailableLines = mSliceHeight;
+ mThread = new DecodeThread(this);
+ if (mThread->run("HeifDecode", ANDROID_PRIORITY_FOREGROUND) == OK) {
+ mFrameDecoded = true;
+ return true;
+ }
+
+ // Fallback to decode without slicing
+ mThread.clear();
+ mNumSlices = 1;
+ mSliceHeight = 0;
+ mAvailableLines = 0;
+ mFrameMemory.clear();
+ }
+
if (mHasImage) {
// image index < 0 to retrieve primary image
mFrameMemory = mRetriever->getImageAtIndex(-1, mOutputColor);
@@ -393,14 +499,14 @@
}
if (mFrameMemory == nullptr || mFrameMemory->pointer() == nullptr) {
- ALOGE("getFrameAtTime: videoFrame is a nullptr");
+ ALOGE("decode: videoFrame is a nullptr");
return false;
}
VideoFrame* videoFrame = static_cast<VideoFrame*>(mFrameMemory->pointer());
if (videoFrame->mSize == 0 ||
mFrameMemory->size() < videoFrame->getFlattenedSize()) {
- ALOGE("getFrameAtTime: videoFrame size is invalid");
+ ALOGE("decode: videoFrame size is invalid");
return false;
}
@@ -424,36 +530,45 @@
}
mFrameDecoded = true;
- // Aggressive clear to avoid holding on to resources
+ // Aggressively clear to avoid holding on to resources
mRetriever.clear();
mDataSource.clear();
return true;
}
-bool HeifDecoderImpl::getScanline(uint8_t* dst) {
+bool HeifDecoderImpl::getScanlineInner(uint8_t* dst) {
if (mFrameMemory == nullptr || mFrameMemory->pointer() == nullptr) {
return false;
}
VideoFrame* videoFrame = static_cast<VideoFrame*>(mFrameMemory->pointer());
- if (mCurScanline >= videoFrame->mHeight) {
- ALOGE("no more scanline available");
- return false;
- }
uint8_t* src = videoFrame->getFlattenedData() + videoFrame->mRowBytes * mCurScanline++;
memcpy(dst, src, videoFrame->mBytesPerPixel * videoFrame->mWidth);
return true;
}
-size_t HeifDecoderImpl::skipScanlines(size_t count) {
- if (mFrameMemory == nullptr || mFrameMemory->pointer() == nullptr) {
- return 0;
+bool HeifDecoderImpl::getScanline(uint8_t* dst) {
+ if (mCurScanline >= mHeight) {
+ ALOGE("no more scanline available");
+ return false;
}
- VideoFrame* videoFrame = static_cast<VideoFrame*>(mFrameMemory->pointer());
+ if (mNumSlices > 1) {
+ Mutex::Autolock autolock(mLock);
+
+ while (!mAsyncDecodeDone && mCurScanline >= mAvailableLines) {
+ mScanlineReady.wait(mLock);
+ }
+ return (mCurScanline < mAvailableLines) ? getScanlineInner(dst) : false;
+ }
+
+ return getScanlineInner(dst);
+}
+
+size_t HeifDecoderImpl::skipScanlines(size_t count) {
uint32_t oldScanline = mCurScanline;
mCurScanline += count;
- if (mCurScanline > videoFrame->mHeight) {
- mCurScanline = videoFrame->mHeight;
+ if (mCurScanline > mHeight) {
+ mCurScanline = mHeight;
}
return (mCurScanline > oldScanline) ? (mCurScanline - oldScanline) : 0;
}
diff --git a/media/libheif/HeifDecoderImpl.h b/media/libheif/HeifDecoderImpl.h
index 406c2c1..528ee3b 100644
--- a/media/libheif/HeifDecoderImpl.h
+++ b/media/libheif/HeifDecoderImpl.h
@@ -19,6 +19,8 @@
#include "include/HeifDecoderAPI.h"
#include <system/graphics.h>
+#include <utils/Condition.h>
+#include <utils/Mutex.h>
#include <utils/RefBase.h>
namespace android {
@@ -49,14 +51,30 @@
size_t skipScanlines(size_t count) override;
private:
+ struct DecodeThread;
+
sp<IDataSource> mDataSource;
sp<MediaMetadataRetriever> mRetriever;
sp<IMemory> mFrameMemory;
android_pixel_format_t mOutputColor;
size_t mCurScanline;
+ uint32_t mWidth;
+ uint32_t mHeight;
bool mFrameDecoded;
bool mHasImage;
bool mHasVideo;
+
+ // Slice decoding only
+ Mutex mLock;
+ Condition mScanlineReady;
+ sp<DecodeThread> mThread;
+ size_t mAvailableLines;
+ size_t mNumSlices;
+ uint32_t mSliceHeight;
+ bool mAsyncDecodeDone;
+
+ bool decodeAsync();
+ bool getScanlineInner(uint8_t* dst);
};
} // namespace android
diff --git a/media/libmedia/IMediaMetadataRetriever.cpp b/media/libmedia/IMediaMetadataRetriever.cpp
index 214117b..590ba1a 100644
--- a/media/libmedia/IMediaMetadataRetriever.cpp
+++ b/media/libmedia/IMediaMetadataRetriever.cpp
@@ -69,6 +69,7 @@
SET_DATA_SOURCE_CALLBACK,
GET_FRAME_AT_TIME,
GET_IMAGE_AT_INDEX,
+ GET_IMAGE_RECT_AT_INDEX,
GET_FRAME_AT_INDEX,
EXTRACT_ALBUM_ART,
EXTRACT_METADATA,
@@ -187,6 +188,30 @@
return interface_cast<IMemory>(reply.readStrongBinder());
}
+ sp<IMemory> getImageRectAtIndex(
+ int index, int colorFormat, int left, int top, int right, int bottom)
+ {
+ ALOGV("getImageRectAtIndex: index %d, colorFormat(%d) rect {%d, %d, %d, %d}",
+ index, colorFormat, left, top, right, bottom);
+ Parcel data, reply;
+ data.writeInterfaceToken(IMediaMetadataRetriever::getInterfaceDescriptor());
+ data.writeInt32(index);
+ data.writeInt32(colorFormat);
+ data.writeInt32(left);
+ data.writeInt32(top);
+ data.writeInt32(right);
+ data.writeInt32(bottom);
+#ifndef DISABLE_GROUP_SCHEDULE_HACK
+ sendSchedPolicy(data);
+#endif
+ remote()->transact(GET_IMAGE_RECT_AT_INDEX, data, &reply);
+ status_t ret = reply.readInt32();
+ if (ret != NO_ERROR) {
+ return NULL;
+ }
+ return interface_cast<IMemory>(reply.readStrongBinder());
+ }
+
status_t getFrameAtIndex(std::vector<sp<IMemory> > *frames,
int frameIndex, int numFrames, int colorFormat, bool metaOnly)
{
@@ -375,6 +400,34 @@
#endif
return NO_ERROR;
} break;
+
+ case GET_IMAGE_RECT_AT_INDEX: {
+ CHECK_INTERFACE(IMediaMetadataRetriever, data, reply);
+ int index = data.readInt32();
+ int colorFormat = data.readInt32();
+ int left = data.readInt32();
+ int top = data.readInt32();
+ int right = data.readInt32();
+ int bottom = data.readInt32();
+ ALOGV("getImageRectAtIndex: index(%d), colorFormat(%d), rect {%d, %d, %d, %d}",
+ index, colorFormat, left, top, right, bottom);
+#ifndef DISABLE_GROUP_SCHEDULE_HACK
+ setSchedPolicy(data);
+#endif
+ sp<IMemory> bitmap = getImageRectAtIndex(
+ index, colorFormat, left, top, right, bottom);
+ if (bitmap != 0) { // Don't send NULL across the binder interface
+ reply->writeInt32(NO_ERROR);
+ reply->writeStrongBinder(IInterface::asBinder(bitmap));
+ } else {
+ reply->writeInt32(UNKNOWN_ERROR);
+ }
+#ifndef DISABLE_GROUP_SCHEDULE_HACK
+ restoreSchedPolicy();
+#endif
+ return NO_ERROR;
+ } break;
+
case GET_FRAME_AT_INDEX: {
CHECK_INTERFACE(IMediaMetadataRetriever, data, reply);
int frameIndex = data.readInt32();
diff --git a/media/libmedia/include/media/CryptoHal.h b/media/libmedia/include/media/CryptoHal.h
index 4414e9d..ff8789d 100644
--- a/media/libmedia/include/media/CryptoHal.h
+++ b/media/libmedia/include/media/CryptoHal.h
@@ -81,7 +81,20 @@
*/
status_t mInitCheck;
- KeyedVector<int32_t, uint32_t> mHeapBases;
+ struct HeapBase {
+ HeapBase() : mBufferId(0), mSize(0) {}
+ HeapBase(uint32_t bufferId, size_t size) :
+ mBufferId(bufferId), mSize(size) {}
+
+ uint32_t getBufferId() const {return mBufferId;}
+ size_t getSize() const {return mSize;}
+
+ private:
+ uint32_t mBufferId;
+ size_t mSize;
+ };
+
+ KeyedVector<int32_t, HeapBase> mHeapBases;
uint32_t mNextBufferId;
int32_t mHeapSeqNum;
diff --git a/media/libmedia/include/media/IMediaMetadataRetriever.h b/media/libmedia/include/media/IMediaMetadataRetriever.h
index 1a04552..c6f422d 100644
--- a/media/libmedia/include/media/IMediaMetadataRetriever.h
+++ b/media/libmedia/include/media/IMediaMetadataRetriever.h
@@ -46,6 +46,8 @@
int64_t timeUs, int option, int colorFormat, bool metaOnly) = 0;
virtual sp<IMemory> getImageAtIndex(
int index, int colorFormat, bool metaOnly, bool thumbnail) = 0;
+ virtual sp<IMemory> getImageRectAtIndex(
+ int index, int colorFormat, int left, int top, int right, int bottom) = 0;
virtual status_t getFrameAtIndex(
std::vector<sp<IMemory> > *frames,
int frameIndex, int numFrames, int colorFormat, bool metaOnly) = 0;
diff --git a/media/libmedia/include/media/MediaMetadataRetrieverInterface.h b/media/libmedia/include/media/MediaMetadataRetrieverInterface.h
index 992e230..98d300f 100644
--- a/media/libmedia/include/media/MediaMetadataRetrieverInterface.h
+++ b/media/libmedia/include/media/MediaMetadataRetrieverInterface.h
@@ -47,6 +47,8 @@
int64_t timeUs, int option, int colorFormat, bool metaOnly) = 0;
virtual sp<IMemory> getImageAtIndex(
int index, int colorFormat, bool metaOnly, bool thumbnail) = 0;
+ virtual sp<IMemory> getImageRectAtIndex(
+ int index, int colorFormat, int left, int top, int right, int bottom) = 0;
virtual status_t getFrameAtIndex(
std::vector<sp<IMemory> >* frames,
int frameIndex, int numFrames, int colorFormat, bool metaOnly) = 0;
@@ -54,27 +56,6 @@
virtual const char* extractMetadata(int keyCode) = 0;
};
-// MediaMetadataRetrieverInterface
-class MediaMetadataRetrieverInterface : public MediaMetadataRetrieverBase
-{
-public:
- MediaMetadataRetrieverInterface() {}
-
- virtual ~MediaMetadataRetrieverInterface() {}
- virtual sp<IMemory> getFrameAtTime(
- int64_t /*timeUs*/, int /*option*/, int /*colorFormat*/, bool /*metaOnly*/)
- { return NULL; }
- virtual sp<IMemory> getImageAtIndex(
- int /*index*/, int /*colorFormat*/, bool /*metaOnly*/, bool /*thumbnail*/)
- { return NULL; }
- virtual status_t getFrameAtIndex(
- std::vector<sp<IMemory> >* /*frames*/,
- int /*frameIndex*/, int /*numFrames*/, int /*colorFormat*/, bool /*metaOnly*/)
- { return ERROR_UNSUPPORTED; }
- virtual MediaAlbumArt* extractAlbumArt() { return NULL; }
- virtual const char* extractMetadata(int /*keyCode*/) { return NULL; }
-};
-
}; // namespace android
#endif // ANDROID_MEDIAMETADATARETRIEVERINTERFACE_H
diff --git a/media/libmedia/include/media/mediametadataretriever.h b/media/libmedia/include/media/mediametadataretriever.h
index 4cdeeb7..cdef637 100644
--- a/media/libmedia/include/media/mediametadataretriever.h
+++ b/media/libmedia/include/media/mediametadataretriever.h
@@ -91,6 +91,8 @@
int colorFormat = HAL_PIXEL_FORMAT_RGB_565, bool metaOnly = false);
sp<IMemory> getImageAtIndex(int index,
int colorFormat = HAL_PIXEL_FORMAT_RGB_565, bool metaOnly = false, bool thumbnail = false);
+ sp<IMemory> getImageRectAtIndex(
+ int index, int colorFormat, int left, int top, int right, int bottom);
status_t getFrameAtIndex(
std::vector<sp<IMemory> > *frames, int frameIndex, int numFrames = 1,
int colorFormat = HAL_PIXEL_FORMAT_RGB_565, bool metaOnly = false);
diff --git a/media/libmedia/mediametadataretriever.cpp b/media/libmedia/mediametadataretriever.cpp
index c10a907..e61b04d 100644
--- a/media/libmedia/mediametadataretriever.cpp
+++ b/media/libmedia/mediametadataretriever.cpp
@@ -166,6 +166,19 @@
return mRetriever->getImageAtIndex(index, colorFormat, metaOnly, thumbnail);
}
+sp<IMemory> MediaMetadataRetriever::getImageRectAtIndex(
+ int index, int colorFormat, int left, int top, int right, int bottom) {
+ ALOGV("getImageRectAtIndex: index(%d) colorFormat(%d) rect {%d, %d, %d, %d}",
+ index, colorFormat, left, top, right, bottom);
+ Mutex::Autolock _l(mLock);
+ if (mRetriever == 0) {
+ ALOGE("retriever is not initialized");
+ return NULL;
+ }
+ return mRetriever->getImageRectAtIndex(
+ index, colorFormat, left, top, right, bottom);
+}
+
status_t MediaMetadataRetriever::getFrameAtIndex(
std::vector<sp<IMemory> > *frames,
int frameIndex, int numFrames, int colorFormat, bool metaOnly) {
diff --git a/media/libmediaextractor/MediaBuffer.cpp b/media/libmediaextractor/MediaBuffer.cpp
index 39f8d6e..d197b3f 100644
--- a/media/libmediaextractor/MediaBuffer.cpp
+++ b/media/libmediaextractor/MediaBuffer.cpp
@@ -39,7 +39,7 @@
mRangeOffset(0),
mRangeLength(size),
mOwnsData(false),
- mMetaData(new MetaData),
+ mMetaData(new MetaDataBase),
mOriginal(NULL) {
}
@@ -51,7 +51,7 @@
mRangeOffset(0),
mRangeLength(size),
mOwnsData(true),
- mMetaData(new MetaData),
+ mMetaData(new MetaDataBase),
mOriginal(NULL) {
if (size < kSharedMemThreshold
|| std::atomic_load_explicit(&mUseSharedMemory, std::memory_order_seq_cst) == 0) {
@@ -84,7 +84,7 @@
mRangeLength(mSize),
mBuffer(buffer),
mOwnsData(false),
- mMetaData(new MetaData),
+ mMetaData(new MetaDataBase),
mOriginal(NULL) {
}
@@ -96,7 +96,7 @@
return;
}
- int prevCount = __sync_fetch_and_sub(&mRefCount, 1);
+ int prevCount = mRefCount.fetch_sub(1);
if (prevCount == 1) {
if (mObserver == NULL) {
delete this;
@@ -110,13 +110,13 @@
void MediaBuffer::claim() {
CHECK(mObserver != NULL);
- CHECK_EQ(mRefCount, 1);
+ CHECK_EQ(mRefCount.load(std::memory_order_relaxed), 1);
- mRefCount = 0;
+ mRefCount.store(0, std::memory_order_relaxed);
}
void MediaBuffer::add_ref() {
- (void) __sync_fetch_and_add(&mRefCount, 1);
+ (void) mRefCount.fetch_add(1);
}
void *MediaBuffer::data() const {
diff --git a/media/libmediaextractor/include/media/stagefright/MediaBuffer.h b/media/libmediaextractor/include/media/stagefright/MediaBuffer.h
index f944d51..5a25965 100644
--- a/media/libmediaextractor/include/media/stagefright/MediaBuffer.h
+++ b/media/libmediaextractor/include/media/stagefright/MediaBuffer.h
@@ -86,12 +86,14 @@
virtual MediaBufferBase *clone();
// sum of localRefcount() and remoteRefcount()
+ // Result should be treated as approximate unless the result precludes concurrent accesses.
virtual int refcount() const {
return localRefcount() + remoteRefcount();
}
+ // Result should be treated as approximate unless the result precludes concurrent accesses.
virtual int localRefcount() const {
- return mRefCount;
+ return mRefCount.load(std::memory_order_relaxed);
}
virtual int remoteRefcount() const {
@@ -146,7 +148,7 @@
void claim();
MediaBufferObserver *mObserver;
- int mRefCount;
+ std::atomic<int> mRefCount;
void *mData;
size_t mSize, mRangeOffset, mRangeLength;
diff --git a/media/libmediametrics/MediaAnalyticsItem.cpp b/media/libmediametrics/MediaAnalyticsItem.cpp
index dc2bec8..135c9b6 100644
--- a/media/libmediametrics/MediaAnalyticsItem.cpp
+++ b/media/libmediametrics/MediaAnalyticsItem.cpp
@@ -248,12 +248,17 @@
}
void MediaAnalyticsItem::Prop::setName(const char *name, size_t len) {
- mNameLen = len;
+ free((void *)mName);
mName = (const char *) malloc(len+1);
+ LOG_ALWAYS_FATAL_IF(mName == NULL,
+ "failed malloc() for property '%s' (len %zu)",
+ name, len);
memcpy ((void *)mName, name, len+1);
+ mNameLen = len;
}
-// used only as part of a storing operation
+// consider this "find-or-allocate".
+// caller validates type and uses clearPropValue() accordingly
MediaAnalyticsItem::Prop *MediaAnalyticsItem::allocateProp(const char *name) {
size_t len = strlen(name);
size_t i = findPropIndex(name, len);
@@ -271,7 +276,6 @@
i = mPropCount++;
prop = &mProps[i];
prop->setName(name, len);
- prop->mType = kTypeNone; // make caller set type info
}
return prop;
@@ -299,6 +303,7 @@
void MediaAnalyticsItem::setInt32(MediaAnalyticsItem::Attr name, int32_t value) {
Prop *prop = allocateProp(name);
if (prop != NULL) {
+ clearPropValue(prop);
prop->mType = kTypeInt32;
prop->u.int32Value = value;
}
@@ -307,6 +312,7 @@
void MediaAnalyticsItem::setInt64(MediaAnalyticsItem::Attr name, int64_t value) {
Prop *prop = allocateProp(name);
if (prop != NULL) {
+ clearPropValue(prop);
prop->mType = kTypeInt64;
prop->u.int64Value = value;
}
@@ -315,6 +321,7 @@
void MediaAnalyticsItem::setDouble(MediaAnalyticsItem::Attr name, double value) {
Prop *prop = allocateProp(name);
if (prop != NULL) {
+ clearPropValue(prop);
prop->mType = kTypeDouble;
prop->u.doubleValue = value;
}
@@ -325,6 +332,7 @@
Prop *prop = allocateProp(name);
// any old value will be gone
if (prop != NULL) {
+ clearPropValue(prop);
prop->mType = kTypeCString;
prop->u.CStringValue = strdup(value);
}
@@ -333,6 +341,7 @@
void MediaAnalyticsItem::setRate(MediaAnalyticsItem::Attr name, int64_t count, int64_t duration) {
Prop *prop = allocateProp(name);
if (prop != NULL) {
+ clearPropValue(prop);
prop->mType = kTypeRate;
prop->u.rate.count = count;
prop->u.rate.duration = duration;
@@ -585,6 +594,9 @@
// fix any pointers that we blindly copied, so we have our own copies
if (dst->mName) {
void *p = malloc(dst->mNameLen + 1);
+ LOG_ALWAYS_FATAL_IF(p == NULL,
+ "failed malloc() duping property '%s' (len %zu)",
+ dst->mName, dst->mNameLen);
memcpy (p, src->mName, dst->mNameLen + 1);
dst->mName = (const char *) p;
}
diff --git a/media/libmediaplayer2/nuplayer2/Android.bp b/media/libmediaplayer2/nuplayer2/Android.bp
index c40b361..1634f35 100644
--- a/media/libmediaplayer2/nuplayer2/Android.bp
+++ b/media/libmediaplayer2/nuplayer2/Android.bp
@@ -58,8 +58,6 @@
name: "libstagefright_nuplayer2",
- tags: ["eng"],
-
sanitize: {
cfi: true,
diag: {
diff --git a/media/libmediaplayerservice/MetadataRetrieverClient.cpp b/media/libmediaplayerservice/MetadataRetrieverClient.cpp
index fa41c06..40b17bf 100644
--- a/media/libmediaplayerservice/MetadataRetrieverClient.cpp
+++ b/media/libmediaplayerservice/MetadataRetrieverClient.cpp
@@ -213,7 +213,7 @@
sp<IMemory> MetadataRetrieverClient::getImageAtIndex(
int index, int colorFormat, bool metaOnly, bool thumbnail) {
- ALOGV("getFrameAtTime: index(%d) colorFormat(%d), metaOnly(%d) thumbnail(%d)",
+ ALOGV("getImageAtIndex: index(%d) colorFormat(%d), metaOnly(%d) thumbnail(%d)",
index, colorFormat, metaOnly, thumbnail);
Mutex::Autolock lock(mLock);
Mutex::Autolock glock(sLock);
@@ -229,6 +229,25 @@
return frame;
}
+sp<IMemory> MetadataRetrieverClient::getImageRectAtIndex(
+ int index, int colorFormat, int left, int top, int right, int bottom) {
+ ALOGV("getImageRectAtIndex: index(%d) colorFormat(%d), rect {%d, %d, %d, %d}",
+ index, colorFormat, left, top, right, bottom);
+ Mutex::Autolock lock(mLock);
+ Mutex::Autolock glock(sLock);
+ if (mRetriever == NULL) {
+ ALOGE("retriever is not initialized");
+ return NULL;
+ }
+ sp<IMemory> frame = mRetriever->getImageRectAtIndex(
+ index, colorFormat, left, top, right, bottom);
+ if (frame == NULL) {
+ ALOGE("failed to extract image");
+ return NULL;
+ }
+ return frame;
+}
+
status_t MetadataRetrieverClient::getFrameAtIndex(
std::vector<sp<IMemory> > *frames,
int frameIndex, int numFrames, int colorFormat, bool metaOnly) {
diff --git a/media/libmediaplayerservice/MetadataRetrieverClient.h b/media/libmediaplayerservice/MetadataRetrieverClient.h
index 63ba44a..272d093 100644
--- a/media/libmediaplayerservice/MetadataRetrieverClient.h
+++ b/media/libmediaplayerservice/MetadataRetrieverClient.h
@@ -54,6 +54,8 @@
int64_t timeUs, int option, int colorFormat, bool metaOnly);
virtual sp<IMemory> getImageAtIndex(
int index, int colorFormat, bool metaOnly, bool thumbnail);
+ virtual sp<IMemory> getImageRectAtIndex(
+ int index, int colorFormat, int left, int top, int right, int bottom);
virtual status_t getFrameAtIndex(
std::vector<sp<IMemory> > *frames,
int frameIndex, int numFrames, int colorFormat, bool metaOnly);
diff --git a/media/libmediaplayerservice/nuplayer/Android.bp b/media/libmediaplayerservice/nuplayer/Android.bp
index 645bb7a..a4da564 100644
--- a/media/libmediaplayerservice/nuplayer/Android.bp
+++ b/media/libmediaplayerservice/nuplayer/Android.bp
@@ -54,8 +54,6 @@
name: "libstagefright_nuplayer",
- tags: ["eng"],
-
sanitize: {
cfi: true,
diag: {
diff --git a/media/libmediaplayerservice/tests/Android.bp b/media/libmediaplayerservice/tests/Android.bp
index e936bdd..e86b68a 100644
--- a/media/libmediaplayerservice/tests/Android.bp
+++ b/media/libmediaplayerservice/tests/Android.bp
@@ -2,8 +2,6 @@
name: "DrmSessionManager_test",
- tags: ["tests"],
-
srcs: ["DrmSessionManager_test.cpp"],
shared_libs: [
diff --git a/media/libstagefright/Android.bp b/media/libstagefright/Android.bp
index 22b1e59..48e351b 100644
--- a/media/libstagefright/Android.bp
+++ b/media/libstagefright/Android.bp
@@ -162,7 +162,6 @@
"libmedia_helper",
"libstagefright_codecbase",
"libstagefright_foundation",
- "libstagefright_omx",
"libstagefright_omx_utils",
"libstagefright_xmlparser",
"libRScpp",
diff --git a/media/libstagefright/FrameDecoder.cpp b/media/libstagefright/FrameDecoder.cpp
index e2605ca..29a219f 100644
--- a/media/libstagefright/FrameDecoder.cpp
+++ b/media/libstagefright/FrameDecoder.cpp
@@ -43,7 +43,8 @@
static const size_t kRetryCount = 50; // must be >0
sp<IMemory> allocVideoFrame(const sp<MetaData>& trackMeta,
- int32_t width, int32_t height, int32_t dstBpp, bool metaOnly = false) {
+ int32_t width, int32_t height, int32_t tileWidth, int32_t tileHeight,
+ int32_t dstBpp, bool metaOnly = false) {
int32_t rotationAngle;
if (!trackMeta->findInt32(kKeyRotation, &rotationAngle)) {
rotationAngle = 0; // By default, no rotation
@@ -74,7 +75,7 @@
}
VideoFrame frame(width, height, displayWidth, displayHeight,
- rotationAngle, dstBpp, !metaOnly, iccSize);
+ tileWidth, tileHeight, rotationAngle, dstBpp, !metaOnly, iccSize);
size_t size = frame.getFlattenedSize();
sp<MemoryHeapBase> heap = new MemoryHeapBase(size, 0, "MetadataRetrieverClient");
@@ -155,7 +156,7 @@
return NULL;
}
- int32_t width, height;
+ int32_t width, height, tileWidth = 0, tileHeight = 0;
if (thumbnail) {
if (!findThumbnailInfo(trackMeta, &width, &height)) {
return NULL;
@@ -163,8 +164,14 @@
} else {
CHECK(trackMeta->findInt32(kKeyWidth, &width));
CHECK(trackMeta->findInt32(kKeyHeight, &height));
+
+ int32_t gridRows, gridCols;
+ if (!findGridInfo(trackMeta, &tileWidth, &tileHeight, &gridRows, &gridCols)) {
+ tileWidth = tileHeight = 0;
+ }
}
- return allocVideoFrame(trackMeta, width, height, dstBpp, true /*metaOnly*/);
+ return allocVideoFrame(trackMeta,
+ width, height, tileWidth, tileHeight, dstBpp, true /*metaOnly*/);
}
FrameDecoder::FrameDecoder(
@@ -237,8 +244,11 @@
return OK;
}
-sp<IMemory> FrameDecoder::extractFrame() {
- status_t err = extractInternal();
+sp<IMemory> FrameDecoder::extractFrame(FrameRect *rect) {
+ status_t err = onExtractRect(rect);
+ if (err == OK) {
+ err = extractInternal();
+ }
if (err != OK) {
return NULL;
}
@@ -503,6 +513,8 @@
trackMeta(),
(crop_right - crop_left + 1),
(crop_bottom - crop_top + 1),
+ 0,
+ 0,
dstBpp());
addFrame(frameMem);
VideoFrame* frame = static_cast<VideoFrame*>(frameMem->pointer());
@@ -541,7 +553,10 @@
mHeight(0),
mGridRows(1),
mGridCols(1),
- mTilesDecoded(0) {
+ mTileWidth(0),
+ mTileHeight(0),
+ mTilesDecoded(0),
+ mTargetTiles(0) {
}
sp<AMessage> ImageDecoder::onGetFormatAndSeekOptions(
@@ -585,10 +600,12 @@
overrideMeta = new MetaData(*(trackMeta()));
overrideMeta->setInt32(kKeyWidth, tileWidth);
overrideMeta->setInt32(kKeyHeight, tileHeight);
+ mTileWidth = tileWidth;
+ mTileHeight = tileHeight;
mGridCols = gridCols;
mGridRows = gridRows;
} else {
- ALOGE("ignore bad grid: %dx%d, tile size: %dx%d, picture size: %dx%d",
+ ALOGW("ignore bad grid: %dx%d, tile size: %dx%d, picture size: %dx%d",
gridCols, gridRows, tileWidth, tileHeight, mWidth, mHeight);
}
}
@@ -596,6 +613,7 @@
overrideMeta = trackMeta();
}
}
+ mTargetTiles = mGridCols * mGridRows;
sp<AMessage> videoFormat;
if (convertMetaDataToMessage(overrideMeta, &videoFormat) != OK) {
@@ -614,6 +632,45 @@
return videoFormat;
}
+status_t ImageDecoder::onExtractRect(FrameRect *rect) {
+ // TODO:
+ // This callback is for verifying whether we can decode the rect,
+ // and if so, set up the internal variables for decoding.
+ // Currently, rect decoding is restricted to sequentially decoding one
+ // row of tiles at a time. We can't decode arbitrary rects, as the image
+ // track doesn't yet support seeking by tiles. So all we do here is to
+ // verify the rect against what we expect.
+ // When seeking by tile is supported, this code should be updated to
+ // set the seek parameters.
+ if (rect == NULL) {
+ if (mTilesDecoded > 0) {
+ return ERROR_UNSUPPORTED;
+ }
+ mTargetTiles = mGridRows * mGridCols;
+ return OK;
+ }
+
+ if (mTileWidth <= 0 || mTileHeight <=0) {
+ return ERROR_UNSUPPORTED;
+ }
+
+ int32_t row = mTilesDecoded / mGridCols;
+ int32_t expectedTop = row * mTileHeight;
+ int32_t expectedBot = (row + 1) * mTileHeight;
+ if (expectedBot > mHeight) {
+ expectedBot = mHeight;
+ }
+ if (rect->left != 0 || rect->top != expectedTop
+ || rect->right != mWidth || rect->bottom != expectedBot) {
+ ALOGE("currently only support sequential decoding of slices");
+ return ERROR_UNSUPPORTED;
+ }
+
+ // advance one row
+ mTargetTiles = mTilesDecoded + mGridCols;
+ return OK;
+}
+
status_t ImageDecoder::onOutputReceived(
const sp<MediaCodecBuffer> &videoFrameBuffer,
const sp<AMessage> &outputFormat, int64_t /*timeUs*/, bool *done) {
@@ -626,7 +683,8 @@
CHECK(outputFormat->findInt32("height", &height));
if (mFrame == NULL) {
- sp<IMemory> frameMem = allocVideoFrame(trackMeta(), mWidth, mHeight, dstBpp());
+ sp<IMemory> frameMem = allocVideoFrame(
+ trackMeta(), mWidth, mHeight, mTileWidth, mTileHeight, dstBpp());
mFrame = static_cast<VideoFrame*>(frameMem->pointer());
addFrame(frameMem);
@@ -638,8 +696,6 @@
ColorConverter converter((OMX_COLOR_FORMATTYPE)srcFormat, dstFormat());
int32_t dstLeft, dstTop, dstRight, dstBottom;
- int32_t numTiles = mGridRows * mGridCols;
-
dstLeft = mTilesDecoded % mGridCols * width;
dstTop = mTilesDecoded / mGridCols * height;
dstRight = dstLeft + width - 1;
@@ -663,7 +719,7 @@
dstBottom = dstTop + crop_bottom;
}
- *done = (++mTilesDecoded >= numTiles);
+ *done = (++mTilesDecoded >= mTargetTiles);
if (converter.isValid()) {
converter.convert(
diff --git a/media/libstagefright/OmxInfoBuilder.cpp b/media/libstagefright/OmxInfoBuilder.cpp
index fe141ab..96b896b 100644
--- a/media/libstagefright/OmxInfoBuilder.cpp
+++ b/media/libstagefright/OmxInfoBuilder.cpp
@@ -108,24 +108,6 @@
if (!transStatus.isOk()) {
ALOGE("Fail to obtain codec roles from IOmxStore.");
return NO_INIT;
- } else if (roles.size() == 0) {
- ALOGW("IOmxStore has empty implementation. "
- "Creating a local default instance...");
- omxStore = new implementation::OmxStore();
- if (omxStore == nullptr) {
- ALOGE("Cannot create a local default instance.");
- return NO_INIT;
- }
- ALOGI("IOmxStore local default instance created.");
- transStatus = omxStore->listRoles(
- [&roles] (
- const hidl_vec<IOmxStore::RoleInfo>& inRoleList) {
- roles = inRoleList;
- });
- if (!transStatus.isOk()) {
- ALOGE("Fail to obtain codec roles from local IOmxStore.");
- return NO_INIT;
- }
}
hidl_vec<IOmxStore::ServiceAttribute> serviceAttributes;
diff --git a/media/libstagefright/StagefrightMetadataRetriever.cpp b/media/libstagefright/StagefrightMetadataRetriever.cpp
index e6c318c..e80ec3b 100644
--- a/media/libstagefright/StagefrightMetadataRetriever.cpp
+++ b/media/libstagefright/StagefrightMetadataRetriever.cpp
@@ -40,7 +40,8 @@
StagefrightMetadataRetriever::StagefrightMetadataRetriever()
: mParsedMetaData(false),
- mAlbumArt(NULL) {
+ mAlbumArt(NULL),
+ mLastImageIndex(-1) {
ALOGV("StagefrightMetadataRetriever()");
}
@@ -126,10 +127,30 @@
sp<IMemory> StagefrightMetadataRetriever::getImageAtIndex(
int index, int colorFormat, bool metaOnly, bool thumbnail) {
-
ALOGV("getImageAtIndex: index(%d) colorFormat(%d) metaOnly(%d) thumbnail(%d)",
index, colorFormat, metaOnly, thumbnail);
+ return getImageInternal(index, colorFormat, metaOnly, thumbnail, NULL);
+}
+
+sp<IMemory> StagefrightMetadataRetriever::getImageRectAtIndex(
+ int index, int colorFormat, int left, int top, int right, int bottom) {
+ ALOGV("getImageRectAtIndex: index(%d) colorFormat(%d) rect {%d, %d, %d, %d}",
+ index, colorFormat, left, top, right, bottom);
+
+ FrameRect rect = {left, top, right, bottom};
+
+ if (mImageDecoder != NULL && index == mLastImageIndex) {
+ return mImageDecoder->extractFrame(&rect);
+ }
+
+ return getImageInternal(
+ index, colorFormat, false /*metaOnly*/, false /*thumbnail*/, &rect);
+}
+
+sp<IMemory> StagefrightMetadataRetriever::getImageInternal(
+ int index, int colorFormat, bool metaOnly, bool thumbnail, FrameRect* rect) {
+
if (mExtractor.get() == NULL) {
ALOGE("no extractor.");
return NULL;
@@ -192,12 +213,17 @@
for (size_t i = 0; i < matchingCodecs.size(); ++i) {
const AString &componentName = matchingCodecs[i];
- ImageDecoder decoder(componentName, trackMeta, source);
+ sp<ImageDecoder> decoder = new ImageDecoder(componentName, trackMeta, source);
int64_t frameTimeUs = thumbnail ? -1 : 0;
- if (decoder.init(frameTimeUs, 1 /*numFrames*/, 0 /*option*/, colorFormat) == OK) {
- sp<IMemory> frame = decoder.extractFrame();
+ if (decoder->init(frameTimeUs, 1 /*numFrames*/, 0 /*option*/, colorFormat) == OK) {
+ sp<IMemory> frame = decoder->extractFrame(rect);
if (frame != NULL) {
+ if (rect != NULL) {
+ // keep the decoder if slice decoding
+ mImageDecoder = decoder;
+ mLastImageIndex = index;
+ }
return frame;
}
}
diff --git a/media/libstagefright/codecs/aacdec/SoftAAC2.cpp b/media/libstagefright/codecs/aacdec/SoftAAC2.cpp
index ecd2512..417ca55 100644
--- a/media/libstagefright/codecs/aacdec/SoftAAC2.cpp
+++ b/media/libstagefright/codecs/aacdec/SoftAAC2.cpp
@@ -45,7 +45,7 @@
#define PROP_DRC_OVERRIDE_BOOST "aac_drc_boost"
#define PROP_DRC_OVERRIDE_HEAVY "aac_drc_heavy"
#define PROP_DRC_OVERRIDE_ENC_LEVEL "aac_drc_enc_target_level"
-#define PROP_DRC_OVERRIDE_EFFECT "aac_drc_effect_type"
+#define PROP_DRC_OVERRIDE_EFFECT "ro.aac_drc_effect_type"
namespace android {
@@ -210,10 +210,8 @@
mDrcWrap.setParam(DRC_PRES_MODE_WRAP_ENCODER_TARGET, DRC_DEFAULT_MOBILE_ENC_LEVEL);
}
// AAC_UNIDRC_SET_EFFECT
- int32_t effectType = DRC_DEFAULT_MOBILE_DRC_EFFECT;
- // FIXME can't read default property for DRC effect type
- //int32_t effectType =
- // property_get_int32(PROP_DRC_OVERRIDE_EFFECT, DRC_DEFAULT_MOBILE_DRC_EFFECT);
+ int32_t effectType =
+ property_get_int32(PROP_DRC_OVERRIDE_EFFECT, DRC_DEFAULT_MOBILE_DRC_EFFECT);
if (effectType < -1 || effectType > 8) {
effectType = DRC_DEFAULT_MOBILE_DRC_EFFECT;
}
diff --git a/media/libstagefright/colorconversion/ColorConverter.cpp b/media/libstagefright/colorconversion/ColorConverter.cpp
index 1b38852..05f4104 100644
--- a/media/libstagefright/colorconversion/ColorConverter.cpp
+++ b/media/libstagefright/colorconversion/ColorConverter.cpp
@@ -25,7 +25,7 @@
#include "libyuv/convert_from.h"
#include "libyuv/video_common.h"
-
+#include <functional>
#include <sys/time.h>
#define USE_LIBYUV
@@ -58,14 +58,16 @@
bool ColorConverter::isValid() const {
switch (mSrcFormat) {
+ case OMX_COLOR_FormatYUV420Planar16:
+ if (mDstFormat == OMX_COLOR_FormatYUV444Y410) {
+ return true;
+ }
+ // fall-thru
case OMX_COLOR_FormatYUV420Planar:
return mDstFormat == OMX_COLOR_Format16bitRGB565
|| mDstFormat == OMX_COLOR_Format32BitRGBA8888
|| mDstFormat == OMX_COLOR_Format32bitBGRA8888;
- case OMX_COLOR_FormatYUV420Planar16:
- return mDstFormat == OMX_COLOR_FormatYUV444Y410;
-
case OMX_COLOR_FormatCbYCrY:
case OMX_QCOM_COLOR_FormatYVU420SemiPlanar:
case OMX_COLOR_FormatYUV420SemiPlanar:
@@ -311,84 +313,120 @@
return OK;
}
-void ColorConverter::writeToDst(
- void *dst_ptr, uint8_t *kAdjustedClip, bool uncropped,
- signed r1, signed g1, signed b1,
- signed r2, signed g2, signed b2) {
- switch (mDstFormat) {
+std::function<void (void *, void *, void *, size_t,
+ signed *, signed *, signed *, signed *)>
+getReadFromSrc(OMX_COLOR_FORMATTYPE srcFormat) {
+ switch(srcFormat) {
+ case OMX_COLOR_FormatYUV420Planar:
+ return [](void *src_y, void *src_u, void *src_v, size_t x,
+ signed *y1, signed *y2, signed *u, signed *v) {
+ *y1 = ((uint8_t*)src_y)[x] - 16;
+ *y2 = ((uint8_t*)src_y)[x + 1] - 16;
+ *u = ((uint8_t*)src_u)[x / 2] - 128;
+ *v = ((uint8_t*)src_v)[x / 2] - 128;
+ };
+ case OMX_COLOR_FormatYUV420Planar16:
+ return [](void *src_y, void *src_u, void *src_v, size_t x,
+ signed *y1, signed *y2, signed *u, signed *v) {
+ *y1 = (signed)(((uint16_t*)src_y)[x] >> 2) - 16;
+ *y2 = (signed)(((uint16_t*)src_y)[x + 1] >> 2) - 16;
+ *u = (signed)(((uint16_t*)src_u)[x / 2] >> 2) - 128;
+ *v = (signed)(((uint16_t*)src_v)[x / 2] >> 2) - 128;
+ };
+ default:
+ TRESPASS();
+ }
+ return nullptr;
+}
+
+std::function<void (void *, bool, signed, signed, signed, signed, signed, signed)>
+getWriteToDst(OMX_COLOR_FORMATTYPE dstFormat, uint8_t *kAdjustedClip) {
+ switch (dstFormat) {
case OMX_COLOR_Format16bitRGB565:
{
- uint32_t rgb1 =
- ((kAdjustedClip[r1] >> 3) << 11)
- | ((kAdjustedClip[g1] >> 2) << 5)
- | (kAdjustedClip[b1] >> 3);
+ return [kAdjustedClip](void *dst_ptr, bool uncropped,
+ signed r1, signed g1, signed b1,
+ signed r2, signed g2, signed b2) {
+ uint32_t rgb1 =
+ ((kAdjustedClip[r1] >> 3) << 11)
+ | ((kAdjustedClip[g1] >> 2) << 5)
+ | (kAdjustedClip[b1] >> 3);
- if (uncropped) {
- uint32_t rgb2 =
- ((kAdjustedClip[r2] >> 3) << 11)
- | ((kAdjustedClip[g2] >> 2) << 5)
- | (kAdjustedClip[b2] >> 3);
+ if (uncropped) {
+ uint32_t rgb2 =
+ ((kAdjustedClip[r2] >> 3) << 11)
+ | ((kAdjustedClip[g2] >> 2) << 5)
+ | (kAdjustedClip[b2] >> 3);
- *(uint32_t *)dst_ptr = (rgb2 << 16) | rgb1;
- } else {
- *(uint16_t *)dst_ptr = rgb1;
- }
- break;
+ *(uint32_t *)dst_ptr = (rgb2 << 16) | rgb1;
+ } else {
+ *(uint16_t *)dst_ptr = rgb1;
+ }
+ };
}
case OMX_COLOR_Format32BitRGBA8888:
{
- ((uint32_t *)dst_ptr)[0] =
- (kAdjustedClip[r1])
- | (kAdjustedClip[g1] << 8)
- | (kAdjustedClip[b1] << 16)
- | (0xFF << 24);
-
- if (uncropped) {
- ((uint32_t *)dst_ptr)[1] =
- (kAdjustedClip[r2])
- | (kAdjustedClip[g2] << 8)
- | (kAdjustedClip[b2] << 16)
+ return [kAdjustedClip](void *dst_ptr, bool uncropped,
+ signed r1, signed g1, signed b1,
+ signed r2, signed g2, signed b2) {
+ ((uint32_t *)dst_ptr)[0] =
+ (kAdjustedClip[r1])
+ | (kAdjustedClip[g1] << 8)
+ | (kAdjustedClip[b1] << 16)
| (0xFF << 24);
- }
- break;
+
+ if (uncropped) {
+ ((uint32_t *)dst_ptr)[1] =
+ (kAdjustedClip[r2])
+ | (kAdjustedClip[g2] << 8)
+ | (kAdjustedClip[b2] << 16)
+ | (0xFF << 24);
+ }
+ };
}
case OMX_COLOR_Format32bitBGRA8888:
{
- ((uint32_t *)dst_ptr)[0] =
- (kAdjustedClip[b1])
- | (kAdjustedClip[g1] << 8)
- | (kAdjustedClip[r1] << 16)
- | (0xFF << 24);
-
- if (uncropped) {
- ((uint32_t *)dst_ptr)[1] =
- (kAdjustedClip[b2])
- | (kAdjustedClip[g2] << 8)
- | (kAdjustedClip[r2] << 16)
+ return [kAdjustedClip](void *dst_ptr, bool uncropped,
+ signed r1, signed g1, signed b1,
+ signed r2, signed g2, signed b2) {
+ ((uint32_t *)dst_ptr)[0] =
+ (kAdjustedClip[b1])
+ | (kAdjustedClip[g1] << 8)
+ | (kAdjustedClip[r1] << 16)
| (0xFF << 24);
- }
- break;
+
+ if (uncropped) {
+ ((uint32_t *)dst_ptr)[1] =
+ (kAdjustedClip[b2])
+ | (kAdjustedClip[g2] << 8)
+ | (kAdjustedClip[r2] << 16)
+ | (0xFF << 24);
+ }
+ };
}
default:
- break;
+ TRESPASS();
}
+ return nullptr;
}
+
status_t ColorConverter::convertYUV420Planar(
const BitmapParams &src, const BitmapParams &dst) {
uint8_t *kAdjustedClip = initClip();
+ auto readFromSrc = getReadFromSrc(mSrcFormat);
+ auto writeToDst = getWriteToDst(mDstFormat, kAdjustedClip);
+
uint8_t *dst_ptr = (uint8_t *)dst.mBits
- + dst.mCropTop * dst.mStride + dst.mCropLeft * dst.mBpp;
+ + dst.mCropTop * dst.mStride + dst.mCropLeft * dst.mBpp;
- const uint8_t *src_y =
- (const uint8_t *)src.mBits + src.mCropTop * src.mStride + src.mCropLeft;
+ uint8_t *src_y = (uint8_t *)src.mBits
+ + src.mCropTop * src.mStride + src.mCropLeft * src.mBpp;
- const uint8_t *src_u =
- (const uint8_t *)src.mBits + src.mStride * src.mHeight
- + (src.mCropTop / 2) * (src.mStride / 2) + src.mCropLeft / 2;
+ uint8_t *src_u = (uint8_t *)src.mBits + src.mStride * src.mHeight
+ + (src.mCropTop / 2) * (src.mStride / 2) + src.mCropLeft / 2 * src.mBpp;
- const uint8_t *src_v =
- src_u + (src.mStride / 2) * (src.mHeight / 2);
+ uint8_t *src_v = src_u + (src.mStride / 2) * (src.mHeight / 2);
for (size_t y = 0; y < src.cropHeight(); ++y) {
for (size_t x = 0; x < src.cropWidth(); x += 2) {
@@ -410,11 +448,8 @@
// clip range -278 .. 535
- signed y1 = (signed)src_y[x] - 16;
- signed y2 = (signed)src_y[x + 1] - 16;
-
- signed u = (signed)src_u[x / 2] - 128;
- signed v = (signed)src_v[x / 2] - 128;
+ signed y1, y2, u, v;
+ readFromSrc(src_y, src_u, src_v, x, &y1, &y2, &u, &v);
signed u_b = u * 517;
signed u_g = -u * 100;
@@ -432,8 +467,7 @@
signed r2 = (tmp2 + v_r) / 256;
bool uncropped = x + 1 < src.cropWidth();
- (void)writeToDst(dst_ptr + x * dst.mBpp,
- kAdjustedClip, uncropped, r1, g1, b1, r2, g2, b2);
+ writeToDst(dst_ptr + x * dst.mBpp, uncropped, r1, g1, b1, r2, g2, b2);
}
src_y += src.mStride;
@@ -449,6 +483,15 @@
return OK;
}
+status_t ColorConverter::convertYUV420Planar16(
+ const BitmapParams &src, const BitmapParams &dst) {
+ if (mDstFormat == OMX_COLOR_FormatYUV444Y410) {
+ return convertYUV420Planar16ToY410(src, dst);
+ }
+
+ return convertYUV420Planar(src, dst);
+}
+
/*
* Pack 10-bit YUV into RGBA_1010102.
*
@@ -480,7 +523,7 @@
#if !USE_NEON_Y410
-status_t ColorConverter::convertYUV420Planar16(
+status_t ColorConverter::convertYUV420Planar16ToY410(
const BitmapParams &src, const BitmapParams &dst) {
uint8_t *dst_ptr = (uint8_t *)dst.mBits
+ dst.mCropTop * dst.mStride + dst.mCropLeft * dst.mBpp;
@@ -554,7 +597,7 @@
#else
-status_t ColorConverter::convertYUV420Planar16(
+status_t ColorConverter::convertYUV420Planar16ToY410(
const BitmapParams &src, const BitmapParams &dst) {
uint8_t *out = (uint8_t *)dst.mBits
+ dst.mCropTop * dst.mStride + dst.mCropLeft * dst.mBpp;
diff --git a/media/libstagefright/colorconversion/SoftwareRenderer.cpp b/media/libstagefright/colorconversion/SoftwareRenderer.cpp
index 838bc5f..657a05b 100644
--- a/media/libstagefright/colorconversion/SoftwareRenderer.cpp
+++ b/media/libstagefright/colorconversion/SoftwareRenderer.cpp
@@ -79,13 +79,26 @@
cropBottomNew = heightNew - 1;
}
+ // The native window buffer format for high-bitdepth content could
+ // depend on the dataspace also.
+ android_dataspace dataSpace;
+ bool dataSpaceChangedForPlanar16 = false;
+ if (colorFormatNew == OMX_COLOR_FormatYUV420Planar16
+ && format->findInt32("android._dataspace", (int32_t *)&dataSpace)
+ && dataSpace != mDataSpace) {
+ // Do not modify mDataSpace here, it's only modified at last
+ // when we do native_window_set_buffers_data_space().
+ dataSpaceChangedForPlanar16 = true;
+ }
+
if (static_cast<int32_t>(mColorFormat) == colorFormatNew &&
mWidth == widthNew &&
mHeight == heightNew &&
mCropLeft == cropLeftNew &&
mCropTop == cropTopNew &&
mCropRight == cropRightNew &&
- mCropBottom == cropBottomNew) {
+ mCropBottom == cropBottomNew &&
+ !dataSpaceChangedForPlanar16) {
// Nothing changed, no need to reset renderer.
return;
}
@@ -135,11 +148,16 @@
}
case OMX_COLOR_FormatYUV420Planar16:
{
- // Here we would convert OMX_COLOR_FormatYUV420Planar16 into
- // OMX_COLOR_FormatYUV444Y410, and put it inside a buffer with
- // format HAL_PIXEL_FORMAT_RGBA_1010102. Surfaceflinger will
- // use render engine to convert it to RGB if needed.
- halFormat = HAL_PIXEL_FORMAT_RGBA_1010102;
+ if (((dataSpace & HAL_DATASPACE_STANDARD_MASK) == HAL_DATASPACE_STANDARD_BT2020)
+ && ((dataSpace & HAL_DATASPACE_TRANSFER_MASK) == HAL_DATASPACE_TRANSFER_ST2084)) {
+ // Here we would convert OMX_COLOR_FormatYUV420Planar16 into
+ // OMX_COLOR_FormatYUV444Y410, and put it inside a buffer with
+ // format HAL_PIXEL_FORMAT_RGBA_1010102. Surfaceflinger will
+ // use render engine to convert it to RGB if needed.
+ halFormat = HAL_PIXEL_FORMAT_RGBA_1010102;
+ } else {
+ halFormat = HAL_PIXEL_FORMAT_YV12;
+ }
bufWidth = (mCropWidth + 1) & ~1;
bufHeight = (mCropHeight + 1) & ~1;
break;
@@ -155,7 +173,7 @@
mConverter = new ColorConverter(
mColorFormat, OMX_COLOR_Format16bitRGB565);
CHECK(mConverter->isValid());
- } else if (mColorFormat == OMX_COLOR_FormatYUV420Planar16) {
+ } else if (halFormat == HAL_PIXEL_FORMAT_RGBA_1010102) {
mConverter = new ColorConverter(
mColorFormat, OMX_COLOR_FormatYUV444Y410);
CHECK(mConverter->isValid());
@@ -300,6 +318,46 @@
dst_u += dst_c_stride;
dst_v += dst_c_stride;
}
+ } else if (mColorFormat == OMX_COLOR_FormatYUV420Planar16) {
+ const uint16_t *src_y = (const uint16_t *)data;
+ const uint16_t *src_u = (const uint16_t *)data + mWidth * mHeight;
+ const uint16_t *src_v = src_u + (mWidth / 2 * mHeight / 2);
+
+ src_y += mCropLeft + mCropTop * mWidth;
+ src_u += (mCropLeft + mCropTop * mWidth / 2) / 2;
+ src_v += (mCropLeft + mCropTop * mWidth / 2) / 2;
+
+ uint8_t *dst_y = (uint8_t *)dst;
+ size_t dst_y_size = buf->stride * buf->height;
+ size_t dst_c_stride = ALIGN(buf->stride / 2, 16);
+ size_t dst_c_size = dst_c_stride * buf->height / 2;
+ uint8_t *dst_v = dst_y + dst_y_size;
+ uint8_t *dst_u = dst_v + dst_c_size;
+
+ dst_y += mCropTop * buf->stride + mCropLeft;
+ dst_v += (mCropTop / 2) * dst_c_stride + mCropLeft / 2;
+ dst_u += (mCropTop / 2) * dst_c_stride + mCropLeft / 2;
+
+ for (int y = 0; y < mCropHeight; ++y) {
+ for (int x = 0; x < mCropWidth; ++x) {
+ dst_y[x] = (uint8_t)(src_y[x] >> 2);
+ }
+
+ src_y += mWidth;
+ dst_y += buf->stride;
+ }
+
+ for (int y = 0; y < (mCropHeight + 1) / 2; ++y) {
+ for (int x = 0; x < (mCropWidth + 1) / 2; ++x) {
+ dst_u[x] = (uint8_t)(src_u[x] >> 2);
+ dst_v[x] = (uint8_t)(src_v[x] >> 2);
+ }
+
+ src_u += mWidth / 2;
+ src_v += mWidth / 2;
+ dst_u += dst_c_stride;
+ dst_v += dst_c_stride;
+ }
} else if (mColorFormat == OMX_TI_COLOR_FormatYUV420PackedSemiPlanar
|| mColorFormat == OMX_COLOR_FormatYUV420SemiPlanar) {
const uint8_t *src_y = (const uint8_t *)data;
diff --git a/media/libstagefright/foundation/AMessage.cpp b/media/libstagefright/foundation/AMessage.cpp
index 3b84018..738f066 100644
--- a/media/libstagefright/foundation/AMessage.cpp
+++ b/media/libstagefright/foundation/AMessage.cpp
@@ -944,6 +944,40 @@
return mItems[index].mName;
}
+AMessage::ItemData AMessage::getEntryAt(size_t index) const {
+ ItemData it;
+ if (index < mNumItems) {
+ switch (mItems[index].mType) {
+ case kTypeInt32: it.set(mItems[index].u.int32Value); break;
+ case kTypeInt64: it.set(mItems[index].u.int64Value); break;
+ case kTypeSize: it.set(mItems[index].u.sizeValue); break;
+ case kTypeFloat: it.set(mItems[index].u.floatValue); break;
+ case kTypeDouble: it.set(mItems[index].u.doubleValue); break;
+ case kTypePointer: it.set(mItems[index].u.ptrValue); break;
+ case kTypeRect: it.set(mItems[index].u.rectValue); break;
+ case kTypeString: it.set(*mItems[index].u.stringValue); break;
+ case kTypeObject: {
+ sp<RefBase> obj = mItems[index].u.refValue;
+ it.set(obj);
+ break;
+ }
+ case kTypeMessage: {
+ sp<AMessage> msg = static_cast<AMessage *>(mItems[index].u.refValue);
+ it.set(msg);
+ break;
+ }
+ case kTypeBuffer: {
+ sp<ABuffer> buf = static_cast<ABuffer *>(mItems[index].u.refValue);
+ it.set(buf);
+ break;
+ }
+ default:
+ break;
+ }
+ }
+ return it;
+}
+
status_t AMessage::setEntryNameAt(size_t index, const char *name) {
if (index >= mNumItems) {
return BAD_INDEX;
@@ -964,6 +998,60 @@
return OK;
}
+status_t AMessage::setEntryAt(size_t index, const ItemData &item) {
+ AString stringValue;
+ sp<RefBase> refValue;
+ sp<AMessage> msgValue;
+ sp<ABuffer> bufValue;
+
+ if (index >= mNumItems) {
+ return BAD_INDEX;
+ }
+ if (!item.used()) {
+ return BAD_VALUE;
+ }
+ Item *dst = &mItems[index];
+ freeItemValue(dst);
+
+ // some values can be directly set with the getter. others need items to be allocated
+ if (item.find(&dst->u.int32Value)) {
+ dst->mType = kTypeInt32;
+ } else if (item.find(&dst->u.int64Value)) {
+ dst->mType = kTypeInt64;
+ } else if (item.find(&dst->u.sizeValue)) {
+ dst->mType = kTypeSize;
+ } else if (item.find(&dst->u.floatValue)) {
+ dst->mType = kTypeFloat;
+ } else if (item.find(&dst->u.doubleValue)) {
+ dst->mType = kTypeDouble;
+ } else if (item.find(&dst->u.ptrValue)) {
+ dst->mType = kTypePointer;
+ } else if (item.find(&dst->u.rectValue)) {
+ dst->mType = kTypeRect;
+ } else if (item.find(&stringValue)) {
+ dst->u.stringValue = new AString(stringValue);
+ dst->mType = kTypeString;
+ } else if (item.find(&refValue)) {
+ if (refValue != NULL) { refValue->incStrong(this); }
+ dst->u.refValue = refValue.get();
+ dst->mType = kTypeObject;
+ } else if (item.find(&msgValue)) {
+ if (msgValue != NULL) { msgValue->incStrong(this); }
+ dst->u.refValue = msgValue.get();
+ dst->mType = kTypeMessage;
+ } else if (item.find(&bufValue)) {
+ if (bufValue != NULL) { bufValue->incStrong(this); }
+ dst->u.refValue = bufValue.get();
+ dst->mType = kTypeBuffer;
+ } else {
+ // unsupported item - we should not be here.
+ dst->mType = kTypeInt32;
+ dst->u.int32Value = 0xDEADDEAD;
+ return BAD_TYPE;
+ }
+ return OK;
+}
+
status_t AMessage::removeEntryAt(size_t index) {
if (index >= mNumItems) {
return BAD_INDEX;
@@ -983,6 +1071,34 @@
return OK;
}
+void AMessage::setItem(const char *name, const ItemData &item) {
+ if (item.used()) {
+ Item *it = allocateItem(name);
+ if (it != nullptr) {
+ setEntryAt(it - mItems, item);
+ }
+ }
+}
+
+AMessage::ItemData AMessage::findItem(const char *name) const {
+ return getEntryAt(findEntryByName(name));
+}
+
+void AMessage::extend(const sp<AMessage> &other) {
+ // ignore null messages
+ if (other == nullptr) {
+ return;
+ }
+
+ for (size_t ix = 0; ix < other->mNumItems; ++ix) {
+ Item *it = allocateItem(other->mItems[ix].mName);
+ if (it != nullptr) {
+ ItemData data = other->getEntryAt(ix);
+ setEntryAt(it - mItems, data);
+ }
+ }
+}
+
size_t AMessage::findEntryByName(const char *name) const {
return name == nullptr ? countEntries() : findItemIndex(name, strlen(name));
}
diff --git a/media/libstagefright/foundation/include/media/stagefright/foundation/AData.h b/media/libstagefright/foundation/include/media/stagefright/foundation/AData.h
index 49aa0dc..5acc6d6 100644
--- a/media/libstagefright/foundation/include/media/stagefright/foundation/AData.h
+++ b/media/libstagefright/foundation/include/media/stagefright/foundation/AData.h
@@ -25,6 +25,9 @@
#include <media/stagefright/foundation/TypeTraits.h>
#include <media/stagefright/foundation/Flagged.h>
+#undef HIDE
+#define HIDE __attribute__((visibility("hidden")))
+
namespace android {
/**
@@ -78,7 +81,7 @@
* This class is needed as member function specialization is not allowed for a
* templated class.
*/
-struct _AUnion_impl {
+struct HIDE _AUnion_impl {
/**
* Calls placement constuctor for type T with arbitrary arguments for a storage at an address.
* Storage MUST be large enough to contain T.
@@ -113,13 +116,13 @@
/** Constructor specialization for void type */
template<>
-inline void _AUnion_impl::emplace<void>(size_t totalSize, void *addr) {
+HIDE inline void _AUnion_impl::emplace<void>(size_t totalSize, void *addr) {
memset(addr, 0, totalSize);
}
/** Destructor specialization for void type */
template<>
-inline void _AUnion_impl::del<void>(void *) {
+HIDE inline void _AUnion_impl::del<void>(void *) {
}
/// \endcond
@@ -221,7 +224,7 @@
template<
typename T,
bool=std::is_copy_assignable<T>::value>
-struct _AData_copier {
+struct HIDE _AData_copier {
static_assert(std::is_copy_assignable<T>::value, "T must be copy assignable here");
/**
@@ -294,7 +297,7 @@
*
*/
template<typename T>
-struct _AData_copier<T, false> {
+struct HIDE _AData_copier<T, false> {
static_assert(!std::is_copy_assignable<T>::value, "T must not be copy assignable here");
static_assert(std::is_copy_constructible<T>::value, "T must be copy constructible here");
@@ -318,7 +321,7 @@
template<
typename T,
bool=std::is_move_assignable<T>::value>
-struct _AData_mover {
+struct HIDE _AData_mover {
static_assert(std::is_move_assignable<T>::value, "T must be move assignable here");
/**
@@ -389,7 +392,7 @@
*
*/
template<typename T>
-struct _AData_mover<T, false> {
+struct HIDE _AData_mover<T, false> {
static_assert(!std::is_move_assignable<T>::value, "T must not be move assignable here");
static_assert(std::is_move_constructible<T>::value, "T must be move constructible here");
@@ -407,13 +410,13 @@
* \param Ts types to consider for the member
*/
template<typename Flagger, typename U, typename ...Ts>
-struct _AData_deleter;
+struct HIDE _AData_deleter;
/**
* Template specialization when there are still types to consider (T and rest)
*/
template<typename Flagger, typename U, typename T, typename ...Ts>
-struct _AData_deleter<Flagger, U, T, Ts...> {
+struct HIDE _AData_deleter<Flagger, U, T, Ts...> {
static bool del(typename Flagger::type flags, U &data) {
if (Flagger::canDeleteAs(flags, Flagger::flagFor((T*)0))) {
data.template del<T>();
@@ -427,7 +430,7 @@
* Template specialization when there are no more types to consider.
*/
template<typename Flagger, typename U>
-struct _AData_deleter<Flagger, U> {
+struct HIDE _AData_deleter<Flagger, U> {
inline static bool del(typename Flagger::type, U &) {
return false;
}
diff --git a/media/libstagefright/foundation/include/media/stagefright/foundation/AMessage.h b/media/libstagefright/foundation/include/media/stagefright/foundation/AMessage.h
index d90a0de..742651e 100644
--- a/media/libstagefright/foundation/include/media/stagefright/foundation/AMessage.h
+++ b/media/libstagefright/foundation/include/media/stagefright/foundation/AMessage.h
@@ -19,6 +19,7 @@
#define A_MESSAGE_H_
#include <media/stagefright/foundation/ABase.h>
+#include <media/stagefright/foundation/AData.h>
#include <media/stagefright/foundation/ALooper.h>
#include <utils/KeyedVector.h>
#include <utils/RefBase.h>
@@ -155,6 +156,9 @@
// their refcount incremented.
sp<AMessage> dup() const;
+ // Adds all items from other into this.
+ void extend(const sp<AMessage> &other);
+
// Performs a shallow or deep comparison of |this| and |other| and returns
// an AMessage with the differences.
// Warning: RefBase items, i.e. "objects" are _not_ copied but only have
@@ -180,10 +184,39 @@
kTypeBuffer,
};
+ struct Rect {
+ int32_t mLeft, mTop, mRight, mBottom;
+ };
+
size_t countEntries() const;
const char *getEntryNameAt(size_t index, Type *type) const;
/**
+ * Retrieves the item at a specific index.
+ */
+ typedef AData<
+ int32_t, int64_t, size_t, float, double, Rect, AString,
+ void *, sp<AMessage>, sp<ABuffer>, sp<RefBase>>::Basic ItemData;
+
+ /**
+ * Finds an item by name. This can be used if the type is unknown.
+ *
+ * \param name name of the item
+ * Returns an empty item if no item is present with that name.
+ */
+ ItemData findItem(const char *name) const;
+
+ /**
+ * Sets an item of arbitrary type. Does nothing if the item value is empty.
+ *
+ * \param name name of the item
+ * \param item value of the item
+ */
+ void setItem(const char *name, const ItemData &item);
+
+ ItemData getEntryAt(size_t index) const;
+
+ /**
* Finds an entry by name and returns its index.
*
* \retval countEntries() if the entry is not found.
@@ -204,6 +237,19 @@
status_t setEntryNameAt(size_t index, const char *name);
/**
+ * Sets the item of an entry based on index.
+ *
+ * \param index index of the entry
+ * \param item new item of the entry
+ *
+ * \retval OK the item was set successfully
+ * \retval BAD_INDEX invalid index
+ * \retval BAD_VALUE item is invalid (null)
+ * \retval BAD_TYPE type is unsupported (should not happen)
+ */
+ status_t setEntryAt(size_t index, const ItemData &item);
+
+ /**
* Removes an entry based on index.
*
* \param index index of the entry
@@ -227,10 +273,6 @@
wp<AHandler> mHandler;
wp<ALooper> mLooper;
- struct Rect {
- int32_t mLeft, mTop, mRight, mBottom;
- };
-
struct Item {
union {
int32_t int32Value;
diff --git a/media/libstagefright/foundation/include/media/stagefright/foundation/TypeTraits.h b/media/libstagefright/foundation/include/media/stagefright/foundation/TypeTraits.h
index 1250e9b..2041b22 100644
--- a/media/libstagefright/foundation/include/media/stagefright/foundation/TypeTraits.h
+++ b/media/libstagefright/foundation/include/media/stagefright/foundation/TypeTraits.h
@@ -19,6 +19,9 @@
#include <type_traits>
+#undef HIDE
+#define HIDE __attribute__((visibility("hidden")))
+
namespace android {
/**
@@ -31,7 +34,7 @@
* Type support utility class to check if a type is an integral type or an enum.
*/
template<typename T>
-struct is_integral_or_enum
+struct HIDE is_integral_or_enum
: std::integral_constant<bool, std::is_integral<T>::value || std::is_enum<T>::value> { };
/**
@@ -46,7 +49,7 @@
typename U=typename std::enable_if<is_integral_or_enum<T>::value>::type,
bool=std::is_enum<T>::value,
bool=std::is_integral<T>::value>
-struct underlying_integral_type {
+struct HIDE underlying_integral_type {
static_assert(!std::is_enum<T>::value, "T should not be enum here");
static_assert(!std::is_integral<T>::value, "T should not be integral here");
typedef U type;
@@ -54,7 +57,7 @@
/** Specialization for enums. */
template<typename T, typename U>
-struct underlying_integral_type<T, U, true, false> {
+struct HIDE underlying_integral_type<T, U, true, false> {
static_assert(std::is_enum<T>::value, "T should be enum here");
static_assert(!std::is_integral<T>::value, "T should not be integral here");
typedef typename std::underlying_type<T>::type type;
@@ -62,7 +65,7 @@
/** Specialization for non-enum std-integral types. */
template<typename T, typename U>
-struct underlying_integral_type<T, U, false, true> {
+struct HIDE underlying_integral_type<T, U, false, true> {
static_assert(!std::is_enum<T>::value, "T should not be enum here");
static_assert(std::is_integral<T>::value, "T should be integral here");
typedef T type;
@@ -72,7 +75,7 @@
* Type support utility class to check if the underlying integral type is signed.
*/
template<typename T>
-struct is_signed_integral
+struct HIDE is_signed_integral
: std::integral_constant<bool, std::is_signed<
typename underlying_integral_type<T, unsigned>::type>::value> { };
@@ -80,7 +83,7 @@
* Type support utility class to check if the underlying integral type is unsigned.
*/
template<typename T>
-struct is_unsigned_integral
+struct HIDE is_unsigned_integral
: std::integral_constant<bool, std::is_unsigned<
typename underlying_integral_type<T, signed>::type>::value> {
};
@@ -92,26 +95,26 @@
* member constant |value| equal to true. Otherwise value is false.
*/
template<typename T, typename ...Us>
-struct is_one_of;
+struct HIDE is_one_of;
/// \if 0
/**
* Template specialization when first type matches the searched type.
*/
template<typename T, typename ...Us>
-struct is_one_of<T, T, Us...> : std::true_type {};
+struct HIDE is_one_of<T, T, Us...> : std::true_type {};
/**
* Template specialization when first type does not match the searched type.
*/
template<typename T, typename U, typename ...Us>
-struct is_one_of<T, U, Us...> : is_one_of<T, Us...> {};
+struct HIDE is_one_of<T, U, Us...> : is_one_of<T, Us...> {};
/**
* Template specialization when there are no types to search.
*/
template<typename T>
-struct is_one_of<T> : std::false_type {};
+struct HIDE is_one_of<T> : std::false_type {};
/// \endif
/**
@@ -121,44 +124,44 @@
* Otherwise value is false.
*/
template<typename ...Us>
-struct are_unique;
+struct HIDE are_unique;
/// \if 0
/**
* Template specialization when there are no types.
*/
template<>
-struct are_unique<> : std::true_type {};
+struct HIDE are_unique<> : std::true_type {};
/**
* Template specialization when there is at least one type to check.
*/
template<typename T, typename ...Us>
-struct are_unique<T, Us...>
+struct HIDE are_unique<T, Us...>
: std::integral_constant<bool, are_unique<Us...>::value && !is_one_of<T, Us...>::value> {};
/// \endif
/// \if 0
template<size_t Base, typename T, typename ...Us>
-struct _find_first_impl;
+struct HIDE _find_first_impl;
/**
* Template specialization when there are no types to search.
*/
template<size_t Base, typename T>
-struct _find_first_impl<Base, T> : std::integral_constant<size_t, 0> {};
+struct HIDE _find_first_impl<Base, T> : std::integral_constant<size_t, 0> {};
/**
* Template specialization when T is the first type in Us.
*/
template<size_t Base, typename T, typename ...Us>
-struct _find_first_impl<Base, T, T, Us...> : std::integral_constant<size_t, Base> {};
+struct HIDE _find_first_impl<Base, T, T, Us...> : std::integral_constant<size_t, Base> {};
/**
* Template specialization when T is not the first type in Us.
*/
template<size_t Base, typename T, typename U, typename ...Us>
-struct _find_first_impl<Base, T, U, Us...>
+struct HIDE _find_first_impl<Base, T, U, Us...>
: std::integral_constant<size_t, _find_first_impl<Base + 1, T, Us...>::value> {};
/// \endif
@@ -169,7 +172,7 @@
* If T occurs in Us, index is the 1-based left-most index of T in Us. Otherwise, index is 0.
*/
template<typename T, typename ...Us>
-struct find_first {
+struct HIDE find_first {
static constexpr size_t index = _find_first_impl<1, T, Us...>::value;
};
@@ -180,13 +183,13 @@
* Adds a base index.
*/
template<size_t Base, typename T, typename ...Us>
-struct _find_first_convertible_to_helper;
+struct HIDE _find_first_convertible_to_helper;
/**
* Template specialization for when there are more types to consider
*/
template<size_t Base, typename T, typename U, typename ...Us>
-struct _find_first_convertible_to_helper<Base, T, U, Us...> {
+struct HIDE _find_first_convertible_to_helper<Base, T, U, Us...> {
static constexpr size_t index =
std::is_convertible<T, U>::value ? Base :
_find_first_convertible_to_helper<Base + 1, T, Us...>::index;
@@ -199,7 +202,7 @@
* Template specialization for when there are no more types to consider
*/
template<size_t Base, typename T>
-struct _find_first_convertible_to_helper<Base, T> {
+struct HIDE _find_first_convertible_to_helper<Base, T> {
static constexpr size_t index = 0;
typedef void type;
};
@@ -216,7 +219,7 @@
* \param Us types into which the conversion is considered
*/
template<typename T, typename ...Us>
-struct find_first_convertible_to : public _find_first_convertible_to_helper<1, T, Us...> { };
+struct HIDE find_first_convertible_to : public _find_first_convertible_to_helper<1, T, Us...> { };
} // namespace android
diff --git a/media/libstagefright/include/FrameDecoder.h b/media/libstagefright/include/FrameDecoder.h
index 3d4ea39..dc58c15 100644
--- a/media/libstagefright/include/FrameDecoder.h
+++ b/media/libstagefright/include/FrameDecoder.h
@@ -34,7 +34,11 @@
class VideoFrame;
struct MediaCodec;
-struct FrameDecoder {
+struct FrameRect {
+ int32_t left, top, right, bottom;
+};
+
+struct FrameDecoder : public RefBase {
FrameDecoder(
const AString &componentName,
const sp<MetaData> &trackMeta,
@@ -43,7 +47,7 @@
status_t init(
int64_t frameTimeUs, size_t numFrames, int option, int colorFormat);
- sp<IMemory> extractFrame();
+ sp<IMemory> extractFrame(FrameRect *rect = NULL);
status_t extractFrames(std::vector<sp<IMemory> >* frames);
@@ -59,6 +63,8 @@
int seekMode,
MediaSource::ReadOptions *options) = 0;
+ virtual status_t onExtractRect(FrameRect *rect) = 0;
+
virtual status_t onInputReceived(
const sp<MediaCodecBuffer> &codecBuffer,
MetaDataBase &sampleMeta,
@@ -110,6 +116,11 @@
int seekMode,
MediaSource::ReadOptions *options) override;
+ virtual status_t onExtractRect(FrameRect *rect) override {
+ // Rect extraction for sequences is not supported for now.
+ return (rect == NULL) ? OK : ERROR_UNSUPPORTED;
+ }
+
virtual status_t onInputReceived(
const sp<MediaCodecBuffer> &codecBuffer,
MetaDataBase &sampleMeta,
@@ -143,6 +154,8 @@
int seekMode,
MediaSource::ReadOptions *options) override;
+ virtual status_t onExtractRect(FrameRect *rect) override;
+
virtual status_t onInputReceived(
const sp<MediaCodecBuffer> &codecBuffer __unused,
MetaDataBase &sampleMeta __unused,
@@ -161,7 +174,10 @@
int32_t mHeight;
int32_t mGridRows;
int32_t mGridCols;
+ int32_t mTileWidth;
+ int32_t mTileHeight;
int32_t mTilesDecoded;
+ int32_t mTargetTiles;
};
} // namespace android
diff --git a/media/libstagefright/include/StagefrightMetadataRetriever.h b/media/libstagefright/include/StagefrightMetadataRetriever.h
index 209f850..f78e125 100644
--- a/media/libstagefright/include/StagefrightMetadataRetriever.h
+++ b/media/libstagefright/include/StagefrightMetadataRetriever.h
@@ -27,8 +27,10 @@
class DataSource;
class MediaExtractor;
+struct ImageDecoder;
+struct FrameRect;
-struct StagefrightMetadataRetriever : public MediaMetadataRetrieverInterface {
+struct StagefrightMetadataRetriever : public MediaMetadataRetrieverBase {
StagefrightMetadataRetriever();
virtual ~StagefrightMetadataRetriever();
@@ -44,6 +46,8 @@
int64_t timeUs, int option, int colorFormat, bool metaOnly);
virtual sp<IMemory> getImageAtIndex(
int index, int colorFormat, bool metaOnly, bool thumbnail);
+ virtual sp<IMemory> getImageRectAtIndex(
+ int index, int colorFormat, int left, int top, int right, int bottom);
virtual status_t getFrameAtIndex(
std::vector<sp<IMemory> >* frames,
int frameIndex, int numFrames, int colorFormat, bool metaOnly);
@@ -59,6 +63,8 @@
KeyedVector<int, String8> mMetaData;
MediaAlbumArt *mAlbumArt;
+ sp<ImageDecoder> mImageDecoder;
+ int mLastImageIndex;
void parseMetaData();
// Delete album art and clear metadata.
void clearMetadata();
@@ -66,6 +72,8 @@
status_t getFrameInternal(
int64_t timeUs, int numFrames, int option, int colorFormat, bool metaOnly,
sp<IMemory>* outFrame, std::vector<sp<IMemory> >* outFrames);
+ virtual sp<IMemory> getImageInternal(
+ int index, int colorFormat, bool metaOnly, bool thumbnail, FrameRect* rect);
StagefrightMetadataRetriever(const StagefrightMetadataRetriever &);
diff --git a/media/libstagefright/include/media/stagefright/ColorConverter.h b/media/libstagefright/include/media/stagefright/ColorConverter.h
index a6c8981..5b3543d 100644
--- a/media/libstagefright/include/media/stagefright/ColorConverter.h
+++ b/media/libstagefright/include/media/stagefright/ColorConverter.h
@@ -75,10 +75,16 @@
status_t convertYUV420Planar(
const BitmapParams &src, const BitmapParams &dst);
+ status_t convertYUV420PlanarUseLibYUV(
+ const BitmapParams &src, const BitmapParams &dst);
+
status_t convertYUV420Planar16(
const BitmapParams &src, const BitmapParams &dst);
- status_t convertYUV420PlanarUseLibYUV(
+ status_t convertYUV420Planar16ToY410(
+ const BitmapParams &src, const BitmapParams &dst);
+
+ status_t convertYUV420Planar16ToRGB(
const BitmapParams &src, const BitmapParams &dst);
status_t convertQCOMYUV420SemiPlanar(
@@ -90,10 +96,6 @@
status_t convertTIYUV420PackedSemiPlanar(
const BitmapParams &src, const BitmapParams &dst);
- void writeToDst(void *dst_ptr, uint8_t *kAdjustedClip, bool uncropped,
- signed r1, signed g1, signed b1,
- signed r2, signed g2, signed b2);
-
ColorConverter(const ColorConverter &);
ColorConverter &operator=(const ColorConverter &);
};
diff --git a/media/libstagefright/include/media/stagefright/MediaCodecConstants.h b/media/libstagefright/include/media/stagefright/MediaCodecConstants.h
new file mode 100644
index 0000000..3ef4c0e
--- /dev/null
+++ b/media/libstagefright/include/media/stagefright/MediaCodecConstants.h
@@ -0,0 +1,420 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef MEDIA_CODEC_CONSTANTS_H_
+#define MEDIA_CODEC_CONSTANTS_H_
+
+namespace {
+
+// from MediaCodecInfo.java
+constexpr int32_t AVCProfileBaseline = 0x01;
+constexpr int32_t AVCProfileMain = 0x02;
+constexpr int32_t AVCProfileExtended = 0x04;
+constexpr int32_t AVCProfileHigh = 0x08;
+constexpr int32_t AVCProfileHigh10 = 0x10;
+constexpr int32_t AVCProfileHigh422 = 0x20;
+constexpr int32_t AVCProfileHigh444 = 0x40;
+constexpr int32_t AVCProfileConstrainedBaseline = 0x10000;
+constexpr int32_t AVCProfileConstrainedHigh = 0x80000;
+
+constexpr int32_t AVCLevel1 = 0x01;
+constexpr int32_t AVCLevel1b = 0x02;
+constexpr int32_t AVCLevel11 = 0x04;
+constexpr int32_t AVCLevel12 = 0x08;
+constexpr int32_t AVCLevel13 = 0x10;
+constexpr int32_t AVCLevel2 = 0x20;
+constexpr int32_t AVCLevel21 = 0x40;
+constexpr int32_t AVCLevel22 = 0x80;
+constexpr int32_t AVCLevel3 = 0x100;
+constexpr int32_t AVCLevel31 = 0x200;
+constexpr int32_t AVCLevel32 = 0x400;
+constexpr int32_t AVCLevel4 = 0x800;
+constexpr int32_t AVCLevel41 = 0x1000;
+constexpr int32_t AVCLevel42 = 0x2000;
+constexpr int32_t AVCLevel5 = 0x4000;
+constexpr int32_t AVCLevel51 = 0x8000;
+constexpr int32_t AVCLevel52 = 0x10000;
+
+constexpr int32_t H263ProfileBaseline = 0x01;
+constexpr int32_t H263ProfileH320Coding = 0x02;
+constexpr int32_t H263ProfileBackwardCompatible = 0x04;
+constexpr int32_t H263ProfileISWV2 = 0x08;
+constexpr int32_t H263ProfileISWV3 = 0x10;
+constexpr int32_t H263ProfileHighCompression = 0x20;
+constexpr int32_t H263ProfileInternet = 0x40;
+constexpr int32_t H263ProfileInterlace = 0x80;
+constexpr int32_t H263ProfileHighLatency = 0x100;
+
+constexpr int32_t H263Level10 = 0x01;
+constexpr int32_t H263Level20 = 0x02;
+constexpr int32_t H263Level30 = 0x04;
+constexpr int32_t H263Level40 = 0x08;
+constexpr int32_t H263Level45 = 0x10;
+constexpr int32_t H263Level50 = 0x20;
+constexpr int32_t H263Level60 = 0x40;
+constexpr int32_t H263Level70 = 0x80;
+
+constexpr int32_t MPEG4ProfileSimple = 0x01;
+constexpr int32_t MPEG4ProfileSimpleScalable = 0x02;
+constexpr int32_t MPEG4ProfileCore = 0x04;
+constexpr int32_t MPEG4ProfileMain = 0x08;
+constexpr int32_t MPEG4ProfileNbit = 0x10;
+constexpr int32_t MPEG4ProfileScalableTexture = 0x20;
+constexpr int32_t MPEG4ProfileSimpleFace = 0x40;
+constexpr int32_t MPEG4ProfileSimpleFBA = 0x80;
+constexpr int32_t MPEG4ProfileBasicAnimated = 0x100;
+constexpr int32_t MPEG4ProfileHybrid = 0x200;
+constexpr int32_t MPEG4ProfileAdvancedRealTime = 0x400;
+constexpr int32_t MPEG4ProfileCoreScalable = 0x800;
+constexpr int32_t MPEG4ProfileAdvancedCoding = 0x1000;
+constexpr int32_t MPEG4ProfileAdvancedCore = 0x2000;
+constexpr int32_t MPEG4ProfileAdvancedScalable = 0x4000;
+constexpr int32_t MPEG4ProfileAdvancedSimple = 0x8000;
+
+constexpr int32_t MPEG4Level0 = 0x01;
+constexpr int32_t MPEG4Level0b = 0x02;
+constexpr int32_t MPEG4Level1 = 0x04;
+constexpr int32_t MPEG4Level2 = 0x08;
+constexpr int32_t MPEG4Level3 = 0x10;
+constexpr int32_t MPEG4Level3b = 0x18;
+constexpr int32_t MPEG4Level4 = 0x20;
+constexpr int32_t MPEG4Level4a = 0x40;
+constexpr int32_t MPEG4Level5 = 0x80;
+constexpr int32_t MPEG4Level6 = 0x100;
+
+constexpr int32_t MPEG2ProfileSimple = 0x00;
+constexpr int32_t MPEG2ProfileMain = 0x01;
+constexpr int32_t MPEG2Profile422 = 0x02;
+constexpr int32_t MPEG2ProfileSNR = 0x03;
+constexpr int32_t MPEG2ProfileSpatial = 0x04;
+constexpr int32_t MPEG2ProfileHigh = 0x05;
+
+constexpr int32_t MPEG2LevelLL = 0x00;
+constexpr int32_t MPEG2LevelML = 0x01;
+constexpr int32_t MPEG2LevelH14 = 0x02;
+constexpr int32_t MPEG2LevelHL = 0x03;
+constexpr int32_t MPEG2LevelHP = 0x04;
+
+constexpr int32_t AACObjectMain = 1;
+constexpr int32_t AACObjectLC = 2;
+constexpr int32_t AACObjectSSR = 3;
+constexpr int32_t AACObjectLTP = 4;
+constexpr int32_t AACObjectHE = 5;
+constexpr int32_t AACObjectScalable = 6;
+constexpr int32_t AACObjectERLC = 17;
+constexpr int32_t AACObjectERScalable = 20;
+constexpr int32_t AACObjectLD = 23;
+constexpr int32_t AACObjectHE_PS = 29;
+constexpr int32_t AACObjectELD = 39;
+constexpr int32_t AACObjectXHE = 42;
+
+constexpr int32_t VP8Level_Version0 = 0x01;
+constexpr int32_t VP8Level_Version1 = 0x02;
+constexpr int32_t VP8Level_Version2 = 0x04;
+constexpr int32_t VP8Level_Version3 = 0x08;
+
+constexpr int32_t VP8ProfileMain = 0x01;
+
+constexpr int32_t VP9Profile0 = 0x01;
+constexpr int32_t VP9Profile1 = 0x02;
+constexpr int32_t VP9Profile2 = 0x04;
+constexpr int32_t VP9Profile3 = 0x08;
+constexpr int32_t VP9Profile2HDR = 0x1000;
+constexpr int32_t VP9Profile3HDR = 0x2000;
+
+constexpr int32_t VP9Level1 = 0x1;
+constexpr int32_t VP9Level11 = 0x2;
+constexpr int32_t VP9Level2 = 0x4;
+constexpr int32_t VP9Level21 = 0x8;
+constexpr int32_t VP9Level3 = 0x10;
+constexpr int32_t VP9Level31 = 0x20;
+constexpr int32_t VP9Level4 = 0x40;
+constexpr int32_t VP9Level41 = 0x80;
+constexpr int32_t VP9Level5 = 0x100;
+constexpr int32_t VP9Level51 = 0x200;
+constexpr int32_t VP9Level52 = 0x400;
+constexpr int32_t VP9Level6 = 0x800;
+constexpr int32_t VP9Level61 = 0x1000;
+constexpr int32_t VP9Level62 = 0x2000;
+
+constexpr int32_t HEVCProfileMain = 0x01;
+constexpr int32_t HEVCProfileMain10 = 0x02;
+constexpr int32_t HEVCProfileMainStill = 0x04;
+constexpr int32_t HEVCProfileMain10HDR10 = 0x1000;
+
+constexpr int32_t HEVCMainTierLevel1 = 0x1;
+constexpr int32_t HEVCHighTierLevel1 = 0x2;
+constexpr int32_t HEVCMainTierLevel2 = 0x4;
+constexpr int32_t HEVCHighTierLevel2 = 0x8;
+constexpr int32_t HEVCMainTierLevel21 = 0x10;
+constexpr int32_t HEVCHighTierLevel21 = 0x20;
+constexpr int32_t HEVCMainTierLevel3 = 0x40;
+constexpr int32_t HEVCHighTierLevel3 = 0x80;
+constexpr int32_t HEVCMainTierLevel31 = 0x100;
+constexpr int32_t HEVCHighTierLevel31 = 0x200;
+constexpr int32_t HEVCMainTierLevel4 = 0x400;
+constexpr int32_t HEVCHighTierLevel4 = 0x800;
+constexpr int32_t HEVCMainTierLevel41 = 0x1000;
+constexpr int32_t HEVCHighTierLevel41 = 0x2000;
+constexpr int32_t HEVCMainTierLevel5 = 0x4000;
+constexpr int32_t HEVCHighTierLevel5 = 0x8000;
+constexpr int32_t HEVCMainTierLevel51 = 0x10000;
+constexpr int32_t HEVCHighTierLevel51 = 0x20000;
+constexpr int32_t HEVCMainTierLevel52 = 0x40000;
+constexpr int32_t HEVCHighTierLevel52 = 0x80000;
+constexpr int32_t HEVCMainTierLevel6 = 0x100000;
+constexpr int32_t HEVCHighTierLevel6 = 0x200000;
+constexpr int32_t HEVCMainTierLevel61 = 0x400000;
+constexpr int32_t HEVCHighTierLevel61 = 0x800000;
+constexpr int32_t HEVCMainTierLevel62 = 0x1000000;
+constexpr int32_t HEVCHighTierLevel62 = 0x2000000;
+
+constexpr int32_t DolbyVisionProfileDvavPer = 0x1;
+constexpr int32_t DolbyVisionProfileDvavPen = 0x2;
+constexpr int32_t DolbyVisionProfileDvheDer = 0x4;
+constexpr int32_t DolbyVisionProfileDvheDen = 0x8;
+constexpr int32_t DolbyVisionProfileDvheDtr = 0x10;
+constexpr int32_t DolbyVisionProfileDvheStn = 0x20;
+constexpr int32_t DolbyVisionProfileDvheDth = 0x40;
+constexpr int32_t DolbyVisionProfileDvheDtb = 0x80;
+constexpr int32_t DolbyVisionProfileDvheSt = 0x100;
+constexpr int32_t DolbyVisionProfileDvavSe = 0x200;
+
+constexpr int32_t DolbyVisionLevelHd24 = 0x1;
+constexpr int32_t DolbyVisionLevelHd30 = 0x2;
+constexpr int32_t DolbyVisionLevelFhd24 = 0x4;
+constexpr int32_t DolbyVisionLevelFhd30 = 0x8;
+constexpr int32_t DolbyVisionLevelFhd60 = 0x10;
+constexpr int32_t DolbyVisionLevelUhd24 = 0x20;
+constexpr int32_t DolbyVisionLevelUhd30 = 0x40;
+constexpr int32_t DolbyVisionLevelUhd48 = 0x80;
+constexpr int32_t DolbyVisionLevelUhd60 = 0x100;
+
+constexpr int32_t BITRATE_MODE_CBR = 2;
+constexpr int32_t BITRATE_MODE_CQ = 0;
+constexpr int32_t BITRATE_MODE_VBR = 1;
+
+constexpr int32_t COLOR_Format12bitRGB444 = 3;
+constexpr int32_t COLOR_Format16bitARGB1555 = 5;
+constexpr int32_t COLOR_Format16bitARGB4444 = 4;
+constexpr int32_t COLOR_Format16bitBGR565 = 7;
+constexpr int32_t COLOR_Format16bitRGB565 = 6;
+constexpr int32_t COLOR_Format18bitARGB1665 = 9;
+constexpr int32_t COLOR_Format18BitBGR666 = 41;
+constexpr int32_t COLOR_Format18bitRGB666 = 8;
+constexpr int32_t COLOR_Format19bitARGB1666 = 10;
+constexpr int32_t COLOR_Format24BitABGR6666 = 43;
+constexpr int32_t COLOR_Format24bitARGB1887 = 13;
+constexpr int32_t COLOR_Format24BitARGB6666 = 42;
+constexpr int32_t COLOR_Format24bitBGR888 = 12;
+constexpr int32_t COLOR_Format24bitRGB888 = 11;
+constexpr int32_t COLOR_Format25bitARGB1888 = 14;
+constexpr int32_t COLOR_Format32bitABGR8888 = 0x7F00A000;
+constexpr int32_t COLOR_Format32bitARGB8888 = 16;
+constexpr int32_t COLOR_Format32bitBGRA8888 = 15;
+constexpr int32_t COLOR_Format8bitRGB332 = 2;
+constexpr int32_t COLOR_FormatCbYCrY = 27;
+constexpr int32_t COLOR_FormatCrYCbY = 28;
+constexpr int32_t COLOR_FormatL16 = 36;
+constexpr int32_t COLOR_FormatL2 = 33;
+constexpr int32_t COLOR_FormatL24 = 37;
+constexpr int32_t COLOR_FormatL32 = 38;
+constexpr int32_t COLOR_FormatL4 = 34;
+constexpr int32_t COLOR_FormatL8 = 35;
+constexpr int32_t COLOR_FormatMonochrome = 1;
+constexpr int32_t COLOR_FormatRawBayer10bit = 31;
+constexpr int32_t COLOR_FormatRawBayer8bit = 30;
+constexpr int32_t COLOR_FormatRawBayer8bitcompressed = 32;
+constexpr int32_t COLOR_FormatRGBAFlexible = 0x7F36A888;
+constexpr int32_t COLOR_FormatRGBFlexible = 0x7F36B888;
+constexpr int32_t COLOR_FormatSurface = 0x7F000789;
+constexpr int32_t COLOR_FormatYCbYCr = 25;
+constexpr int32_t COLOR_FormatYCrYCb = 26;
+constexpr int32_t COLOR_FormatYUV411PackedPlanar = 18;
+constexpr int32_t COLOR_FormatYUV411Planar = 17;
+constexpr int32_t COLOR_FormatYUV420Flexible = 0x7F420888;
+constexpr int32_t COLOR_FormatYUV420PackedPlanar = 20;
+constexpr int32_t COLOR_FormatYUV420PackedSemiPlanar = 39;
+constexpr int32_t COLOR_FormatYUV420Planar = 19;
+constexpr int32_t COLOR_FormatYUV420SemiPlanar = 21;
+constexpr int32_t COLOR_FormatYUV422Flexible = 0x7F422888;
+constexpr int32_t COLOR_FormatYUV422PackedPlanar = 23;
+constexpr int32_t COLOR_FormatYUV422PackedSemiPlanar = 40;
+constexpr int32_t COLOR_FormatYUV422Planar = 22;
+constexpr int32_t COLOR_FormatYUV422SemiPlanar = 24;
+constexpr int32_t COLOR_FormatYUV444Flexible = 0x7F444888;
+constexpr int32_t COLOR_FormatYUV444Interleaved = 29;
+constexpr int32_t COLOR_QCOM_FormatYUV420SemiPlanar = 0x7fa30c00;
+constexpr int32_t COLOR_TI_FormatYUV420PackedSemiPlanar = 0x7f000100;
+
+constexpr char FEATURE_AdaptivePlayback[] = "adaptive-playback";
+constexpr char FEATURE_IntraRefresh[] = "intra-refresh";
+constexpr char FEATURE_PartialFrame[] = "partial-frame";
+constexpr char FEATURE_SecurePlayback[] = "secure-playback";
+constexpr char FEATURE_TunneledPlayback[] = "tunneled-playback";
+
+// from MediaFormat.java
+constexpr char MIMETYPE_VIDEO_VP8[] = "video/x-vnd.on2.vp8";
+constexpr char MIMETYPE_VIDEO_VP9[] = "video/x-vnd.on2.vp9";
+constexpr char MIMETYPE_VIDEO_AVC[] = "video/avc";
+constexpr char MIMETYPE_VIDEO_HEVC[] = "video/hevc";
+constexpr char MIMETYPE_VIDEO_MPEG4[] = "video/mp4v-es";
+constexpr char MIMETYPE_VIDEO_H263[] = "video/3gpp";
+constexpr char MIMETYPE_VIDEO_MPEG2[] = "video/mpeg2";
+constexpr char MIMETYPE_VIDEO_RAW[] = "video/raw";
+constexpr char MIMETYPE_VIDEO_DOLBY_VISION[] = "video/dolby-vision";
+constexpr char MIMETYPE_VIDEO_SCRAMBLED[] = "video/scrambled";
+
+constexpr char MIMETYPE_AUDIO_AMR_NB[] = "audio/3gpp";
+constexpr char MIMETYPE_AUDIO_AMR_WB[] = "audio/amr-wb";
+constexpr char MIMETYPE_AUDIO_MPEG[] = "audio/mpeg";
+constexpr char MIMETYPE_AUDIO_AAC[] = "audio/mp4a-latm";
+constexpr char MIMETYPE_AUDIO_QCELP[] = "audio/qcelp";
+constexpr char MIMETYPE_AUDIO_VORBIS[] = "audio/vorbis";
+constexpr char MIMETYPE_AUDIO_OPUS[] = "audio/opus";
+constexpr char MIMETYPE_AUDIO_G711_ALAW[] = "audio/g711-alaw";
+constexpr char MIMETYPE_AUDIO_G711_MLAW[] = "audio/g711-mlaw";
+constexpr char MIMETYPE_AUDIO_RAW[] = "audio/raw";
+constexpr char MIMETYPE_AUDIO_FLAC[] = "audio/flac";
+constexpr char MIMETYPE_AUDIO_MSGSM[] = "audio/gsm";
+constexpr char MIMETYPE_AUDIO_AC3[] = "audio/ac3";
+constexpr char MIMETYPE_AUDIO_EAC3[] = "audio/eac3";
+constexpr char MIMETYPE_AUDIO_SCRAMBLED[] = "audio/scrambled";
+
+constexpr char MIMETYPE_IMAGE_ANDROID_HEIC[] = "image/vnd.android.heic";
+
+constexpr char MIMETYPE_TEXT_CEA_608[] = "text/cea-608";
+constexpr char MIMETYPE_TEXT_CEA_708[] = "text/cea-708";
+constexpr char MIMETYPE_TEXT_SUBRIP[] = "application/x-subrip";
+constexpr char MIMETYPE_TEXT_VTT[] = "text/vtt";
+
+constexpr int32_t COLOR_RANGE_FULL = 1;
+constexpr int32_t COLOR_RANGE_LIMITED = 2;
+constexpr int32_t COLOR_STANDARD_BT2020 = 6;
+constexpr int32_t COLOR_STANDARD_BT601_NTSC = 4;
+constexpr int32_t COLOR_STANDARD_BT601_PAL = 2;
+constexpr int32_t COLOR_STANDARD_BT709 = 1;
+constexpr int32_t COLOR_TRANSFER_HLG = 7;
+constexpr int32_t COLOR_TRANSFER_LINEAR = 1;
+constexpr int32_t COLOR_TRANSFER_SDR_VIDEO = 3;
+constexpr int32_t COLOR_TRANSFER_ST2084 = 6;
+
+constexpr char KEY_AAC_DRC_ATTENUATION_FACTOR[] = "aac-drc-cut-level";
+constexpr char KEY_AAC_DRC_BOOST_FACTOR[] = "aac-drc-boost-level";
+constexpr char KEY_AAC_DRC_EFFECT_TYPE[] = "aac-drc-effect-type";
+constexpr char KEY_AAC_DRC_HEAVY_COMPRESSION[] = "aac-drc-heavy-compression";
+constexpr char KEY_AAC_DRC_TARGET_REFERENCE_LEVEL[] = "aac-target-ref-level";
+constexpr char KEY_AAC_ENCODED_TARGET_LEVEL[] = "aac-encoded-target-level";
+constexpr char KEY_AAC_MAX_OUTPUT_CHANNEL_COUNT[] = "aac-max-output-channel_count";
+constexpr char KEY_AAC_PROFILE[] = "aac-profile";
+constexpr char KEY_AAC_SBR_MODE[] = "aac-sbr-mode";
+constexpr char KEY_AUDIO_SESSION_ID[] = "audio-session-id";
+constexpr char KEY_BIT_RATE[] = "bitrate";
+constexpr char KEY_BITRATE_MODE[] = "bitrate-mode";
+constexpr char KEY_CA_SESSION_ID[] = "ca-session-id";
+constexpr char KEY_CA_SYSTEM_ID[] = "ca-system-id";
+constexpr char KEY_CAPTURE_RATE[] = "capture-rate";
+constexpr char KEY_CHANNEL_COUNT[] = "channel-count";
+constexpr char KEY_CHANNEL_MASK[] = "channel-mask";
+constexpr char KEY_COLOR_FORMAT[] = "color-format";
+constexpr char KEY_COLOR_RANGE[] = "color-range";
+constexpr char KEY_COLOR_STANDARD[] = "color-standard";
+constexpr char KEY_COLOR_TRANSFER[] = "color-transfer";
+constexpr char KEY_COMPLEXITY[] = "complexity";
+constexpr char KEY_DURATION[] = "durationUs";
+constexpr char KEY_FEATURE_[] = "feature-";
+constexpr char KEY_FLAC_COMPRESSION_LEVEL[] = "flac-compression-level";
+constexpr char KEY_FRAME_RATE[] = "frame-rate";
+constexpr char KEY_GRID_COLUMNS[] = "grid-cols";
+constexpr char KEY_GRID_ROWS[] = "grid-rows";
+constexpr char KEY_HDR_STATIC_INFO[] = "hdr-static-info";
+constexpr char KEY_HEIGHT[] = "height";
+constexpr char KEY_I_FRAME_INTERVAL[] = "i-frame-interval";
+constexpr char KEY_INTRA_REFRESH_PERIOD[] = "intra-refresh-period";
+constexpr char KEY_IS_ADTS[] = "is-adts";
+constexpr char KEY_IS_AUTOSELECT[] = "is-autoselect";
+constexpr char KEY_IS_DEFAULT[] = "is-default";
+constexpr char KEY_IS_FORCED_SUBTITLE[] = "is-forced-subtitle";
+constexpr char KEY_IS_TIMED_TEXT[] = "is-timed-text";
+constexpr char KEY_LANGUAGE[] = "language";
+constexpr char KEY_LATENCY[] = "latency";
+constexpr char KEY_LEVEL[] = "level";
+constexpr char KEY_MAX_BIT_RATE[] = "max-bitrate";
+constexpr char KEY_MAX_HEIGHT[] = "max-height";
+constexpr char KEY_MAX_INPUT_SIZE[] = "max-input-size";
+constexpr char KEY_MAX_WIDTH[] = "max-width";
+constexpr char KEY_MIME[] = "mime";
+constexpr char KEY_OPERATING_RATE[] = "operating-rate";
+constexpr char KEY_OUTPUT_REORDER_DEPTH[] = "output-reorder-depth";
+constexpr char KEY_PCM_ENCODING[] = "pcm-encoding";
+constexpr char KEY_PRIORITY[] = "priority";
+constexpr char KEY_PROFILE[] = "profile";
+constexpr char KEY_PUSH_BLANK_BUFFERS_ON_STOP[] = "push-blank-buffers-on-shutdown";
+constexpr char KEY_QUALITY[] = "quality";
+constexpr char KEY_REPEAT_PREVIOUS_FRAME_AFTER[] = "repeat-previous-frame-after";
+constexpr char KEY_ROTATION[] = "rotation-degrees";
+constexpr char KEY_SAMPLE_RATE[] = "sample-rate";
+constexpr char KEY_SLICE_HEIGHT[] = "slice-height";
+constexpr char KEY_STRIDE[] = "stride";
+constexpr char KEY_TEMPORAL_LAYERING[] = "ts-schema";
+constexpr char KEY_TILE_HEIGHT[] = "tile-height";
+constexpr char KEY_TILE_WIDTH[] = "tile-width";
+constexpr char KEY_TRACK_ID[] = "track-id";
+constexpr char KEY_WIDTH[] = "width";
+
+// from MediaCodec.java
+constexpr int32_t ERROR_INSUFFICIENT_OUTPUT_PROTECTION = 4;
+constexpr int32_t ERROR_INSUFFICIENT_RESOURCE = 1100;
+constexpr int32_t ERROR_KEY_EXPIRED = 2;
+constexpr int32_t ERROR_NO_KEY = 1;
+constexpr int32_t ERROR_RECLAIMED = 1101;
+constexpr int32_t ERROR_RESOURCE_BUSY = 3;
+constexpr int32_t ERROR_SESSION_NOT_OPENED = 5;
+constexpr int32_t ERROR_UNSUPPORTED_OPERATION = 6;
+constexpr char CODEC[] = "android.media.mediacodec.codec";
+constexpr char ENCODER[] = "android.media.mediacodec.encoder";
+constexpr char HEIGHT[] = "android.media.mediacodec.height";
+constexpr char MIME_TYPE[] = "android.media.mediacodec.mime";
+constexpr char MODE[] = "android.media.mediacodec.mode";
+constexpr char MODE_AUDIO[] = "audio";
+constexpr char MODE_VIDEO[] = "video";
+constexpr char ROTATION[] = "android.media.mediacodec.rotation";
+constexpr char SECURE[] = "android.media.mediacodec.secure";
+constexpr char WIDTH[] = "android.media.mediacodec.width";
+
+constexpr int32_t BUFFER_FLAG_CODEC_CONFIG = 2;
+constexpr int32_t BUFFER_FLAG_END_OF_STREAM = 4;
+constexpr int32_t BUFFER_FLAG_KEY_FRAME = 1;
+constexpr int32_t BUFFER_FLAG_PARTIAL_FRAME = 8;
+constexpr int32_t BUFFER_FLAG_SYNC_FRAME = 1;
+constexpr int32_t CONFIGURE_FLAG_ENCODE = 1;
+constexpr int32_t CRYPTO_MODE_AES_CBC = 2;
+constexpr int32_t CRYPTO_MODE_AES_CTR = 1;
+constexpr int32_t CRYPTO_MODE_UNENCRYPTED = 0;
+constexpr int32_t INFO_OUTPUT_BUFFERS_CHANGED = -3;
+constexpr int32_t INFO_OUTPUT_FORMAT_CHANGED = -2;
+constexpr int32_t INFO_TRY_AGAIN_LATER = -1;
+constexpr int32_t VIDEO_SCALING_MODE_SCALE_TO_FIT = 1;
+constexpr int32_t VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING = 2;
+constexpr char PARAMETER_KEY_REQUEST_SYNC_FRAME[] = "request-sync";
+constexpr char PARAMETER_KEY_SUSPEND[] = "drop-input-frames";
+constexpr char PARAMETER_KEY_VIDEO_BITRATE[] = "video-bitrate";
+
+}
+
+#endif // MEDIA_CODEC_CONSTANTS_H_
+
diff --git a/services/audioflinger/PatchPanel.h b/services/audioflinger/PatchPanel.h
index 5a68960..f4e43e2 100644
--- a/services/audioflinger/PatchPanel.h
+++ b/services/audioflinger/PatchPanel.h
@@ -46,6 +46,16 @@
template<typename ThreadType, typename TrackType>
class Endpoint {
public:
+ Endpoint() = default;
+ Endpoint(Endpoint&& other) { *this = std::move(other); }
+ Endpoint& operator=(Endpoint&& other) {
+ ALOGE_IF(mHandle != AUDIO_PATCH_HANDLE_NONE,
+ "A non empty Patch Endpoint leaked, handle %d", mHandle);
+ *this = other;
+ other.mHandle = AUDIO_PATCH_HANDLE_NONE;
+ return *this;
+ }
+
status_t checkTrack(TrackType *trackOrNull) const {
if (trackOrNull == nullptr) return NO_MEMORY;
return trackOrNull->initCheck();
@@ -82,6 +92,9 @@
void stopTrack() { if (mTrack) mTrack->stop(); }
private:
+ Endpoint(const Endpoint&) = default;
+ Endpoint& operator=(const Endpoint&) = default;
+
sp<ThreadType> mThread;
bool mCloseThread = true;
audio_patch_handle_t mHandle = AUDIO_PATCH_HANDLE_NONE;
@@ -92,6 +105,10 @@
public:
explicit Patch(const struct audio_patch &patch) : mAudioPatch(patch) {}
~Patch();
+ Patch(const Patch&) = delete;
+ Patch(Patch&&) = default;
+ Patch& operator=(const Patch&) = delete;
+ Patch& operator=(Patch&&) = default;
status_t createConnections(PatchPanel *panel);
void clearConnections(PatchPanel *panel);
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index d8363ee..5db3e44 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -4177,16 +4177,31 @@
// buffer size, then write 0s to the output
if (mSleepTimeUs == 0) {
if (mMixerStatus == MIXER_TRACKS_ENABLED) {
- mSleepTimeUs = mActiveSleepTimeUs >> sleepTimeShift;
- if (mSleepTimeUs < kMinThreadSleepTimeUs) {
- mSleepTimeUs = kMinThreadSleepTimeUs;
- }
- // reduce sleep time in case of consecutive application underruns to avoid
- // starving the audio HAL. As activeSleepTimeUs() is larger than a buffer
- // duration we would end up writing less data than needed by the audio HAL if
- // the condition persists.
- if (sleepTimeShift < kMaxThreadSleepTimeShift) {
- sleepTimeShift++;
+ if (mPipeSink.get() != nullptr && mPipeSink == mNormalSink) {
+ // Using the Monopipe availableToWrite, we estimate the
+ // sleep time to retry for more data (before we underrun).
+ MonoPipe *monoPipe = static_cast<MonoPipe *>(mPipeSink.get());
+ const ssize_t availableToWrite = mPipeSink->availableToWrite();
+ const size_t pipeFrames = monoPipe->maxFrames();
+ const size_t framesLeft = pipeFrames - max(availableToWrite, 0);
+ // HAL_framecount <= framesDelay ~ framesLeft / 2 <= Normal_Mixer_framecount
+ const size_t framesDelay = std::min(
+ mNormalFrameCount, max(framesLeft / 2, mFrameCount));
+ ALOGV("pipeFrames:%zu framesLeft:%zu framesDelay:%zu",
+ pipeFrames, framesLeft, framesDelay);
+ mSleepTimeUs = framesDelay * MICROS_PER_SECOND / mSampleRate;
+ } else {
+ mSleepTimeUs = mActiveSleepTimeUs >> sleepTimeShift;
+ if (mSleepTimeUs < kMinThreadSleepTimeUs) {
+ mSleepTimeUs = kMinThreadSleepTimeUs;
+ }
+ // reduce sleep time in case of consecutive application underruns to avoid
+ // starving the audio HAL. As activeSleepTimeUs() is larger than a buffer
+ // duration we would end up writing less data than needed by the audio HAL if
+ // the condition persists.
+ if (sleepTimeShift < kMaxThreadSleepTimeShift) {
+ sleepTimeShift++;
+ }
}
} else {
mSleepTimeUs = mIdleSleepTimeUs;
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index 49552a1..a7c4253 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -1571,9 +1571,11 @@
status_t status = NO_ERROR;
static const int32_t kMaxTries = 5;
int32_t tryCounter = kMaxTries;
+ const size_t originalFrameCount = buffer->mFrameCount;
do {
if (status == NOT_ENOUGH_DATA) {
restartIfDisabled();
+ buffer->mFrameCount = originalFrameCount; // cleared on error, must be restored.
}
status = mProxy->obtainBuffer(buffer, timeOut);
} while ((status == NOT_ENOUGH_DATA) && (tryCounter-- > 0));
diff --git a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
index 008d655..f6d407f 100644
--- a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
+++ b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
@@ -121,9 +121,11 @@
if (mAudioPolicyManager == NULL) {
return NO_INIT;
}
- if (!settingsAllowed()) {
+
+ if (!modifyAudioRoutingAllowed()) {
return PERMISSION_DENIED;
}
+
if (usage < 0 || usage >= AUDIO_POLICY_FORCE_USE_CNT) {
return BAD_VALUE;
}
@@ -340,6 +342,13 @@
return PERMISSION_DENIED;
}
+ if ((attr->source == AUDIO_SOURCE_VOICE_UPLINK ||
+ attr->source == AUDIO_SOURCE_VOICE_DOWNLINK ||
+ attr->source == AUDIO_SOURCE_VOICE_CALL) &&
+ !captureAudioOutputAllowed(pid, uid)) {
+ return PERMISSION_DENIED;
+ }
+
if ((attr->source == AUDIO_SOURCE_HOTWORD) && !captureHotwordAllowed(pid, uid)) {
return BAD_VALUE;
}
diff --git a/services/camera/libcameraservice/api1/client2/Parameters.cpp b/services/camera/libcameraservice/api1/client2/Parameters.cpp
index 8d8bcab..4a58620 100644
--- a/services/camera/libcameraservice/api1/client2/Parameters.cpp
+++ b/services/camera/libcameraservice/api1/client2/Parameters.cpp
@@ -1215,6 +1215,35 @@
fastInfo.maxJpegSize = getMaxSize(getAvailableJpegSizes());
+ isZslReprocessPresent = false;
+ camera_metadata_ro_entry_t availableCapabilities =
+ staticInfo(ANDROID_REQUEST_AVAILABLE_CAPABILITIES);
+ if (0 < availableCapabilities.count) {
+ const uint8_t *caps = availableCapabilities.data.u8;
+ for (size_t i = 0; i < availableCapabilities.count; i++) {
+ if (ANDROID_REQUEST_AVAILABLE_CAPABILITIES_PRIVATE_REPROCESSING ==
+ caps[i]) {
+ isZslReprocessPresent = true;
+ break;
+ }
+ }
+ }
+ if (isZslReprocessPresent) {
+ Vector<StreamConfiguration> scs = getStreamConfigurations();
+ Size maxPrivInputSize = {0, 0};
+ for (const auto& sc : scs) {
+ if (sc.isInput == ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_INPUT &&
+ sc.format == HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED) {
+ if (sc.width * sc.height > maxPrivInputSize.width * maxPrivInputSize.height) {
+ maxPrivInputSize = {sc.width, sc.height};
+ }
+ }
+ }
+ fastInfo.maxZslSize = maxPrivInputSize;
+ } else {
+ fastInfo.maxZslSize = {0, 0};
+ }
+
return OK;
}
diff --git a/services/camera/libcameraservice/api1/client2/Parameters.h b/services/camera/libcameraservice/api1/client2/Parameters.h
index fe725fd..e35b7a4 100644
--- a/services/camera/libcameraservice/api1/client2/Parameters.h
+++ b/services/camera/libcameraservice/api1/client2/Parameters.h
@@ -242,6 +242,7 @@
float minFocalLength;
bool useFlexibleYuv;
Size maxJpegSize;
+ Size maxZslSize;
} fastInfo;
// Quirks information; these are short-lived flags to enable workarounds for
diff --git a/services/camera/libcameraservice/api1/client2/ZslProcessor.cpp b/services/camera/libcameraservice/api1/client2/ZslProcessor.cpp
index 372a2c5..37e1495 100644
--- a/services/camera/libcameraservice/api1/client2/ZslProcessor.cpp
+++ b/services/camera/libcameraservice/api1/client2/ZslProcessor.cpp
@@ -231,63 +231,9 @@
return INVALID_OPERATION;
}
- if ((mZslStreamId != NO_STREAM) || (mInputStreamId != NO_STREAM)) {
- // Check if stream parameters have to change
- CameraDeviceBase::StreamInfo streamInfo;
- res = device->getStreamInfo(mZslStreamId, &streamInfo);
- if (res != OK) {
- ALOGE("%s: Camera %d: Error querying capture output stream info: "
- "%s (%d)", __FUNCTION__,
- client->getCameraId(), strerror(-res), res);
- return res;
- }
- if (streamInfo.width != (uint32_t)params.fastInfo.arrayWidth ||
- streamInfo.height != (uint32_t)params.fastInfo.arrayHeight) {
- if (mZslStreamId != NO_STREAM) {
- ALOGV("%s: Camera %d: Deleting stream %d since the buffer "
- "dimensions changed",
- __FUNCTION__, client->getCameraId(), mZslStreamId);
- res = device->deleteStream(mZslStreamId);
- if (res == -EBUSY) {
- ALOGV("%s: Camera %d: Device is busy, call updateStream again "
- " after it becomes idle", __FUNCTION__, mId);
- return res;
- } else if(res != OK) {
- ALOGE("%s: Camera %d: Unable to delete old output stream "
- "for ZSL: %s (%d)", __FUNCTION__,
- client->getCameraId(), strerror(-res), res);
- return res;
- }
- mZslStreamId = NO_STREAM;
- }
-
- if (mInputStreamId != NO_STREAM) {
- ALOGV("%s: Camera %d: Deleting stream %d since the buffer "
- "dimensions changed",
- __FUNCTION__, client->getCameraId(), mInputStreamId);
- res = device->deleteStream(mInputStreamId);
- if (res == -EBUSY) {
- ALOGV("%s: Camera %d: Device is busy, call updateStream again "
- " after it becomes idle", __FUNCTION__, mId);
- return res;
- } else if(res != OK) {
- ALOGE("%s: Camera %d: Unable to delete old output stream "
- "for ZSL: %s (%d)", __FUNCTION__,
- client->getCameraId(), strerror(-res), res);
- return res;
- }
- mInputStreamId = NO_STREAM;
- }
- if (nullptr != mInputProducer.get()) {
- mInputProducer->disconnect(NATIVE_WINDOW_API_CPU);
- mInputProducer.clear();
- }
- }
- }
-
if (mInputStreamId == NO_STREAM) {
- res = device->createInputStream(params.fastInfo.arrayWidth,
- params.fastInfo.arrayHeight, HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED,
+ res = device->createInputStream(params.fastInfo.maxZslSize.width,
+ params.fastInfo.maxZslSize.height, HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED,
&mInputStreamId);
if (res != OK) {
ALOGE("%s: Camera %d: Can't create input stream: "
@@ -309,8 +255,8 @@
mProducer->setName(String8("Camera2-ZslRingBufferConsumer"));
sp<Surface> outSurface = new Surface(producer);
- res = device->createStream(outSurface, params.fastInfo.arrayWidth,
- params.fastInfo.arrayHeight, HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED,
+ res = device->createStream(outSurface, params.fastInfo.maxZslSize.width,
+ params.fastInfo.maxZslSize.height, HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED,
HAL_DATASPACE_UNKNOWN, CAMERA3_STREAM_ROTATION_0, &mZslStreamId,
String8());
if (res != OK) {