Merge "mediacodec/mediaextractor: allow multiple Seccomp extensions" am: da4cb8cb6c am: 07d040d389
am: c9c32a8dcc
Change-Id: Ida14853e8bd5aa68e9ac7b21d5aa81338dfb0897
diff --git a/include/media/stagefright/AudioSource.h b/include/media/stagefright/AudioSource.h
index 8fc410d..2ec89a4 100644
--- a/include/media/stagefright/AudioSource.h
+++ b/include/media/stagefright/AudioSource.h
@@ -87,7 +87,6 @@
int64_t mStartTimeUs;
int16_t mMaxAmplitude;
int64_t mPrevSampleTimeUs;
- int64_t mFirstSampleTimeUs;
int64_t mInitialReadTimeUs;
int64_t mNumFramesReceived;
int64_t mNumClientOwnedBuffers;
diff --git a/include/media/stagefright/SimpleDecodingSource.h b/include/media/stagefright/SimpleDecodingSource.h
index 534097b..e6aee6a 100644
--- a/include/media/stagefright/SimpleDecodingSource.h
+++ b/include/media/stagefright/SimpleDecodingSource.h
@@ -71,12 +71,13 @@
// Construct this using a codec, source and looper.
SimpleDecodingSource(
const sp<MediaCodec> &codec, const sp<IMediaSource> &source, const sp<ALooper> &looper,
- bool usingSurface, const sp<AMessage> &format);
+ bool usingSurface, bool isVorbis, const sp<AMessage> &format);
sp<MediaCodec> mCodec;
sp<IMediaSource> mSource;
sp<ALooper> mLooper;
bool mUsingSurface;
+ bool mIsVorbis;
enum State {
INIT,
STARTED,
diff --git a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
index d7b5f65..b79bf2a 100644
--- a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
+++ b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
@@ -2357,8 +2357,12 @@
case EQ_PARAM_BAND_LEVEL:
param2 = *pParamTemp;
- if (param2 >= FIVEBAND_NUMBANDS) {
+ if (param2 < 0 || param2 >= FIVEBAND_NUMBANDS) {
status = -EINVAL;
+ if (param2 < 0) {
+ android_errorWriteLog(0x534e4554, "32438598");
+ ALOGW("\tERROR Equalizer_getParameter() EQ_PARAM_BAND_LEVEL band %d", param2);
+ }
break;
}
*(int16_t *)pValue = (int16_t)EqualizerGetBandLevel(pContext, param2);
@@ -2368,8 +2372,12 @@
case EQ_PARAM_CENTER_FREQ:
param2 = *pParamTemp;
- if (param2 >= FIVEBAND_NUMBANDS) {
+ if (param2 < 0 || param2 >= FIVEBAND_NUMBANDS) {
status = -EINVAL;
+ if (param2 < 0) {
+ android_errorWriteLog(0x534e4554, "32436341");
+ ALOGW("\tERROR Equalizer_getParameter() EQ_PARAM_CENTER_FREQ band %d", param2);
+ }
break;
}
*(int32_t *)pValue = EqualizerGetCentreFrequency(pContext, param2);
@@ -2379,8 +2387,12 @@
case EQ_PARAM_BAND_FREQ_RANGE:
param2 = *pParamTemp;
- if (param2 >= FIVEBAND_NUMBANDS) {
+ if (param2 < 0 || param2 >= FIVEBAND_NUMBANDS) {
status = -EINVAL;
+ if (param2 < 0) {
+ android_errorWriteLog(0x534e4554, "32247948");
+ ALOGW("\tERROR Equalizer_getParameter() EQ_PARAM_BAND_FREQ_RANGE band %d", param2);
+ }
break;
}
EqualizerGetBandFreqRange(pContext, param2, (uint32_t *)pValue, ((uint32_t *)pValue + 1));
diff --git a/media/libeffects/visualizer/EffectVisualizer.cpp b/media/libeffects/visualizer/EffectVisualizer.cpp
index 21fddb1..b7d27d6 100644
--- a/media/libeffects/visualizer/EffectVisualizer.cpp
+++ b/media/libeffects/visualizer/EffectVisualizer.cpp
@@ -59,6 +59,8 @@
#define DISCARD_MEASUREMENTS_TIME_MS 2000 // discard measurements older than this number of ms
+#define MAX_LATENCY_MS 3000 // 3 seconds of latency for audio pipeline
+
// maximum number of buffers for which we keep track of the measurements
#define MEASUREMENT_WINDOW_MAX_SIZE_IN_BUFFERS 25 // note: buffer index is stored in uint8_t
@@ -521,18 +523,29 @@
break;
}
switch (*(uint32_t *)p->data) {
- case VISUALIZER_PARAM_CAPTURE_SIZE:
- pContext->mCaptureSize = *((uint32_t *)p->data + 1);
- ALOGV("set mCaptureSize = %" PRIu32, pContext->mCaptureSize);
- break;
+ case VISUALIZER_PARAM_CAPTURE_SIZE: {
+ const uint32_t captureSize = *((uint32_t *)p->data + 1);
+ if (captureSize > VISUALIZER_CAPTURE_SIZE_MAX) {
+ android_errorWriteLog(0x534e4554, "31781965");
+ *(int32_t *)pReplyData = -EINVAL;
+ ALOGW("set mCaptureSize = %u > %u", captureSize, VISUALIZER_CAPTURE_SIZE_MAX);
+ } else {
+ pContext->mCaptureSize = captureSize;
+ ALOGV("set mCaptureSize = %u", captureSize);
+ }
+ } break;
case VISUALIZER_PARAM_SCALING_MODE:
pContext->mScalingMode = *((uint32_t *)p->data + 1);
ALOGV("set mScalingMode = %" PRIu32, pContext->mScalingMode);
break;
- case VISUALIZER_PARAM_LATENCY:
- pContext->mLatency = *((uint32_t *)p->data + 1);
- ALOGV("set mLatency = %" PRIu32, pContext->mLatency);
- break;
+ case VISUALIZER_PARAM_LATENCY: {
+ uint32_t latency = *((uint32_t *)p->data + 1);
+ if (latency > MAX_LATENCY_MS) {
+ latency = MAX_LATENCY_MS; // clamp latency b/31781965
+ }
+ pContext->mLatency = latency;
+ ALOGV("set mLatency = %u", latency);
+ } break;
case VISUALIZER_PARAM_MEASUREMENT_MODE:
pContext->mMeasurementMode = *((uint32_t *)p->data + 1);
ALOGV("set mMeasurementMode = %" PRIu32, pContext->mMeasurementMode);
@@ -571,10 +584,18 @@
if (latencyMs < 0) {
latencyMs = 0;
}
- const uint32_t deltaSmpl =
- pContext->mConfig.inputCfg.samplingRate * latencyMs / 1000;
- int32_t capturePoint = pContext->mCaptureIdx - captureSize - deltaSmpl;
+ uint32_t deltaSmpl = captureSize
+ + pContext->mConfig.inputCfg.samplingRate * latencyMs / 1000;
+ // large sample rate, latency, or capture size, could cause overflow.
+ // do not offset more than the size of buffer.
+ if (deltaSmpl > CAPTURE_BUF_SIZE) {
+ android_errorWriteLog(0x534e4554, "31781965");
+ deltaSmpl = CAPTURE_BUF_SIZE;
+ }
+
+ int32_t capturePoint = pContext->mCaptureIdx - deltaSmpl;
+ // a negative capturePoint means we wrap the buffer.
if (capturePoint < 0) {
uint32_t size = -capturePoint;
if (size > captureSize) {
diff --git a/media/libstagefright/AudioSource.cpp b/media/libstagefright/AudioSource.cpp
index 790c6da..efdee77 100644
--- a/media/libstagefright/AudioSource.cpp
+++ b/media/libstagefright/AudioSource.cpp
@@ -60,7 +60,6 @@
mStartTimeUs(0),
mMaxAmplitude(0),
mPrevSampleTimeUs(0),
- mFirstSampleTimeUs(-1ll),
mInitialReadTimeUs(0),
mNumFramesReceived(0),
mNumClientOwnedBuffers(0) {
@@ -277,12 +276,8 @@
}
if (mSampleRate != mOutSampleRate) {
- if (mFirstSampleTimeUs < 0) {
- mFirstSampleTimeUs = timeUs;
- }
- timeUs = mFirstSampleTimeUs + (timeUs - mFirstSampleTimeUs)
- * (int64_t)mSampleRate / (int64_t)mOutSampleRate;
- buffer->meta_data()->setInt64(kKeyTime, timeUs);
+ timeUs *= (int64_t)mSampleRate / (int64_t)mOutSampleRate;
+ buffer->meta_data()->setInt64(kKeyTime, timeUs);
}
*out = buffer;
diff --git a/media/libstagefright/SimpleDecodingSource.cpp b/media/libstagefright/SimpleDecodingSource.cpp
index de21c5e..2503a32 100644
--- a/media/libstagefright/SimpleDecodingSource.cpp
+++ b/media/libstagefright/SimpleDecodingSource.cpp
@@ -18,6 +18,7 @@
#include <media/ICrypto.h>
#include <media/stagefright/foundation/ABuffer.h>
+#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/foundation/ALooper.h>
#include <media/stagefright/foundation/AMessage.h>
#include <media/stagefright/foundation/AUtils.h>
@@ -74,7 +75,10 @@
err = codec->getOutputFormat(&format);
}
if (err == OK) {
- return new SimpleDecodingSource(codec, source, looper, surface != NULL, format);
+ return new SimpleDecodingSource(codec, source, looper,
+ surface != NULL,
+ strcmp(mime, MEDIA_MIMETYPE_AUDIO_VORBIS) == 0,
+ format);
}
ALOGD("Failed to configure codec '%s'", componentName.c_str());
@@ -90,11 +94,12 @@
SimpleDecodingSource::SimpleDecodingSource(
const sp<MediaCodec> &codec, const sp<IMediaSource> &source, const sp<ALooper> &looper,
- bool usingSurface, const sp<AMessage> &format)
+ bool usingSurface, bool isVorbis, const sp<AMessage> &format)
: mCodec(codec),
mSource(source),
mLooper(looper),
mUsingSurface(usingSurface),
+ mIsVorbis(isVorbis),
mProtectedState(format) {
mCodec->getName(&mComponentName);
}
@@ -280,16 +285,25 @@
if (in_buf != NULL) {
int64_t timestampUs = 0;
CHECK(in_buf->meta_data()->findInt64(kKeyTime, ×tampUs));
- if (in_buf->range_length() > in_buffer->capacity()) {
+ if (in_buf->range_length() + (mIsVorbis ? 4 : 0) > in_buffer->capacity()) {
ALOGW("'%s' received %zu input bytes for buffer of size %zu",
mComponentName.c_str(),
- in_buf->range_length(), in_buffer->capacity());
+ in_buf->range_length() + (mIsVorbis ? 4 : 0), in_buffer->capacity());
}
+ size_t cpLen = min(in_buf->range_length(), in_buffer->capacity());
memcpy(in_buffer->base(), (uint8_t *)in_buf->data() + in_buf->range_offset(),
- min(in_buf->range_length(), in_buffer->capacity()));
+ cpLen );
+
+ if (mIsVorbis) {
+ int32_t numPageSamples;
+ if (!in_buf->meta_data()->findInt32(kKeyValidSamples, &numPageSamples)) {
+ numPageSamples = -1;
+ }
+ memcpy(in_buffer->base() + cpLen, &numPageSamples, sizeof(numPageSamples));
+ }
res = mCodec->queueInputBuffer(
- in_ix, 0 /* offset */, in_buf->range_length(),
+ in_ix, 0 /* offset */, in_buf->range_length() + (mIsVorbis ? 4 : 0),
timestampUs, 0 /* flags */);
if (res != OK) {
ALOGI("[%s] failed to queue input buffer #%zu", mComponentName.c_str(), in_ix);
diff --git a/media/libstagefright/id3/ID3.cpp b/media/libstagefright/id3/ID3.cpp
index aaf6b3d..a0eb630 100644
--- a/media/libstagefright/id3/ID3.cpp
+++ b/media/libstagefright/id3/ID3.cpp
@@ -839,20 +839,21 @@
}
}
-static size_t StringSize(const uint8_t *start, uint8_t encoding) {
+// return includes terminator; if unterminated, returns > limit
+static size_t StringSize(const uint8_t *start, size_t limit, uint8_t encoding) {
+
if (encoding == 0x00 || encoding == 0x03) {
// ISO 8859-1 or UTF-8
- return strlen((const char *)start) + 1;
+ return strnlen((const char *)start, limit) + 1;
}
// UCS-2
size_t n = 0;
- while (start[n] != '\0' || start[n + 1] != '\0') {
+ while ((n+1 < limit) && (start[n] != '\0' || start[n + 1] != '\0')) {
n += 2;
}
-
- // Add size of null termination.
- return n + 2;
+ n += 2;
+ return n;
}
const void *
@@ -873,11 +874,19 @@
if (mVersion == ID3_V2_3 || mVersion == ID3_V2_4) {
uint8_t encoding = data[0];
- mime->setTo((const char *)&data[1]);
- size_t mimeLen = strlen((const char *)&data[1]) + 1;
+ size_t consumed = 1;
+
+ // *always* in an 8-bit encoding
+ size_t mimeLen = StringSize(&data[consumed], size - consumed, 0x00);
+ if (mimeLen > size - consumed) {
+ ALOGW("bogus album art size: mime");
+ return NULL;
+ }
+ mime->setTo((const char *)&data[consumed]);
+ consumed += mimeLen;
#if 0
- uint8_t picType = data[1 + mimeLen];
+ uint8_t picType = data[consumed];
if (picType != 0x03) {
// Front Cover Art
it.next();
@@ -885,20 +894,30 @@
}
#endif
- size_t descLen = StringSize(&data[2 + mimeLen], encoding);
-
- if (size < 2 ||
- size - 2 < mimeLen ||
- size - 2 - mimeLen < descLen) {
- ALOGW("bogus album art sizes");
+ consumed++;
+ if (consumed >= size) {
+ ALOGW("bogus album art size: pic type");
return NULL;
}
- *length = size - 2 - mimeLen - descLen;
- return &data[2 + mimeLen + descLen];
+ size_t descLen = StringSize(&data[consumed], size - consumed, encoding);
+ consumed += descLen;
+
+ if (consumed >= size) {
+ ALOGW("bogus album art size: description");
+ return NULL;
+ }
+
+ *length = size - consumed;
+
+ return &data[consumed];
} else {
uint8_t encoding = data[0];
+ if (size <= 5) {
+ return NULL;
+ }
+
if (!memcmp(&data[1], "PNG", 3)) {
mime->setTo("image/png");
} else if (!memcmp(&data[1], "JPG", 3)) {
@@ -918,7 +937,10 @@
}
#endif
- size_t descLen = StringSize(&data[5], encoding);
+ size_t descLen = StringSize(&data[5], size - 5, encoding);
+ if (descLen > size - 5) {
+ return NULL;
+ }
*length = size - 5 - descLen;
diff --git a/media/libstagefright/omx/GraphicBufferSource.cpp b/media/libstagefright/omx/GraphicBufferSource.cpp
index 1d819b5..267f24d 100644
--- a/media/libstagefright/omx/GraphicBufferSource.cpp
+++ b/media/libstagefright/omx/GraphicBufferSource.cpp
@@ -792,7 +792,8 @@
if (mPrevCaptureUs < 0ll) {
// first capture
mPrevCaptureUs = timeUs;
- mPrevFrameUs = timeUs;
+ // adjust the first sample timestamp.
+ mPrevFrameUs = (timeUs * mTimePerFrameUs) / mTimePerCaptureUs;
} else {
// snap to nearest capture point
int64_t nFrames = (timeUs + mTimePerCaptureUs / 2 - mPrevCaptureUs)
diff --git a/media/libstagefright/omx/OMXNodeInstance.cpp b/media/libstagefright/omx/OMXNodeInstance.cpp
index 8c10310..355a2dd 100644
--- a/media/libstagefright/omx/OMXNodeInstance.cpp
+++ b/media/libstagefright/omx/OMXNodeInstance.cpp
@@ -805,13 +805,6 @@
}
memset(data, 0, allottedSize);
- // if we are not connecting the buffers, the sizes must match
- if (allottedSize != params->size()) {
- CLOG_ERROR(useBuffer, BAD_VALUE, SIMPLE_BUFFER(portIndex, (size_t)allottedSize, data));
- delete[] data;
- return BAD_VALUE;
- }
-
buffer_meta = new BufferMeta(
params, portIndex, false /* copyToOmx */, false /* copyFromOmx */, data);
} else {
diff --git a/media/ndk/NdkMediaDrm.cpp b/media/ndk/NdkMediaDrm.cpp
index be71f43..166e6f1 100644
--- a/media/ndk/NdkMediaDrm.cpp
+++ b/media/ndk/NdkMediaDrm.cpp
@@ -221,8 +221,7 @@
static bool findId(AMediaDrm *mObj, const AMediaDrmByteArray &id, List<idvec_t>::iterator &iter) {
- iter = mObj->mIds.begin();
- while (iter != mObj->mIds.end()) {
+ for (iter = mObj->mIds.begin(); iter != mObj->mIds.end(); ++iter) {
if (iter->array() == id.ptr && iter->size() == id.length) {
return true;
}
diff --git a/services/audioflinger/Effects.cpp b/services/audioflinger/Effects.cpp
index 20d2896..3675998 100644
--- a/services/audioflinger/Effects.cpp
+++ b/services/audioflinger/Effects.cpp
@@ -602,6 +602,13 @@
android_errorWriteLog(0x534e4554, "29251553");
return -EINVAL;
}
+ if (cmdCode == EFFECT_CMD_GET_PARAM &&
+ (sizeof(effect_param_t) > cmdSize ||
+ ((effect_param_t *)pCmdData)->psize > cmdSize
+ - sizeof(effect_param_t))) {
+ android_errorWriteLog(0x534e4554, "32438594");
+ return -EINVAL;
+ }
if ((cmdCode == EFFECT_CMD_SET_PARAM
|| cmdCode == EFFECT_CMD_SET_PARAM_DEFERRED) && // DEFERRED not generally used
(sizeof(effect_param_t) > cmdSize
diff --git a/services/camera/libcameraservice/api1/client2/Parameters.cpp b/services/camera/libcameraservice/api1/client2/Parameters.cpp
index 9d5f33c..9a7839b 100644
--- a/services/camera/libcameraservice/api1/client2/Parameters.cpp
+++ b/services/camera/libcameraservice/api1/client2/Parameters.cpp
@@ -238,6 +238,10 @@
{
String8 supportedPreviewFpsRange;
for (size_t i=0; i < availableFpsRanges.count; i += 2) {
+ if (!isFpsSupported(availablePreviewSizes,
+ HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED, availableFpsRanges.data.i32[i+1])) {
+ continue;
+ }
if (i != 0) supportedPreviewFpsRange += ",";
supportedPreviewFpsRange += String8::format("(%d,%d)",
availableFpsRanges.data.i32[i] * kFpsToApiScale,
@@ -255,7 +259,10 @@
// from the [min, max] fps range use the max value
int fps = fpsFromRange(availableFpsRanges.data.i32[i],
availableFpsRanges.data.i32[i+1]);
-
+ if (!isFpsSupported(availablePreviewSizes,
+ HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED, fps)) {
+ continue;
+ }
// de-dupe frame rates
if (sortedPreviewFrameRates.indexOf(fps) == NAME_NOT_FOUND) {
sortedPreviewFrameRates.add(fps);
@@ -951,21 +958,40 @@
return NO_INIT;
}
+ // Get supported preview fps ranges.
+ Vector<Size> supportedPreviewSizes;
+ Vector<FpsRange> supportedPreviewFpsRanges;
+ const Size PREVIEW_SIZE_BOUND = { MAX_PREVIEW_WIDTH, MAX_PREVIEW_HEIGHT };
+ status_t res = getFilteredSizes(PREVIEW_SIZE_BOUND, &supportedPreviewSizes);
+ if (res != OK) return res;
+ for (size_t i=0; i < availableFpsRanges.count; i += 2) {
+ if (!isFpsSupported(supportedPreviewSizes,
+ HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED, availableFpsRanges.data.i32[i+1])) {
+ continue;
+ }
+ FpsRange fpsRange = {availableFpsRanges.data.i32[i], availableFpsRanges.data.i32[i+1]};
+ supportedPreviewFpsRanges.add(fpsRange);
+ }
+ if (supportedPreviewFpsRanges.size() == 0) {
+ ALOGE("Supported preview fps range is empty");
+ return NO_INIT;
+ }
+
int32_t bestStillCaptureFpsRange[2] = {
- availableFpsRanges.data.i32[0], availableFpsRanges.data.i32[1]
+ supportedPreviewFpsRanges[0].low, supportedPreviewFpsRanges[0].high
};
int32_t curRange =
bestStillCaptureFpsRange[1] - bestStillCaptureFpsRange[0];
- for (size_t i = 2; i < availableFpsRanges.count; i += 2) {
+ for (size_t i = 1; i < supportedPreviewFpsRanges.size(); i ++) {
int32_t nextRange =
- availableFpsRanges.data.i32[i + 1] -
- availableFpsRanges.data.i32[i];
+ supportedPreviewFpsRanges[i].high -
+ supportedPreviewFpsRanges[i].low;
if ( (nextRange > curRange) || // Maximize size of FPS range first
(nextRange == curRange && // Then minimize low-end FPS
- bestStillCaptureFpsRange[0] > availableFpsRanges.data.i32[i])) {
+ bestStillCaptureFpsRange[0] > supportedPreviewFpsRanges[i].low)) {
- bestStillCaptureFpsRange[0] = availableFpsRanges.data.i32[i];
- bestStillCaptureFpsRange[1] = availableFpsRanges.data.i32[i + 1];
+ bestStillCaptureFpsRange[0] = supportedPreviewFpsRanges[i].low;
+ bestStillCaptureFpsRange[1] = supportedPreviewFpsRanges[i].high;
curRange = nextRange;
}
}
@@ -2836,22 +2862,7 @@
int64_t Parameters::getJpegStreamMinFrameDurationNs(Parameters::Size size) {
if (mDeviceVersion >= CAMERA_DEVICE_API_VERSION_3_2) {
- const int STREAM_DURATION_SIZE = 4;
- const int STREAM_FORMAT_OFFSET = 0;
- const int STREAM_WIDTH_OFFSET = 1;
- const int STREAM_HEIGHT_OFFSET = 2;
- const int STREAM_DURATION_OFFSET = 3;
- camera_metadata_ro_entry_t availableStreamMinDurations =
- staticInfo(ANDROID_SCALER_AVAILABLE_MIN_FRAME_DURATIONS);
- for (size_t i = 0; i < availableStreamMinDurations.count; i+= STREAM_DURATION_SIZE) {
- int64_t format = availableStreamMinDurations.data.i64[i + STREAM_FORMAT_OFFSET];
- int64_t width = availableStreamMinDurations.data.i64[i + STREAM_WIDTH_OFFSET];
- int64_t height = availableStreamMinDurations.data.i64[i + STREAM_HEIGHT_OFFSET];
- int64_t duration = availableStreamMinDurations.data.i64[i + STREAM_DURATION_OFFSET];
- if (format == HAL_PIXEL_FORMAT_BLOB && width == size.width && height == size.height) {
- return duration;
- }
- }
+ return getMinFrameDurationNs(size, HAL_PIXEL_FORMAT_BLOB);
} else {
Vector<Size> availableJpegSizes = getAvailableJpegSizes();
size_t streamIdx = availableJpegSizes.size();
@@ -2875,6 +2886,57 @@
return -1;
}
+int64_t Parameters::getMinFrameDurationNs(Parameters::Size size, int fmt) {
+ if (mDeviceVersion < CAMERA_DEVICE_API_VERSION_3_2) {
+ ALOGE("Min frame duration for HAL 3.1 or lower is not supported");
+ return -1;
+ }
+
+ const int STREAM_DURATION_SIZE = 4;
+ const int STREAM_FORMAT_OFFSET = 0;
+ const int STREAM_WIDTH_OFFSET = 1;
+ const int STREAM_HEIGHT_OFFSET = 2;
+ const int STREAM_DURATION_OFFSET = 3;
+ camera_metadata_ro_entry_t availableStreamMinDurations =
+ staticInfo(ANDROID_SCALER_AVAILABLE_MIN_FRAME_DURATIONS);
+ for (size_t i = 0; i < availableStreamMinDurations.count; i+= STREAM_DURATION_SIZE) {
+ int64_t format = availableStreamMinDurations.data.i64[i + STREAM_FORMAT_OFFSET];
+ int64_t width = availableStreamMinDurations.data.i64[i + STREAM_WIDTH_OFFSET];
+ int64_t height = availableStreamMinDurations.data.i64[i + STREAM_HEIGHT_OFFSET];
+ int64_t duration = availableStreamMinDurations.data.i64[i + STREAM_DURATION_OFFSET];
+ if (format == fmt && width == size.width && height == size.height) {
+ return duration;
+ }
+ }
+
+ return -1;
+}
+
+bool Parameters::isFpsSupported(const Vector<Size> &sizes, int format, int32_t fps) {
+ // Skip the check for older HAL version, as the min duration is not supported.
+ if (mDeviceVersion < CAMERA_DEVICE_API_VERSION_3_2) {
+ return true;
+ }
+
+ // Get min frame duration for each size and check if the given fps range can be supported.
+ const int32_t FPS_MARGIN = 1;
+ for (size_t i = 0 ; i < sizes.size(); i++) {
+ int64_t minFrameDuration = getMinFrameDurationNs(sizes[i], format);
+ if (minFrameDuration <= 0) {
+ ALOGE("Min frame duration (%" PRId64") for size (%dx%d) and format 0x%x is wrong!",
+ minFrameDuration, sizes[i].width, sizes[i].height, format);
+ return false;
+ }
+ int32_t maxSupportedFps = 1e9 / minFrameDuration;
+ // Add some margin here for the case where the hal supports 29.xxxfps.
+ maxSupportedFps += FPS_MARGIN;
+ if (fps > maxSupportedFps) {
+ return false;
+ }
+ }
+ return true;
+}
+
SortedVector<int32_t> Parameters::getAvailableOutputFormats() {
SortedVector<int32_t> outputFormats; // Non-duplicated output formats
if (mDeviceVersion >= CAMERA_DEVICE_API_VERSION_3_2) {
diff --git a/services/camera/libcameraservice/api1/client2/Parameters.h b/services/camera/libcameraservice/api1/client2/Parameters.h
index 798aab5..c8ecbba 100644
--- a/services/camera/libcameraservice/api1/client2/Parameters.h
+++ b/services/camera/libcameraservice/api1/client2/Parameters.h
@@ -115,6 +115,11 @@
int32_t height;
};
+ struct FpsRange {
+ int32_t low;
+ int32_t high;
+ };
+
int32_t exposureCompensation;
bool autoExposureLock;
bool autoWhiteBalanceLock;
@@ -390,6 +395,15 @@
// return -1 if input jpeg size cannot be found in supported size list
int64_t getJpegStreamMinFrameDurationNs(Parameters::Size size);
+ // Helper function to get minimum frame duration for a size/format combination
+ // return -1 if input size/format combination cannot be found.
+ int64_t getMinFrameDurationNs(Parameters::Size size, int format);
+
+ // Helper function to check if a given fps is supported by all the sizes with
+ // the same format.
+ // return true if the device doesn't support min frame duration metadata tag.
+ bool isFpsSupported(const Vector<Size> &size, int format, int32_t fps);
+
// Helper function to get non-duplicated available output formats
SortedVector<int32_t> getAvailableOutputFormats();
// Helper function to get available output jpeg sizes
diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp
index 73a4124..bfa04f6 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
@@ -2222,6 +2222,14 @@
}
}
+void Camera3Device::removeInFlightMapEntryLocked(int idx) {
+ mInFlightMap.removeItemsAt(idx, 1);
+
+ // Indicate idle inFlightMap to the status tracker
+ if (mInFlightMap.size() == 0) {
+ mStatusTracker->markComponentIdle(mInFlightStatusId, Fence::NO_FENCE);
+ }
+}
void Camera3Device::removeInFlightRequestIfReadyLocked(int idx) {
@@ -2257,13 +2265,7 @@
returnOutputBuffers(request.pendingOutputBuffers.array(),
request.pendingOutputBuffers.size(), 0);
- mInFlightMap.removeItemsAt(idx, 1);
-
- // Indicate idle inFlightMap to the status tracker
- if (mInFlightMap.size() == 0) {
- mStatusTracker->markComponentIdle(mInFlightStatusId, Fence::NO_FENCE);
- }
-
+ removeInFlightMapEntryLocked(idx);
ALOGVV("%s: removed frame %d from InFlightMap", __FUNCTION__, frameNumber);
}
@@ -3438,6 +3440,20 @@
captureRequest->mResultExtras);
}
}
+
+ // Remove yet-to-be submitted inflight request from inflightMap
+ {
+ sp<Camera3Device> parent = mParent.promote();
+ if (parent != NULL) {
+ Mutex::Autolock l(parent->mInFlightLock);
+ ssize_t idx = parent->mInFlightMap.indexOfKey(captureRequest->mResultExtras.frameNumber);
+ if (idx >= 0) {
+ ALOGV("%s: Remove inflight request from queue: frameNumber %" PRId64,
+ __FUNCTION__, captureRequest->mResultExtras.frameNumber);
+ parent->removeInFlightMapEntryLocked(idx);
+ }
+ }
+ }
}
Mutex::Autolock l(mRequestLock);
diff --git a/services/camera/libcameraservice/device3/Camera3Device.h b/services/camera/libcameraservice/device3/Camera3Device.h
index 33429a6..87c43f3 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.h
+++ b/services/camera/libcameraservice/device3/Camera3Device.h
@@ -849,6 +849,9 @@
/**** Scope for mInFlightLock ****/
+ // Remove the in-flight map entry of the given index from mInFlightMap.
+ // It must only be called with mInFlightLock held.
+ void removeInFlightMapEntryLocked(int idx);
// Remove the in-flight request of the given index from mInFlightMap
// if it's no longer needed. It must only be called with mInFlightLock held.
void removeInFlightRequestIfReadyLocked(int idx);